@h3ravel/musket 0.1.0 → 0.1.1

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.
package/dist/index.cjs ADDED
@@ -0,0 +1,951 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let __h3ravel_shared = require("@h3ravel/shared");
25
+ __h3ravel_shared = __toESM(__h3ravel_shared);
26
+ let commander = require("commander");
27
+ commander = __toESM(commander);
28
+ let tsdown = require("tsdown");
29
+ tsdown = __toESM(tsdown);
30
+ let glob = require("glob");
31
+ glob = __toESM(glob);
32
+ let node_path = require("node:path");
33
+ node_path = __toESM(node_path);
34
+ let __h3ravel_support = require("@h3ravel/support");
35
+ __h3ravel_support = __toESM(__h3ravel_support);
36
+ let node_fs_promises = require("node:fs/promises");
37
+ node_fs_promises = __toESM(node_fs_promises);
38
+
39
+ //#region src/Core/Command.ts
40
+ var Command = class {
41
+ constructor(app, kernel) {
42
+ this.app = app;
43
+ this.kernel = kernel;
44
+ }
45
+ /**
46
+ * The underlying commander instance.
47
+ *
48
+ * @var Command
49
+ */
50
+ program;
51
+ /**
52
+ * The name and signature of the console command.
53
+ *
54
+ * @var string
55
+ */
56
+ signature;
57
+ /**
58
+ * A dictionary of signatures or what not.
59
+ *
60
+ * @var object
61
+ */
62
+ dictionary = {};
63
+ /**
64
+ * The console command description.
65
+ *
66
+ * @var string
67
+ */
68
+ description;
69
+ /**
70
+ * The console command input.
71
+ *
72
+ * @var object
73
+ */
74
+ input = {
75
+ options: {},
76
+ arguments: {}
77
+ };
78
+ /**
79
+ * Execute the console command.
80
+ */
81
+ async handle(..._args) {}
82
+ setApplication(app) {
83
+ this.app = app;
84
+ }
85
+ setInput(options, args, regArgs, dictionary, program$1) {
86
+ this.program = program$1;
87
+ this.dictionary = dictionary;
88
+ this.input.options = options;
89
+ this.input.arguments = regArgs.map((e, i) => ({ [e.name()]: args[i] })).reduce((e, x) => Object.assign(e, x), {});
90
+ this.loadBaseFlags();
91
+ __h3ravel_shared.Logger.configure({
92
+ verbosity: this.option("verbose"),
93
+ silent: this.option("silent"),
94
+ quiet: this.option("quiet")
95
+ });
96
+ return this;
97
+ }
98
+ setOption(key, value) {
99
+ this.program.setOptionValue(key, value);
100
+ return this;
101
+ }
102
+ setProgram(program$1) {
103
+ this.program = program$1;
104
+ return this;
105
+ }
106
+ getSignature() {
107
+ return this.signature;
108
+ }
109
+ getDescription() {
110
+ return this.description;
111
+ }
112
+ option(key, def) {
113
+ const option = this.input.options[key] ?? def;
114
+ return option === "null" || option === "undefined" ? void 0 : option;
115
+ }
116
+ options(key) {
117
+ if (key) return this.input.options[key];
118
+ return this.input.options;
119
+ }
120
+ argument(key, def) {
121
+ return this.input.arguments[key] ?? def;
122
+ }
123
+ arguments() {
124
+ return this.input.arguments;
125
+ }
126
+ loadBaseFlags() {
127
+ let verbose = 0;
128
+ if (this.program.getOptionValue("verbose") == "v") verbose = 2;
129
+ else if (this.program.getOptionValue("verbose") == "vv") verbose = 3;
130
+ else verbose = Number(this.program.getOptionValue("verbose") ?? 0);
131
+ this.input.options.quiet = this.program.getOptionValue("quiet") ?? false;
132
+ this.input.options.silent = this.program.getOptionValue("silent") ?? false;
133
+ this.input.options.verbose = verbose;
134
+ this.input.options.interaction = this.program.getOptionValue("interaction") ?? false;
135
+ }
136
+ /**
137
+ * Check if the command is quiet
138
+ *
139
+ * @returns
140
+ */
141
+ isQuiet() {
142
+ return this.option("quiet");
143
+ }
144
+ /**
145
+ * Check if the command is silent
146
+ *
147
+ * @returns
148
+ */
149
+ isSilent() {
150
+ return this.option("silent");
151
+ }
152
+ /**
153
+ * Check if the command is non interactive
154
+ *
155
+ * @returns
156
+ */
157
+ isNonInteractive() {
158
+ return this.option("interaction") === false;
159
+ }
160
+ /**
161
+ * Get the verbosity of the command
162
+ *
163
+ * @returns
164
+ */
165
+ getVerbosity() {
166
+ return Number(this.option("verbose"));
167
+ }
168
+ /**
169
+ * Log an info message
170
+ */
171
+ info(message) {
172
+ __h3ravel_shared.Logger.info(message);
173
+ return this;
174
+ }
175
+ /**
176
+ * Log a warning message
177
+ */
178
+ warn(message) {
179
+ __h3ravel_shared.Logger.warn(message);
180
+ return this;
181
+ }
182
+ /**
183
+ * Log a line message
184
+ */
185
+ line(message) {
186
+ __h3ravel_shared.Logger.log(message, "white");
187
+ return this;
188
+ }
189
+ /**
190
+ * Log a new line
191
+ */
192
+ newLine(count = 1) {
193
+ if (Number(this.getVerbosity()) >= 3 || !this.isSilent() && !this.isQuiet()) for (let i = 0; i < count; i++) console.log("");
194
+ return this;
195
+ }
196
+ /**
197
+ * Log a success message
198
+ */
199
+ success(message) {
200
+ __h3ravel_shared.Logger.success(message);
201
+ return this;
202
+ }
203
+ /**
204
+ * Log an error message
205
+ */
206
+ error(message) {
207
+ __h3ravel_shared.Logger.error(message, false);
208
+ return this;
209
+ }
210
+ /**
211
+ * Log an error message and terminate execution of the command
212
+ * return an exit code of 1
213
+ *
214
+ * This method is not chainable
215
+ */
216
+ fail(message) {
217
+ this.error(message);
218
+ process.exit(1);
219
+ }
220
+ /**
221
+ * Log a debug message
222
+ */
223
+ debug(message) {
224
+ __h3ravel_shared.Logger.debug(message);
225
+ return this;
226
+ }
227
+ };
228
+
229
+ //#endregion
230
+ //#region src/Signature.ts
231
+ var Signature = class Signature {
232
+ /**
233
+ * Helper to parse options inside a block of text
234
+ *
235
+ * @param block
236
+ * @returns
237
+ */
238
+ static parseOptions(block) {
239
+ const options = [];
240
+ /**
241
+ * Match { ... } blocks at top level
242
+ */
243
+ const regex = /\{([^{}]+(?:\{[^{}]*\}[^{}]*)*)\}/g;
244
+ let match;
245
+ while ((match = regex.exec(block)) !== null) {
246
+ const shared = "^" === match[1][0] || /:[#^]/.test(match[1]);
247
+ const isHidden = (["#", "^"].includes(match[1][0]) || /:[#^]/.test(match[1])) && !shared;
248
+ const content = match[1].trim().replace(/[#^]/, "");
249
+ /**
250
+ * Split by first ':' to separate name and description+nested
251
+ */
252
+ const colonIndex = content.indexOf(":");
253
+ if (colonIndex === -1) {
254
+ /**
255
+ * No description, treat whole as name
256
+ */
257
+ options.push({ name: content });
258
+ continue;
259
+ }
260
+ const namePart = content.substring(0, colonIndex).trim();
261
+ const rest = content.substring(colonIndex + 1).trim();
262
+ /**
263
+ * Check for nested options after '|'
264
+ */
265
+ let description$1 = rest;
266
+ let nestedOptions;
267
+ const pipeIndex = rest.indexOf("|");
268
+ if (pipeIndex !== -1) {
269
+ description$1 = rest.substring(0, pipeIndex).trim();
270
+ /**
271
+ * nestedText should start with '{' and end with ')', clean it
272
+ * Also Remove trailing ')' if present
273
+ */
274
+ const cleanedNestedText = rest.substring(pipeIndex + 1).trim().replace(/^\{/, "").trim();
275
+ /**
276
+ * Parse nested options recursively
277
+ */
278
+ nestedOptions = Signature.parseOptions("{" + cleanedNestedText + "}");
279
+ } else
280
+ /**
281
+ * Trim the string
282
+ */
283
+ description$1 = description$1.trim();
284
+ let name$1 = namePart;
285
+ let flags;
286
+ let choices = [];
287
+ let required = /[^a-zA-Z0-9_|-]/.test(name$1);
288
+ let multiple = false;
289
+ let placeholder;
290
+ let defaultValue;
291
+ /**
292
+ * Parse the command name
293
+ */
294
+ if (name$1.includes("=")) {
295
+ const [rawName, rawDefault] = name$1.split("=");
296
+ name$1 = rawName.trim();
297
+ const hold = rawName.trim().split("|");
298
+ const holder = (hold.at(1) ?? hold.at(0)).replace("--", "");
299
+ defaultValue = rawDefault.trim();
300
+ placeholder = defaultValue ? `[${holder}]` : `<${holder}>`;
301
+ required = false;
302
+ }
303
+ /**
304
+ * Parse name modifiers (?, *, ?*)
305
+ */
306
+ if (name$1.endsWith("?*")) {
307
+ required = false;
308
+ multiple = true;
309
+ name$1 = name$1.slice(0, -2);
310
+ } else if (name$1.endsWith("*")) {
311
+ multiple = true;
312
+ name$1 = name$1.slice(0, -1);
313
+ } else if (name$1.endsWith("?")) {
314
+ required = false;
315
+ name$1 = name$1.slice(0, -1);
316
+ placeholder = `[${name$1.split("--").at(1)?.split("|").at(1) ?? name$1}]`;
317
+ }
318
+ /**
319
+ * Check if it's a flag option (starts with --)
320
+ */
321
+ const isFlag = name$1.startsWith("--");
322
+ if (isFlag) {
323
+ /**
324
+ * Parse flags and default values
325
+ */
326
+ const flagParts = name$1.split("|").map((s) => s.trim());
327
+ flags = [];
328
+ for (let part of flagParts) {
329
+ if (part.startsWith("--") && part.slice(2).length === 1) part = "-" + part.slice(2);
330
+ else if (part.startsWith("-") && !part.startsWith("--") && part.slice(1).length > 1) part = "--" + part.slice(1);
331
+ else if (!part.startsWith("-") && part.slice(1).length > 1) part = "--" + part;
332
+ const eqIndex = part.indexOf("=");
333
+ if (eqIndex !== -1) {
334
+ flags.push(part.substring(0, eqIndex));
335
+ const val = part.substring(eqIndex + 1);
336
+ if (val === "*") defaultValue = [];
337
+ else if (val === "true" || val === "false" || !val && !required) defaultValue = val === "true";
338
+ else if (!isNaN(Number(val))) defaultValue = Number(val);
339
+ else defaultValue = val;
340
+ } else flags.push(part);
341
+ }
342
+ }
343
+ const desc = description$1.match(/^([^:]+?)\s*:\s*\[?([\w\s,]+)\]?$/);
344
+ if (match) {
345
+ description$1 = desc?.[1].trim() ?? description$1;
346
+ choices = desc?.[2].split(",").map((s) => s.trim()).filter(Boolean) ?? choices;
347
+ }
348
+ options.push({
349
+ name: isFlag ? flags[flags.length - 1] : name$1,
350
+ choices,
351
+ required,
352
+ multiple,
353
+ description: description$1,
354
+ flags,
355
+ shared,
356
+ isFlag,
357
+ isHidden,
358
+ placeholder,
359
+ defaultValue,
360
+ nestedOptions
361
+ });
362
+ }
363
+ return options;
364
+ }
365
+ /**
366
+ * Helper to parse a command's signature
367
+ *
368
+ * @param signature
369
+ * @param commandClass
370
+ * @returns
371
+ */
372
+ static parseSignature(signature, commandClass) {
373
+ const lines = signature.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
374
+ const isHidden = ["#", "^"].includes(lines[0][0]) || /:[#^]/.test(lines[0]);
375
+ const baseCommand = lines[0].split("{")[0].trim().replace(/[^\w:-]/g, "");
376
+ const description$1 = commandClass.getDescription();
377
+ const isNamespaceCommand = baseCommand.endsWith(":");
378
+ /**
379
+ * Join the rest lines to a single string for parsing
380
+ */
381
+ const rest = lines.slice(1).join(" ");
382
+ /**
383
+ * Parse all top-level options/subcommands
384
+ */
385
+ const allOptions = Signature.parseOptions(rest);
386
+ if (isNamespaceCommand)
387
+ /**
388
+ * Separate subcommands (those without flags) and base options (flags)
389
+ * Here we assume subcommands are those without flags (isFlag false)
390
+ * and base options are flags or options after subcommands
391
+
392
+ * For simplicity, treat all top-level options as subcommands
393
+ * and assume base command options come after subcommands in signature (not shown in example)
394
+ */
395
+ return {
396
+ baseCommand: baseCommand.slice(0, -1),
397
+ isNamespaceCommand,
398
+ subCommands: allOptions.filter((e) => !e.flags && !e.isHidden),
399
+ description: description$1,
400
+ commandClass,
401
+ options: allOptions.filter((e) => !!e.flags),
402
+ isHidden
403
+ };
404
+ else return {
405
+ baseCommand,
406
+ isNamespaceCommand,
407
+ options: allOptions,
408
+ description: description$1,
409
+ commandClass,
410
+ isHidden
411
+ };
412
+ }
413
+ };
414
+
415
+ //#endregion
416
+ //#region src/logo.ts
417
+ const logo = String.raw`
418
+ 111
419
+ 111111111
420
+ 1111111111 111111
421
+ 111111 111 111111
422
+ 111111 111 111111
423
+ 11111 111 11111
424
+ 1111111 111 1111111
425
+ 111 11111 111 111111 111 1111 1111 11111111 1111
426
+ 111 11111 1111 111111 111 1111 1111 1111 11111 1111
427
+ 111 11111 11111 111 1111 1111 111111111111 111111111111 1111 1111111 1111
428
+ 111 111111 1111 111 111111111111 111111 11111 1111 111 1111 11111111 1111 1111
429
+ 111 111 11111111 111 1101 1101 111111111 11111111 1111 1111111111111111101
430
+ 111 1111111111111111 1111 111 1111 1111 111 11111011 1111 111 1111111 1101 1111
431
+ 111 11111 1110111111111111 111 1111 1111 1111111101 1111 111111111 1111011 111111111 1111
432
+ 1111111 111110111110 111 1111 1111 111111 1111 11011101 10111 11111 1111
433
+ 11011 111111 11 11111
434
+ 111111 11101 111111
435
+ 111111 111 111111
436
+ 111111 111 111111
437
+ 111111111
438
+ 110
439
+ `;
440
+ const altLogo = String.raw`
441
+ _ _ _____ _
442
+ | | | |___ / _ __ __ ___ _____| |
443
+ | |_| | |_ \| '__/ _ \ \ / / _ \ |
444
+ | _ |___) | | | (_| |\ V / __/ |
445
+ |_| |_|____/|_| \__,_| \_/ \___|_|
446
+
447
+ `;
448
+
449
+ //#endregion
450
+ //#region src/Commands/HelpCommand.ts
451
+ var HelpCommand = class extends Command {
452
+ /**
453
+ * The name and signature of the console command.
454
+ *
455
+ * @var string
456
+ */
457
+ signature = `help
458
+ {command_name=help : The command name}
459
+ {--format=txt : The output format}
460
+ `;
461
+ /**
462
+ * The console command description.
463
+ *
464
+ * @var string
465
+ */
466
+ description = "Display help for a command";
467
+ async handle() {
468
+ const cmd = this.argument("command_name");
469
+ if (!cmd) {
470
+ this.program.outputHelp();
471
+ return;
472
+ }
473
+ const target = this.program.commands.find((c) => c.name() === cmd);
474
+ if (!target) {
475
+ this.error(`ERROR: Unknown command: ${__h3ravel_shared.Logger.log(cmd, ["italic", "grey"], false)}.`);
476
+ process.exit(1);
477
+ }
478
+ target.outputHelp();
479
+ }
480
+ };
481
+
482
+ //#endregion
483
+ //#region src/Commands/ListCommand.ts
484
+ var ListCommand = class ListCommand extends Command {
485
+ /**
486
+ * The name and signature of the console command.
487
+ *
488
+ * @var string
489
+ */
490
+ signature = "list";
491
+ /**
492
+ * The console command description.
493
+ *
494
+ * @var string
495
+ */
496
+ description = "List all available commands";
497
+ async handle() {
498
+ const options = [{
499
+ short: "-h",
500
+ long: "--help",
501
+ description: "Display help for the given command. When no command is given display help for the list command"
502
+ }].concat(this.program.options).map((e) => {
503
+ return __h3ravel_shared.Logger.describe(__h3ravel_shared.Logger.log(" " + [e.short, e.long].filter((e$1) => !!e$1).join(", "), "green", false), e.description, 25, false).join("");
504
+ });
505
+ /** Get the program commands */
506
+ const commands = this.program.commands.map((e) => {
507
+ return __h3ravel_shared.Logger.describe(__h3ravel_shared.Logger.log(" " + e.name(), "green", false), e.description(), 25, false).join("");
508
+ });
509
+ const list = ListCommand.groupItems(commands);
510
+ /** Output the modules version */
511
+ const version$1 = this.kernel.modules.map((e) => {
512
+ return __h3ravel_shared.Logger.log([[__h3ravel_support.Str.of(e.name).after("/").apa().toString(), "white"], [e.version, "green"]], " ", false);
513
+ }).join(" | ");
514
+ this.newLine();
515
+ console.log(version$1);
516
+ this.newLine();
517
+ console.log(altLogo);
518
+ this.newLine();
519
+ __h3ravel_shared.Logger.log("Usage:", "yellow");
520
+ __h3ravel_shared.Logger.log(" command [options] [arguments]", "white");
521
+ this.newLine();
522
+ /** Output the options */
523
+ __h3ravel_shared.Logger.log("Options:", "yellow");
524
+ console.log(options.join("\n").trim());
525
+ this.newLine();
526
+ /** Ootput the commands */
527
+ __h3ravel_shared.Logger.log("Available Commands:", "yellow");
528
+ console.log(list.join("\n\n").trim());
529
+ this.newLine();
530
+ }
531
+ /**
532
+ * Group Commands based on thier names
533
+ *
534
+ * @param commands
535
+ * @returns
536
+ */
537
+ static groupItems(commands, fmtd = false) {
538
+ const grouped = commands.reduce((acc, cmd) => {
539
+ /** strip colors before checking prefix */
540
+ const clean = cmd.replace(/\x1b\[\d+m/g, "");
541
+ const prefix = clean.includes(":") ? clean.split(":")[0].trim() : "__root__";
542
+ acc[prefix] ??= [];
543
+ /** keep original with colors */
544
+ acc[prefix].push(cmd);
545
+ return acc;
546
+ }, {});
547
+ return Object.entries(grouped).map(([group, cmds]) => {
548
+ const label = group === "__root__" ? "" : group;
549
+ let out = [__h3ravel_shared.Logger.log(label, "yellow", false), cmds.join("\n")].join("\n");
550
+ if (fmtd) out += "\n";
551
+ return out;
552
+ });
553
+ }
554
+ };
555
+
556
+ //#endregion
557
+ //#region src/Musket.ts
558
+ var Musket = class Musket {
559
+ /**
560
+ * The name of the CLI app we're building
561
+ *
562
+ * @default musket
563
+ */
564
+ cliName = "musket";
565
+ config = {};
566
+ commands = [];
567
+ constructor(app, kernel, baseCommands = [], resolver, tsDownConfig = {}) {
568
+ this.app = app;
569
+ this.kernel = kernel;
570
+ this.baseCommands = baseCommands;
571
+ this.resolver = resolver;
572
+ this.tsDownConfig = tsDownConfig;
573
+ }
574
+ async build() {
575
+ this.loadBaseCommands();
576
+ await this.loadDiscoveredCommands();
577
+ return await this.initialize();
578
+ }
579
+ loadBaseCommands() {
580
+ this.baseCommands.concat([new HelpCommand(this.app, this.kernel), new ListCommand(this.app, this.kernel)]).forEach((e) => this.addCommand(e));
581
+ }
582
+ /**
583
+ * Provide the configuration to initialize the CLI with
584
+ *
585
+ * @param config
586
+ * @returns
587
+ */
588
+ configure(config) {
589
+ this.config = config;
590
+ return this;
591
+ }
592
+ /**
593
+ * Set the paths where the cli can search and auto discover commands
594
+ *
595
+ * @param paths
596
+ *
597
+ * @example instance.discoverCommandsFrom('Console/Commands/*.js')
598
+ * @example instance.discoverCommandsFrom(['Console/Commands/*.js', 'App/Commands/*.js'])
599
+ *
600
+ * @returns the current cli intance
601
+ */
602
+ discoverCommandsFrom(paths) {
603
+ this.config.discoveryPaths = paths;
604
+ return this;
605
+ }
606
+ async loadDiscoveredCommands() {
607
+ const commands = [...(this.app.registeredCommands ?? []).map((cmd) => new cmd(this.app, this.kernel))];
608
+ const paths = __h3ravel_support.Arr.wrap(this.config.discoveryPaths);
609
+ /**
610
+ * CLI Commands auto registration
611
+ */
612
+ for await (const pth of glob.glob.stream(paths)) {
613
+ const name$1 = node_path.default.basename(pth).replace(".js", "").replace(".ts", "");
614
+ try {
615
+ const cmdClass = (await import(pth))[name$1];
616
+ commands.push(new cmdClass(this.app, this.kernel));
617
+ } catch {}
618
+ }
619
+ commands.forEach((e) => this.addCommand(e));
620
+ }
621
+ addCommand(command) {
622
+ this.commands.push(Signature.parseSignature(command.getSignature(), command));
623
+ }
624
+ async initialize() {
625
+ if (process.argv.includes("--help") || process.argv.includes("-h")) await this.rebuild("help");
626
+ /**
627
+ * Get the provided packages versions
628
+ */
629
+ const moduleVersions = this.kernel.modules.map((e) => {
630
+ return __h3ravel_shared.Logger.parse([[`${__h3ravel_support.Str.of(e.name).after("/").apa().title().replace("cli", "CLI", false)}:`, "white"], [e.version, "green"]], " ", false);
631
+ }).join("\n");
632
+ const additional = {
633
+ quiet: ["-q, --quiet", "Do not output any message except errors and warnings"],
634
+ silent: ["--silent", "Do not output any message"],
635
+ verbose: ["-v, --verbose [level]", "Increase the verbosity of messages: 1 for normal output, 2 and v for more verbose output and 3 and vv for debug"],
636
+ noInteraction: ["-n, --no-interaction", "Do not ask any interactive question"]
637
+ };
638
+ /**
639
+ * Init Commander
640
+ */
641
+ commander.program.name(this.cliName).version(moduleVersions).description(this.config.logo ?? altLogo).configureHelp({ showGlobalOptions: true }).addOption(new commander.Option(additional.quiet[0], additional.quiet[1])).addOption(new commander.Option(additional.silent[0], additional.silent[1]).implies({ quiet: true })).addOption(new commander.Option(additional.verbose[0], additional.verbose[1]).choices([
642
+ "1",
643
+ "2",
644
+ "3",
645
+ "v",
646
+ "vv"
647
+ ]).default("1")).addOption(new commander.Option(additional.noInteraction[0], additional.noInteraction[1])).action(async () => {
648
+ const instance = new ListCommand(this.app, this.kernel);
649
+ instance.setInput(commander.program.opts(), commander.program.args, commander.program.registeredArguments, {}, commander.program);
650
+ await this.handle(instance);
651
+ });
652
+ /**
653
+ * Format the help command display
654
+ */
655
+ commander.program.configureHelp({
656
+ styleTitle: (str) => __h3ravel_shared.Logger.log(str, "yellow", false),
657
+ styleOptionTerm: (str) => __h3ravel_shared.Logger.log(str, "green", false),
658
+ styleArgumentTerm: (str) => __h3ravel_shared.Logger.log(str, "green", false),
659
+ styleSubcommandTerm: (str) => __h3ravel_shared.Logger.log(str, "green", false),
660
+ formatItemList(heading, items) {
661
+ if (items.length < 1) return [];
662
+ if (!heading.includes("Commands:")) return items;
663
+ const c = (str) => str.replace(/[^A-Za-z0-9-,]/g, "").replace("32m", "");
664
+ let flags = items.filter((e) => c(e).startsWith("--") || c(e).includes(",--"));
665
+ if (flags.length > 0) flags = [__h3ravel_shared.Logger.log("\n" + heading + "\n", "yellow", false)].concat(flags);
666
+ const list = items.filter((e) => !c(e).startsWith("--") && !c(e).includes(",--"));
667
+ if (list.length < 1) return flags;
668
+ const _heading = c(heading).includes("Arguments") ? heading : "Available Commands:";
669
+ return flags.concat(__h3ravel_shared.Logger.log(`\n${_heading}`, "yellow", false), ListCommand.groupItems(list, true));
670
+ },
671
+ showGlobalOptions: true
672
+ });
673
+ /**
674
+ * Loop through all the available commands
675
+ */
676
+ for (let i = 0; i < this.commands.length; i++) {
677
+ const command = this.commands[i];
678
+ const instance = command.commandClass;
679
+ if (command.isNamespaceCommand && command.subCommands) {
680
+ /**
681
+ * Initialize the base command
682
+ */
683
+ const cmd = command.isHidden ? commander.program : commander.program.command(command.baseCommand).description(command.description ?? "").action(async () => {
684
+ instance.setInput(cmd.opts(), cmd.args, cmd.registeredArguments, command, commander.program);
685
+ await this.handle(instance);
686
+ });
687
+ /**
688
+ * Add options to the base command if it has any
689
+ */
690
+ if ((command.options?.length ?? 0) > 0) command.options?.filter((v, i$1, a) => a.findIndex((t) => t.name === v.name) === i$1).forEach((opt) => {
691
+ this.makeOption(opt, cmd);
692
+ });
693
+ /**
694
+ * Initialize the sub commands
695
+ */
696
+ command.subCommands.filter((v, i$1, a) => !v.shared && a.findIndex((t) => t.name === v.name) === i$1).forEach((sub) => {
697
+ const cmd$1 = commander.program.command(`${command.baseCommand}:${sub.name}`).description(sub.description || "").action(async () => {
698
+ instance.setInput(cmd$1.opts(), cmd$1.args, cmd$1.registeredArguments, sub, commander.program);
699
+ await this.handle(instance);
700
+ });
701
+ /**
702
+ * Add the shared arguments here
703
+ */
704
+ command.subCommands?.filter((e) => e.shared).forEach((opt) => {
705
+ this.makeOption(opt, cmd$1, false, sub);
706
+ });
707
+ /**
708
+ * Add the shared options here
709
+ */
710
+ command.options?.filter((e) => e.shared).forEach((opt) => {
711
+ this.makeOption(opt, cmd$1, false, sub);
712
+ });
713
+ /**
714
+ * Add options to the sub command if it has any
715
+ */
716
+ if (sub.nestedOptions) sub.nestedOptions.filter((v, i$1, a) => a.findIndex((t) => t.name === v.name) === i$1).forEach((opt) => {
717
+ this.makeOption(opt, cmd$1);
718
+ });
719
+ });
720
+ } else {
721
+ /**
722
+ * Initialize command with options
723
+ */
724
+ const cmd = commander.program.command(command.baseCommand).description(command.description ?? "");
725
+ command?.options?.filter((v, i$1, a) => a.findIndex((t) => t.name === v.name) === i$1).forEach((opt) => {
726
+ this.makeOption(opt, cmd, true);
727
+ });
728
+ cmd.action(async () => {
729
+ instance.setInput(cmd.opts(), cmd.args, cmd.registeredArguments, command, commander.program);
730
+ await this.handle(instance);
731
+ });
732
+ }
733
+ }
734
+ /**
735
+ * Rebuild the app on every command except fire so we wont need TS
736
+ */
737
+ commander.program.hook("preAction", async (_, cmd) => {
738
+ this.rebuild(cmd.name());
739
+ });
740
+ return commander.program;
741
+ }
742
+ async rebuild(name$1) {
743
+ if (name$1 !== "fire" && name$1 !== "build") await (0, tsdown.build)({
744
+ ...this.tsDownConfig,
745
+ logLevel: "silent",
746
+ watch: false,
747
+ plugins: []
748
+ });
749
+ }
750
+ makeOption(opt, cmd, parse, parent) {
751
+ const description$1 = opt.description?.replace(/\[(\w+)\]/g, (_, k) => parent?.[k] ?? `[${k}]`) ?? "";
752
+ const type$1 = opt.name.replaceAll("-", "");
753
+ if (opt.isFlag) if (parse) {
754
+ let flags = opt.flags?.map((f) => f.length === 1 ? `-${f}` : `--${f.replace(/^-+/, "")}`).join(", ") ?? void 0;
755
+ if (opt.required && !opt.placeholder) flags += ` <${type$1}>`;
756
+ else if (opt.placeholder) flags += " " + opt.placeholder;
757
+ let optn = new commander.Option(flags || "", description$1).default(opt.defaultValue);
758
+ if (opt.choices && opt.choices.length) optn = optn.choices(opt.choices ?? []);
759
+ cmd.addOption(optn);
760
+ } else {
761
+ let flags = opt.flags?.join(", ") ?? "";
762
+ if (opt.required && !opt.placeholder) flags += ` <${type$1}>`;
763
+ else if (opt.placeholder) flags += " " + opt.placeholder;
764
+ let optn = new commander.Option(flags, description$1).default(opt.defaultValue);
765
+ if (opt.choices && opt.choices.length) optn = optn.choices(opt.choices ?? []);
766
+ cmd.addOption(optn);
767
+ }
768
+ else {
769
+ let name$1 = opt.placeholder;
770
+ if (!name$1) name$1 = opt.required ? `<${opt.name}>` : `[${opt.name}]`;
771
+ let arg = new commander.Argument(name$1, description$1);
772
+ if (opt.choices && opt.choices.length) arg = arg.choices(opt.choices ?? []);
773
+ if (opt.defaultValue) arg.default(opt.defaultValue);
774
+ cmd.addArgument(arg);
775
+ }
776
+ }
777
+ async handle(cmd) {
778
+ if (this.resolver) return await this.resolver(cmd, "handle");
779
+ await cmd.handle(this.app);
780
+ }
781
+ static async parse(kernel, config = {}) {
782
+ const commands = config.baseCommands?.map((e) => new e(kernel.app, kernel));
783
+ const cli = new Musket(kernel.app, kernel, commands, config.resolver).configure(config);
784
+ if (config.cliName) cli.cliName = config.cliName;
785
+ const command = (await cli.build()).exitOverride((e) => {
786
+ if (e.exitCode <= 0) return;
787
+ __h3ravel_shared.Logger.log("Unknown command or argument.", "white");
788
+ __h3ravel_shared.Logger.log([
789
+ ["Run", "white"],
790
+ [`\`${config.cliName} --help\``, ["grey", "italic"]],
791
+ ["to see available commands.", "white"]
792
+ ], " ");
793
+ });
794
+ if (!config.skipParsing) await command.parseAsync(process.argv).catch((e) => e);
795
+ if (cli.app) cli.app.musket = cli;
796
+ return command;
797
+ }
798
+ };
799
+
800
+ //#endregion
801
+ //#region package.json
802
+ var name = "@h3ravel/musket";
803
+ var version = "0.1.0";
804
+ var description = "Musket CLI is a framework-agnostic CLI framework designed to allow you build artisan-like CLI apps and for use in the H3ravel framework.";
805
+ var type = "module";
806
+ var exports$1 = {
807
+ ".": {
808
+ "import": "./dist/index.js",
809
+ "require": "./dist/index.cjs"
810
+ },
811
+ "./Utils": {
812
+ "import": "./dist/Utils.js",
813
+ "require": "./dist/Utils.cjs"
814
+ }
815
+ };
816
+ var typesVersions = { "*": {
817
+ "Utils": ["dist/Utils.d.ts"],
818
+ "*": ["dist/index.d.ts"]
819
+ } };
820
+ var files = ["dist"];
821
+ var publishConfig = { "access": "public" };
822
+ var homepage = "https://h3ravel.toneflix.net/guide/deeper/musket";
823
+ var repository = {
824
+ "type": "git",
825
+ "url": "git+https://github.com/h3ravel/musket.git"
826
+ };
827
+ var keywords = [
828
+ "h3ravel",
829
+ "modern",
830
+ "web",
831
+ "H3",
832
+ "framework",
833
+ "nodejs",
834
+ "typescript",
835
+ "laravel",
836
+ "artisan",
837
+ "musket",
838
+ "commander",
839
+ "command",
840
+ "CLI",
841
+ "build",
842
+ "console"
843
+ ];
844
+ var scripts = {
845
+ "build": "tsdown --config-loader unconfig",
846
+ "lint": "eslint . --ext .ts",
847
+ "barrel": "barrelize >/dev/null",
848
+ "test": "vitest",
849
+ "coverage": "vitest --coverage",
850
+ "cmd": "tsx --experimental-specifier-resolution=node tests/run",
851
+ "release:patch": "pnpm build && pnpm version patch && git add . && git commit -m \"version: bump console package version\" && pnpm publish --tag latest",
852
+ "version-patch": "pnpm version patch",
853
+ "postinstall": "pnpm barrel"
854
+ };
855
+ var peerDependencies = { "@h3ravel/support": "^0.14.1" };
856
+ var devDependencies = {
857
+ "@types/node": "^24.7.2",
858
+ "@typescript-eslint/eslint-plugin": "^8.44.0",
859
+ "@typescript-eslint/parser": "^8.44.0",
860
+ "@vitest/coverage-v8": "^3.2.4",
861
+ "barrelize": "^1.6.4",
862
+ "eslint": "^9.36.0",
863
+ "husky": "^9.1.7",
864
+ "tsdown": "^0.15.7",
865
+ "typescript": "^5.9.2",
866
+ "vite-tsconfig-paths": "^5.1.4",
867
+ "vitest": "^3.2.4"
868
+ };
869
+ var dependencies = {
870
+ "@h3ravel/shared": "^0.22.2",
871
+ "chalk": "^5.6.2",
872
+ "commander": "^14.0.1",
873
+ "dayjs": "^1.11.18",
874
+ "execa": "^9.6.0",
875
+ "glob": "^11.0.3",
876
+ "preferred-pm": "^4.1.1",
877
+ "radashi": "^12.6.2",
878
+ "resolve-from": "^5.0.0",
879
+ "tsx": "^4.20.5"
880
+ };
881
+ var packageManager = "pnpm@10.18.2";
882
+ var engines = { "node": "^20.19.0 || >=22.12.0" };
883
+ var package_default = {
884
+ name,
885
+ version,
886
+ description,
887
+ type,
888
+ exports: exports$1,
889
+ typesVersions,
890
+ files,
891
+ publishConfig,
892
+ homepage,
893
+ repository,
894
+ keywords,
895
+ scripts,
896
+ peerDependencies,
897
+ devDependencies,
898
+ dependencies,
899
+ packageManager,
900
+ engines
901
+ };
902
+
903
+ //#endregion
904
+ //#region src/Core/Kernel.ts
905
+ var Kernel = class Kernel {
906
+ cwd;
907
+ output = typeof __h3ravel_shared.Logger;
908
+ modules = [];
909
+ basePath = "";
910
+ packages = [];
911
+ config = {};
912
+ constructor(app) {
913
+ this.app = app;
914
+ }
915
+ async ensureDirectoryExists(dir) {
916
+ await (0, node_fs_promises.mkdir)(dir, { recursive: true });
917
+ }
918
+ static async init(app, config = {}) {
919
+ const instance = new Kernel(app);
920
+ instance.config = config;
921
+ instance.packages = config.packages ?? [];
922
+ return (await instance.loadRequirements()).run();
923
+ }
924
+ async run() {
925
+ return await Musket.parse(this, this.config);
926
+ }
927
+ async loadRequirements() {
928
+ this.cwd = node_path.default.join(process.cwd(), this.basePath);
929
+ try {
930
+ package_default.name = this.config.cliName ?? package_default.name;
931
+ this.modules.push(package_default);
932
+ } catch {}
933
+ for (let i = 0; i < this.packages.length; i++) try {
934
+ const name$1 = this.packages[i];
935
+ const modulePath = __h3ravel_shared.FileSystem.findModulePkg(name$1, this.cwd) ?? "";
936
+ this.modules.push(await import(node_path.default.join(modulePath, "package.json")));
937
+ } catch (e) {
938
+ this.modules.push({
939
+ version: "N/A",
940
+ name: "Unknown"
941
+ });
942
+ }
943
+ return this;
944
+ }
945
+ };
946
+
947
+ //#endregion
948
+ exports.Command = Command;
949
+ exports.Kernel = Kernel;
950
+ exports.Musket = Musket;
951
+ exports.Signature = Signature;