@visulima/cerebro 3.0.0-alpha.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +591 -0
  2. package/LICENSE.md +1295 -3950
  3. package/README.md +182 -2
  4. package/dist/commands/completion-command.d.ts +6 -5
  5. package/dist/commands/completion-command.js +5 -203
  6. package/dist/commands/help-command.d.ts +10 -9
  7. package/dist/commands/help-command.js +1 -3
  8. package/dist/commands/readme-command.d.ts +6 -5
  9. package/dist/commands/readme-command.js +32 -330
  10. package/dist/commands/version-command.d.ts +4 -3
  11. package/dist/commands/version-command.js +1 -18
  12. package/dist/index.d.ts +516 -95
  13. package/dist/index.js +1 -7
  14. package/dist/logger/create-pail-logger.d.ts +770 -8
  15. package/dist/logger/create-pail-logger.js +1 -34
  16. package/dist/packem_chunks/has-new-version.js +1 -259
  17. package/dist/packem_shared/Cerebro-Czc4t-75.js +4 -0
  18. package/dist/packem_shared/VERBOSITY_DEBUG-XPultrIA.js +1 -0
  19. package/dist/packem_shared/VisulimaError-C90oeIMu.js +76 -0
  20. package/dist/packem_shared/VisulimaError-DTMgXonA-CzaryRgZ.js +1 -0
  21. package/dist/packem_shared/cerebro-error-BjBcYVRO.js +1 -0
  22. package/dist/packem_shared/command.d-DbhtfXF4.d.ts +639 -0
  23. package/dist/packem_shared/index-B7-8G-9s.js +29 -0
  24. package/dist/packem_shared/index.d-BL4NtVR3.d.ts +127 -0
  25. package/dist/packem_shared/lazyNamed-DMUm8mZe.js +1 -0
  26. package/dist/packem_shared/renderError-B3ePOoBG-BmZlyMcr.js +25 -0
  27. package/dist/packem_shared/runtime-process-Dmz0vCJy.js +1 -0
  28. package/dist/packem_shared/split-by-case-Dbpgd7rf.js +1 -0
  29. package/dist/plugins/error-handler-plugin.d.ts +21 -19
  30. package/dist/plugins/error-handler-plugin.js +1 -636
  31. package/dist/plugins/runtime-version-check-plugin.d.ts +22 -20
  32. package/dist/plugins/runtime-version-check-plugin.js +1 -77
  33. package/dist/plugins/update-notifier/update-notifier-plugin.d.ts +28 -8
  34. package/dist/plugins/update-notifier/update-notifier-plugin.js +1 -517
  35. package/dist/util/general/compile-cache.d.ts +41 -0
  36. package/dist/util/general/compile-cache.js +1 -0
  37. package/dist/util/general/heap-tuning.d.ts +18 -0
  38. package/dist/util/general/heap-tuning.js +1 -0
  39. package/package.json +33 -28
  40. package/dist/cli.d.ts +0 -203
  41. package/dist/constants.d.ts +0 -29
  42. package/dist/default-env.d.ts +0 -7
  43. package/dist/default-options.d.ts +0 -3
  44. package/dist/empty-toolbox.d.ts +0 -15
  45. package/dist/errors/cerebro-error.d.ts +0 -10
  46. package/dist/errors/command-not-found-error.d.ts +0 -9
  47. package/dist/errors/command-validation-error.d.ts +0 -10
  48. package/dist/errors/completion-error.d.ts +0 -9
  49. package/dist/errors/conflicting-options-error.d.ts +0 -10
  50. package/dist/errors/plugin-error.d.ts +0 -9
  51. package/dist/errors/update-notifier-error.d.ts +0 -7
  52. package/dist/packem_shared/Cerebro-C2mnCyQf.js +0 -3313
  53. package/dist/packem_shared/VERBOSITY_QUIET-Dp46zlLW.js +0 -10
  54. package/dist/packem_shared/VisulimaError-DA7QsCxH.js +0 -34
  55. package/dist/packem_shared/cerebro-error-GmJ3jN7Q.js +0 -16
  56. package/dist/packem_shared/help-command-BY7rQUvM.js +0 -249
  57. package/dist/packem_shared/index-C2-8b3A4.js +0 -259
  58. package/dist/packem_shared/runtime-process-B6ZplyWn.js +0 -187
  59. package/dist/plugin-manager.d.ts +0 -53
  60. package/dist/plugins/update-notifier/cache.d.ts +0 -11
  61. package/dist/plugins/update-notifier/get-distribution-version.d.ts +0 -2
  62. package/dist/plugins/update-notifier/has-new-version.d.ts +0 -14
  63. package/dist/types/cli.d.ts +0 -102
  64. package/dist/types/command-line-usage.d.ts +0 -37
  65. package/dist/types/command.d.ts +0 -136
  66. package/dist/types/option-types.d.ts +0 -83
  67. package/dist/types/options.d.ts +0 -4
  68. package/dist/types/plugin.d.ts +0 -53
  69. package/dist/types/toolbox.d.ts +0 -96
  70. package/dist/util/arg-processing/get-boolean-values.d.ts +0 -7
  71. package/dist/util/arg-processing/get-parameter-option.d.ts +0 -7
  72. package/dist/util/arg-processing/map-option-type-label.d.ts +0 -3
  73. package/dist/util/arg-processing/option-is-boolean.d.ts +0 -9
  74. package/dist/util/arg-processing/remove-boolean-values.d.ts +0 -9
  75. package/dist/util/command-line-commands.d.ts +0 -10
  76. package/dist/util/command-line-usage/get-terminal-width.d.ts +0 -7
  77. package/dist/util/command-line-usage/index.d.ts +0 -3
  78. package/dist/util/command-line-usage/section/base-section.d.ts +0 -8
  79. package/dist/util/command-line-usage/section/content-section.d.ts +0 -65
  80. package/dist/util/command-line-usage/section/option-list-section.d.ts +0 -44
  81. package/dist/util/command-processing/command-processor.d.ts +0 -37
  82. package/dist/util/command-processing/command-validation.d.ts +0 -17
  83. package/dist/util/command-processing/nested-command-parser.d.ts +0 -25
  84. package/dist/util/command-processing/option-processor.d.ts +0 -44
  85. package/dist/util/data-processing/list-missing-arguments.d.ts +0 -15
  86. package/dist/util/data-processing/merge-arguments.d.ts +0 -7
  87. package/dist/util/general/find-alternatives.d.ts +0 -8
  88. package/dist/util/general/hide-bin.d.ts +0 -2
  89. package/dist/util/general/parse-raw-command.d.ts +0 -7
  90. package/dist/util/general/register-exception-handler.d.ts +0 -9
  91. package/dist/util/general/runtime-process.d.ts +0 -65
  92. package/dist/util/general/semver-gt.d.ts +0 -2
  93. package/dist/util/general/validate-input.d.ts +0 -24
  94. package/dist/util/process-env-variables.d.ts +0 -9
  95. package/dist/util/security.d.ts +0 -58
  96. package/dist/util/text-processing/template-format.d.ts +0 -5
package/README.md CHANGED
@@ -158,16 +158,45 @@ You should see help output and command execution based on the options provided:
158
158
 
159
159
  ![Cli Output](./__assets__/cli_output.png)
160
160
 
161
+ ## Lazy commands
162
+
163
+ For CLIs with many subcommands or heavy per-command dependencies, you can defer importing each handler until the command is actually invoked. Declare the metadata inline and point `loader` at a dynamic `import()`:
164
+
165
+ ```ts
166
+ // commands/build.ts
167
+ export default ({ logger, options }) => {
168
+ logger.info(`Building to ${options.output ?? "dist"}`);
169
+ };
170
+ ```
171
+
172
+ ```ts
173
+ // index.ts
174
+ cli.addCommand({
175
+ name: "build",
176
+ description: "Build the project",
177
+ options: [{ name: "output", alias: "o", type: String, description: "Output directory" }],
178
+ argument: { name: "target", type: String },
179
+ loader: () => import("./commands/build"),
180
+ });
181
+ ```
182
+
183
+ `loader` is a zero-argument function that returns a promise resolving to a module — typically `() => import("./path")`. The handler module's **default export** is the toolbox-receiving function. Help, completion, and option validation work entirely from the metadata you declared on `addCommand` and never trigger the loader. The first invocation of the command imports the module; subsequent calls reuse the cached handler.
184
+
185
+ A command may declare either `execute` or `loader`, but not both. If a loader rejects or returns a module without a default-exported function, a `CommandLoaderError` is thrown.
186
+
161
187
  ## Toolbox API
162
188
 
163
189
  When your command's `execute` function is called, it receives a toolbox object with various utilities and context. Here's what you can access:
164
190
 
165
191
  ### Core Properties
166
192
 
167
- - **`logger`**: Logger instance for output (debug, info, warn, error)
193
+ - **`logger`**: Logger instance for output (debug, info, warn, error). Verbosity-gated via `--quiet`/`--verbose`/`--debug`.
194
+ - **`console`**: Alias for `logger`. Use it when porting goke-style code or when a `console`-named parameter reads more naturally.
168
195
  - **`options`**: Parsed command-line options (camelCase keys)
169
196
  - **`argument`**: Array of positional arguments
170
- - **`env`**: Environment variables (camelCase keys)
197
+ - **`env`**: Environment variables (camelCase keys) processed from the command's `env: [...]` definitions
198
+ - **`fs`**: Injected filesystem adapter (subset of `node:fs/promises`). Swap via `CliOptions.fs` for tests or sandboxed runtimes.
199
+ - **`process`**: Runtime snapshot — `cwd`, `env`, `argv`, `stdin`, `exit`, `platform`, `arch`. Prefer this over the global `process` so commands stay portable across Node, Deno, Bun, and mocked test runtimes.
171
200
  - **`runtime`**: Reference to the CLI instance
172
201
  - **`argv`**: Original command-line arguments array
173
202
 
@@ -215,6 +244,157 @@ cli.addCommand({
215
244
  });
216
245
  ```
217
246
 
247
+ ## Runtime Injection
248
+
249
+ Commands receive an injected `{ fs, console, process }` context on the toolbox. Prefer reading from these over reaching for `node:fs/promises`, the global `console`, or the global `process` — commands written against the injected context stay testable, portable across Node/Deno/Bun, and ready to run inside sandboxed environments like MCP servers.
250
+
251
+ ```ts
252
+ import { Cerebro } from "@visulima/cerebro";
253
+
254
+ const cli = new Cerebro("acme");
255
+
256
+ cli.addCommand({
257
+ name: "login",
258
+ description: "Save an auth token",
259
+ options: [{ name: "token", type: String, description: "API token" }],
260
+ execute: async ({ fs, console, process, options }) => {
261
+ await fs.mkdir(".acme", { recursive: true });
262
+ await fs.writeFile(".acme/auth.json", JSON.stringify({ token: options.token }), "utf8");
263
+ console.log("saved credentials in", process.cwd);
264
+ },
265
+ });
266
+
267
+ await cli.run();
268
+ ```
269
+
270
+ ### Overriding the runtime
271
+
272
+ Pass any of the new `CliOptions` to swap the runtime context. Each override defaults to a sensible host value:
273
+
274
+ | Option | Default | Used for |
275
+ | --------------- | ---------------------------- | ---------------------------------------------------------------------------------- |
276
+ | `fs` | `node:fs/promises` adapter | Filesystem operations from `toolbox.fs` |
277
+ | `exit` | Runtime-agnostic exit helper | `toolbox.process.exit` |
278
+ | `env` | Host `process.env` | `toolbox.process.env` (does **not** affect `toolbox.env`) |
279
+ | `stdin` | `""` (empty string) | `toolbox.process.stdin` |
280
+ | `cwd` | Runtime cwd | `toolbox.process.cwd` |
281
+ | `logger` | Verbosity-aware console shim | `toolbox.logger` and `toolbox.console` |
282
+ | `maxArguments` | A very generous cap | Upper bound on argv tokens; set `Number.POSITIVE_INFINITY` to disable entirely |
283
+ | `strictOptions` | `false` | Reject unknown `--options` (before `--`) with a did-you-mean instead of swallowing |
284
+
285
+ ```ts
286
+ const exitSpy = vi.fn();
287
+ const fakeFs = new InMemoryFs();
288
+
289
+ const cli = new Cerebro("acme", {
290
+ cwd: "/virtual/project",
291
+ fs: fakeFs,
292
+ exit: exitSpy,
293
+ env: { NODE_ENV: "test" },
294
+ stdin: "y\n",
295
+ });
296
+ ```
297
+
298
+ ### Testing with mocked runtime
299
+
300
+ The runtime overrides remove the need for `vi.spyOn(process, "exit")` or `vi.spyOn(console, "log")` in command tests. Pass mocks at CLI construction; assert on them directly.
301
+
302
+ ```ts
303
+ import { describe, expect, test, vi } from "vitest";
304
+ import { Cerebro } from "@visulima/cerebro";
305
+
306
+ describe("deploy command", () => {
307
+ test("exits with code 2 when env is missing", async () => {
308
+ const exit = vi.fn();
309
+ const calls: string[] = [];
310
+ const logger = {
311
+ log: (...args: unknown[]) => calls.push(String(args[0])),
312
+ info: () => {},
313
+ warn: () => {},
314
+ error: () => {},
315
+ debug: () => {},
316
+ };
317
+
318
+ const cli = new Cerebro("acme", { argv: ["deploy"], exit, logger });
319
+ cli.addCommand({
320
+ name: "deploy",
321
+ execute: ({ console, process, options }) => {
322
+ if (!options.env) {
323
+ console.log("missing --env");
324
+ process.exit(2);
325
+ }
326
+ },
327
+ });
328
+
329
+ await cli.run({ shouldExitProcess: false });
330
+
331
+ expect(exit).toHaveBeenCalledWith(2);
332
+ expect(calls).toStrictEqual(["missing --env"]);
333
+ });
334
+ });
335
+ ```
336
+
337
+ ### `cli.clone(options?)`
338
+
339
+ Creates an independent CLI sharing the same command definitions. The clone has its own commands map, global options, default-command setting, and plugin manager — so adding commands or changing options on the clone never mutates the original. Primarily useful in tests to run the same CLI with different `argv`/`exit`/`fs` overrides without rebuilding the command tree.
340
+
341
+ ```ts
342
+ const cli = new Cerebro("acme");
343
+ cli.addCommand({ name: "build", execute: ({ console }) => console.log("building") });
344
+
345
+ // In tests: clone with mocked exit + captured argv
346
+ const isolatedExit = vi.fn();
347
+ const isolated = cli.clone({ argv: ["build"], exit: isolatedExit });
348
+ await isolated.run({ shouldExitProcess: false });
349
+ ```
350
+
351
+ ### `cli.getAction(commandName)`
352
+
353
+ Returns the resolved `execute` function for a registered command. For lazy commands defined with `loader`, the module is loaded once and cached. Supports space-separated nested command paths.
354
+
355
+ ```ts
356
+ const cli = new Cerebro("acme");
357
+
358
+ cli.addCommand({
359
+ name: "deploy",
360
+ execute: ({ console, options }) => console.log("deploying to", options.env),
361
+ });
362
+
363
+ // Call the action directly with a synthesized toolbox — no argv parsing.
364
+ const action = await cli.getAction("deploy");
365
+ await action({ console: fakeConsole, options: { env: "staging" } } as never);
366
+ ```
367
+
368
+ Use this when you want to unit-test a command action in isolation without going through `run()`'s full lifecycle (plugin init, exception handlers, exit). For end-to-end tests that exercise argv parsing and lifecycle hooks, prefer `cli.clone(...).run(...)` instead.
369
+
370
+ ## Validating option values with `choices`
371
+
372
+ Restrict an option to a fixed set of values, validated at parse time (like commander's `.choices()` / yargs `choices`). For `multiple` options every provided value must be a member of the set. An invalid value throws an `InvalidChoiceError` with a hint listing the allowed values.
373
+
374
+ ```ts
375
+ cli.addCommand({
376
+ name: "fmt",
377
+ options: [{ name: "format", type: String, choices: ["json", "yaml", "table"] }],
378
+ execute: ({ options }) => {
379
+ // options.format is guaranteed to be one of json | yaml | table
380
+ },
381
+ });
382
+
383
+ // `mycli fmt --format xml` → Invalid value "xml" for option "format". Allowed values: json, yaml, table
384
+ ```
385
+
386
+ ## Strict unknown-option handling
387
+
388
+ By default, unknown long options on commands that accept a positional `argument` are routed to `toolbox.rawUnknown` (the passthrough buffer) rather than rejected. Set `strictOptions: true` to fail fast on a typo'd flag — tokens after a `--` separator are always preserved as passthrough.
389
+
390
+ ```ts
391
+ const cli = new Cerebro("mycli", { argv: ["build", "app", "--produciton"], strictOptions: true });
392
+ // → throws UnknownOptionError: Found unknown option: --produciton (Did you mean: --production?)
393
+
394
+ // Tokens after `--` are still passthrough, even in strict mode:
395
+ // `mycli build app -- --produciton` → toolbox.rawUnknown === ["--produciton"]
396
+ ```
397
+
218
398
  ## Built-in Commands
219
399
 
220
400
  Cerebro comes with several built-in commands that are automatically available:
@@ -1,6 +1,7 @@
1
- import type { Command as ICommand } from "../types/command.d.ts";
1
+ import { C as Command } from "../packem_shared/command.d-DbhtfXF4.js";
2
+ import '@visulima/tabular';
2
3
  /**
3
- * Generates shell completion scripts for the CLI application.
4
- */
5
- declare const completionCommand: ICommand;
6
- export default completionCommand;
4
+ * Generates shell completion scripts for the CLI application.
5
+ */
6
+ declare const completionCommand: Command;
7
+ export { completionCommand as default };
@@ -1,203 +1,5 @@
1
- import tab from '@bomb.sh/tab';
2
- import { C as CerebroError } from '../packem_shared/cerebro-error-GmJ3jN7Q.js';
3
-
4
- class CompletionError extends CerebroError {
5
- troubleshooting;
6
- constructor(message, code, troubleshooting = []) {
7
- super(message, code, { troubleshooting });
8
- this.name = "CompletionError";
9
- this.troubleshooting = troubleshooting;
10
- if (troubleshooting.length > 0) {
11
- this.hint = troubleshooting.join("\n");
12
- }
13
- }
14
- }
15
-
16
- const validShells = ["bash", "zsh", "fish", "powershell"];
17
- const validRuntimes = ["node", "bun", "deno"];
18
- const hasDeno = (global) => "Deno" in global;
19
- const hasBun = (global) => "Bun" in global;
20
- const detectRuntime = () => {
21
- if (hasDeno(globalThis)) {
22
- return "deno";
23
- }
24
- if (hasBun(globalThis)) {
25
- return "bun";
26
- }
27
- return "node";
28
- };
29
- const detectShell = (toolboxEnv) => {
30
- const starshipShell = toolboxEnv?.starshipShell;
31
- const shell = starshipShell ?? toolboxEnv?.shell;
32
- if (shell) {
33
- const shellPath = shell.toLowerCase();
34
- if (shellPath.includes("zsh")) {
35
- return "zsh";
36
- }
37
- if (shellPath.includes("bash")) {
38
- return "bash";
39
- }
40
- if (shellPath.includes("fish")) {
41
- return "fish";
42
- }
43
- }
44
- const psModulePath = toolboxEnv?.psModulePath;
45
- const prompt = toolboxEnv?.prompt;
46
- if (psModulePath || prompt?.includes("PS")) {
47
- return "powershell";
48
- }
49
- const comSpec = toolboxEnv?.comSpec;
50
- if (comSpec?.toLowerCase().includes("cmd.exe")) {
51
- return "bash";
52
- }
53
- return void 0;
54
- };
55
- const tabInstance = tab;
56
- const registerCommandOptions = (cmd, options) => {
57
- for (const option of options) {
58
- if (option.hidden) {
59
- continue;
60
- }
61
- if (option.name) {
62
- cmd.option(option.name, option.description || "");
63
- }
64
- if (option.alias) {
65
- cmd.option(option.alias, option.description || "");
66
- }
67
- }
68
- };
69
- const registerCommands = (tabInstance2, commands) => {
70
- for (const [commandName, command] of commands) {
71
- if (command.name !== commandName || command.hidden) {
72
- continue;
73
- }
74
- const cmd = tabInstance2.command(command.name, command.description || "");
75
- if (command.options) {
76
- registerCommandOptions(cmd, command.options);
77
- }
78
- }
79
- };
80
- const validateShell = (shell) => {
81
- if (!validShells.includes(shell)) {
82
- throw new CompletionError(`Invalid shell type: ${shell}`, "INVALID_SHELL", [
83
- `Valid shells are: ${validShells.join(", ")}`,
84
- "Shell will be auto-detected if not specified"
85
- ]);
86
- }
87
- };
88
- const validateRuntime = (runtime) => {
89
- if (runtime && !validRuntimes.includes(runtime)) {
90
- throw new CompletionError(`Invalid runtime: ${runtime}`, "INVALID_RUNTIME", [
91
- `Valid runtimes are: ${validRuntimes.join(", ")}`,
92
- "Runtime will be auto-detected if not specified"
93
- ]);
94
- }
95
- };
96
- const printUsageInstructions = (logger, cliName) => {
97
- logger.error("Could not detect current shell");
98
- const usageInfo = [
99
- `Usage: ${cliName} completion --shell=<bash|zsh|fish|powershell> [--runtime=<node|bun|deno>]`,
100
- "",
101
- "Examples:",
102
- ` # Install completions for zsh:`,
103
- ` ${cliName} completion --shell=zsh > ~/.${cliName}-completion.zsh`,
104
- ` echo 'source ~/.${cliName}-completion.zsh' >> ~/.zshrc`,
105
- "",
106
- ` # Install completions for bash with custom runtime:`,
107
- ` ${cliName} completion --shell=bash --runtime=bun > ~/.${cliName}-completion.bash`,
108
- ` echo 'source ~/.${cliName}-completion.bash' >> ~/.bashrc`,
109
- "",
110
- ` # Install completions for fish:`,
111
- ` ${cliName} completion --shell=fish > ~/.config/fish/completions/${cliName}.fish`
112
- ].join("\n");
113
- logger.info(usageInfo);
114
- };
115
- const completionCommand = {
116
- description: "Generate shell completion scripts",
117
- env: [
118
- {
119
- description: "Shell path (Unix-like systems). Used for shell detection.",
120
- name: "SHELL",
121
- type: String
122
- },
123
- {
124
- description: "Starship shell configuration. Takes precedence over SHELL for detection.",
125
- name: "STARSHIP_SHELL",
126
- type: String
127
- },
128
- {
129
- description: "PowerShell module path (Windows). Used for PowerShell detection.",
130
- name: "PSModulePath",
131
- type: String
132
- },
133
- {
134
- description: "Command prompt variable (Windows). Used for PowerShell detection.",
135
- name: "PROMPT",
136
- type: String
137
- },
138
- {
139
- description: "Command processor (Windows). Used for Windows Command Prompt detection.",
140
- name: "ComSpec",
141
- type: String
142
- }
143
- ],
144
- execute: async ({ env: toolboxEnv, logger, options, runtime }) => {
145
- const cliName = runtime.getCliName();
146
- const shell = options?.shell || detectShell(toolboxEnv);
147
- if (!shell) {
148
- printUsageInstructions(logger, cliName);
149
- return;
150
- }
151
- try {
152
- validateShell(shell);
153
- validateRuntime(options?.runtime);
154
- registerCommands(tabInstance, runtime.getCommands());
155
- const jsRuntime = options?.runtime || detectRuntime();
156
- const scriptPath = `${jsRuntime} ${cliName}`;
157
- tabInstance.setup(cliName, scriptPath, shell);
158
- } catch (error) {
159
- if (error instanceof CompletionError) {
160
- const errorMessages = [`Failed to generate completion script: ${error.message}`, `Error code: ${error.code}`];
161
- if (error.troubleshooting.length > 0) {
162
- errorMessages.push("", "Troubleshooting:", ...error.troubleshooting.map((tip) => ` • ${tip}`));
163
- }
164
- logger.error(errorMessages.join("\n"));
165
- throw error;
166
- } else {
167
- const errorMessage = error instanceof Error ? error.message : String(error);
168
- const errorMessages = [
169
- "Failed to generate completion script",
170
- `Error: ${errorMessage}`,
171
- "",
172
- "Troubleshooting:",
173
- " • Ensure @bomb.sh/tab is installed: pnpm add @bomb.sh/tab",
174
- ` • Verify shell is supported: ${validShells.join(", ")}`,
175
- ` • Verify runtime is supported: ${validRuntimes.join(", ")}`,
176
- " • Check that your CLI name is correct"
177
- ];
178
- logger.error(errorMessages.join("\n"));
179
- }
180
- }
181
- },
182
- name: "completion",
183
- options: [
184
- {
185
- defaultOption: true,
186
- defaultValue: detectShell(),
187
- description: "Shell type (bash, zsh, fish, powershell). Defaults to current shell if detected.",
188
- name: "shell",
189
- type: String,
190
- typeLabel: "{underline shell}"
191
- },
192
- {
193
- defaultOption: true,
194
- defaultValue: detectRuntime(),
195
- description: "JavaScript runtime (node, bun, deno). Defaults to current runtime if detected.",
196
- name: "runtime",
197
- type: String,
198
- typeLabel: "{underline runtime}"
199
- }
200
- ]
201
- };
202
-
203
- export { completionCommand as default };
1
+ import{t as u}from"../packem_shared/cerebro-error-BjBcYVRO.js";class h extends u{troubleshooting;constructor(o,t,i=[]){super(o,t,{troubleshooting:i}),this.name="CompletionError",this.troubleshooting=i,i.length>0&&(this.hint=i.join(`
2
+ `))}}const a=["bash","zsh","fish","powershell"],c=["node","bun","deno"],f=e=>"Deno"in e,b=e=>"Bun"in e,d=()=>f(globalThis)?"deno":b(globalThis)?"bun":"node",p=e=>{const o=e?.starshipShell??e?.shell;if(o){const s=o.toLowerCase();if(s.includes("zsh"))return"zsh";if(s.includes("bash"))return"bash";if(s.includes("fish"))return"fish"}const t=e?.psModulePath,i=e?.prompt;if(t||i?.includes("PS"))return"powershell";if(e?.comSpec?.toLowerCase().includes("cmd.exe"))return"bash"},g=async()=>(await import("@bomb.sh/tab")).default,S=(e,o)=>{for(const t of o)t.hidden||(t.name&&e.option(t.name,t.description??""),t.alias&&e.option(t.alias,t.description??""))},w=(e,o)=>{for(const[t,i]of o){if(i.name!==t||i.hidden)continue;const s=e.command(i.name,i.description??"");i.options&&S(s,i.options)}},$=e=>{if(!a.includes(e))throw new h(`Invalid shell type: ${e}`,"INVALID_SHELL",[`Valid shells are: ${a.join(", ")}`,"Shell will be auto-detected if not specified"])},y=e=>{if(e&&!c.includes(e))throw new h(`Invalid runtime: ${e}`,"INVALID_RUNTIME",[`Valid runtimes are: ${c.join(", ")}`,"Runtime will be auto-detected if not specified"])},L=(e,o)=>{e.error("Could not detect current shell");const t=[`Usage: ${o} completion --shell=<bash|zsh|fish|powershell> [--runtime=<node|bun|deno>]`,"","Examples:"," # Install completions for zsh:",` ${o} completion --shell=zsh > ~/.${o}-completion.zsh`,` echo 'source ~/.${o}-completion.zsh' >> ~/.zshrc`,""," # Install completions for bash with custom runtime:",` ${o} completion --shell=bash --runtime=bun > ~/.${o}-completion.bash`,` echo 'source ~/.${o}-completion.bash' >> ~/.bashrc`,""," # Install completions for fish:",` ${o} completion --shell=fish > ~/.config/fish/completions/${o}.fish`].join(`
3
+ `);e.info(t)},I={description:"Generate shell completion scripts",env:[{description:"Shell path (Unix-like systems). Used for shell detection.",name:"SHELL",type:String},{description:"Starship shell configuration. Takes precedence over SHELL for detection.",name:"STARSHIP_SHELL",type:String},{description:"PowerShell module path (Windows). Used for PowerShell detection.",name:"PSModulePath",type:String},{description:"Command prompt variable (Windows). Used for PowerShell detection.",name:"PROMPT",type:String},{description:"Command processor (Windows). Used for Windows Command Prompt detection.",name:"ComSpec",type:String}],execute:async({env:e,logger:o,options:t,runtime:i})=>{const s=i.getCliName(),l=t.shell??p(e);if(!l){L(o,s);return}try{$(l),y(t.runtime);const n=await g();w(n,i.getCommands());const r=`${t.runtime??d()} ${s}`;n.setup(s,r,l)}catch(n){if(n instanceof h){const r=[`Failed to generate completion script: ${n.message}`,`Error code: ${n.code}`];throw n.troubleshooting.length>0&&r.push("","Troubleshooting:",...n.troubleshooting.map(m=>` • ${m}`)),o.error(r.join(`
4
+ `)),n}else{const r=["Failed to generate completion script",`Error: ${n instanceof Error?n.message:String(n)}`,"","Troubleshooting:"," • Ensure @bomb.sh/tab is installed: pnpm add @bomb.sh/tab",` • Verify shell is supported: ${a.join(", ")}`,` • Verify runtime is supported: ${c.join(", ")}`," • Check that your CLI name is correct"];o.error(r.join(`
5
+ `))}}},name:"completion",options:[{defaultOption:!0,defaultValue:p(),description:"Shell type (bash, zsh, fish, powershell). Defaults to current shell if detected.",name:"shell",type:String,typeLabel:"{underline shell}"},{defaultValue:d(),description:"JavaScript runtime (node, bun, deno). Defaults to current runtime if detected.",name:"runtime",type:String,typeLabel:"{underline runtime}"}]};export{I as default};
@@ -1,10 +1,11 @@
1
- import type { Command as ICommand, OptionDefinition } from "../types/command.d.ts";
2
- import type { Toolbox as IToolbox } from "../types/toolbox.d.ts";
3
- declare class HelpCommand<TLogger extends Console = Console> implements ICommand<OptionDefinition<string>, TLogger> {
4
- name: string;
5
- options: OptionDefinition<string>[];
6
- private readonly commands;
7
- constructor(commands: Map<string, ICommand<OptionDefinition<unknown>, TLogger>>);
8
- execute(toolbox: IToolbox<TLogger>): void;
1
+ import { O as OptionDefinition, A as ArgumentDefinition, C as Command, T as Toolbox } from "../packem_shared/command.d-DbhtfXF4.js";
2
+ import '@visulima/tabular';
3
+ declare class HelpCommand<TLogger extends Console = Console> implements Command<OptionDefinition<string>, TLogger> {
4
+ argument: ArgumentDefinition<string>;
5
+ name: string;
6
+ options: OptionDefinition<string>[];
7
+ private readonly commands;
8
+ constructor(commands: Map<string, Command<OptionDefinition<unknown>, TLogger>>);
9
+ execute(toolbox: Toolbox<TLogger>): void;
9
10
  }
10
- export default HelpCommand;
11
+ export { HelpCommand as default };
@@ -1,3 +1 @@
1
- import '@visulima/colorize';
2
- export { H as default } from '../packem_shared/help-command-BY7rQUvM.js';
3
- import '../packem_shared/index-C2-8b3A4.js';
1
+ import{inverse as p,cyan as u,green as h,yellow as g}from"@visulima/colorize";import{a as y,r as f}from"../packem_shared/index-B7-8G-9s.js";const O=[{defaultValue:"32",description:"Controls the verbosity level of output. Valid values: '16' (quiet), '32' (normal), '64' (verbose), '128' (debug)",name:"CEREBRO_OUTPUT_LEVEL",type:String},{description:"Sets the minimum required Node.js version. Overrides the default minimum version check",name:"CEREBRO_MIN_NODE_VERSION",type:Number},{defaultValue:!1,description:"When set, disables the update notifier check",name:"NO_UPDATE_NOTIFIER",type:Boolean},{description:"Standard Node.js environment variable. When set to 'test', disables update notifier",name:"NODE_ENV",type:String},{defaultValue:!1,description:"When set, enables debug output (same as --debug flag)",name:"DEBUG",type:Boolean},{description:"Sets the terminal width for table rendering. Useful for testing and consistent output",name:"CEREBRO_TERMINAL_WIDTH",type:Number}],b="__Other",v=s=>s.charAt(0).toUpperCase()+s.slice(1),w=(s,r,l,o)=>{s.debug("no command given, printing general help...");let m=[...new Set(l.values())].filter(n=>!n.hidden);o&&(m=m.filter(n=>n.group===o));const e=m.reduce((n,i)=>{const d=i.group??b;return n[d]??=[],n[d].push(i),n},{}),a=n=>n.map(i=>{let d="";typeof i.alias=="string"?d=i.alias:Array.isArray(i.alias)&&(d=i.alias.join(", ")),d!==""&&(d=` [${d}]`);let t=i.name;return i.commandPath&&i.commandPath.length>0&&(t=`${i.commandPath.join(" ")} ${i.name}`),[`${h(t)}${d}`,i.description??""]});(s.raw??s.log)(f([{content:`${u(r.getCliName())} ${h("<command>")} [positional arguments] ${g("[options]")}`,header:p.cyan(" Usage ")},...Object.keys(e).map(n=>{const i=o?` ${v(o)}`:"";return{content:a(e[n]),header:n===b||o?p.green(` Available${i} Commands `):` ${p.green(` ${v(n)} `)}`}}),l.has("help")?{header:p.yellow(" Command Options "),optionList:l.get("help").options?.filter(n=>!n.hidden)}:void 0,{header:p.yellow(" Global Options "),optionList:r.getGlobalOptions()},{content:O.filter(n=>!n.hidden).map(n=>[n.name,n.description??""]),header:p.magenta(" Environment Variables ")},{content:`Run "${u(r.getCliName())} ${h("help <command>")}" or "${u(r.getCliName())} ${h("<command>")} ${g("--help")}" for help with a specific command.`,raw:!0}].filter(Boolean)))},$=(s,r)=>{const l=[];for(const o of s.values()){if(o.hidden)continue;const m=o.commandPath??[];if(m.length!==r.length)continue;let e=!0;for(const[a,n]of r.entries())if(m[a]!==n){e=!1;break}e&&l.push(o)}return l},E=(s,r,l,o)=>{const m=l.join(" "),e=[{content:`${u(r.getCliName())} ${h(m)} ${h("<subcommand>")} [positional arguments] ${g("[options]")}`,header:p.cyan(" Usage ")},{content:o.map(a=>{const n=[...a.commandPath??[],a.name].join(" ");return[h(n),a.description??""]}),header:p.green(" Subcommands ")},{header:p.yellow(" Global Options "),optionList:r.getGlobalOptions()},{content:`Run "${u(r.getCliName())} ${h(`${m} <subcommand>`)} ${g("--help")}" for help with a specific subcommand.`,raw:!0}];(s.raw??s.log)(f(e))},N=(s,r,l,o,m)=>{let e=m??l.get(o);if(!e)for(const t of l.values()){const c=t.commandPath?[...t.commandPath,t.name]:[t.name];if(c.at(-1)===o||c.join(" ")===o){e=t;break}}if(!e){const t=o.split(" ").filter(Boolean),c=t.length>0?$(l,t):[];if(c.length>0){E(s,r,t,c);return}s.error(`Command "${o}" not found`);return}const a=[],n=(e.commandPath?[...e.commandPath,e.name]:[e.name]).join(" ");if(a.push({content:`${u(r.getCliName())} ${h(n)}${e.argument?" [positional arguments]":""}${e.options?" [options]":""}`,header:p.cyan(" Usage ")}),e.description&&a.push({content:e.description,header:p.green(" Description ")}),e.argument&&a.push({header:"Command Positional Arguments",isArgument:!0,optionList:[e.argument]}),Array.isArray(e.options)&&e.options.length>0&&a.push({header:p.yellow(" Command Options "),optionList:e.options.filter(t=>!t.hidden)}),a.push({header:p.yellow(" Global Options "),optionList:r.getGlobalOptions()}),Array.isArray(e.env)&&e.env.length>0){const t=e.env.filter(c=>!c.hidden);t.length>0&&a.push({content:t.map(c=>[c.name,c.description??""]),header:p.magenta(" Environment Variables ")})}if(e.alias!==void 0&&e.alias.length>0){let t=e.alias;typeof e.alias=="string"&&(t=[e.alias]),a.splice(1,0,{content:t,header:"Alias(es)"})}Array.isArray(e.examples)&&e.examples.length>0&&a.push({content:e.examples,header:"Examples"});const i=[...e.commandPath??[],e.name],d=$(l,i);d.length>0&&a.push({content:d.map(t=>{const c=[...t.commandPath??[],t.name].join(" ");return[h(c),t.description??""]}),header:p.green(" Subcommands ")}),(s.raw??s.log)(f(a))};class P{argument={description:"Command to show help for (subcommand path supported, e.g. `cli help docker build`)",name:"command",type:String};name="help";options=[{description:"Display only the specified group",name:"group",type:String}];commands;constructor(r){this.commands=r}execute(r){const{argument:l,command:o,commandName:m,logger:e,options:a,runtime:n}=r,{footer:i,header:d}=n.getCommandSection();d&&(e.raw??e.log)(y(d));const t=m==="help"&&Array.isArray(l)&&l.length>0?l.join(" "):void 0;if(m==="help"&&t===void 0)w(e,n,this.commands,typeof a?.group=="string"?a.group:void 0);else{const c=t!==void 0||o===void 0||o.name==="help"?void 0:o;N(e,n,this.commands,t??m,c)}i&&(e.raw??e.log)(y(i))}}export{P as default};
@@ -1,6 +1,7 @@
1
- import type { Command as ICommand } from "../types/command.d.ts";
1
+ import { C as Command } from "../packem_shared/command.d-DbhtfXF4.js";
2
+ import '@visulima/tabular';
2
3
  /**
3
- * Generates README documentation for cerebro CLI commands.
4
- */
5
- declare const readmeCommand: ICommand;
6
- export default readmeCommand;
4
+ * Generates README documentation for cerebro CLI commands.
5
+ */
6
+ declare const readmeCommand: Command;
7
+ export { readmeCommand as default };