@vhyxvoid/agent 1.0.2 → 1.0.6

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.
@@ -0,0 +1,4952 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __commonJS = (cb, mod) => function __require() {
5
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
6
+ };
7
+
8
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/error.js
9
+ var require_error = __commonJS({
10
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/error.js"(exports2) {
11
+ var CommanderError = class extends Error {
12
+ /**
13
+ * Constructs the CommanderError class
14
+ * @param {number} exitCode suggested exit code which could be used with process.exit
15
+ * @param {string} code an id string representing the error
16
+ * @param {string} message human-readable description of the error
17
+ */
18
+ constructor(exitCode, code, message) {
19
+ super(message);
20
+ Error.captureStackTrace(this, this.constructor);
21
+ this.name = this.constructor.name;
22
+ this.code = code;
23
+ this.exitCode = exitCode;
24
+ this.nestedError = void 0;
25
+ }
26
+ };
27
+ var InvalidArgumentError = class extends CommanderError {
28
+ /**
29
+ * Constructs the InvalidArgumentError class
30
+ * @param {string} [message] explanation of why argument is invalid
31
+ */
32
+ constructor(message) {
33
+ super(1, "commander.invalidArgument", message);
34
+ Error.captureStackTrace(this, this.constructor);
35
+ this.name = this.constructor.name;
36
+ }
37
+ };
38
+ exports2.CommanderError = CommanderError;
39
+ exports2.InvalidArgumentError = InvalidArgumentError;
40
+ }
41
+ });
42
+
43
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/argument.js
44
+ var require_argument = __commonJS({
45
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/argument.js"(exports2) {
46
+ var { InvalidArgumentError } = require_error();
47
+ var Argument = class {
48
+ /**
49
+ * Initialize a new command argument with the given name and description.
50
+ * The default is that the argument is required, and you can explicitly
51
+ * indicate this with <> around the name. Put [] around the name for an optional argument.
52
+ *
53
+ * @param {string} name
54
+ * @param {string} [description]
55
+ */
56
+ constructor(name, description) {
57
+ this.description = description || "";
58
+ this.variadic = false;
59
+ this.parseArg = void 0;
60
+ this.defaultValue = void 0;
61
+ this.defaultValueDescription = void 0;
62
+ this.argChoices = void 0;
63
+ switch (name[0]) {
64
+ case "<":
65
+ this.required = true;
66
+ this._name = name.slice(1, -1);
67
+ break;
68
+ case "[":
69
+ this.required = false;
70
+ this._name = name.slice(1, -1);
71
+ break;
72
+ default:
73
+ this.required = true;
74
+ this._name = name;
75
+ break;
76
+ }
77
+ if (this._name.endsWith("...")) {
78
+ this.variadic = true;
79
+ this._name = this._name.slice(0, -3);
80
+ }
81
+ }
82
+ /**
83
+ * Return argument name.
84
+ *
85
+ * @return {string}
86
+ */
87
+ name() {
88
+ return this._name;
89
+ }
90
+ /**
91
+ * @package
92
+ */
93
+ _collectValue(value, previous) {
94
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
95
+ return [value];
96
+ }
97
+ previous.push(value);
98
+ return previous;
99
+ }
100
+ /**
101
+ * Set the default value, and optionally supply the description to be displayed in the help.
102
+ *
103
+ * @param {*} value
104
+ * @param {string} [description]
105
+ * @return {Argument}
106
+ */
107
+ default(value, description) {
108
+ this.defaultValue = value;
109
+ this.defaultValueDescription = description;
110
+ return this;
111
+ }
112
+ /**
113
+ * Set the custom handler for processing CLI command arguments into argument values.
114
+ *
115
+ * @param {Function} [fn]
116
+ * @return {Argument}
117
+ */
118
+ argParser(fn) {
119
+ this.parseArg = fn;
120
+ return this;
121
+ }
122
+ /**
123
+ * Only allow argument value to be one of choices.
124
+ *
125
+ * @param {string[]} values
126
+ * @return {Argument}
127
+ */
128
+ choices(values) {
129
+ this.argChoices = values.slice();
130
+ this.parseArg = (arg, previous) => {
131
+ if (!this.argChoices.includes(arg)) {
132
+ throw new InvalidArgumentError(
133
+ `Allowed choices are ${this.argChoices.join(", ")}.`
134
+ );
135
+ }
136
+ if (this.variadic) {
137
+ return this._collectValue(arg, previous);
138
+ }
139
+ return arg;
140
+ };
141
+ return this;
142
+ }
143
+ /**
144
+ * Make argument required.
145
+ *
146
+ * @returns {Argument}
147
+ */
148
+ argRequired() {
149
+ this.required = true;
150
+ return this;
151
+ }
152
+ /**
153
+ * Make argument optional.
154
+ *
155
+ * @returns {Argument}
156
+ */
157
+ argOptional() {
158
+ this.required = false;
159
+ return this;
160
+ }
161
+ };
162
+ function humanReadableArgName(arg) {
163
+ const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
164
+ return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
165
+ }
166
+ exports2.Argument = Argument;
167
+ exports2.humanReadableArgName = humanReadableArgName;
168
+ }
169
+ });
170
+
171
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/help.js
172
+ var require_help = __commonJS({
173
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/help.js"(exports2) {
174
+ var { humanReadableArgName } = require_argument();
175
+ var Help = class {
176
+ constructor() {
177
+ this.helpWidth = void 0;
178
+ this.minWidthToWrap = 40;
179
+ this.sortSubcommands = false;
180
+ this.sortOptions = false;
181
+ this.showGlobalOptions = false;
182
+ }
183
+ /**
184
+ * prepareContext is called by Commander after applying overrides from `Command.configureHelp()`
185
+ * and just before calling `formatHelp()`.
186
+ *
187
+ * Commander just uses the helpWidth and the rest is provided for optional use by more complex subclasses.
188
+ *
189
+ * @param {{ error?: boolean, helpWidth?: number, outputHasColors?: boolean }} contextOptions
190
+ */
191
+ prepareContext(contextOptions) {
192
+ this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
193
+ }
194
+ /**
195
+ * Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
196
+ *
197
+ * @param {Command} cmd
198
+ * @returns {Command[]}
199
+ */
200
+ visibleCommands(cmd) {
201
+ const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
202
+ const helpCommand = cmd._getHelpCommand();
203
+ if (helpCommand && !helpCommand._hidden) {
204
+ visibleCommands.push(helpCommand);
205
+ }
206
+ if (this.sortSubcommands) {
207
+ visibleCommands.sort((a, b) => {
208
+ return a.name().localeCompare(b.name());
209
+ });
210
+ }
211
+ return visibleCommands;
212
+ }
213
+ /**
214
+ * Compare options for sort.
215
+ *
216
+ * @param {Option} a
217
+ * @param {Option} b
218
+ * @returns {number}
219
+ */
220
+ compareOptions(a, b) {
221
+ const getSortKey = (option) => {
222
+ return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
223
+ };
224
+ return getSortKey(a).localeCompare(getSortKey(b));
225
+ }
226
+ /**
227
+ * Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
228
+ *
229
+ * @param {Command} cmd
230
+ * @returns {Option[]}
231
+ */
232
+ visibleOptions(cmd) {
233
+ const visibleOptions = cmd.options.filter((option) => !option.hidden);
234
+ const helpOption = cmd._getHelpOption();
235
+ if (helpOption && !helpOption.hidden) {
236
+ const removeShort = helpOption.short && cmd._findOption(helpOption.short);
237
+ const removeLong = helpOption.long && cmd._findOption(helpOption.long);
238
+ if (!removeShort && !removeLong) {
239
+ visibleOptions.push(helpOption);
240
+ } else if (helpOption.long && !removeLong) {
241
+ visibleOptions.push(
242
+ cmd.createOption(helpOption.long, helpOption.description)
243
+ );
244
+ } else if (helpOption.short && !removeShort) {
245
+ visibleOptions.push(
246
+ cmd.createOption(helpOption.short, helpOption.description)
247
+ );
248
+ }
249
+ }
250
+ if (this.sortOptions) {
251
+ visibleOptions.sort(this.compareOptions);
252
+ }
253
+ return visibleOptions;
254
+ }
255
+ /**
256
+ * Get an array of the visible global options. (Not including help.)
257
+ *
258
+ * @param {Command} cmd
259
+ * @returns {Option[]}
260
+ */
261
+ visibleGlobalOptions(cmd) {
262
+ if (!this.showGlobalOptions) return [];
263
+ const globalOptions = [];
264
+ for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
265
+ const visibleOptions = ancestorCmd.options.filter(
266
+ (option) => !option.hidden
267
+ );
268
+ globalOptions.push(...visibleOptions);
269
+ }
270
+ if (this.sortOptions) {
271
+ globalOptions.sort(this.compareOptions);
272
+ }
273
+ return globalOptions;
274
+ }
275
+ /**
276
+ * Get an array of the arguments if any have a description.
277
+ *
278
+ * @param {Command} cmd
279
+ * @returns {Argument[]}
280
+ */
281
+ visibleArguments(cmd) {
282
+ if (cmd._argsDescription) {
283
+ cmd.registeredArguments.forEach((argument) => {
284
+ argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
285
+ });
286
+ }
287
+ if (cmd.registeredArguments.find((argument) => argument.description)) {
288
+ return cmd.registeredArguments;
289
+ }
290
+ return [];
291
+ }
292
+ /**
293
+ * Get the command term to show in the list of subcommands.
294
+ *
295
+ * @param {Command} cmd
296
+ * @returns {string}
297
+ */
298
+ subcommandTerm(cmd) {
299
+ const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
300
+ return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option
301
+ (args ? " " + args : "");
302
+ }
303
+ /**
304
+ * Get the option term to show in the list of options.
305
+ *
306
+ * @param {Option} option
307
+ * @returns {string}
308
+ */
309
+ optionTerm(option) {
310
+ return option.flags;
311
+ }
312
+ /**
313
+ * Get the argument term to show in the list of arguments.
314
+ *
315
+ * @param {Argument} argument
316
+ * @returns {string}
317
+ */
318
+ argumentTerm(argument) {
319
+ return argument.name();
320
+ }
321
+ /**
322
+ * Get the longest command term length.
323
+ *
324
+ * @param {Command} cmd
325
+ * @param {Help} helper
326
+ * @returns {number}
327
+ */
328
+ longestSubcommandTermLength(cmd, helper) {
329
+ return helper.visibleCommands(cmd).reduce((max, command) => {
330
+ return Math.max(
331
+ max,
332
+ this.displayWidth(
333
+ helper.styleSubcommandTerm(helper.subcommandTerm(command))
334
+ )
335
+ );
336
+ }, 0);
337
+ }
338
+ /**
339
+ * Get the longest option term length.
340
+ *
341
+ * @param {Command} cmd
342
+ * @param {Help} helper
343
+ * @returns {number}
344
+ */
345
+ longestOptionTermLength(cmd, helper) {
346
+ return helper.visibleOptions(cmd).reduce((max, option) => {
347
+ return Math.max(
348
+ max,
349
+ this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))
350
+ );
351
+ }, 0);
352
+ }
353
+ /**
354
+ * Get the longest global option term length.
355
+ *
356
+ * @param {Command} cmd
357
+ * @param {Help} helper
358
+ * @returns {number}
359
+ */
360
+ longestGlobalOptionTermLength(cmd, helper) {
361
+ return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
362
+ return Math.max(
363
+ max,
364
+ this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))
365
+ );
366
+ }, 0);
367
+ }
368
+ /**
369
+ * Get the longest argument term length.
370
+ *
371
+ * @param {Command} cmd
372
+ * @param {Help} helper
373
+ * @returns {number}
374
+ */
375
+ longestArgumentTermLength(cmd, helper) {
376
+ return helper.visibleArguments(cmd).reduce((max, argument) => {
377
+ return Math.max(
378
+ max,
379
+ this.displayWidth(
380
+ helper.styleArgumentTerm(helper.argumentTerm(argument))
381
+ )
382
+ );
383
+ }, 0);
384
+ }
385
+ /**
386
+ * Get the command usage to be displayed at the top of the built-in help.
387
+ *
388
+ * @param {Command} cmd
389
+ * @returns {string}
390
+ */
391
+ commandUsage(cmd) {
392
+ let cmdName = cmd._name;
393
+ if (cmd._aliases[0]) {
394
+ cmdName = cmdName + "|" + cmd._aliases[0];
395
+ }
396
+ let ancestorCmdNames = "";
397
+ for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
398
+ ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
399
+ }
400
+ return ancestorCmdNames + cmdName + " " + cmd.usage();
401
+ }
402
+ /**
403
+ * Get the description for the command.
404
+ *
405
+ * @param {Command} cmd
406
+ * @returns {string}
407
+ */
408
+ commandDescription(cmd) {
409
+ return cmd.description();
410
+ }
411
+ /**
412
+ * Get the subcommand summary to show in the list of subcommands.
413
+ * (Fallback to description for backwards compatibility.)
414
+ *
415
+ * @param {Command} cmd
416
+ * @returns {string}
417
+ */
418
+ subcommandDescription(cmd) {
419
+ return cmd.summary() || cmd.description();
420
+ }
421
+ /**
422
+ * Get the option description to show in the list of options.
423
+ *
424
+ * @param {Option} option
425
+ * @return {string}
426
+ */
427
+ optionDescription(option) {
428
+ const extraInfo = [];
429
+ if (option.argChoices) {
430
+ extraInfo.push(
431
+ // use stringify to match the display of the default value
432
+ `choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
433
+ );
434
+ }
435
+ if (option.defaultValue !== void 0) {
436
+ const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
437
+ if (showDefault) {
438
+ extraInfo.push(
439
+ `default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`
440
+ );
441
+ }
442
+ }
443
+ if (option.presetArg !== void 0 && option.optional) {
444
+ extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
445
+ }
446
+ if (option.envVar !== void 0) {
447
+ extraInfo.push(`env: ${option.envVar}`);
448
+ }
449
+ if (extraInfo.length > 0) {
450
+ const extraDescription = `(${extraInfo.join(", ")})`;
451
+ if (option.description) {
452
+ return `${option.description} ${extraDescription}`;
453
+ }
454
+ return extraDescription;
455
+ }
456
+ return option.description;
457
+ }
458
+ /**
459
+ * Get the argument description to show in the list of arguments.
460
+ *
461
+ * @param {Argument} argument
462
+ * @return {string}
463
+ */
464
+ argumentDescription(argument) {
465
+ const extraInfo = [];
466
+ if (argument.argChoices) {
467
+ extraInfo.push(
468
+ // use stringify to match the display of the default value
469
+ `choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
470
+ );
471
+ }
472
+ if (argument.defaultValue !== void 0) {
473
+ extraInfo.push(
474
+ `default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`
475
+ );
476
+ }
477
+ if (extraInfo.length > 0) {
478
+ const extraDescription = `(${extraInfo.join(", ")})`;
479
+ if (argument.description) {
480
+ return `${argument.description} ${extraDescription}`;
481
+ }
482
+ return extraDescription;
483
+ }
484
+ return argument.description;
485
+ }
486
+ /**
487
+ * Format a list of items, given a heading and an array of formatted items.
488
+ *
489
+ * @param {string} heading
490
+ * @param {string[]} items
491
+ * @param {Help} helper
492
+ * @returns string[]
493
+ */
494
+ formatItemList(heading, items, helper) {
495
+ if (items.length === 0) return [];
496
+ return [helper.styleTitle(heading), ...items, ""];
497
+ }
498
+ /**
499
+ * Group items by their help group heading.
500
+ *
501
+ * @param {Command[] | Option[]} unsortedItems
502
+ * @param {Command[] | Option[]} visibleItems
503
+ * @param {Function} getGroup
504
+ * @returns {Map<string, Command[] | Option[]>}
505
+ */
506
+ groupItems(unsortedItems, visibleItems, getGroup) {
507
+ const result = /* @__PURE__ */ new Map();
508
+ unsortedItems.forEach((item) => {
509
+ const group = getGroup(item);
510
+ if (!result.has(group)) result.set(group, []);
511
+ });
512
+ visibleItems.forEach((item) => {
513
+ const group = getGroup(item);
514
+ if (!result.has(group)) {
515
+ result.set(group, []);
516
+ }
517
+ result.get(group).push(item);
518
+ });
519
+ return result;
520
+ }
521
+ /**
522
+ * Generate the built-in help text.
523
+ *
524
+ * @param {Command} cmd
525
+ * @param {Help} helper
526
+ * @returns {string}
527
+ */
528
+ formatHelp(cmd, helper) {
529
+ const termWidth = helper.padWidth(cmd, helper);
530
+ const helpWidth = helper.helpWidth ?? 80;
531
+ function callFormatItem(term, description) {
532
+ return helper.formatItem(term, termWidth, description, helper);
533
+ }
534
+ let output = [
535
+ `${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
536
+ ""
537
+ ];
538
+ const commandDescription = helper.commandDescription(cmd);
539
+ if (commandDescription.length > 0) {
540
+ output = output.concat([
541
+ helper.boxWrap(
542
+ helper.styleCommandDescription(commandDescription),
543
+ helpWidth
544
+ ),
545
+ ""
546
+ ]);
547
+ }
548
+ const argumentList = helper.visibleArguments(cmd).map((argument) => {
549
+ return callFormatItem(
550
+ helper.styleArgumentTerm(helper.argumentTerm(argument)),
551
+ helper.styleArgumentDescription(helper.argumentDescription(argument))
552
+ );
553
+ });
554
+ output = output.concat(
555
+ this.formatItemList("Arguments:", argumentList, helper)
556
+ );
557
+ const optionGroups = this.groupItems(
558
+ cmd.options,
559
+ helper.visibleOptions(cmd),
560
+ (option) => option.helpGroupHeading ?? "Options:"
561
+ );
562
+ optionGroups.forEach((options, group) => {
563
+ const optionList = options.map((option) => {
564
+ return callFormatItem(
565
+ helper.styleOptionTerm(helper.optionTerm(option)),
566
+ helper.styleOptionDescription(helper.optionDescription(option))
567
+ );
568
+ });
569
+ output = output.concat(this.formatItemList(group, optionList, helper));
570
+ });
571
+ if (helper.showGlobalOptions) {
572
+ const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
573
+ return callFormatItem(
574
+ helper.styleOptionTerm(helper.optionTerm(option)),
575
+ helper.styleOptionDescription(helper.optionDescription(option))
576
+ );
577
+ });
578
+ output = output.concat(
579
+ this.formatItemList("Global Options:", globalOptionList, helper)
580
+ );
581
+ }
582
+ const commandGroups = this.groupItems(
583
+ cmd.commands,
584
+ helper.visibleCommands(cmd),
585
+ (sub) => sub.helpGroup() || "Commands:"
586
+ );
587
+ commandGroups.forEach((commands, group) => {
588
+ const commandList = commands.map((sub) => {
589
+ return callFormatItem(
590
+ helper.styleSubcommandTerm(helper.subcommandTerm(sub)),
591
+ helper.styleSubcommandDescription(helper.subcommandDescription(sub))
592
+ );
593
+ });
594
+ output = output.concat(this.formatItemList(group, commandList, helper));
595
+ });
596
+ return output.join("\n");
597
+ }
598
+ /**
599
+ * Return display width of string, ignoring ANSI escape sequences. Used in padding and wrapping calculations.
600
+ *
601
+ * @param {string} str
602
+ * @returns {number}
603
+ */
604
+ displayWidth(str) {
605
+ return stripColor(str).length;
606
+ }
607
+ /**
608
+ * Style the title for displaying in the help. Called with 'Usage:', 'Options:', etc.
609
+ *
610
+ * @param {string} str
611
+ * @returns {string}
612
+ */
613
+ styleTitle(str) {
614
+ return str;
615
+ }
616
+ styleUsage(str) {
617
+ return str.split(" ").map((word) => {
618
+ if (word === "[options]") return this.styleOptionText(word);
619
+ if (word === "[command]") return this.styleSubcommandText(word);
620
+ if (word[0] === "[" || word[0] === "<")
621
+ return this.styleArgumentText(word);
622
+ return this.styleCommandText(word);
623
+ }).join(" ");
624
+ }
625
+ styleCommandDescription(str) {
626
+ return this.styleDescriptionText(str);
627
+ }
628
+ styleOptionDescription(str) {
629
+ return this.styleDescriptionText(str);
630
+ }
631
+ styleSubcommandDescription(str) {
632
+ return this.styleDescriptionText(str);
633
+ }
634
+ styleArgumentDescription(str) {
635
+ return this.styleDescriptionText(str);
636
+ }
637
+ styleDescriptionText(str) {
638
+ return str;
639
+ }
640
+ styleOptionTerm(str) {
641
+ return this.styleOptionText(str);
642
+ }
643
+ styleSubcommandTerm(str) {
644
+ return str.split(" ").map((word) => {
645
+ if (word === "[options]") return this.styleOptionText(word);
646
+ if (word[0] === "[" || word[0] === "<")
647
+ return this.styleArgumentText(word);
648
+ return this.styleSubcommandText(word);
649
+ }).join(" ");
650
+ }
651
+ styleArgumentTerm(str) {
652
+ return this.styleArgumentText(str);
653
+ }
654
+ styleOptionText(str) {
655
+ return str;
656
+ }
657
+ styleArgumentText(str) {
658
+ return str;
659
+ }
660
+ styleSubcommandText(str) {
661
+ return str;
662
+ }
663
+ styleCommandText(str) {
664
+ return str;
665
+ }
666
+ /**
667
+ * Calculate the pad width from the maximum term length.
668
+ *
669
+ * @param {Command} cmd
670
+ * @param {Help} helper
671
+ * @returns {number}
672
+ */
673
+ padWidth(cmd, helper) {
674
+ return Math.max(
675
+ helper.longestOptionTermLength(cmd, helper),
676
+ helper.longestGlobalOptionTermLength(cmd, helper),
677
+ helper.longestSubcommandTermLength(cmd, helper),
678
+ helper.longestArgumentTermLength(cmd, helper)
679
+ );
680
+ }
681
+ /**
682
+ * Detect manually wrapped and indented strings by checking for line break followed by whitespace.
683
+ *
684
+ * @param {string} str
685
+ * @returns {boolean}
686
+ */
687
+ preformatted(str) {
688
+ return /\n[^\S\r\n]/.test(str);
689
+ }
690
+ /**
691
+ * Format the "item", which consists of a term and description. Pad the term and wrap the description, indenting the following lines.
692
+ *
693
+ * So "TTT", 5, "DDD DDDD DD DDD" might be formatted for this.helpWidth=17 like so:
694
+ * TTT DDD DDDD
695
+ * DD DDD
696
+ *
697
+ * @param {string} term
698
+ * @param {number} termWidth
699
+ * @param {string} description
700
+ * @param {Help} helper
701
+ * @returns {string}
702
+ */
703
+ formatItem(term, termWidth, description, helper) {
704
+ const itemIndent = 2;
705
+ const itemIndentStr = " ".repeat(itemIndent);
706
+ if (!description) return itemIndentStr + term;
707
+ const paddedTerm = term.padEnd(
708
+ termWidth + term.length - helper.displayWidth(term)
709
+ );
710
+ const spacerWidth = 2;
711
+ const helpWidth = this.helpWidth ?? 80;
712
+ const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
713
+ let formattedDescription;
714
+ if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
715
+ formattedDescription = description;
716
+ } else {
717
+ const wrappedDescription = helper.boxWrap(description, remainingWidth);
718
+ formattedDescription = wrappedDescription.replace(
719
+ /\n/g,
720
+ "\n" + " ".repeat(termWidth + spacerWidth)
721
+ );
722
+ }
723
+ return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
724
+ ${itemIndentStr}`);
725
+ }
726
+ /**
727
+ * Wrap a string at whitespace, preserving existing line breaks.
728
+ * Wrapping is skipped if the width is less than `minWidthToWrap`.
729
+ *
730
+ * @param {string} str
731
+ * @param {number} width
732
+ * @returns {string}
733
+ */
734
+ boxWrap(str, width) {
735
+ if (width < this.minWidthToWrap) return str;
736
+ const rawLines = str.split(/\r\n|\n/);
737
+ const chunkPattern = /[\s]*[^\s]+/g;
738
+ const wrappedLines = [];
739
+ rawLines.forEach((line) => {
740
+ const chunks = line.match(chunkPattern);
741
+ if (chunks === null) {
742
+ wrappedLines.push("");
743
+ return;
744
+ }
745
+ let sumChunks = [chunks.shift()];
746
+ let sumWidth = this.displayWidth(sumChunks[0]);
747
+ chunks.forEach((chunk) => {
748
+ const visibleWidth = this.displayWidth(chunk);
749
+ if (sumWidth + visibleWidth <= width) {
750
+ sumChunks.push(chunk);
751
+ sumWidth += visibleWidth;
752
+ return;
753
+ }
754
+ wrappedLines.push(sumChunks.join(""));
755
+ const nextChunk = chunk.trimStart();
756
+ sumChunks = [nextChunk];
757
+ sumWidth = this.displayWidth(nextChunk);
758
+ });
759
+ wrappedLines.push(sumChunks.join(""));
760
+ });
761
+ return wrappedLines.join("\n");
762
+ }
763
+ };
764
+ function stripColor(str) {
765
+ const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
766
+ return str.replace(sgrPattern, "");
767
+ }
768
+ exports2.Help = Help;
769
+ exports2.stripColor = stripColor;
770
+ }
771
+ });
772
+
773
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/option.js
774
+ var require_option = __commonJS({
775
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/option.js"(exports2) {
776
+ var { InvalidArgumentError } = require_error();
777
+ var Option = class {
778
+ /**
779
+ * Initialize a new `Option` with the given `flags` and `description`.
780
+ *
781
+ * @param {string} flags
782
+ * @param {string} [description]
783
+ */
784
+ constructor(flags, description) {
785
+ this.flags = flags;
786
+ this.description = description || "";
787
+ this.required = flags.includes("<");
788
+ this.optional = flags.includes("[");
789
+ this.variadic = /\w\.\.\.[>\]]$/.test(flags);
790
+ this.mandatory = false;
791
+ const optionFlags = splitOptionFlags(flags);
792
+ this.short = optionFlags.shortFlag;
793
+ this.long = optionFlags.longFlag;
794
+ this.negate = false;
795
+ if (this.long) {
796
+ this.negate = this.long.startsWith("--no-");
797
+ }
798
+ this.defaultValue = void 0;
799
+ this.defaultValueDescription = void 0;
800
+ this.presetArg = void 0;
801
+ this.envVar = void 0;
802
+ this.parseArg = void 0;
803
+ this.hidden = false;
804
+ this.argChoices = void 0;
805
+ this.conflictsWith = [];
806
+ this.implied = void 0;
807
+ this.helpGroupHeading = void 0;
808
+ }
809
+ /**
810
+ * Set the default value, and optionally supply the description to be displayed in the help.
811
+ *
812
+ * @param {*} value
813
+ * @param {string} [description]
814
+ * @return {Option}
815
+ */
816
+ default(value, description) {
817
+ this.defaultValue = value;
818
+ this.defaultValueDescription = description;
819
+ return this;
820
+ }
821
+ /**
822
+ * Preset to use when option used without option-argument, especially optional but also boolean and negated.
823
+ * The custom processing (parseArg) is called.
824
+ *
825
+ * @example
826
+ * new Option('--color').default('GREYSCALE').preset('RGB');
827
+ * new Option('--donate [amount]').preset('20').argParser(parseFloat);
828
+ *
829
+ * @param {*} arg
830
+ * @return {Option}
831
+ */
832
+ preset(arg) {
833
+ this.presetArg = arg;
834
+ return this;
835
+ }
836
+ /**
837
+ * Add option name(s) that conflict with this option.
838
+ * An error will be displayed if conflicting options are found during parsing.
839
+ *
840
+ * @example
841
+ * new Option('--rgb').conflicts('cmyk');
842
+ * new Option('--js').conflicts(['ts', 'jsx']);
843
+ *
844
+ * @param {(string | string[])} names
845
+ * @return {Option}
846
+ */
847
+ conflicts(names) {
848
+ this.conflictsWith = this.conflictsWith.concat(names);
849
+ return this;
850
+ }
851
+ /**
852
+ * Specify implied option values for when this option is set and the implied options are not.
853
+ *
854
+ * The custom processing (parseArg) is not called on the implied values.
855
+ *
856
+ * @example
857
+ * program
858
+ * .addOption(new Option('--log', 'write logging information to file'))
859
+ * .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
860
+ *
861
+ * @param {object} impliedOptionValues
862
+ * @return {Option}
863
+ */
864
+ implies(impliedOptionValues) {
865
+ let newImplied = impliedOptionValues;
866
+ if (typeof impliedOptionValues === "string") {
867
+ newImplied = { [impliedOptionValues]: true };
868
+ }
869
+ this.implied = Object.assign(this.implied || {}, newImplied);
870
+ return this;
871
+ }
872
+ /**
873
+ * Set environment variable to check for option value.
874
+ *
875
+ * An environment variable is only used if when processed the current option value is
876
+ * undefined, or the source of the current value is 'default' or 'config' or 'env'.
877
+ *
878
+ * @param {string} name
879
+ * @return {Option}
880
+ */
881
+ env(name) {
882
+ this.envVar = name;
883
+ return this;
884
+ }
885
+ /**
886
+ * Set the custom handler for processing CLI option arguments into option values.
887
+ *
888
+ * @param {Function} [fn]
889
+ * @return {Option}
890
+ */
891
+ argParser(fn) {
892
+ this.parseArg = fn;
893
+ return this;
894
+ }
895
+ /**
896
+ * Whether the option is mandatory and must have a value after parsing.
897
+ *
898
+ * @param {boolean} [mandatory=true]
899
+ * @return {Option}
900
+ */
901
+ makeOptionMandatory(mandatory = true) {
902
+ this.mandatory = !!mandatory;
903
+ return this;
904
+ }
905
+ /**
906
+ * Hide option in help.
907
+ *
908
+ * @param {boolean} [hide=true]
909
+ * @return {Option}
910
+ */
911
+ hideHelp(hide = true) {
912
+ this.hidden = !!hide;
913
+ return this;
914
+ }
915
+ /**
916
+ * @package
917
+ */
918
+ _collectValue(value, previous) {
919
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
920
+ return [value];
921
+ }
922
+ previous.push(value);
923
+ return previous;
924
+ }
925
+ /**
926
+ * Only allow option value to be one of choices.
927
+ *
928
+ * @param {string[]} values
929
+ * @return {Option}
930
+ */
931
+ choices(values) {
932
+ this.argChoices = values.slice();
933
+ this.parseArg = (arg, previous) => {
934
+ if (!this.argChoices.includes(arg)) {
935
+ throw new InvalidArgumentError(
936
+ `Allowed choices are ${this.argChoices.join(", ")}.`
937
+ );
938
+ }
939
+ if (this.variadic) {
940
+ return this._collectValue(arg, previous);
941
+ }
942
+ return arg;
943
+ };
944
+ return this;
945
+ }
946
+ /**
947
+ * Return option name.
948
+ *
949
+ * @return {string}
950
+ */
951
+ name() {
952
+ if (this.long) {
953
+ return this.long.replace(/^--/, "");
954
+ }
955
+ return this.short.replace(/^-/, "");
956
+ }
957
+ /**
958
+ * Return option name, in a camelcase format that can be used
959
+ * as an object attribute key.
960
+ *
961
+ * @return {string}
962
+ */
963
+ attributeName() {
964
+ if (this.negate) {
965
+ return camelcase(this.name().replace(/^no-/, ""));
966
+ }
967
+ return camelcase(this.name());
968
+ }
969
+ /**
970
+ * Set the help group heading.
971
+ *
972
+ * @param {string} heading
973
+ * @return {Option}
974
+ */
975
+ helpGroup(heading) {
976
+ this.helpGroupHeading = heading;
977
+ return this;
978
+ }
979
+ /**
980
+ * Check if `arg` matches the short or long flag.
981
+ *
982
+ * @param {string} arg
983
+ * @return {boolean}
984
+ * @package
985
+ */
986
+ is(arg) {
987
+ return this.short === arg || this.long === arg;
988
+ }
989
+ /**
990
+ * Return whether a boolean option.
991
+ *
992
+ * Options are one of boolean, negated, required argument, or optional argument.
993
+ *
994
+ * @return {boolean}
995
+ * @package
996
+ */
997
+ isBoolean() {
998
+ return !this.required && !this.optional && !this.negate;
999
+ }
1000
+ };
1001
+ var DualOptions = class {
1002
+ /**
1003
+ * @param {Option[]} options
1004
+ */
1005
+ constructor(options) {
1006
+ this.positiveOptions = /* @__PURE__ */ new Map();
1007
+ this.negativeOptions = /* @__PURE__ */ new Map();
1008
+ this.dualOptions = /* @__PURE__ */ new Set();
1009
+ options.forEach((option) => {
1010
+ if (option.negate) {
1011
+ this.negativeOptions.set(option.attributeName(), option);
1012
+ } else {
1013
+ this.positiveOptions.set(option.attributeName(), option);
1014
+ }
1015
+ });
1016
+ this.negativeOptions.forEach((value, key) => {
1017
+ if (this.positiveOptions.has(key)) {
1018
+ this.dualOptions.add(key);
1019
+ }
1020
+ });
1021
+ }
1022
+ /**
1023
+ * Did the value come from the option, and not from possible matching dual option?
1024
+ *
1025
+ * @param {*} value
1026
+ * @param {Option} option
1027
+ * @returns {boolean}
1028
+ */
1029
+ valueFromOption(value, option) {
1030
+ const optionKey = option.attributeName();
1031
+ if (!this.dualOptions.has(optionKey)) return true;
1032
+ const preset = this.negativeOptions.get(optionKey).presetArg;
1033
+ const negativeValue = preset !== void 0 ? preset : false;
1034
+ return option.negate === (negativeValue === value);
1035
+ }
1036
+ };
1037
+ function camelcase(str) {
1038
+ return str.split("-").reduce((str2, word) => {
1039
+ return str2 + word[0].toUpperCase() + word.slice(1);
1040
+ });
1041
+ }
1042
+ function splitOptionFlags(flags) {
1043
+ let shortFlag;
1044
+ let longFlag;
1045
+ const shortFlagExp = /^-[^-]$/;
1046
+ const longFlagExp = /^--[^-]/;
1047
+ const flagParts = flags.split(/[ |,]+/).concat("guard");
1048
+ if (shortFlagExp.test(flagParts[0])) shortFlag = flagParts.shift();
1049
+ if (longFlagExp.test(flagParts[0])) longFlag = flagParts.shift();
1050
+ if (!shortFlag && shortFlagExp.test(flagParts[0]))
1051
+ shortFlag = flagParts.shift();
1052
+ if (!shortFlag && longFlagExp.test(flagParts[0])) {
1053
+ shortFlag = longFlag;
1054
+ longFlag = flagParts.shift();
1055
+ }
1056
+ if (flagParts[0].startsWith("-")) {
1057
+ const unsupportedFlag = flagParts[0];
1058
+ const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
1059
+ if (/^-[^-][^-]/.test(unsupportedFlag))
1060
+ throw new Error(
1061
+ `${baseError}
1062
+ - a short flag is a single dash and a single character
1063
+ - either use a single dash and a single character (for a short flag)
1064
+ - or use a double dash for a long option (and can have two, like '--ws, --workspace')`
1065
+ );
1066
+ if (shortFlagExp.test(unsupportedFlag))
1067
+ throw new Error(`${baseError}
1068
+ - too many short flags`);
1069
+ if (longFlagExp.test(unsupportedFlag))
1070
+ throw new Error(`${baseError}
1071
+ - too many long flags`);
1072
+ throw new Error(`${baseError}
1073
+ - unrecognised flag format`);
1074
+ }
1075
+ if (shortFlag === void 0 && longFlag === void 0)
1076
+ throw new Error(
1077
+ `option creation failed due to no flags found in '${flags}'.`
1078
+ );
1079
+ return { shortFlag, longFlag };
1080
+ }
1081
+ exports2.Option = Option;
1082
+ exports2.DualOptions = DualOptions;
1083
+ }
1084
+ });
1085
+
1086
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/suggestSimilar.js
1087
+ var require_suggestSimilar = __commonJS({
1088
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/suggestSimilar.js"(exports2) {
1089
+ var maxDistance = 3;
1090
+ function editDistance(a, b) {
1091
+ if (Math.abs(a.length - b.length) > maxDistance)
1092
+ return Math.max(a.length, b.length);
1093
+ const d = [];
1094
+ for (let i = 0; i <= a.length; i++) {
1095
+ d[i] = [i];
1096
+ }
1097
+ for (let j = 0; j <= b.length; j++) {
1098
+ d[0][j] = j;
1099
+ }
1100
+ for (let j = 1; j <= b.length; j++) {
1101
+ for (let i = 1; i <= a.length; i++) {
1102
+ let cost = 1;
1103
+ if (a[i - 1] === b[j - 1]) {
1104
+ cost = 0;
1105
+ } else {
1106
+ cost = 1;
1107
+ }
1108
+ d[i][j] = Math.min(
1109
+ d[i - 1][j] + 1,
1110
+ // deletion
1111
+ d[i][j - 1] + 1,
1112
+ // insertion
1113
+ d[i - 1][j - 1] + cost
1114
+ // substitution
1115
+ );
1116
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
1117
+ d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
1118
+ }
1119
+ }
1120
+ }
1121
+ return d[a.length][b.length];
1122
+ }
1123
+ function suggestSimilar(word, candidates) {
1124
+ if (!candidates || candidates.length === 0) return "";
1125
+ candidates = Array.from(new Set(candidates));
1126
+ const searchingOptions = word.startsWith("--");
1127
+ if (searchingOptions) {
1128
+ word = word.slice(2);
1129
+ candidates = candidates.map((candidate) => candidate.slice(2));
1130
+ }
1131
+ let similar = [];
1132
+ let bestDistance = maxDistance;
1133
+ const minSimilarity = 0.4;
1134
+ candidates.forEach((candidate) => {
1135
+ if (candidate.length <= 1) return;
1136
+ const distance = editDistance(word, candidate);
1137
+ const length = Math.max(word.length, candidate.length);
1138
+ const similarity = (length - distance) / length;
1139
+ if (similarity > minSimilarity) {
1140
+ if (distance < bestDistance) {
1141
+ bestDistance = distance;
1142
+ similar = [candidate];
1143
+ } else if (distance === bestDistance) {
1144
+ similar.push(candidate);
1145
+ }
1146
+ }
1147
+ });
1148
+ similar.sort((a, b) => a.localeCompare(b));
1149
+ if (searchingOptions) {
1150
+ similar = similar.map((candidate) => `--${candidate}`);
1151
+ }
1152
+ if (similar.length > 1) {
1153
+ return `
1154
+ (Did you mean one of ${similar.join(", ")}?)`;
1155
+ }
1156
+ if (similar.length === 1) {
1157
+ return `
1158
+ (Did you mean ${similar[0]}?)`;
1159
+ }
1160
+ return "";
1161
+ }
1162
+ exports2.suggestSimilar = suggestSimilar;
1163
+ }
1164
+ });
1165
+
1166
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/command.js
1167
+ var require_command = __commonJS({
1168
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/command.js"(exports2) {
1169
+ var EventEmitter = require("node:events").EventEmitter;
1170
+ var childProcess = require("node:child_process");
1171
+ var path = require("node:path");
1172
+ var fs = require("node:fs");
1173
+ var process2 = require("node:process");
1174
+ var { Argument, humanReadableArgName } = require_argument();
1175
+ var { CommanderError } = require_error();
1176
+ var { Help, stripColor } = require_help();
1177
+ var { Option, DualOptions } = require_option();
1178
+ var { suggestSimilar } = require_suggestSimilar();
1179
+ var Command = class _Command extends EventEmitter {
1180
+ /**
1181
+ * Initialize a new `Command`.
1182
+ *
1183
+ * @param {string} [name]
1184
+ */
1185
+ constructor(name) {
1186
+ super();
1187
+ this.commands = [];
1188
+ this.options = [];
1189
+ this.parent = null;
1190
+ this._allowUnknownOption = false;
1191
+ this._allowExcessArguments = false;
1192
+ this.registeredArguments = [];
1193
+ this._args = this.registeredArguments;
1194
+ this.args = [];
1195
+ this.rawArgs = [];
1196
+ this.processedArgs = [];
1197
+ this._scriptPath = null;
1198
+ this._name = name || "";
1199
+ this._optionValues = {};
1200
+ this._optionValueSources = {};
1201
+ this._storeOptionsAsProperties = false;
1202
+ this._actionHandler = null;
1203
+ this._executableHandler = false;
1204
+ this._executableFile = null;
1205
+ this._executableDir = null;
1206
+ this._defaultCommandName = null;
1207
+ this._exitCallback = null;
1208
+ this._aliases = [];
1209
+ this._combineFlagAndOptionalValue = true;
1210
+ this._description = "";
1211
+ this._summary = "";
1212
+ this._argsDescription = void 0;
1213
+ this._enablePositionalOptions = false;
1214
+ this._passThroughOptions = false;
1215
+ this._lifeCycleHooks = {};
1216
+ this._showHelpAfterError = false;
1217
+ this._showSuggestionAfterError = true;
1218
+ this._savedState = null;
1219
+ this._outputConfiguration = {
1220
+ writeOut: (str) => process2.stdout.write(str),
1221
+ writeErr: (str) => process2.stderr.write(str),
1222
+ outputError: (str, write) => write(str),
1223
+ getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
1224
+ getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
1225
+ getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
1226
+ getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
1227
+ stripColor: (str) => stripColor(str)
1228
+ };
1229
+ this._hidden = false;
1230
+ this._helpOption = void 0;
1231
+ this._addImplicitHelpCommand = void 0;
1232
+ this._helpCommand = void 0;
1233
+ this._helpConfiguration = {};
1234
+ this._helpGroupHeading = void 0;
1235
+ this._defaultCommandGroup = void 0;
1236
+ this._defaultOptionGroup = void 0;
1237
+ }
1238
+ /**
1239
+ * Copy settings that are useful to have in common across root command and subcommands.
1240
+ *
1241
+ * (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
1242
+ *
1243
+ * @param {Command} sourceCommand
1244
+ * @return {Command} `this` command for chaining
1245
+ */
1246
+ copyInheritedSettings(sourceCommand) {
1247
+ this._outputConfiguration = sourceCommand._outputConfiguration;
1248
+ this._helpOption = sourceCommand._helpOption;
1249
+ this._helpCommand = sourceCommand._helpCommand;
1250
+ this._helpConfiguration = sourceCommand._helpConfiguration;
1251
+ this._exitCallback = sourceCommand._exitCallback;
1252
+ this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
1253
+ this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
1254
+ this._allowExcessArguments = sourceCommand._allowExcessArguments;
1255
+ this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
1256
+ this._showHelpAfterError = sourceCommand._showHelpAfterError;
1257
+ this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
1258
+ return this;
1259
+ }
1260
+ /**
1261
+ * @returns {Command[]}
1262
+ * @private
1263
+ */
1264
+ _getCommandAndAncestors() {
1265
+ const result = [];
1266
+ for (let command = this; command; command = command.parent) {
1267
+ result.push(command);
1268
+ }
1269
+ return result;
1270
+ }
1271
+ /**
1272
+ * Define a command.
1273
+ *
1274
+ * There are two styles of command: pay attention to where to put the description.
1275
+ *
1276
+ * @example
1277
+ * // Command implemented using action handler (description is supplied separately to `.command`)
1278
+ * program
1279
+ * .command('clone <source> [destination]')
1280
+ * .description('clone a repository into a newly created directory')
1281
+ * .action((source, destination) => {
1282
+ * console.log('clone command called');
1283
+ * });
1284
+ *
1285
+ * // Command implemented using separate executable file (description is second parameter to `.command`)
1286
+ * program
1287
+ * .command('start <service>', 'start named service')
1288
+ * .command('stop [service]', 'stop named service, or all if no name supplied');
1289
+ *
1290
+ * @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
1291
+ * @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
1292
+ * @param {object} [execOpts] - configuration options (for executable)
1293
+ * @return {Command} returns new command for action handler, or `this` for executable command
1294
+ */
1295
+ command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
1296
+ let desc = actionOptsOrExecDesc;
1297
+ let opts2 = execOpts;
1298
+ if (typeof desc === "object" && desc !== null) {
1299
+ opts2 = desc;
1300
+ desc = null;
1301
+ }
1302
+ opts2 = opts2 || {};
1303
+ const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
1304
+ const cmd = this.createCommand(name);
1305
+ if (desc) {
1306
+ cmd.description(desc);
1307
+ cmd._executableHandler = true;
1308
+ }
1309
+ if (opts2.isDefault) this._defaultCommandName = cmd._name;
1310
+ cmd._hidden = !!(opts2.noHelp || opts2.hidden);
1311
+ cmd._executableFile = opts2.executableFile || null;
1312
+ if (args) cmd.arguments(args);
1313
+ this._registerCommand(cmd);
1314
+ cmd.parent = this;
1315
+ cmd.copyInheritedSettings(this);
1316
+ if (desc) return this;
1317
+ return cmd;
1318
+ }
1319
+ /**
1320
+ * Factory routine to create a new unattached command.
1321
+ *
1322
+ * See .command() for creating an attached subcommand, which uses this routine to
1323
+ * create the command. You can override createCommand to customise subcommands.
1324
+ *
1325
+ * @param {string} [name]
1326
+ * @return {Command} new command
1327
+ */
1328
+ createCommand(name) {
1329
+ return new _Command(name);
1330
+ }
1331
+ /**
1332
+ * You can customise the help with a subclass of Help by overriding createHelp,
1333
+ * or by overriding Help properties using configureHelp().
1334
+ *
1335
+ * @return {Help}
1336
+ */
1337
+ createHelp() {
1338
+ return Object.assign(new Help(), this.configureHelp());
1339
+ }
1340
+ /**
1341
+ * You can customise the help by overriding Help properties using configureHelp(),
1342
+ * or with a subclass of Help by overriding createHelp().
1343
+ *
1344
+ * @param {object} [configuration] - configuration options
1345
+ * @return {(Command | object)} `this` command for chaining, or stored configuration
1346
+ */
1347
+ configureHelp(configuration) {
1348
+ if (configuration === void 0) return this._helpConfiguration;
1349
+ this._helpConfiguration = configuration;
1350
+ return this;
1351
+ }
1352
+ /**
1353
+ * The default output goes to stdout and stderr. You can customise this for special
1354
+ * applications. You can also customise the display of errors by overriding outputError.
1355
+ *
1356
+ * The configuration properties are all functions:
1357
+ *
1358
+ * // change how output being written, defaults to stdout and stderr
1359
+ * writeOut(str)
1360
+ * writeErr(str)
1361
+ * // change how output being written for errors, defaults to writeErr
1362
+ * outputError(str, write) // used for displaying errors and not used for displaying help
1363
+ * // specify width for wrapping help
1364
+ * getOutHelpWidth()
1365
+ * getErrHelpWidth()
1366
+ * // color support, currently only used with Help
1367
+ * getOutHasColors()
1368
+ * getErrHasColors()
1369
+ * stripColor() // used to remove ANSI escape codes if output does not have colors
1370
+ *
1371
+ * @param {object} [configuration] - configuration options
1372
+ * @return {(Command | object)} `this` command for chaining, or stored configuration
1373
+ */
1374
+ configureOutput(configuration) {
1375
+ if (configuration === void 0) return this._outputConfiguration;
1376
+ this._outputConfiguration = {
1377
+ ...this._outputConfiguration,
1378
+ ...configuration
1379
+ };
1380
+ return this;
1381
+ }
1382
+ /**
1383
+ * Display the help or a custom message after an error occurs.
1384
+ *
1385
+ * @param {(boolean|string)} [displayHelp]
1386
+ * @return {Command} `this` command for chaining
1387
+ */
1388
+ showHelpAfterError(displayHelp = true) {
1389
+ if (typeof displayHelp !== "string") displayHelp = !!displayHelp;
1390
+ this._showHelpAfterError = displayHelp;
1391
+ return this;
1392
+ }
1393
+ /**
1394
+ * Display suggestion of similar commands for unknown commands, or options for unknown options.
1395
+ *
1396
+ * @param {boolean} [displaySuggestion]
1397
+ * @return {Command} `this` command for chaining
1398
+ */
1399
+ showSuggestionAfterError(displaySuggestion = true) {
1400
+ this._showSuggestionAfterError = !!displaySuggestion;
1401
+ return this;
1402
+ }
1403
+ /**
1404
+ * Add a prepared subcommand.
1405
+ *
1406
+ * See .command() for creating an attached subcommand which inherits settings from its parent.
1407
+ *
1408
+ * @param {Command} cmd - new subcommand
1409
+ * @param {object} [opts] - configuration options
1410
+ * @return {Command} `this` command for chaining
1411
+ */
1412
+ addCommand(cmd, opts2) {
1413
+ if (!cmd._name) {
1414
+ throw new Error(`Command passed to .addCommand() must have a name
1415
+ - specify the name in Command constructor or using .name()`);
1416
+ }
1417
+ opts2 = opts2 || {};
1418
+ if (opts2.isDefault) this._defaultCommandName = cmd._name;
1419
+ if (opts2.noHelp || opts2.hidden) cmd._hidden = true;
1420
+ this._registerCommand(cmd);
1421
+ cmd.parent = this;
1422
+ cmd._checkForBrokenPassThrough();
1423
+ return this;
1424
+ }
1425
+ /**
1426
+ * Factory routine to create a new unattached argument.
1427
+ *
1428
+ * See .argument() for creating an attached argument, which uses this routine to
1429
+ * create the argument. You can override createArgument to return a custom argument.
1430
+ *
1431
+ * @param {string} name
1432
+ * @param {string} [description]
1433
+ * @return {Argument} new argument
1434
+ */
1435
+ createArgument(name, description) {
1436
+ return new Argument(name, description);
1437
+ }
1438
+ /**
1439
+ * Define argument syntax for command.
1440
+ *
1441
+ * The default is that the argument is required, and you can explicitly
1442
+ * indicate this with <> around the name. Put [] around the name for an optional argument.
1443
+ *
1444
+ * @example
1445
+ * program.argument('<input-file>');
1446
+ * program.argument('[output-file]');
1447
+ *
1448
+ * @param {string} name
1449
+ * @param {string} [description]
1450
+ * @param {(Function|*)} [parseArg] - custom argument processing function or default value
1451
+ * @param {*} [defaultValue]
1452
+ * @return {Command} `this` command for chaining
1453
+ */
1454
+ argument(name, description, parseArg, defaultValue) {
1455
+ const argument = this.createArgument(name, description);
1456
+ if (typeof parseArg === "function") {
1457
+ argument.default(defaultValue).argParser(parseArg);
1458
+ } else {
1459
+ argument.default(parseArg);
1460
+ }
1461
+ this.addArgument(argument);
1462
+ return this;
1463
+ }
1464
+ /**
1465
+ * Define argument syntax for command, adding multiple at once (without descriptions).
1466
+ *
1467
+ * See also .argument().
1468
+ *
1469
+ * @example
1470
+ * program.arguments('<cmd> [env]');
1471
+ *
1472
+ * @param {string} names
1473
+ * @return {Command} `this` command for chaining
1474
+ */
1475
+ arguments(names) {
1476
+ names.trim().split(/ +/).forEach((detail) => {
1477
+ this.argument(detail);
1478
+ });
1479
+ return this;
1480
+ }
1481
+ /**
1482
+ * Define argument syntax for command, adding a prepared argument.
1483
+ *
1484
+ * @param {Argument} argument
1485
+ * @return {Command} `this` command for chaining
1486
+ */
1487
+ addArgument(argument) {
1488
+ const previousArgument = this.registeredArguments.slice(-1)[0];
1489
+ if (previousArgument?.variadic) {
1490
+ throw new Error(
1491
+ `only the last argument can be variadic '${previousArgument.name()}'`
1492
+ );
1493
+ }
1494
+ if (argument.required && argument.defaultValue !== void 0 && argument.parseArg === void 0) {
1495
+ throw new Error(
1496
+ `a default value for a required argument is never used: '${argument.name()}'`
1497
+ );
1498
+ }
1499
+ this.registeredArguments.push(argument);
1500
+ return this;
1501
+ }
1502
+ /**
1503
+ * Customise or override default help command. By default a help command is automatically added if your command has subcommands.
1504
+ *
1505
+ * @example
1506
+ * program.helpCommand('help [cmd]');
1507
+ * program.helpCommand('help [cmd]', 'show help');
1508
+ * program.helpCommand(false); // suppress default help command
1509
+ * program.helpCommand(true); // add help command even if no subcommands
1510
+ *
1511
+ * @param {string|boolean} enableOrNameAndArgs - enable with custom name and/or arguments, or boolean to override whether added
1512
+ * @param {string} [description] - custom description
1513
+ * @return {Command} `this` command for chaining
1514
+ */
1515
+ helpCommand(enableOrNameAndArgs, description) {
1516
+ if (typeof enableOrNameAndArgs === "boolean") {
1517
+ this._addImplicitHelpCommand = enableOrNameAndArgs;
1518
+ if (enableOrNameAndArgs && this._defaultCommandGroup) {
1519
+ this._initCommandGroup(this._getHelpCommand());
1520
+ }
1521
+ return this;
1522
+ }
1523
+ const nameAndArgs = enableOrNameAndArgs ?? "help [command]";
1524
+ const [, helpName, helpArgs] = nameAndArgs.match(/([^ ]+) *(.*)/);
1525
+ const helpDescription = description ?? "display help for command";
1526
+ const helpCommand = this.createCommand(helpName);
1527
+ helpCommand.helpOption(false);
1528
+ if (helpArgs) helpCommand.arguments(helpArgs);
1529
+ if (helpDescription) helpCommand.description(helpDescription);
1530
+ this._addImplicitHelpCommand = true;
1531
+ this._helpCommand = helpCommand;
1532
+ if (enableOrNameAndArgs || description) this._initCommandGroup(helpCommand);
1533
+ return this;
1534
+ }
1535
+ /**
1536
+ * Add prepared custom help command.
1537
+ *
1538
+ * @param {(Command|string|boolean)} helpCommand - custom help command, or deprecated enableOrNameAndArgs as for `.helpCommand()`
1539
+ * @param {string} [deprecatedDescription] - deprecated custom description used with custom name only
1540
+ * @return {Command} `this` command for chaining
1541
+ */
1542
+ addHelpCommand(helpCommand, deprecatedDescription) {
1543
+ if (typeof helpCommand !== "object") {
1544
+ this.helpCommand(helpCommand, deprecatedDescription);
1545
+ return this;
1546
+ }
1547
+ this._addImplicitHelpCommand = true;
1548
+ this._helpCommand = helpCommand;
1549
+ this._initCommandGroup(helpCommand);
1550
+ return this;
1551
+ }
1552
+ /**
1553
+ * Lazy create help command.
1554
+ *
1555
+ * @return {(Command|null)}
1556
+ * @package
1557
+ */
1558
+ _getHelpCommand() {
1559
+ const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
1560
+ if (hasImplicitHelpCommand) {
1561
+ if (this._helpCommand === void 0) {
1562
+ this.helpCommand(void 0, void 0);
1563
+ }
1564
+ return this._helpCommand;
1565
+ }
1566
+ return null;
1567
+ }
1568
+ /**
1569
+ * Add hook for life cycle event.
1570
+ *
1571
+ * @param {string} event
1572
+ * @param {Function} listener
1573
+ * @return {Command} `this` command for chaining
1574
+ */
1575
+ hook(event, listener) {
1576
+ const allowedValues = ["preSubcommand", "preAction", "postAction"];
1577
+ if (!allowedValues.includes(event)) {
1578
+ throw new Error(`Unexpected value for event passed to hook : '${event}'.
1579
+ Expecting one of '${allowedValues.join("', '")}'`);
1580
+ }
1581
+ if (this._lifeCycleHooks[event]) {
1582
+ this._lifeCycleHooks[event].push(listener);
1583
+ } else {
1584
+ this._lifeCycleHooks[event] = [listener];
1585
+ }
1586
+ return this;
1587
+ }
1588
+ /**
1589
+ * Register callback to use as replacement for calling process.exit.
1590
+ *
1591
+ * @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
1592
+ * @return {Command} `this` command for chaining
1593
+ */
1594
+ exitOverride(fn) {
1595
+ if (fn) {
1596
+ this._exitCallback = fn;
1597
+ } else {
1598
+ this._exitCallback = (err) => {
1599
+ if (err.code !== "commander.executeSubCommandAsync") {
1600
+ throw err;
1601
+ } else {
1602
+ }
1603
+ };
1604
+ }
1605
+ return this;
1606
+ }
1607
+ /**
1608
+ * Call process.exit, and _exitCallback if defined.
1609
+ *
1610
+ * @param {number} exitCode exit code for using with process.exit
1611
+ * @param {string} code an id string representing the error
1612
+ * @param {string} message human-readable description of the error
1613
+ * @return never
1614
+ * @private
1615
+ */
1616
+ _exit(exitCode, code, message) {
1617
+ if (this._exitCallback) {
1618
+ this._exitCallback(new CommanderError(exitCode, code, message));
1619
+ }
1620
+ process2.exit(exitCode);
1621
+ }
1622
+ /**
1623
+ * Register callback `fn` for the command.
1624
+ *
1625
+ * @example
1626
+ * program
1627
+ * .command('serve')
1628
+ * .description('start service')
1629
+ * .action(function() {
1630
+ * // do work here
1631
+ * });
1632
+ *
1633
+ * @param {Function} fn
1634
+ * @return {Command} `this` command for chaining
1635
+ */
1636
+ action(fn) {
1637
+ const listener = (args) => {
1638
+ const expectedArgsCount = this.registeredArguments.length;
1639
+ const actionArgs = args.slice(0, expectedArgsCount);
1640
+ if (this._storeOptionsAsProperties) {
1641
+ actionArgs[expectedArgsCount] = this;
1642
+ } else {
1643
+ actionArgs[expectedArgsCount] = this.opts();
1644
+ }
1645
+ actionArgs.push(this);
1646
+ return fn.apply(this, actionArgs);
1647
+ };
1648
+ this._actionHandler = listener;
1649
+ return this;
1650
+ }
1651
+ /**
1652
+ * Factory routine to create a new unattached option.
1653
+ *
1654
+ * See .option() for creating an attached option, which uses this routine to
1655
+ * create the option. You can override createOption to return a custom option.
1656
+ *
1657
+ * @param {string} flags
1658
+ * @param {string} [description]
1659
+ * @return {Option} new option
1660
+ */
1661
+ createOption(flags, description) {
1662
+ return new Option(flags, description);
1663
+ }
1664
+ /**
1665
+ * Wrap parseArgs to catch 'commander.invalidArgument'.
1666
+ *
1667
+ * @param {(Option | Argument)} target
1668
+ * @param {string} value
1669
+ * @param {*} previous
1670
+ * @param {string} invalidArgumentMessage
1671
+ * @private
1672
+ */
1673
+ _callParseArg(target, value, previous, invalidArgumentMessage) {
1674
+ try {
1675
+ return target.parseArg(value, previous);
1676
+ } catch (err) {
1677
+ if (err.code === "commander.invalidArgument") {
1678
+ const message = `${invalidArgumentMessage} ${err.message}`;
1679
+ this.error(message, { exitCode: err.exitCode, code: err.code });
1680
+ }
1681
+ throw err;
1682
+ }
1683
+ }
1684
+ /**
1685
+ * Check for option flag conflicts.
1686
+ * Register option if no conflicts found, or throw on conflict.
1687
+ *
1688
+ * @param {Option} option
1689
+ * @private
1690
+ */
1691
+ _registerOption(option) {
1692
+ const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
1693
+ if (matchingOption) {
1694
+ const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short;
1695
+ throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
1696
+ - already used by option '${matchingOption.flags}'`);
1697
+ }
1698
+ this._initOptionGroup(option);
1699
+ this.options.push(option);
1700
+ }
1701
+ /**
1702
+ * Check for command name and alias conflicts with existing commands.
1703
+ * Register command if no conflicts found, or throw on conflict.
1704
+ *
1705
+ * @param {Command} command
1706
+ * @private
1707
+ */
1708
+ _registerCommand(command) {
1709
+ const knownBy = (cmd) => {
1710
+ return [cmd.name()].concat(cmd.aliases());
1711
+ };
1712
+ const alreadyUsed = knownBy(command).find(
1713
+ (name) => this._findCommand(name)
1714
+ );
1715
+ if (alreadyUsed) {
1716
+ const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
1717
+ const newCmd = knownBy(command).join("|");
1718
+ throw new Error(
1719
+ `cannot add command '${newCmd}' as already have command '${existingCmd}'`
1720
+ );
1721
+ }
1722
+ this._initCommandGroup(command);
1723
+ this.commands.push(command);
1724
+ }
1725
+ /**
1726
+ * Add an option.
1727
+ *
1728
+ * @param {Option} option
1729
+ * @return {Command} `this` command for chaining
1730
+ */
1731
+ addOption(option) {
1732
+ this._registerOption(option);
1733
+ const oname = option.name();
1734
+ const name = option.attributeName();
1735
+ if (option.negate) {
1736
+ const positiveLongFlag = option.long.replace(/^--no-/, "--");
1737
+ if (!this._findOption(positiveLongFlag)) {
1738
+ this.setOptionValueWithSource(
1739
+ name,
1740
+ option.defaultValue === void 0 ? true : option.defaultValue,
1741
+ "default"
1742
+ );
1743
+ }
1744
+ } else if (option.defaultValue !== void 0) {
1745
+ this.setOptionValueWithSource(name, option.defaultValue, "default");
1746
+ }
1747
+ const handleOptionValue = (val, invalidValueMessage, valueSource) => {
1748
+ if (val == null && option.presetArg !== void 0) {
1749
+ val = option.presetArg;
1750
+ }
1751
+ const oldValue = this.getOptionValue(name);
1752
+ if (val !== null && option.parseArg) {
1753
+ val = this._callParseArg(option, val, oldValue, invalidValueMessage);
1754
+ } else if (val !== null && option.variadic) {
1755
+ val = option._collectValue(val, oldValue);
1756
+ }
1757
+ if (val == null) {
1758
+ if (option.negate) {
1759
+ val = false;
1760
+ } else if (option.isBoolean() || option.optional) {
1761
+ val = true;
1762
+ } else {
1763
+ val = "";
1764
+ }
1765
+ }
1766
+ this.setOptionValueWithSource(name, val, valueSource);
1767
+ };
1768
+ this.on("option:" + oname, (val) => {
1769
+ const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
1770
+ handleOptionValue(val, invalidValueMessage, "cli");
1771
+ });
1772
+ if (option.envVar) {
1773
+ this.on("optionEnv:" + oname, (val) => {
1774
+ const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
1775
+ handleOptionValue(val, invalidValueMessage, "env");
1776
+ });
1777
+ }
1778
+ return this;
1779
+ }
1780
+ /**
1781
+ * Internal implementation shared by .option() and .requiredOption()
1782
+ *
1783
+ * @return {Command} `this` command for chaining
1784
+ * @private
1785
+ */
1786
+ _optionEx(config, flags, description, fn, defaultValue) {
1787
+ if (typeof flags === "object" && flags instanceof Option) {
1788
+ throw new Error(
1789
+ "To add an Option object use addOption() instead of option() or requiredOption()"
1790
+ );
1791
+ }
1792
+ const option = this.createOption(flags, description);
1793
+ option.makeOptionMandatory(!!config.mandatory);
1794
+ if (typeof fn === "function") {
1795
+ option.default(defaultValue).argParser(fn);
1796
+ } else if (fn instanceof RegExp) {
1797
+ const regex = fn;
1798
+ fn = (val, def) => {
1799
+ const m = regex.exec(val);
1800
+ return m ? m[0] : def;
1801
+ };
1802
+ option.default(defaultValue).argParser(fn);
1803
+ } else {
1804
+ option.default(fn);
1805
+ }
1806
+ return this.addOption(option);
1807
+ }
1808
+ /**
1809
+ * Define option with `flags`, `description`, and optional argument parsing function or `defaultValue` or both.
1810
+ *
1811
+ * The `flags` string contains the short and/or long flags, separated by comma, a pipe or space. A required
1812
+ * option-argument is indicated by `<>` and an optional option-argument by `[]`.
1813
+ *
1814
+ * See the README for more details, and see also addOption() and requiredOption().
1815
+ *
1816
+ * @example
1817
+ * program
1818
+ * .option('-p, --pepper', 'add pepper')
1819
+ * .option('--pt, --pizza-type <TYPE>', 'type of pizza') // required option-argument
1820
+ * .option('-c, --cheese [CHEESE]', 'add extra cheese', 'mozzarella') // optional option-argument with default
1821
+ * .option('-t, --tip <VALUE>', 'add tip to purchase cost', parseFloat) // custom parse function
1822
+ *
1823
+ * @param {string} flags
1824
+ * @param {string} [description]
1825
+ * @param {(Function|*)} [parseArg] - custom option processing function or default value
1826
+ * @param {*} [defaultValue]
1827
+ * @return {Command} `this` command for chaining
1828
+ */
1829
+ option(flags, description, parseArg, defaultValue) {
1830
+ return this._optionEx({}, flags, description, parseArg, defaultValue);
1831
+ }
1832
+ /**
1833
+ * Add a required option which must have a value after parsing. This usually means
1834
+ * the option must be specified on the command line. (Otherwise the same as .option().)
1835
+ *
1836
+ * The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
1837
+ *
1838
+ * @param {string} flags
1839
+ * @param {string} [description]
1840
+ * @param {(Function|*)} [parseArg] - custom option processing function or default value
1841
+ * @param {*} [defaultValue]
1842
+ * @return {Command} `this` command for chaining
1843
+ */
1844
+ requiredOption(flags, description, parseArg, defaultValue) {
1845
+ return this._optionEx(
1846
+ { mandatory: true },
1847
+ flags,
1848
+ description,
1849
+ parseArg,
1850
+ defaultValue
1851
+ );
1852
+ }
1853
+ /**
1854
+ * Alter parsing of short flags with optional values.
1855
+ *
1856
+ * @example
1857
+ * // for `.option('-f,--flag [value]'):
1858
+ * program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
1859
+ * program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
1860
+ *
1861
+ * @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
1862
+ * @return {Command} `this` command for chaining
1863
+ */
1864
+ combineFlagAndOptionalValue(combine = true) {
1865
+ this._combineFlagAndOptionalValue = !!combine;
1866
+ return this;
1867
+ }
1868
+ /**
1869
+ * Allow unknown options on the command line.
1870
+ *
1871
+ * @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
1872
+ * @return {Command} `this` command for chaining
1873
+ */
1874
+ allowUnknownOption(allowUnknown = true) {
1875
+ this._allowUnknownOption = !!allowUnknown;
1876
+ return this;
1877
+ }
1878
+ /**
1879
+ * Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
1880
+ *
1881
+ * @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
1882
+ * @return {Command} `this` command for chaining
1883
+ */
1884
+ allowExcessArguments(allowExcess = true) {
1885
+ this._allowExcessArguments = !!allowExcess;
1886
+ return this;
1887
+ }
1888
+ /**
1889
+ * Enable positional options. Positional means global options are specified before subcommands which lets
1890
+ * subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
1891
+ * The default behaviour is non-positional and global options may appear anywhere on the command line.
1892
+ *
1893
+ * @param {boolean} [positional]
1894
+ * @return {Command} `this` command for chaining
1895
+ */
1896
+ enablePositionalOptions(positional = true) {
1897
+ this._enablePositionalOptions = !!positional;
1898
+ return this;
1899
+ }
1900
+ /**
1901
+ * Pass through options that come after command-arguments rather than treat them as command-options,
1902
+ * so actual command-options come before command-arguments. Turning this on for a subcommand requires
1903
+ * positional options to have been enabled on the program (parent commands).
1904
+ * The default behaviour is non-positional and options may appear before or after command-arguments.
1905
+ *
1906
+ * @param {boolean} [passThrough] for unknown options.
1907
+ * @return {Command} `this` command for chaining
1908
+ */
1909
+ passThroughOptions(passThrough = true) {
1910
+ this._passThroughOptions = !!passThrough;
1911
+ this._checkForBrokenPassThrough();
1912
+ return this;
1913
+ }
1914
+ /**
1915
+ * @private
1916
+ */
1917
+ _checkForBrokenPassThrough() {
1918
+ if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
1919
+ throw new Error(
1920
+ `passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`
1921
+ );
1922
+ }
1923
+ }
1924
+ /**
1925
+ * Whether to store option values as properties on command object,
1926
+ * or store separately (specify false). In both cases the option values can be accessed using .opts().
1927
+ *
1928
+ * @param {boolean} [storeAsProperties=true]
1929
+ * @return {Command} `this` command for chaining
1930
+ */
1931
+ storeOptionsAsProperties(storeAsProperties = true) {
1932
+ if (this.options.length) {
1933
+ throw new Error("call .storeOptionsAsProperties() before adding options");
1934
+ }
1935
+ if (Object.keys(this._optionValues).length) {
1936
+ throw new Error(
1937
+ "call .storeOptionsAsProperties() before setting option values"
1938
+ );
1939
+ }
1940
+ this._storeOptionsAsProperties = !!storeAsProperties;
1941
+ return this;
1942
+ }
1943
+ /**
1944
+ * Retrieve option value.
1945
+ *
1946
+ * @param {string} key
1947
+ * @return {object} value
1948
+ */
1949
+ getOptionValue(key) {
1950
+ if (this._storeOptionsAsProperties) {
1951
+ return this[key];
1952
+ }
1953
+ return this._optionValues[key];
1954
+ }
1955
+ /**
1956
+ * Store option value.
1957
+ *
1958
+ * @param {string} key
1959
+ * @param {object} value
1960
+ * @return {Command} `this` command for chaining
1961
+ */
1962
+ setOptionValue(key, value) {
1963
+ return this.setOptionValueWithSource(key, value, void 0);
1964
+ }
1965
+ /**
1966
+ * Store option value and where the value came from.
1967
+ *
1968
+ * @param {string} key
1969
+ * @param {object} value
1970
+ * @param {string} source - expected values are default/config/env/cli/implied
1971
+ * @return {Command} `this` command for chaining
1972
+ */
1973
+ setOptionValueWithSource(key, value, source) {
1974
+ if (this._storeOptionsAsProperties) {
1975
+ this[key] = value;
1976
+ } else {
1977
+ this._optionValues[key] = value;
1978
+ }
1979
+ this._optionValueSources[key] = source;
1980
+ return this;
1981
+ }
1982
+ /**
1983
+ * Get source of option value.
1984
+ * Expected values are default | config | env | cli | implied
1985
+ *
1986
+ * @param {string} key
1987
+ * @return {string}
1988
+ */
1989
+ getOptionValueSource(key) {
1990
+ return this._optionValueSources[key];
1991
+ }
1992
+ /**
1993
+ * Get source of option value. See also .optsWithGlobals().
1994
+ * Expected values are default | config | env | cli | implied
1995
+ *
1996
+ * @param {string} key
1997
+ * @return {string}
1998
+ */
1999
+ getOptionValueSourceWithGlobals(key) {
2000
+ let source;
2001
+ this._getCommandAndAncestors().forEach((cmd) => {
2002
+ if (cmd.getOptionValueSource(key) !== void 0) {
2003
+ source = cmd.getOptionValueSource(key);
2004
+ }
2005
+ });
2006
+ return source;
2007
+ }
2008
+ /**
2009
+ * Get user arguments from implied or explicit arguments.
2010
+ * Side-effects: set _scriptPath if args included script. Used for default program name, and subcommand searches.
2011
+ *
2012
+ * @private
2013
+ */
2014
+ _prepareUserArgs(argv, parseOptions) {
2015
+ if (argv !== void 0 && !Array.isArray(argv)) {
2016
+ throw new Error("first parameter to parse must be array or undefined");
2017
+ }
2018
+ parseOptions = parseOptions || {};
2019
+ if (argv === void 0 && parseOptions.from === void 0) {
2020
+ if (process2.versions?.electron) {
2021
+ parseOptions.from = "electron";
2022
+ }
2023
+ const execArgv = process2.execArgv ?? [];
2024
+ if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
2025
+ parseOptions.from = "eval";
2026
+ }
2027
+ }
2028
+ if (argv === void 0) {
2029
+ argv = process2.argv;
2030
+ }
2031
+ this.rawArgs = argv.slice();
2032
+ let userArgs;
2033
+ switch (parseOptions.from) {
2034
+ case void 0:
2035
+ case "node":
2036
+ this._scriptPath = argv[1];
2037
+ userArgs = argv.slice(2);
2038
+ break;
2039
+ case "electron":
2040
+ if (process2.defaultApp) {
2041
+ this._scriptPath = argv[1];
2042
+ userArgs = argv.slice(2);
2043
+ } else {
2044
+ userArgs = argv.slice(1);
2045
+ }
2046
+ break;
2047
+ case "user":
2048
+ userArgs = argv.slice(0);
2049
+ break;
2050
+ case "eval":
2051
+ userArgs = argv.slice(1);
2052
+ break;
2053
+ default:
2054
+ throw new Error(
2055
+ `unexpected parse option { from: '${parseOptions.from}' }`
2056
+ );
2057
+ }
2058
+ if (!this._name && this._scriptPath)
2059
+ this.nameFromFilename(this._scriptPath);
2060
+ this._name = this._name || "program";
2061
+ return userArgs;
2062
+ }
2063
+ /**
2064
+ * Parse `argv`, setting options and invoking commands when defined.
2065
+ *
2066
+ * Use parseAsync instead of parse if any of your action handlers are async.
2067
+ *
2068
+ * Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
2069
+ *
2070
+ * Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
2071
+ * - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
2072
+ * - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
2073
+ * - `'user'`: just user arguments
2074
+ *
2075
+ * @example
2076
+ * program.parse(); // parse process.argv and auto-detect electron and special node flags
2077
+ * program.parse(process.argv); // assume argv[0] is app and argv[1] is script
2078
+ * program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
2079
+ *
2080
+ * @param {string[]} [argv] - optional, defaults to process.argv
2081
+ * @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
2082
+ * @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
2083
+ * @return {Command} `this` command for chaining
2084
+ */
2085
+ parse(argv, parseOptions) {
2086
+ this._prepareForParse();
2087
+ const userArgs = this._prepareUserArgs(argv, parseOptions);
2088
+ this._parseCommand([], userArgs);
2089
+ return this;
2090
+ }
2091
+ /**
2092
+ * Parse `argv`, setting options and invoking commands when defined.
2093
+ *
2094
+ * Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
2095
+ *
2096
+ * Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
2097
+ * - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
2098
+ * - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
2099
+ * - `'user'`: just user arguments
2100
+ *
2101
+ * @example
2102
+ * await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
2103
+ * await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
2104
+ * await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
2105
+ *
2106
+ * @param {string[]} [argv]
2107
+ * @param {object} [parseOptions]
2108
+ * @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
2109
+ * @return {Promise}
2110
+ */
2111
+ async parseAsync(argv, parseOptions) {
2112
+ this._prepareForParse();
2113
+ const userArgs = this._prepareUserArgs(argv, parseOptions);
2114
+ await this._parseCommand([], userArgs);
2115
+ return this;
2116
+ }
2117
+ _prepareForParse() {
2118
+ if (this._savedState === null) {
2119
+ this.saveStateBeforeParse();
2120
+ } else {
2121
+ this.restoreStateBeforeParse();
2122
+ }
2123
+ }
2124
+ /**
2125
+ * Called the first time parse is called to save state and allow a restore before subsequent calls to parse.
2126
+ * Not usually called directly, but available for subclasses to save their custom state.
2127
+ *
2128
+ * This is called in a lazy way. Only commands used in parsing chain will have state saved.
2129
+ */
2130
+ saveStateBeforeParse() {
2131
+ this._savedState = {
2132
+ // name is stable if supplied by author, but may be unspecified for root command and deduced during parsing
2133
+ _name: this._name,
2134
+ // option values before parse have default values (including false for negated options)
2135
+ // shallow clones
2136
+ _optionValues: { ...this._optionValues },
2137
+ _optionValueSources: { ...this._optionValueSources }
2138
+ };
2139
+ }
2140
+ /**
2141
+ * Restore state before parse for calls after the first.
2142
+ * Not usually called directly, but available for subclasses to save their custom state.
2143
+ *
2144
+ * This is called in a lazy way. Only commands used in parsing chain will have state restored.
2145
+ */
2146
+ restoreStateBeforeParse() {
2147
+ if (this._storeOptionsAsProperties)
2148
+ throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
2149
+ - either make a new Command for each call to parse, or stop storing options as properties`);
2150
+ this._name = this._savedState._name;
2151
+ this._scriptPath = null;
2152
+ this.rawArgs = [];
2153
+ this._optionValues = { ...this._savedState._optionValues };
2154
+ this._optionValueSources = { ...this._savedState._optionValueSources };
2155
+ this.args = [];
2156
+ this.processedArgs = [];
2157
+ }
2158
+ /**
2159
+ * Throw if expected executable is missing. Add lots of help for author.
2160
+ *
2161
+ * @param {string} executableFile
2162
+ * @param {string} executableDir
2163
+ * @param {string} subcommandName
2164
+ */
2165
+ _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
2166
+ if (fs.existsSync(executableFile)) return;
2167
+ const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2168
+ const executableMissing = `'${executableFile}' does not exist
2169
+ - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
2170
+ - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
2171
+ - ${executableDirMessage}`;
2172
+ throw new Error(executableMissing);
2173
+ }
2174
+ /**
2175
+ * Execute a sub-command executable.
2176
+ *
2177
+ * @private
2178
+ */
2179
+ _executeSubCommand(subcommand, args) {
2180
+ args = args.slice();
2181
+ let launchWithNode = false;
2182
+ const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2183
+ function findFile(baseDir, baseName) {
2184
+ const localBin = path.resolve(baseDir, baseName);
2185
+ if (fs.existsSync(localBin)) return localBin;
2186
+ if (sourceExt.includes(path.extname(baseName))) return void 0;
2187
+ const foundExt = sourceExt.find(
2188
+ (ext) => fs.existsSync(`${localBin}${ext}`)
2189
+ );
2190
+ if (foundExt) return `${localBin}${foundExt}`;
2191
+ return void 0;
2192
+ }
2193
+ this._checkForMissingMandatoryOptions();
2194
+ this._checkForConflictingOptions();
2195
+ let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
2196
+ let executableDir = this._executableDir || "";
2197
+ if (this._scriptPath) {
2198
+ let resolvedScriptPath;
2199
+ try {
2200
+ resolvedScriptPath = fs.realpathSync(this._scriptPath);
2201
+ } catch {
2202
+ resolvedScriptPath = this._scriptPath;
2203
+ }
2204
+ executableDir = path.resolve(
2205
+ path.dirname(resolvedScriptPath),
2206
+ executableDir
2207
+ );
2208
+ }
2209
+ if (executableDir) {
2210
+ let localFile = findFile(executableDir, executableFile);
2211
+ if (!localFile && !subcommand._executableFile && this._scriptPath) {
2212
+ const legacyName = path.basename(
2213
+ this._scriptPath,
2214
+ path.extname(this._scriptPath)
2215
+ );
2216
+ if (legacyName !== this._name) {
2217
+ localFile = findFile(
2218
+ executableDir,
2219
+ `${legacyName}-${subcommand._name}`
2220
+ );
2221
+ }
2222
+ }
2223
+ executableFile = localFile || executableFile;
2224
+ }
2225
+ launchWithNode = sourceExt.includes(path.extname(executableFile));
2226
+ let proc;
2227
+ if (process2.platform !== "win32") {
2228
+ if (launchWithNode) {
2229
+ args.unshift(executableFile);
2230
+ args = incrementNodeInspectorPort(process2.execArgv).concat(args);
2231
+ proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
2232
+ } else {
2233
+ proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
2234
+ }
2235
+ } else {
2236
+ this._checkForMissingExecutable(
2237
+ executableFile,
2238
+ executableDir,
2239
+ subcommand._name
2240
+ );
2241
+ args.unshift(executableFile);
2242
+ args = incrementNodeInspectorPort(process2.execArgv).concat(args);
2243
+ proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
2244
+ }
2245
+ if (!proc.killed) {
2246
+ const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
2247
+ signals.forEach((signal) => {
2248
+ process2.on(signal, () => {
2249
+ if (proc.killed === false && proc.exitCode === null) {
2250
+ proc.kill(signal);
2251
+ }
2252
+ });
2253
+ });
2254
+ }
2255
+ const exitCallback = this._exitCallback;
2256
+ proc.on("close", (code) => {
2257
+ code = code ?? 1;
2258
+ if (!exitCallback) {
2259
+ process2.exit(code);
2260
+ } else {
2261
+ exitCallback(
2262
+ new CommanderError(
2263
+ code,
2264
+ "commander.executeSubCommandAsync",
2265
+ "(close)"
2266
+ )
2267
+ );
2268
+ }
2269
+ });
2270
+ proc.on("error", (err) => {
2271
+ if (err.code === "ENOENT") {
2272
+ this._checkForMissingExecutable(
2273
+ executableFile,
2274
+ executableDir,
2275
+ subcommand._name
2276
+ );
2277
+ } else if (err.code === "EACCES") {
2278
+ throw new Error(`'${executableFile}' not executable`);
2279
+ }
2280
+ if (!exitCallback) {
2281
+ process2.exit(1);
2282
+ } else {
2283
+ const wrappedError = new CommanderError(
2284
+ 1,
2285
+ "commander.executeSubCommandAsync",
2286
+ "(error)"
2287
+ );
2288
+ wrappedError.nestedError = err;
2289
+ exitCallback(wrappedError);
2290
+ }
2291
+ });
2292
+ this.runningCommand = proc;
2293
+ }
2294
+ /**
2295
+ * @private
2296
+ */
2297
+ _dispatchSubcommand(commandName, operands, unknown) {
2298
+ const subCommand = this._findCommand(commandName);
2299
+ if (!subCommand) this.help({ error: true });
2300
+ subCommand._prepareForParse();
2301
+ let promiseChain;
2302
+ promiseChain = this._chainOrCallSubCommandHook(
2303
+ promiseChain,
2304
+ subCommand,
2305
+ "preSubcommand"
2306
+ );
2307
+ promiseChain = this._chainOrCall(promiseChain, () => {
2308
+ if (subCommand._executableHandler) {
2309
+ this._executeSubCommand(subCommand, operands.concat(unknown));
2310
+ } else {
2311
+ return subCommand._parseCommand(operands, unknown);
2312
+ }
2313
+ });
2314
+ return promiseChain;
2315
+ }
2316
+ /**
2317
+ * Invoke help directly if possible, or dispatch if necessary.
2318
+ * e.g. help foo
2319
+ *
2320
+ * @private
2321
+ */
2322
+ _dispatchHelpCommand(subcommandName) {
2323
+ if (!subcommandName) {
2324
+ this.help();
2325
+ }
2326
+ const subCommand = this._findCommand(subcommandName);
2327
+ if (subCommand && !subCommand._executableHandler) {
2328
+ subCommand.help();
2329
+ }
2330
+ return this._dispatchSubcommand(
2331
+ subcommandName,
2332
+ [],
2333
+ [this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]
2334
+ );
2335
+ }
2336
+ /**
2337
+ * Check this.args against expected this.registeredArguments.
2338
+ *
2339
+ * @private
2340
+ */
2341
+ _checkNumberOfArguments() {
2342
+ this.registeredArguments.forEach((arg, i) => {
2343
+ if (arg.required && this.args[i] == null) {
2344
+ this.missingArgument(arg.name());
2345
+ }
2346
+ });
2347
+ if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
2348
+ return;
2349
+ }
2350
+ if (this.args.length > this.registeredArguments.length) {
2351
+ this._excessArguments(this.args);
2352
+ }
2353
+ }
2354
+ /**
2355
+ * Process this.args using this.registeredArguments and save as this.processedArgs!
2356
+ *
2357
+ * @private
2358
+ */
2359
+ _processArguments() {
2360
+ const myParseArg = (argument, value, previous) => {
2361
+ let parsedValue = value;
2362
+ if (value !== null && argument.parseArg) {
2363
+ const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
2364
+ parsedValue = this._callParseArg(
2365
+ argument,
2366
+ value,
2367
+ previous,
2368
+ invalidValueMessage
2369
+ );
2370
+ }
2371
+ return parsedValue;
2372
+ };
2373
+ this._checkNumberOfArguments();
2374
+ const processedArgs = [];
2375
+ this.registeredArguments.forEach((declaredArg, index) => {
2376
+ let value = declaredArg.defaultValue;
2377
+ if (declaredArg.variadic) {
2378
+ if (index < this.args.length) {
2379
+ value = this.args.slice(index);
2380
+ if (declaredArg.parseArg) {
2381
+ value = value.reduce((processed, v) => {
2382
+ return myParseArg(declaredArg, v, processed);
2383
+ }, declaredArg.defaultValue);
2384
+ }
2385
+ } else if (value === void 0) {
2386
+ value = [];
2387
+ }
2388
+ } else if (index < this.args.length) {
2389
+ value = this.args[index];
2390
+ if (declaredArg.parseArg) {
2391
+ value = myParseArg(declaredArg, value, declaredArg.defaultValue);
2392
+ }
2393
+ }
2394
+ processedArgs[index] = value;
2395
+ });
2396
+ this.processedArgs = processedArgs;
2397
+ }
2398
+ /**
2399
+ * Once we have a promise we chain, but call synchronously until then.
2400
+ *
2401
+ * @param {(Promise|undefined)} promise
2402
+ * @param {Function} fn
2403
+ * @return {(Promise|undefined)}
2404
+ * @private
2405
+ */
2406
+ _chainOrCall(promise, fn) {
2407
+ if (promise?.then && typeof promise.then === "function") {
2408
+ return promise.then(() => fn());
2409
+ }
2410
+ return fn();
2411
+ }
2412
+ /**
2413
+ *
2414
+ * @param {(Promise|undefined)} promise
2415
+ * @param {string} event
2416
+ * @return {(Promise|undefined)}
2417
+ * @private
2418
+ */
2419
+ _chainOrCallHooks(promise, event) {
2420
+ let result = promise;
2421
+ const hooks = [];
2422
+ this._getCommandAndAncestors().reverse().filter((cmd) => cmd._lifeCycleHooks[event] !== void 0).forEach((hookedCommand) => {
2423
+ hookedCommand._lifeCycleHooks[event].forEach((callback) => {
2424
+ hooks.push({ hookedCommand, callback });
2425
+ });
2426
+ });
2427
+ if (event === "postAction") {
2428
+ hooks.reverse();
2429
+ }
2430
+ hooks.forEach((hookDetail) => {
2431
+ result = this._chainOrCall(result, () => {
2432
+ return hookDetail.callback(hookDetail.hookedCommand, this);
2433
+ });
2434
+ });
2435
+ return result;
2436
+ }
2437
+ /**
2438
+ *
2439
+ * @param {(Promise|undefined)} promise
2440
+ * @param {Command} subCommand
2441
+ * @param {string} event
2442
+ * @return {(Promise|undefined)}
2443
+ * @private
2444
+ */
2445
+ _chainOrCallSubCommandHook(promise, subCommand, event) {
2446
+ let result = promise;
2447
+ if (this._lifeCycleHooks[event] !== void 0) {
2448
+ this._lifeCycleHooks[event].forEach((hook) => {
2449
+ result = this._chainOrCall(result, () => {
2450
+ return hook(this, subCommand);
2451
+ });
2452
+ });
2453
+ }
2454
+ return result;
2455
+ }
2456
+ /**
2457
+ * Process arguments in context of this command.
2458
+ * Returns action result, in case it is a promise.
2459
+ *
2460
+ * @private
2461
+ */
2462
+ _parseCommand(operands, unknown) {
2463
+ const parsed = this.parseOptions(unknown);
2464
+ this._parseOptionsEnv();
2465
+ this._parseOptionsImplied();
2466
+ operands = operands.concat(parsed.operands);
2467
+ unknown = parsed.unknown;
2468
+ this.args = operands.concat(unknown);
2469
+ if (operands && this._findCommand(operands[0])) {
2470
+ return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
2471
+ }
2472
+ if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) {
2473
+ return this._dispatchHelpCommand(operands[1]);
2474
+ }
2475
+ if (this._defaultCommandName) {
2476
+ this._outputHelpIfRequested(unknown);
2477
+ return this._dispatchSubcommand(
2478
+ this._defaultCommandName,
2479
+ operands,
2480
+ unknown
2481
+ );
2482
+ }
2483
+ if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
2484
+ this.help({ error: true });
2485
+ }
2486
+ this._outputHelpIfRequested(parsed.unknown);
2487
+ this._checkForMissingMandatoryOptions();
2488
+ this._checkForConflictingOptions();
2489
+ const checkForUnknownOptions = () => {
2490
+ if (parsed.unknown.length > 0) {
2491
+ this.unknownOption(parsed.unknown[0]);
2492
+ }
2493
+ };
2494
+ const commandEvent = `command:${this.name()}`;
2495
+ if (this._actionHandler) {
2496
+ checkForUnknownOptions();
2497
+ this._processArguments();
2498
+ let promiseChain;
2499
+ promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
2500
+ promiseChain = this._chainOrCall(
2501
+ promiseChain,
2502
+ () => this._actionHandler(this.processedArgs)
2503
+ );
2504
+ if (this.parent) {
2505
+ promiseChain = this._chainOrCall(promiseChain, () => {
2506
+ this.parent.emit(commandEvent, operands, unknown);
2507
+ });
2508
+ }
2509
+ promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
2510
+ return promiseChain;
2511
+ }
2512
+ if (this.parent?.listenerCount(commandEvent)) {
2513
+ checkForUnknownOptions();
2514
+ this._processArguments();
2515
+ this.parent.emit(commandEvent, operands, unknown);
2516
+ } else if (operands.length) {
2517
+ if (this._findCommand("*")) {
2518
+ return this._dispatchSubcommand("*", operands, unknown);
2519
+ }
2520
+ if (this.listenerCount("command:*")) {
2521
+ this.emit("command:*", operands, unknown);
2522
+ } else if (this.commands.length) {
2523
+ this.unknownCommand();
2524
+ } else {
2525
+ checkForUnknownOptions();
2526
+ this._processArguments();
2527
+ }
2528
+ } else if (this.commands.length) {
2529
+ checkForUnknownOptions();
2530
+ this.help({ error: true });
2531
+ } else {
2532
+ checkForUnknownOptions();
2533
+ this._processArguments();
2534
+ }
2535
+ }
2536
+ /**
2537
+ * Find matching command.
2538
+ *
2539
+ * @private
2540
+ * @return {Command | undefined}
2541
+ */
2542
+ _findCommand(name) {
2543
+ if (!name) return void 0;
2544
+ return this.commands.find(
2545
+ (cmd) => cmd._name === name || cmd._aliases.includes(name)
2546
+ );
2547
+ }
2548
+ /**
2549
+ * Return an option matching `arg` if any.
2550
+ *
2551
+ * @param {string} arg
2552
+ * @return {Option}
2553
+ * @package
2554
+ */
2555
+ _findOption(arg) {
2556
+ return this.options.find((option) => option.is(arg));
2557
+ }
2558
+ /**
2559
+ * Display an error message if a mandatory option does not have a value.
2560
+ * Called after checking for help flags in leaf subcommand.
2561
+ *
2562
+ * @private
2563
+ */
2564
+ _checkForMissingMandatoryOptions() {
2565
+ this._getCommandAndAncestors().forEach((cmd) => {
2566
+ cmd.options.forEach((anOption) => {
2567
+ if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === void 0) {
2568
+ cmd.missingMandatoryOptionValue(anOption);
2569
+ }
2570
+ });
2571
+ });
2572
+ }
2573
+ /**
2574
+ * Display an error message if conflicting options are used together in this.
2575
+ *
2576
+ * @private
2577
+ */
2578
+ _checkForConflictingLocalOptions() {
2579
+ const definedNonDefaultOptions = this.options.filter((option) => {
2580
+ const optionKey = option.attributeName();
2581
+ if (this.getOptionValue(optionKey) === void 0) {
2582
+ return false;
2583
+ }
2584
+ return this.getOptionValueSource(optionKey) !== "default";
2585
+ });
2586
+ const optionsWithConflicting = definedNonDefaultOptions.filter(
2587
+ (option) => option.conflictsWith.length > 0
2588
+ );
2589
+ optionsWithConflicting.forEach((option) => {
2590
+ const conflictingAndDefined = definedNonDefaultOptions.find(
2591
+ (defined) => option.conflictsWith.includes(defined.attributeName())
2592
+ );
2593
+ if (conflictingAndDefined) {
2594
+ this._conflictingOption(option, conflictingAndDefined);
2595
+ }
2596
+ });
2597
+ }
2598
+ /**
2599
+ * Display an error message if conflicting options are used together.
2600
+ * Called after checking for help flags in leaf subcommand.
2601
+ *
2602
+ * @private
2603
+ */
2604
+ _checkForConflictingOptions() {
2605
+ this._getCommandAndAncestors().forEach((cmd) => {
2606
+ cmd._checkForConflictingLocalOptions();
2607
+ });
2608
+ }
2609
+ /**
2610
+ * Parse options from `argv` removing known options,
2611
+ * and return argv split into operands and unknown arguments.
2612
+ *
2613
+ * Side effects: modifies command by storing options. Does not reset state if called again.
2614
+ *
2615
+ * Examples:
2616
+ *
2617
+ * argv => operands, unknown
2618
+ * --known kkk op => [op], []
2619
+ * op --known kkk => [op], []
2620
+ * sub --unknown uuu op => [sub], [--unknown uuu op]
2621
+ * sub -- --unknown uuu op => [sub --unknown uuu op], []
2622
+ *
2623
+ * @param {string[]} args
2624
+ * @return {{operands: string[], unknown: string[]}}
2625
+ */
2626
+ parseOptions(args) {
2627
+ const operands = [];
2628
+ const unknown = [];
2629
+ let dest = operands;
2630
+ function maybeOption(arg) {
2631
+ return arg.length > 1 && arg[0] === "-";
2632
+ }
2633
+ const negativeNumberArg = (arg) => {
2634
+ if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)) return false;
2635
+ return !this._getCommandAndAncestors().some(
2636
+ (cmd) => cmd.options.map((opt) => opt.short).some((short) => /^-\d$/.test(short))
2637
+ );
2638
+ };
2639
+ let activeVariadicOption = null;
2640
+ let activeGroup = null;
2641
+ let i = 0;
2642
+ while (i < args.length || activeGroup) {
2643
+ const arg = activeGroup ?? args[i++];
2644
+ activeGroup = null;
2645
+ if (arg === "--") {
2646
+ if (dest === unknown) dest.push(arg);
2647
+ dest.push(...args.slice(i));
2648
+ break;
2649
+ }
2650
+ if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
2651
+ this.emit(`option:${activeVariadicOption.name()}`, arg);
2652
+ continue;
2653
+ }
2654
+ activeVariadicOption = null;
2655
+ if (maybeOption(arg)) {
2656
+ const option = this._findOption(arg);
2657
+ if (option) {
2658
+ if (option.required) {
2659
+ const value = args[i++];
2660
+ if (value === void 0) this.optionMissingArgument(option);
2661
+ this.emit(`option:${option.name()}`, value);
2662
+ } else if (option.optional) {
2663
+ let value = null;
2664
+ if (i < args.length && (!maybeOption(args[i]) || negativeNumberArg(args[i]))) {
2665
+ value = args[i++];
2666
+ }
2667
+ this.emit(`option:${option.name()}`, value);
2668
+ } else {
2669
+ this.emit(`option:${option.name()}`);
2670
+ }
2671
+ activeVariadicOption = option.variadic ? option : null;
2672
+ continue;
2673
+ }
2674
+ }
2675
+ if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
2676
+ const option = this._findOption(`-${arg[1]}`);
2677
+ if (option) {
2678
+ if (option.required || option.optional && this._combineFlagAndOptionalValue) {
2679
+ this.emit(`option:${option.name()}`, arg.slice(2));
2680
+ } else {
2681
+ this.emit(`option:${option.name()}`);
2682
+ activeGroup = `-${arg.slice(2)}`;
2683
+ }
2684
+ continue;
2685
+ }
2686
+ }
2687
+ if (/^--[^=]+=/.test(arg)) {
2688
+ const index = arg.indexOf("=");
2689
+ const option = this._findOption(arg.slice(0, index));
2690
+ if (option && (option.required || option.optional)) {
2691
+ this.emit(`option:${option.name()}`, arg.slice(index + 1));
2692
+ continue;
2693
+ }
2694
+ }
2695
+ if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
2696
+ dest = unknown;
2697
+ }
2698
+ if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
2699
+ if (this._findCommand(arg)) {
2700
+ operands.push(arg);
2701
+ unknown.push(...args.slice(i));
2702
+ break;
2703
+ } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
2704
+ operands.push(arg, ...args.slice(i));
2705
+ break;
2706
+ } else if (this._defaultCommandName) {
2707
+ unknown.push(arg, ...args.slice(i));
2708
+ break;
2709
+ }
2710
+ }
2711
+ if (this._passThroughOptions) {
2712
+ dest.push(arg, ...args.slice(i));
2713
+ break;
2714
+ }
2715
+ dest.push(arg);
2716
+ }
2717
+ return { operands, unknown };
2718
+ }
2719
+ /**
2720
+ * Return an object containing local option values as key-value pairs.
2721
+ *
2722
+ * @return {object}
2723
+ */
2724
+ opts() {
2725
+ if (this._storeOptionsAsProperties) {
2726
+ const result = {};
2727
+ const len = this.options.length;
2728
+ for (let i = 0; i < len; i++) {
2729
+ const key = this.options[i].attributeName();
2730
+ result[key] = key === this._versionOptionName ? this._version : this[key];
2731
+ }
2732
+ return result;
2733
+ }
2734
+ return this._optionValues;
2735
+ }
2736
+ /**
2737
+ * Return an object containing merged local and global option values as key-value pairs.
2738
+ *
2739
+ * @return {object}
2740
+ */
2741
+ optsWithGlobals() {
2742
+ return this._getCommandAndAncestors().reduce(
2743
+ (combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
2744
+ {}
2745
+ );
2746
+ }
2747
+ /**
2748
+ * Display error message and exit (or call exitOverride).
2749
+ *
2750
+ * @param {string} message
2751
+ * @param {object} [errorOptions]
2752
+ * @param {string} [errorOptions.code] - an id string representing the error
2753
+ * @param {number} [errorOptions.exitCode] - used with process.exit
2754
+ */
2755
+ error(message, errorOptions) {
2756
+ this._outputConfiguration.outputError(
2757
+ `${message}
2758
+ `,
2759
+ this._outputConfiguration.writeErr
2760
+ );
2761
+ if (typeof this._showHelpAfterError === "string") {
2762
+ this._outputConfiguration.writeErr(`${this._showHelpAfterError}
2763
+ `);
2764
+ } else if (this._showHelpAfterError) {
2765
+ this._outputConfiguration.writeErr("\n");
2766
+ this.outputHelp({ error: true });
2767
+ }
2768
+ const config = errorOptions || {};
2769
+ const exitCode = config.exitCode || 1;
2770
+ const code = config.code || "commander.error";
2771
+ this._exit(exitCode, code, message);
2772
+ }
2773
+ /**
2774
+ * Apply any option related environment variables, if option does
2775
+ * not have a value from cli or client code.
2776
+ *
2777
+ * @private
2778
+ */
2779
+ _parseOptionsEnv() {
2780
+ this.options.forEach((option) => {
2781
+ if (option.envVar && option.envVar in process2.env) {
2782
+ const optionKey = option.attributeName();
2783
+ if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
2784
+ this.getOptionValueSource(optionKey)
2785
+ )) {
2786
+ if (option.required || option.optional) {
2787
+ this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
2788
+ } else {
2789
+ this.emit(`optionEnv:${option.name()}`);
2790
+ }
2791
+ }
2792
+ }
2793
+ });
2794
+ }
2795
+ /**
2796
+ * Apply any implied option values, if option is undefined or default value.
2797
+ *
2798
+ * @private
2799
+ */
2800
+ _parseOptionsImplied() {
2801
+ const dualHelper = new DualOptions(this.options);
2802
+ const hasCustomOptionValue = (optionKey) => {
2803
+ return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
2804
+ };
2805
+ this.options.filter(
2806
+ (option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
2807
+ this.getOptionValue(option.attributeName()),
2808
+ option
2809
+ )
2810
+ ).forEach((option) => {
2811
+ Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
2812
+ this.setOptionValueWithSource(
2813
+ impliedKey,
2814
+ option.implied[impliedKey],
2815
+ "implied"
2816
+ );
2817
+ });
2818
+ });
2819
+ }
2820
+ /**
2821
+ * Argument `name` is missing.
2822
+ *
2823
+ * @param {string} name
2824
+ * @private
2825
+ */
2826
+ missingArgument(name) {
2827
+ const message = `error: missing required argument '${name}'`;
2828
+ this.error(message, { code: "commander.missingArgument" });
2829
+ }
2830
+ /**
2831
+ * `Option` is missing an argument.
2832
+ *
2833
+ * @param {Option} option
2834
+ * @private
2835
+ */
2836
+ optionMissingArgument(option) {
2837
+ const message = `error: option '${option.flags}' argument missing`;
2838
+ this.error(message, { code: "commander.optionMissingArgument" });
2839
+ }
2840
+ /**
2841
+ * `Option` does not have a value, and is a mandatory option.
2842
+ *
2843
+ * @param {Option} option
2844
+ * @private
2845
+ */
2846
+ missingMandatoryOptionValue(option) {
2847
+ const message = `error: required option '${option.flags}' not specified`;
2848
+ this.error(message, { code: "commander.missingMandatoryOptionValue" });
2849
+ }
2850
+ /**
2851
+ * `Option` conflicts with another option.
2852
+ *
2853
+ * @param {Option} option
2854
+ * @param {Option} conflictingOption
2855
+ * @private
2856
+ */
2857
+ _conflictingOption(option, conflictingOption) {
2858
+ const findBestOptionFromValue = (option2) => {
2859
+ const optionKey = option2.attributeName();
2860
+ const optionValue = this.getOptionValue(optionKey);
2861
+ const negativeOption = this.options.find(
2862
+ (target) => target.negate && optionKey === target.attributeName()
2863
+ );
2864
+ const positiveOption = this.options.find(
2865
+ (target) => !target.negate && optionKey === target.attributeName()
2866
+ );
2867
+ if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
2868
+ return negativeOption;
2869
+ }
2870
+ return positiveOption || option2;
2871
+ };
2872
+ const getErrorMessage = (option2) => {
2873
+ const bestOption = findBestOptionFromValue(option2);
2874
+ const optionKey = bestOption.attributeName();
2875
+ const source = this.getOptionValueSource(optionKey);
2876
+ if (source === "env") {
2877
+ return `environment variable '${bestOption.envVar}'`;
2878
+ }
2879
+ return `option '${bestOption.flags}'`;
2880
+ };
2881
+ const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
2882
+ this.error(message, { code: "commander.conflictingOption" });
2883
+ }
2884
+ /**
2885
+ * Unknown option `flag`.
2886
+ *
2887
+ * @param {string} flag
2888
+ * @private
2889
+ */
2890
+ unknownOption(flag) {
2891
+ if (this._allowUnknownOption) return;
2892
+ let suggestion = "";
2893
+ if (flag.startsWith("--") && this._showSuggestionAfterError) {
2894
+ let candidateFlags = [];
2895
+ let command = this;
2896
+ do {
2897
+ const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
2898
+ candidateFlags = candidateFlags.concat(moreFlags);
2899
+ command = command.parent;
2900
+ } while (command && !command._enablePositionalOptions);
2901
+ suggestion = suggestSimilar(flag, candidateFlags);
2902
+ }
2903
+ const message = `error: unknown option '${flag}'${suggestion}`;
2904
+ this.error(message, { code: "commander.unknownOption" });
2905
+ }
2906
+ /**
2907
+ * Excess arguments, more than expected.
2908
+ *
2909
+ * @param {string[]} receivedArgs
2910
+ * @private
2911
+ */
2912
+ _excessArguments(receivedArgs) {
2913
+ if (this._allowExcessArguments) return;
2914
+ const expected = this.registeredArguments.length;
2915
+ const s = expected === 1 ? "" : "s";
2916
+ const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
2917
+ const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
2918
+ this.error(message, { code: "commander.excessArguments" });
2919
+ }
2920
+ /**
2921
+ * Unknown command.
2922
+ *
2923
+ * @private
2924
+ */
2925
+ unknownCommand() {
2926
+ const unknownName = this.args[0];
2927
+ let suggestion = "";
2928
+ if (this._showSuggestionAfterError) {
2929
+ const candidateNames = [];
2930
+ this.createHelp().visibleCommands(this).forEach((command) => {
2931
+ candidateNames.push(command.name());
2932
+ if (command.alias()) candidateNames.push(command.alias());
2933
+ });
2934
+ suggestion = suggestSimilar(unknownName, candidateNames);
2935
+ }
2936
+ const message = `error: unknown command '${unknownName}'${suggestion}`;
2937
+ this.error(message, { code: "commander.unknownCommand" });
2938
+ }
2939
+ /**
2940
+ * Get or set the program version.
2941
+ *
2942
+ * This method auto-registers the "-V, --version" option which will print the version number.
2943
+ *
2944
+ * You can optionally supply the flags and description to override the defaults.
2945
+ *
2946
+ * @param {string} [str]
2947
+ * @param {string} [flags]
2948
+ * @param {string} [description]
2949
+ * @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
2950
+ */
2951
+ version(str, flags, description) {
2952
+ if (str === void 0) return this._version;
2953
+ this._version = str;
2954
+ flags = flags || "-V, --version";
2955
+ description = description || "output the version number";
2956
+ const versionOption = this.createOption(flags, description);
2957
+ this._versionOptionName = versionOption.attributeName();
2958
+ this._registerOption(versionOption);
2959
+ this.on("option:" + versionOption.name(), () => {
2960
+ this._outputConfiguration.writeOut(`${str}
2961
+ `);
2962
+ this._exit(0, "commander.version", str);
2963
+ });
2964
+ return this;
2965
+ }
2966
+ /**
2967
+ * Set the description.
2968
+ *
2969
+ * @param {string} [str]
2970
+ * @param {object} [argsDescription]
2971
+ * @return {(string|Command)}
2972
+ */
2973
+ description(str, argsDescription) {
2974
+ if (str === void 0 && argsDescription === void 0)
2975
+ return this._description;
2976
+ this._description = str;
2977
+ if (argsDescription) {
2978
+ this._argsDescription = argsDescription;
2979
+ }
2980
+ return this;
2981
+ }
2982
+ /**
2983
+ * Set the summary. Used when listed as subcommand of parent.
2984
+ *
2985
+ * @param {string} [str]
2986
+ * @return {(string|Command)}
2987
+ */
2988
+ summary(str) {
2989
+ if (str === void 0) return this._summary;
2990
+ this._summary = str;
2991
+ return this;
2992
+ }
2993
+ /**
2994
+ * Set an alias for the command.
2995
+ *
2996
+ * You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
2997
+ *
2998
+ * @param {string} [alias]
2999
+ * @return {(string|Command)}
3000
+ */
3001
+ alias(alias) {
3002
+ if (alias === void 0) return this._aliases[0];
3003
+ let command = this;
3004
+ if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
3005
+ command = this.commands[this.commands.length - 1];
3006
+ }
3007
+ if (alias === command._name)
3008
+ throw new Error("Command alias can't be the same as its name");
3009
+ const matchingCommand = this.parent?._findCommand(alias);
3010
+ if (matchingCommand) {
3011
+ const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
3012
+ throw new Error(
3013
+ `cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
3014
+ );
3015
+ }
3016
+ command._aliases.push(alias);
3017
+ return this;
3018
+ }
3019
+ /**
3020
+ * Set aliases for the command.
3021
+ *
3022
+ * Only the first alias is shown in the auto-generated help.
3023
+ *
3024
+ * @param {string[]} [aliases]
3025
+ * @return {(string[]|Command)}
3026
+ */
3027
+ aliases(aliases) {
3028
+ if (aliases === void 0) return this._aliases;
3029
+ aliases.forEach((alias) => this.alias(alias));
3030
+ return this;
3031
+ }
3032
+ /**
3033
+ * Set / get the command usage `str`.
3034
+ *
3035
+ * @param {string} [str]
3036
+ * @return {(string|Command)}
3037
+ */
3038
+ usage(str) {
3039
+ if (str === void 0) {
3040
+ if (this._usage) return this._usage;
3041
+ const args = this.registeredArguments.map((arg) => {
3042
+ return humanReadableArgName(arg);
3043
+ });
3044
+ return [].concat(
3045
+ this.options.length || this._helpOption !== null ? "[options]" : [],
3046
+ this.commands.length ? "[command]" : [],
3047
+ this.registeredArguments.length ? args : []
3048
+ ).join(" ");
3049
+ }
3050
+ this._usage = str;
3051
+ return this;
3052
+ }
3053
+ /**
3054
+ * Get or set the name of the command.
3055
+ *
3056
+ * @param {string} [str]
3057
+ * @return {(string|Command)}
3058
+ */
3059
+ name(str) {
3060
+ if (str === void 0) return this._name;
3061
+ this._name = str;
3062
+ return this;
3063
+ }
3064
+ /**
3065
+ * Set/get the help group heading for this subcommand in parent command's help.
3066
+ *
3067
+ * @param {string} [heading]
3068
+ * @return {Command | string}
3069
+ */
3070
+ helpGroup(heading) {
3071
+ if (heading === void 0) return this._helpGroupHeading ?? "";
3072
+ this._helpGroupHeading = heading;
3073
+ return this;
3074
+ }
3075
+ /**
3076
+ * Set/get the default help group heading for subcommands added to this command.
3077
+ * (This does not override a group set directly on the subcommand using .helpGroup().)
3078
+ *
3079
+ * @example
3080
+ * program.commandsGroup('Development Commands:);
3081
+ * program.command('watch')...
3082
+ * program.command('lint')...
3083
+ * ...
3084
+ *
3085
+ * @param {string} [heading]
3086
+ * @returns {Command | string}
3087
+ */
3088
+ commandsGroup(heading) {
3089
+ if (heading === void 0) return this._defaultCommandGroup ?? "";
3090
+ this._defaultCommandGroup = heading;
3091
+ return this;
3092
+ }
3093
+ /**
3094
+ * Set/get the default help group heading for options added to this command.
3095
+ * (This does not override a group set directly on the option using .helpGroup().)
3096
+ *
3097
+ * @example
3098
+ * program
3099
+ * .optionsGroup('Development Options:')
3100
+ * .option('-d, --debug', 'output extra debugging')
3101
+ * .option('-p, --profile', 'output profiling information')
3102
+ *
3103
+ * @param {string} [heading]
3104
+ * @returns {Command | string}
3105
+ */
3106
+ optionsGroup(heading) {
3107
+ if (heading === void 0) return this._defaultOptionGroup ?? "";
3108
+ this._defaultOptionGroup = heading;
3109
+ return this;
3110
+ }
3111
+ /**
3112
+ * @param {Option} option
3113
+ * @private
3114
+ */
3115
+ _initOptionGroup(option) {
3116
+ if (this._defaultOptionGroup && !option.helpGroupHeading)
3117
+ option.helpGroup(this._defaultOptionGroup);
3118
+ }
3119
+ /**
3120
+ * @param {Command} cmd
3121
+ * @private
3122
+ */
3123
+ _initCommandGroup(cmd) {
3124
+ if (this._defaultCommandGroup && !cmd.helpGroup())
3125
+ cmd.helpGroup(this._defaultCommandGroup);
3126
+ }
3127
+ /**
3128
+ * Set the name of the command from script filename, such as process.argv[1],
3129
+ * or require.main.filename, or __filename.
3130
+ *
3131
+ * (Used internally and public although not documented in README.)
3132
+ *
3133
+ * @example
3134
+ * program.nameFromFilename(require.main.filename);
3135
+ *
3136
+ * @param {string} filename
3137
+ * @return {Command}
3138
+ */
3139
+ nameFromFilename(filename) {
3140
+ this._name = path.basename(filename, path.extname(filename));
3141
+ return this;
3142
+ }
3143
+ /**
3144
+ * Get or set the directory for searching for executable subcommands of this command.
3145
+ *
3146
+ * @example
3147
+ * program.executableDir(__dirname);
3148
+ * // or
3149
+ * program.executableDir('subcommands');
3150
+ *
3151
+ * @param {string} [path]
3152
+ * @return {(string|null|Command)}
3153
+ */
3154
+ executableDir(path2) {
3155
+ if (path2 === void 0) return this._executableDir;
3156
+ this._executableDir = path2;
3157
+ return this;
3158
+ }
3159
+ /**
3160
+ * Return program help documentation.
3161
+ *
3162
+ * @param {{ error: boolean }} [contextOptions] - pass {error:true} to wrap for stderr instead of stdout
3163
+ * @return {string}
3164
+ */
3165
+ helpInformation(contextOptions) {
3166
+ const helper = this.createHelp();
3167
+ const context = this._getOutputContext(contextOptions);
3168
+ helper.prepareContext({
3169
+ error: context.error,
3170
+ helpWidth: context.helpWidth,
3171
+ outputHasColors: context.hasColors
3172
+ });
3173
+ const text = helper.formatHelp(this, helper);
3174
+ if (context.hasColors) return text;
3175
+ return this._outputConfiguration.stripColor(text);
3176
+ }
3177
+ /**
3178
+ * @typedef HelpContext
3179
+ * @type {object}
3180
+ * @property {boolean} error
3181
+ * @property {number} helpWidth
3182
+ * @property {boolean} hasColors
3183
+ * @property {function} write - includes stripColor if needed
3184
+ *
3185
+ * @returns {HelpContext}
3186
+ * @private
3187
+ */
3188
+ _getOutputContext(contextOptions) {
3189
+ contextOptions = contextOptions || {};
3190
+ const error = !!contextOptions.error;
3191
+ let baseWrite;
3192
+ let hasColors;
3193
+ let helpWidth;
3194
+ if (error) {
3195
+ baseWrite = (str) => this._outputConfiguration.writeErr(str);
3196
+ hasColors = this._outputConfiguration.getErrHasColors();
3197
+ helpWidth = this._outputConfiguration.getErrHelpWidth();
3198
+ } else {
3199
+ baseWrite = (str) => this._outputConfiguration.writeOut(str);
3200
+ hasColors = this._outputConfiguration.getOutHasColors();
3201
+ helpWidth = this._outputConfiguration.getOutHelpWidth();
3202
+ }
3203
+ const write = (str) => {
3204
+ if (!hasColors) str = this._outputConfiguration.stripColor(str);
3205
+ return baseWrite(str);
3206
+ };
3207
+ return { error, write, hasColors, helpWidth };
3208
+ }
3209
+ /**
3210
+ * Output help information for this command.
3211
+ *
3212
+ * Outputs built-in help, and custom text added using `.addHelpText()`.
3213
+ *
3214
+ * @param {{ error: boolean } | Function} [contextOptions] - pass {error:true} to write to stderr instead of stdout
3215
+ */
3216
+ outputHelp(contextOptions) {
3217
+ let deprecatedCallback;
3218
+ if (typeof contextOptions === "function") {
3219
+ deprecatedCallback = contextOptions;
3220
+ contextOptions = void 0;
3221
+ }
3222
+ const outputContext = this._getOutputContext(contextOptions);
3223
+ const eventContext = {
3224
+ error: outputContext.error,
3225
+ write: outputContext.write,
3226
+ command: this
3227
+ };
3228
+ this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
3229
+ this.emit("beforeHelp", eventContext);
3230
+ let helpInformation = this.helpInformation({ error: outputContext.error });
3231
+ if (deprecatedCallback) {
3232
+ helpInformation = deprecatedCallback(helpInformation);
3233
+ if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
3234
+ throw new Error("outputHelp callback must return a string or a Buffer");
3235
+ }
3236
+ }
3237
+ outputContext.write(helpInformation);
3238
+ if (this._getHelpOption()?.long) {
3239
+ this.emit(this._getHelpOption().long);
3240
+ }
3241
+ this.emit("afterHelp", eventContext);
3242
+ this._getCommandAndAncestors().forEach(
3243
+ (command) => command.emit("afterAllHelp", eventContext)
3244
+ );
3245
+ }
3246
+ /**
3247
+ * You can pass in flags and a description to customise the built-in help option.
3248
+ * Pass in false to disable the built-in help option.
3249
+ *
3250
+ * @example
3251
+ * program.helpOption('-?, --help' 'show help'); // customise
3252
+ * program.helpOption(false); // disable
3253
+ *
3254
+ * @param {(string | boolean)} flags
3255
+ * @param {string} [description]
3256
+ * @return {Command} `this` command for chaining
3257
+ */
3258
+ helpOption(flags, description) {
3259
+ if (typeof flags === "boolean") {
3260
+ if (flags) {
3261
+ if (this._helpOption === null) this._helpOption = void 0;
3262
+ if (this._defaultOptionGroup) {
3263
+ this._initOptionGroup(this._getHelpOption());
3264
+ }
3265
+ } else {
3266
+ this._helpOption = null;
3267
+ }
3268
+ return this;
3269
+ }
3270
+ this._helpOption = this.createOption(
3271
+ flags ?? "-h, --help",
3272
+ description ?? "display help for command"
3273
+ );
3274
+ if (flags || description) this._initOptionGroup(this._helpOption);
3275
+ return this;
3276
+ }
3277
+ /**
3278
+ * Lazy create help option.
3279
+ * Returns null if has been disabled with .helpOption(false).
3280
+ *
3281
+ * @returns {(Option | null)} the help option
3282
+ * @package
3283
+ */
3284
+ _getHelpOption() {
3285
+ if (this._helpOption === void 0) {
3286
+ this.helpOption(void 0, void 0);
3287
+ }
3288
+ return this._helpOption;
3289
+ }
3290
+ /**
3291
+ * Supply your own option to use for the built-in help option.
3292
+ * This is an alternative to using helpOption() to customise the flags and description etc.
3293
+ *
3294
+ * @param {Option} option
3295
+ * @return {Command} `this` command for chaining
3296
+ */
3297
+ addHelpOption(option) {
3298
+ this._helpOption = option;
3299
+ this._initOptionGroup(option);
3300
+ return this;
3301
+ }
3302
+ /**
3303
+ * Output help information and exit.
3304
+ *
3305
+ * Outputs built-in help, and custom text added using `.addHelpText()`.
3306
+ *
3307
+ * @param {{ error: boolean }} [contextOptions] - pass {error:true} to write to stderr instead of stdout
3308
+ */
3309
+ help(contextOptions) {
3310
+ this.outputHelp(contextOptions);
3311
+ let exitCode = Number(process2.exitCode ?? 0);
3312
+ if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
3313
+ exitCode = 1;
3314
+ }
3315
+ this._exit(exitCode, "commander.help", "(outputHelp)");
3316
+ }
3317
+ /**
3318
+ * // Do a little typing to coordinate emit and listener for the help text events.
3319
+ * @typedef HelpTextEventContext
3320
+ * @type {object}
3321
+ * @property {boolean} error
3322
+ * @property {Command} command
3323
+ * @property {function} write
3324
+ */
3325
+ /**
3326
+ * Add additional text to be displayed with the built-in help.
3327
+ *
3328
+ * Position is 'before' or 'after' to affect just this command,
3329
+ * and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
3330
+ *
3331
+ * @param {string} position - before or after built-in help
3332
+ * @param {(string | Function)} text - string to add, or a function returning a string
3333
+ * @return {Command} `this` command for chaining
3334
+ */
3335
+ addHelpText(position, text) {
3336
+ const allowedValues = ["beforeAll", "before", "after", "afterAll"];
3337
+ if (!allowedValues.includes(position)) {
3338
+ throw new Error(`Unexpected value for position to addHelpText.
3339
+ Expecting one of '${allowedValues.join("', '")}'`);
3340
+ }
3341
+ const helpEvent = `${position}Help`;
3342
+ this.on(helpEvent, (context) => {
3343
+ let helpStr;
3344
+ if (typeof text === "function") {
3345
+ helpStr = text({ error: context.error, command: context.command });
3346
+ } else {
3347
+ helpStr = text;
3348
+ }
3349
+ if (helpStr) {
3350
+ context.write(`${helpStr}
3351
+ `);
3352
+ }
3353
+ });
3354
+ return this;
3355
+ }
3356
+ /**
3357
+ * Output help information if help flags specified
3358
+ *
3359
+ * @param {Array} args - array of options to search for help flags
3360
+ * @private
3361
+ */
3362
+ _outputHelpIfRequested(args) {
3363
+ const helpOption = this._getHelpOption();
3364
+ const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
3365
+ if (helpRequested) {
3366
+ this.outputHelp();
3367
+ this._exit(0, "commander.helpDisplayed", "(outputHelp)");
3368
+ }
3369
+ }
3370
+ };
3371
+ function incrementNodeInspectorPort(args) {
3372
+ return args.map((arg) => {
3373
+ if (!arg.startsWith("--inspect")) {
3374
+ return arg;
3375
+ }
3376
+ let debugOption;
3377
+ let debugHost = "127.0.0.1";
3378
+ let debugPort = "9229";
3379
+ let match;
3380
+ if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
3381
+ debugOption = match[1];
3382
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
3383
+ debugOption = match[1];
3384
+ if (/^\d+$/.test(match[3])) {
3385
+ debugPort = match[3];
3386
+ } else {
3387
+ debugHost = match[3];
3388
+ }
3389
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
3390
+ debugOption = match[1];
3391
+ debugHost = match[3];
3392
+ debugPort = match[4];
3393
+ }
3394
+ if (debugOption && debugPort !== "0") {
3395
+ return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
3396
+ }
3397
+ return arg;
3398
+ });
3399
+ }
3400
+ function useColor() {
3401
+ if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
3402
+ return false;
3403
+ if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== void 0)
3404
+ return true;
3405
+ return void 0;
3406
+ }
3407
+ exports2.Command = Command;
3408
+ exports2.useColor = useColor;
3409
+ }
3410
+ });
3411
+
3412
+ // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/index.js
3413
+ var require_commander = __commonJS({
3414
+ "../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/index.js"(exports2) {
3415
+ var { Argument } = require_argument();
3416
+ var { Command } = require_command();
3417
+ var { CommanderError, InvalidArgumentError } = require_error();
3418
+ var { Help } = require_help();
3419
+ var { Option } = require_option();
3420
+ exports2.program = new Command();
3421
+ exports2.createCommand = (name) => new Command(name);
3422
+ exports2.createOption = (flags, description) => new Option(flags, description);
3423
+ exports2.createArgument = (name, description) => new Argument(name, description);
3424
+ exports2.Command = Command;
3425
+ exports2.Option = Option;
3426
+ exports2.Argument = Argument;
3427
+ exports2.Help = Help;
3428
+ exports2.CommanderError = CommanderError;
3429
+ exports2.InvalidArgumentError = InvalidArgumentError;
3430
+ exports2.InvalidOptionArgumentError = InvalidArgumentError;
3431
+ }
3432
+ });
3433
+
3434
+ // ../protocol/dist/messages.js
3435
+ var require_messages = __commonJS({
3436
+ "../protocol/dist/messages.js"(exports2) {
3437
+ "use strict";
3438
+ Object.defineProperty(exports2, "__esModule", { value: true });
3439
+ }
3440
+ });
3441
+
3442
+ // ../protocol/dist/canonical.js
3443
+ var require_canonical = __commonJS({
3444
+ "../protocol/dist/canonical.js"(exports2) {
3445
+ "use strict";
3446
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
3447
+ return mod && mod.__esModule ? mod : { "default": mod };
3448
+ };
3449
+ Object.defineProperty(exports2, "__esModule", { value: true });
3450
+ exports2.buildCanonical = buildCanonical;
3451
+ exports2.signCanonical = signCanonical;
3452
+ exports2.verifyCanonical = verifyCanonical;
3453
+ var crypto_1 = __importDefault(require("crypto"));
3454
+ function buildCanonical(params) {
3455
+ const bodyHash = params.body ? crypto_1.default.createHash("sha256").update(params.body, "utf8").digest("hex") : "";
3456
+ return [
3457
+ params.method.toUpperCase(),
3458
+ params.path,
3459
+ params.query,
3460
+ bodyHash,
3461
+ params.requestId,
3462
+ params.ts.toString()
3463
+ ].join("|");
3464
+ }
3465
+ function signCanonical(canonical, secretHash) {
3466
+ return crypto_1.default.createHmac("sha256", secretHash).update(canonical).digest("hex");
3467
+ }
3468
+ function verifyCanonical(canonical, signature, secretHash) {
3469
+ try {
3470
+ const expected = signCanonical(canonical, secretHash);
3471
+ const a = Buffer.from(expected, "hex");
3472
+ const b = Buffer.from(signature, "hex");
3473
+ if (a.length !== b.length)
3474
+ return false;
3475
+ return crypto_1.default.timingSafeEqual(a, b);
3476
+ } catch {
3477
+ return false;
3478
+ }
3479
+ }
3480
+ }
3481
+ });
3482
+
3483
+ // ../protocol/dist/constants.js
3484
+ var require_constants = __commonJS({
3485
+ "../protocol/dist/constants.js"(exports2) {
3486
+ "use strict";
3487
+ Object.defineProperty(exports2, "__esModule", { value: true });
3488
+ exports2.PLAN_AGENT_LIMITS = exports2.LIMITS = exports2.TIMING = exports2.PROTOCOL_VERSION = void 0;
3489
+ exports2.PROTOCOL_VERSION = "1";
3490
+ exports2.TIMING = {
3491
+ /** How long hub waits for agent response before timing out the SDK request */
3492
+ REQUEST_TIMEOUT_MS: 3e4,
3493
+ /** Buffer over REQUEST_TIMEOUT_MS for hub:pending Redis TTL */
3494
+ PENDING_TTL_MS: 32e3,
3495
+ /** Hub pings every N ms */
3496
+ HEARTBEAT_INTERVAL_MS: 1e4,
3497
+ /** Miss this many pings → agent evicted */
3498
+ MAX_MISSED_PINGS: 3,
3499
+ /** Redis presence key TTL (must be > HEARTBEAT_INTERVAL_MS) */
3500
+ AGENT_PRESENCE_TTL_SEC: 25,
3501
+ /** Agent reconnect: initial delay */
3502
+ RECONNECT_INITIAL_MS: 1e3,
3503
+ /** Agent reconnect: maximum delay cap */
3504
+ RECONNECT_MAX_MS: 3e5,
3505
+ /** Signature timestamp tolerance */
3506
+ SIGNATURE_WINDOW_MS: 6e4,
3507
+ /** MessageBatcher flush window */
3508
+ BATCH_WINDOW_MS: 50,
3509
+ /** MessageBatcher max items before immediate flush */
3510
+ BATCH_MAX_SIZE: 100,
3511
+ /** LocalAgentDiscovery timeout */
3512
+ LOCAL_DISCOVERY_TIMEOUT_MS: 50
3513
+ };
3514
+ exports2.LIMITS = {
3515
+ /** Max WS message size (10MB) */
3516
+ MAX_PAYLOAD_BYTES: 10 * 1024 * 1024,
3517
+ /** Port agent broadcasts for local discovery */
3518
+ LOCAL_AGENT_DISCOVERY_PORT: 4242,
3519
+ /** Max retry attempts for queue items */
3520
+ QUEUE_MAX_ATTEMPTS_OUTBOUND: 10,
3521
+ QUEUE_MAX_ATTEMPTS_INBOUND: 5
3522
+ };
3523
+ exports2.PLAN_AGENT_LIMITS = {
3524
+ FREE: 1,
3525
+ PRO: 5,
3526
+ ENTERPRISE: Infinity
3527
+ };
3528
+ }
3529
+ });
3530
+
3531
+ // ../protocol/dist/serializer.js
3532
+ var require_serializer = __commonJS({
3533
+ "../protocol/dist/serializer.js"(exports2) {
3534
+ "use strict";
3535
+ Object.defineProperty(exports2, "__esModule", { value: true });
3536
+ exports2.ProtocolError = void 0;
3537
+ exports2.serialize = serialize;
3538
+ exports2.deserialize = deserialize;
3539
+ exports2.parseMessage = parseMessage;
3540
+ var constants_1 = require_constants();
3541
+ function serialize(msg) {
3542
+ return JSON.stringify(msg);
3543
+ }
3544
+ function deserialize(data) {
3545
+ const str = Buffer.isBuffer(data) ? data.toString("utf8") : data;
3546
+ return JSON.parse(str);
3547
+ }
3548
+ function parseMessage(data) {
3549
+ let msg;
3550
+ try {
3551
+ msg = deserialize(data);
3552
+ } catch {
3553
+ throw new ProtocolError("INVALID_MESSAGE", "Message is not valid JSON");
3554
+ }
3555
+ if (!msg || typeof msg !== "object") {
3556
+ throw new ProtocolError("INVALID_MESSAGE", "Message must be a JSON object");
3557
+ }
3558
+ if (msg.v !== constants_1.PROTOCOL_VERSION) {
3559
+ throw new ProtocolError("VERSION_UNSUPPORTED", `Protocol version "${msg.v}" is not supported. Expected "${constants_1.PROTOCOL_VERSION}".`);
3560
+ }
3561
+ if (!msg.type || typeof msg.type !== "string") {
3562
+ throw new ProtocolError("INVALID_MESSAGE", 'Message missing required "type" field');
3563
+ }
3564
+ return msg;
3565
+ }
3566
+ var ProtocolError = class extends Error {
3567
+ code;
3568
+ constructor(code, message) {
3569
+ super(message);
3570
+ this.code = code;
3571
+ this.name = "ProtocolError";
3572
+ }
3573
+ };
3574
+ exports2.ProtocolError = ProtocolError;
3575
+ }
3576
+ });
3577
+
3578
+ // ../protocol/dist/errors.js
3579
+ var require_errors = __commonJS({
3580
+ "../protocol/dist/errors.js"(exports2) {
3581
+ "use strict";
3582
+ Object.defineProperty(exports2, "__esModule", { value: true });
3583
+ exports2.WS_CLOSE_CODES = void 0;
3584
+ exports2.WS_CLOSE_CODES = {
3585
+ AUTH_FAILED: 4001,
3586
+ VERSION_UNSUPPORTED: 4002,
3587
+ AGENT_LIMIT_REACHED: 4003,
3588
+ RATE_LIMITED: 4004,
3589
+ INTERNAL_ERROR: 4999
3590
+ };
3591
+ }
3592
+ });
3593
+
3594
+ // ../protocol/dist/index.js
3595
+ var require_dist = __commonJS({
3596
+ "../protocol/dist/index.js"(exports2) {
3597
+ "use strict";
3598
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
3599
+ if (k2 === void 0) k2 = k;
3600
+ var desc = Object.getOwnPropertyDescriptor(m, k);
3601
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
3602
+ desc = { enumerable: true, get: function() {
3603
+ return m[k];
3604
+ } };
3605
+ }
3606
+ Object.defineProperty(o, k2, desc);
3607
+ }) : (function(o, m, k, k2) {
3608
+ if (k2 === void 0) k2 = k;
3609
+ o[k2] = m[k];
3610
+ }));
3611
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
3612
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
3613
+ };
3614
+ Object.defineProperty(exports2, "__esModule", { value: true });
3615
+ __exportStar(require_messages(), exports2);
3616
+ __exportStar(require_canonical(), exports2);
3617
+ __exportStar(require_serializer(), exports2);
3618
+ __exportStar(require_constants(), exports2);
3619
+ __exportStar(require_errors(), exports2);
3620
+ }
3621
+ });
3622
+
3623
+ // dist/queue/DurableQueue.js
3624
+ var require_DurableQueue = __commonJS({
3625
+ "dist/queue/DurableQueue.js"(exports2) {
3626
+ "use strict";
3627
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
3628
+ return mod && mod.__esModule ? mod : { "default": mod };
3629
+ };
3630
+ Object.defineProperty(exports2, "__esModule", { value: true });
3631
+ exports2.DurableQueue = void 0;
3632
+ var better_sqlite3_1 = __importDefault(require("better-sqlite3"));
3633
+ var crypto_1 = require("crypto");
3634
+ var protocol_1 = require_dist();
3635
+ var DurableQueue = class {
3636
+ db;
3637
+ constructor(dbPath) {
3638
+ this.db = new better_sqlite3_1.default(dbPath);
3639
+ this.db.pragma("journal_mode = WAL");
3640
+ this.db.pragma("synchronous = NORMAL");
3641
+ this.db.pragma("foreign_keys = ON");
3642
+ this.db.pragma("busy_timeout = 5000");
3643
+ this.migrate();
3644
+ }
3645
+ migrate() {
3646
+ this.db.exec(`
3647
+ CREATE TABLE IF NOT EXISTS queue (
3648
+ id TEXT PRIMARY KEY,
3649
+ direction TEXT NOT NULL CHECK(direction IN ('inbound', 'outbound')),
3650
+ payload TEXT NOT NULL,
3651
+ ts INTEGER NOT NULL,
3652
+ attempts INTEGER NOT NULL DEFAULT 0,
3653
+ max_attempts INTEGER NOT NULL DEFAULT 5,
3654
+ next_retry_at INTEGER NOT NULL DEFAULT 0
3655
+ );
3656
+
3657
+ CREATE INDEX IF NOT EXISTS idx_queue_direction_retry
3658
+ ON queue(direction, next_retry_at);
3659
+
3660
+ CREATE INDEX IF NOT EXISTS idx_queue_ts
3661
+ ON queue(ts);
3662
+
3663
+ -- Dead letter: items that exceeded max_attempts
3664
+ CREATE TABLE IF NOT EXISTS dead_letter (
3665
+ id TEXT PRIMARY KEY,
3666
+ direction TEXT NOT NULL,
3667
+ payload TEXT NOT NULL,
3668
+ ts INTEGER NOT NULL,
3669
+ attempts INTEGER NOT NULL,
3670
+ failed_at INTEGER NOT NULL
3671
+ );
3672
+ `);
3673
+ }
3674
+ enqueueInbound(payload) {
3675
+ this.db.prepare(`
3676
+ INSERT INTO queue (id, direction, payload, ts, attempts, max_attempts, next_retry_at)
3677
+ VALUES (?, 'inbound', ?, ?, 0, ?, 0)
3678
+ `).run((0, crypto_1.randomUUID)(), JSON.stringify(payload), Date.now(), protocol_1.LIMITS.QUEUE_MAX_ATTEMPTS_INBOUND);
3679
+ }
3680
+ enqueueOutbound(payload) {
3681
+ this.db.prepare(`
3682
+ INSERT INTO queue (id, direction, payload, ts, attempts, max_attempts, next_retry_at)
3683
+ VALUES (?, 'outbound', ?, ?, 0, ?, 0)
3684
+ `).run((0, crypto_1.randomUUID)(), JSON.stringify(payload), Date.now(), protocol_1.LIMITS.QUEUE_MAX_ATTEMPTS_OUTBOUND);
3685
+ }
3686
+ /**
3687
+ * Returns all items ready for replay, ordered:
3688
+ * 1. OUTBOUND first (send cached responses before processing new requests)
3689
+ * 2. Within same direction: oldest first (preserve request ordering)
3690
+ */
3691
+ drainForReplay() {
3692
+ return this.db.prepare(`
3693
+ SELECT id, direction, payload, ts, attempts, max_attempts, next_retry_at
3694
+ FROM queue
3695
+ WHERE next_retry_at <= ?
3696
+ ORDER BY
3697
+ CASE direction WHEN 'outbound' THEN 0 ELSE 1 END ASC,
3698
+ ts ASC
3699
+ `).all(Date.now());
3700
+ }
3701
+ markSuccess(id) {
3702
+ this.db.prepare("DELETE FROM queue WHERE id = ?").run(id);
3703
+ }
3704
+ markFailed(id) {
3705
+ const item = this.db.prepare("SELECT * FROM queue WHERE id = ?").get(id);
3706
+ if (!item)
3707
+ return;
3708
+ const newAttempts = item.attempts + 1;
3709
+ if (newAttempts >= item.maxAttempts) {
3710
+ this.db.transaction(() => {
3711
+ this.db.prepare(`
3712
+ INSERT INTO dead_letter (id, direction, payload, ts, attempts, failed_at)
3713
+ VALUES (?, ?, ?, ?, ?, ?)
3714
+ `).run(item.id, item.direction, item.payload, item.ts, newAttempts, Date.now());
3715
+ this.db.prepare("DELETE FROM queue WHERE id = ?").run(id);
3716
+ })();
3717
+ return;
3718
+ }
3719
+ const backoffMs = Math.min(1e3 * Math.pow(2, newAttempts - 1), 3e5);
3720
+ this.db.prepare(`
3721
+ UPDATE queue SET attempts = ?, next_retry_at = ? WHERE id = ?
3722
+ `).run(newAttempts, Date.now() + backoffMs, id);
3723
+ }
3724
+ count() {
3725
+ const now = Date.now();
3726
+ const ready = this.db.prepare("SELECT COUNT(*) as n FROM queue WHERE next_retry_at <= ?").get(now).n;
3727
+ const pending = this.db.prepare("SELECT COUNT(*) as n FROM queue WHERE next_retry_at > ?").get(now).n;
3728
+ const deadLetter = this.db.prepare("SELECT COUNT(*) as n FROM dead_letter").get().n;
3729
+ return { ready, pending, deadLetter };
3730
+ }
3731
+ /** Drain dead letter for inspection. Returns last N items. */
3732
+ deadLetterItems(limit = 50) {
3733
+ return this.db.prepare(`
3734
+ SELECT id, direction, payload, ts, attempts, 0 as max_attempts, failed_at as next_retry_at
3735
+ FROM dead_letter ORDER BY failed_at DESC LIMIT ?
3736
+ `).all(limit);
3737
+ }
3738
+ close() {
3739
+ this.db.close();
3740
+ }
3741
+ };
3742
+ exports2.DurableQueue = DurableQueue;
3743
+ }
3744
+ });
3745
+
3746
+ // dist/cache/ResponseCache.js
3747
+ var require_ResponseCache = __commonJS({
3748
+ "dist/cache/ResponseCache.js"(exports2) {
3749
+ "use strict";
3750
+ Object.defineProperty(exports2, "__esModule", { value: true });
3751
+ exports2.ResponseCache = void 0;
3752
+ var ResponseCache = class {
3753
+ store = /* @__PURE__ */ new Map();
3754
+ // Evict entries when cache exceeds this size (LRU-lite: evict oldest)
3755
+ MAX_ENTRIES = 500;
3756
+ /**
3757
+ * Try to get a cached response.
3758
+ * Returns null on miss or if method is not GET.
3759
+ */
3760
+ get(method, path, query) {
3761
+ if (method.toUpperCase() !== "GET")
3762
+ return null;
3763
+ const key = this.buildKey(path, query);
3764
+ const cached = this.store.get(key);
3765
+ if (!cached)
3766
+ return null;
3767
+ if (Date.now() > cached.expiresAt) {
3768
+ this.store.delete(key);
3769
+ return null;
3770
+ }
3771
+ cached.hits += 1;
3772
+ return cached;
3773
+ }
3774
+ /**
3775
+ * Store a response if the backend's Cache-Control header allows it.
3776
+ * Does nothing for non-GET methods or non-cacheable responses.
3777
+ */
3778
+ set(method, path, query, response) {
3779
+ if (method.toUpperCase() !== "GET")
3780
+ return;
3781
+ if (response.status < 200 || response.status >= 300)
3782
+ return;
3783
+ const maxAge = this.parseMaxAge(response.headers["cache-control"] ?? "");
3784
+ if (maxAge <= 0)
3785
+ return;
3786
+ const now = Date.now();
3787
+ const key = this.buildKey(path, query);
3788
+ if (this.store.size >= this.MAX_ENTRIES && !this.store.has(key)) {
3789
+ const oldest = this.store.keys().next().value;
3790
+ if (oldest)
3791
+ this.store.delete(oldest);
3792
+ }
3793
+ this.store.set(key, {
3794
+ ...response,
3795
+ cachedAt: now,
3796
+ expiresAt: now + maxAge * 1e3,
3797
+ hits: 0
3798
+ });
3799
+ }
3800
+ /**
3801
+ * Invalidate all cached entries for a path prefix.
3802
+ * Call after any POST/PUT/PATCH/DELETE to related resources.
3803
+ */
3804
+ invalidatePrefix(pathPrefix) {
3805
+ let count = 0;
3806
+ for (const key of this.store.keys()) {
3807
+ if (key.startsWith(pathPrefix)) {
3808
+ this.store.delete(key);
3809
+ count++;
3810
+ }
3811
+ }
3812
+ return count;
3813
+ }
3814
+ /** Remove all expired entries. Called periodically. */
3815
+ evictExpired() {
3816
+ const now = Date.now();
3817
+ let count = 0;
3818
+ for (const [key, entry] of this.store) {
3819
+ if (now > entry.expiresAt) {
3820
+ this.store.delete(key);
3821
+ count++;
3822
+ }
3823
+ }
3824
+ return count;
3825
+ }
3826
+ stats() {
3827
+ let totalHits = 0;
3828
+ for (const entry of this.store.values())
3829
+ totalHits += entry.hits;
3830
+ return { size: this.store.size, totalHits };
3831
+ }
3832
+ clear() {
3833
+ this.store.clear();
3834
+ }
3835
+ // ── Private helpers ─────────────────────────────────────────────────────────
3836
+ buildKey(path, query) {
3837
+ return query ? `${path}?${query}` : path;
3838
+ }
3839
+ /**
3840
+ * Parse max-age seconds from a Cache-Control header value.
3841
+ * Returns 0 if no caching is allowed.
3842
+ *
3843
+ * Examples:
3844
+ * "max-age=300" → 300
3845
+ * "public, max-age=60" → 60
3846
+ * "no-cache" → 0
3847
+ * "no-store" → 0
3848
+ * "private, max-age=120" → 0 (private = don't cache in shared proxy)
3849
+ * "" → 0
3850
+ */
3851
+ parseMaxAge(cacheControl) {
3852
+ if (!cacheControl)
3853
+ return 0;
3854
+ const lower = cacheControl.toLowerCase();
3855
+ if (lower.includes("no-store") || lower.includes("no-cache"))
3856
+ return 0;
3857
+ if (lower.includes("private"))
3858
+ return 0;
3859
+ const match = lower.match(/max-age\s*=\s*(\d+)/);
3860
+ if (!match)
3861
+ return 0;
3862
+ const seconds = parseInt(match[1], 10);
3863
+ return isNaN(seconds) ? 0 : seconds;
3864
+ }
3865
+ };
3866
+ exports2.ResponseCache = ResponseCache;
3867
+ }
3868
+ });
3869
+
3870
+ // dist/proxy/BackendProxy.js
3871
+ var require_BackendProxy = __commonJS({
3872
+ "dist/proxy/BackendProxy.js"(exports2) {
3873
+ "use strict";
3874
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
3875
+ return mod && mod.__esModule ? mod : { "default": mod };
3876
+ };
3877
+ Object.defineProperty(exports2, "__esModule", { value: true });
3878
+ exports2.BackendProxy = void 0;
3879
+ var axios_1 = __importDefault(require("axios"));
3880
+ var protocol_1 = require_dist();
3881
+ var ResponseCache_1 = require_ResponseCache();
3882
+ var HOP_BY_HOP = /* @__PURE__ */ new Set([
3883
+ "connection",
3884
+ "keep-alive",
3885
+ "proxy-authenticate",
3886
+ "proxy-authorization",
3887
+ "te",
3888
+ "trailers",
3889
+ "transfer-encoding",
3890
+ "upgrade"
3891
+ ]);
3892
+ var CACHE_EVICT_INTERVAL_MS = 6e4;
3893
+ var BackendProxy = class {
3894
+ port;
3895
+ client;
3896
+ cache = new ResponseCache_1.ResponseCache();
3897
+ evictTimer = null;
3898
+ constructor(port2) {
3899
+ this.port = port2;
3900
+ this.client = axios_1.default.create({
3901
+ baseURL: `http://127.0.0.1:${port2}`,
3902
+ timeout: 28e3,
3903
+ maxContentLength: protocol_1.LIMITS.MAX_PAYLOAD_BYTES,
3904
+ maxBodyLength: protocol_1.LIMITS.MAX_PAYLOAD_BYTES,
3905
+ validateStatus: () => true,
3906
+ decompress: true,
3907
+ responseType: "arraybuffer"
3908
+ });
3909
+ this.evictTimer = setInterval(() => this.cache.evictExpired(), CACHE_EVICT_INTERVAL_MS);
3910
+ this.evictTimer.unref?.();
3911
+ }
3912
+ async forward(msg) {
3913
+ const cached = this.cache.get(msg.method, msg.path, msg.query);
3914
+ if (cached) {
3915
+ return {
3916
+ status: cached.status,
3917
+ headers: { ...cached.headers, "x-vhyxvoid-cache": "HIT" },
3918
+ body: cached.body,
3919
+ durationMs: 0
3920
+ // served from memory
3921
+ };
3922
+ }
3923
+ const start = Date.now();
3924
+ const url = msg.path + (msg.query ? `?${msg.query}` : "");
3925
+ const response = await this.client.request({
3926
+ method: msg.method,
3927
+ url,
3928
+ headers: this.sanitizeInboundHeaders(msg.headers),
3929
+ data: msg.body ?? void 0
3930
+ });
3931
+ const bodyBuffer = response.data;
3932
+ const bodyStr = bodyBuffer.length > 0 ? bodyBuffer.toString("utf8") : null;
3933
+ const headers = this.sanitizeOutboundHeaders(response.headers);
3934
+ const durationMs = Date.now() - start;
3935
+ this.cache.set(msg.method, msg.path, msg.query, {
3936
+ status: response.status,
3937
+ headers,
3938
+ body: bodyStr,
3939
+ durationMs
3940
+ });
3941
+ return {
3942
+ status: response.status,
3943
+ headers: { ...headers, "x-vhyxvoid-cache": "MISS" },
3944
+ body: bodyStr,
3945
+ durationMs
3946
+ };
3947
+ }
3948
+ /** Invalidate cached GETs related to a mutating request path */
3949
+ invalidateCacheFor(method, path) {
3950
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method.toUpperCase())) {
3951
+ const basePath = path.split("/").slice(0, -1).join("/");
3952
+ this.cache.invalidatePrefix(basePath || path);
3953
+ }
3954
+ }
3955
+ getCacheStats() {
3956
+ return this.cache.stats();
3957
+ }
3958
+ stop() {
3959
+ if (this.evictTimer) {
3960
+ clearInterval(this.evictTimer);
3961
+ this.evictTimer = null;
3962
+ }
3963
+ this.cache.clear();
3964
+ }
3965
+ sanitizeInboundHeaders(headers) {
3966
+ const clean = {};
3967
+ for (const [k, v] of Object.entries(headers)) {
3968
+ if (!HOP_BY_HOP.has(k.toLowerCase()))
3969
+ clean[k] = v;
3970
+ }
3971
+ clean["x-forwarded-by"] = "vhyxvoid";
3972
+ clean["x-forwarded-host"] = `127.0.0.1:${this.port}`;
3973
+ return clean;
3974
+ }
3975
+ sanitizeOutboundHeaders(headers) {
3976
+ const clean = {};
3977
+ for (const [k, v] of Object.entries(headers)) {
3978
+ if (!HOP_BY_HOP.has(k.toLowerCase()) && typeof v === "string")
3979
+ clean[k] = v;
3980
+ }
3981
+ return clean;
3982
+ }
3983
+ };
3984
+ exports2.BackendProxy = BackendProxy;
3985
+ }
3986
+ });
3987
+
3988
+ // dist/batcher/MessageBatcher.js
3989
+ var require_MessageBatcher = __commonJS({
3990
+ "dist/batcher/MessageBatcher.js"(exports2) {
3991
+ "use strict";
3992
+ Object.defineProperty(exports2, "__esModule", { value: true });
3993
+ exports2.MessageBatcher = void 0;
3994
+ var protocol_1 = require_dist();
3995
+ var MessageBatcher = class {
3996
+ onFlush;
3997
+ onQueueFallback;
3998
+ isConnected;
3999
+ buffer = [];
4000
+ timer = null;
4001
+ constructor(onFlush, onQueueFallback, isConnected) {
4002
+ this.onFlush = onFlush;
4003
+ this.onQueueFallback = onQueueFallback;
4004
+ this.isConnected = isConnected;
4005
+ }
4006
+ /** Add a message to the batch. Flushes immediately if MAX_BATCH_SIZE reached. */
4007
+ add(msg) {
4008
+ this.buffer.push(msg);
4009
+ if (this.buffer.length >= protocol_1.TIMING.BATCH_MAX_SIZE) {
4010
+ this.flush();
4011
+ } else if (!this.timer) {
4012
+ this.timer = setTimeout(() => this.flush(), protocol_1.TIMING.BATCH_WINDOW_MS);
4013
+ }
4014
+ }
4015
+ /**
4016
+ * Flush the buffer.
4017
+ * - If WS is connected: send as batch (or single message if only one item)
4018
+ * - If WS is down: route non-pong messages to DurableQueue
4019
+ */
4020
+ flush() {
4021
+ if (this.buffer.length === 0)
4022
+ return;
4023
+ if (this.timer) {
4024
+ clearTimeout(this.timer);
4025
+ this.timer = null;
4026
+ }
4027
+ const messages = this.buffer.splice(0);
4028
+ if (!this.isConnected()) {
4029
+ for (const msg of messages) {
4030
+ if (msg.type !== "agent:pong") {
4031
+ this.onQueueFallback(msg);
4032
+ }
4033
+ }
4034
+ return;
4035
+ }
4036
+ const serialized = messages.length === 1 ? (0, protocol_1.serialize)(messages[0]) : (0, protocol_1.serialize)({ v: "1", type: "agent:batch", messages });
4037
+ this.onFlush(serialized);
4038
+ }
4039
+ /**
4040
+ * Called on WS close BEFORE reconnect starts.
4041
+ * Moves everything currently in the buffer to DurableQueue.
4042
+ * Pongs are discarded (they are point-in-time, not meaningful after disconnect).
4043
+ */
4044
+ flushToQueue() {
4045
+ if (this.timer) {
4046
+ clearTimeout(this.timer);
4047
+ this.timer = null;
4048
+ }
4049
+ const messages = this.buffer.splice(0);
4050
+ for (const msg of messages) {
4051
+ if (msg.type !== "agent:pong") {
4052
+ this.onQueueFallback(msg);
4053
+ }
4054
+ }
4055
+ }
4056
+ /** Number of messages currently buffered (for diagnostics). */
4057
+ size() {
4058
+ return this.buffer.length;
4059
+ }
4060
+ };
4061
+ exports2.MessageBatcher = MessageBatcher;
4062
+ }
4063
+ });
4064
+
4065
+ // dist/replay/replayQueue.js
4066
+ var require_replayQueue = __commonJS({
4067
+ "dist/replay/replayQueue.js"(exports2) {
4068
+ "use strict";
4069
+ Object.defineProperty(exports2, "__esModule", { value: true });
4070
+ exports2.replayQueue = replayQueue;
4071
+ var protocol_1 = require_dist();
4072
+ async function replayQueue(queue, send, proxy) {
4073
+ const items = queue.drainForReplay();
4074
+ if (items.length === 0) {
4075
+ return { succeeded: 0, failed: 0, skipped: 0 };
4076
+ }
4077
+ console.info(`[replay] processing ${items.length} queued items`);
4078
+ let succeeded = 0;
4079
+ let failed = 0;
4080
+ let skipped = 0;
4081
+ for (const item of items) {
4082
+ try {
4083
+ if (item.direction === "outbound") {
4084
+ await replayOutbound(item, send);
4085
+ } else {
4086
+ await replayInbound(item, send, proxy);
4087
+ }
4088
+ queue.markSuccess(item.id);
4089
+ succeeded++;
4090
+ } catch (err) {
4091
+ queue.markFailed(item.id);
4092
+ failed++;
4093
+ console.warn(`[replay] item ${item.id} failed (attempt ${item.attempts + 1}): ${err.message}`);
4094
+ }
4095
+ }
4096
+ const counts = queue.count();
4097
+ console.info(`[replay] done \u2014 succeeded: ${succeeded}, failed: ${failed}, remaining: ${counts.ready + counts.pending}`);
4098
+ return { succeeded, failed, skipped };
4099
+ }
4100
+ async function replayOutbound(item, send) {
4101
+ const msg = JSON.parse(item.payload);
4102
+ send((0, protocol_1.serialize)(msg));
4103
+ }
4104
+ async function replayInbound(item, send, proxy) {
4105
+ const forward = JSON.parse(item.payload);
4106
+ const result = await proxy.forward(forward);
4107
+ const response = {
4108
+ v: protocol_1.PROTOCOL_VERSION,
4109
+ type: "tunnel:response",
4110
+ requestId: forward.requestId,
4111
+ ...result
4112
+ };
4113
+ send((0, protocol_1.serialize)(response));
4114
+ }
4115
+ }
4116
+ });
4117
+
4118
+ // dist/discovery/LocalDiscoveryServer.js
4119
+ var require_LocalDiscoveryServer = __commonJS({
4120
+ "dist/discovery/LocalDiscoveryServer.js"(exports2) {
4121
+ "use strict";
4122
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
4123
+ return mod && mod.__esModule ? mod : { "default": mod };
4124
+ };
4125
+ Object.defineProperty(exports2, "__esModule", { value: true });
4126
+ exports2.LocalDiscoveryServer = void 0;
4127
+ var http_1 = __importDefault(require("http"));
4128
+ var protocol_1 = require_dist();
4129
+ var LocalDiscoveryServer = class {
4130
+ server = null;
4131
+ payload;
4132
+ constructor(payload) {
4133
+ this.payload = payload;
4134
+ }
4135
+ /** Update the accountIdHash after hub registration completes */
4136
+ setAccountIdHash(hash) {
4137
+ this.payload = { ...this.payload, accountIdHash: hash };
4138
+ }
4139
+ start() {
4140
+ this.server = http_1.default.createServer((req, res) => {
4141
+ if (req.url !== "/vhyxvoid" || req.method !== "GET") {
4142
+ res.writeHead(404).end();
4143
+ return;
4144
+ }
4145
+ const body = JSON.stringify(this.payload);
4146
+ res.writeHead(200, {
4147
+ "Content-Type": "application/json",
4148
+ "Content-Length": Buffer.byteLength(body).toString(),
4149
+ "Cache-Control": "no-cache"
4150
+ });
4151
+ res.end(body);
4152
+ });
4153
+ this.server.listen(protocol_1.LIMITS.LOCAL_AGENT_DISCOVERY_PORT, "127.0.0.1", () => {
4154
+ console.info(`[discovery] local discovery server ready on port ${protocol_1.LIMITS.LOCAL_AGENT_DISCOVERY_PORT}`);
4155
+ });
4156
+ this.server.on("error", (err) => {
4157
+ if (err.code === "EADDRINUSE") {
4158
+ console.warn(`[discovery] port ${protocol_1.LIMITS.LOCAL_AGENT_DISCOVERY_PORT} in use \u2014 local discovery disabled. Another agent may already be running.`);
4159
+ } else {
4160
+ console.warn(`[discovery] server error: ${err.message}`);
4161
+ }
4162
+ });
4163
+ }
4164
+ stop() {
4165
+ this.server?.close();
4166
+ this.server = null;
4167
+ }
4168
+ };
4169
+ exports2.LocalDiscoveryServer = LocalDiscoveryServer;
4170
+ }
4171
+ });
4172
+
4173
+ // dist/AgentClient.js
4174
+ var require_AgentClient = __commonJS({
4175
+ "dist/AgentClient.js"(exports2) {
4176
+ "use strict";
4177
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
4178
+ return mod && mod.__esModule ? mod : { "default": mod };
4179
+ };
4180
+ Object.defineProperty(exports2, "__esModule", { value: true });
4181
+ exports2.AgentClient = void 0;
4182
+ var ws_1 = __importDefault(require("ws"));
4183
+ var path_1 = __importDefault(require("path"));
4184
+ var os_1 = __importDefault(require("os"));
4185
+ var fs_1 = __importDefault(require("fs"));
4186
+ var protocol_1 = require_dist();
4187
+ var DurableQueue_1 = require_DurableQueue();
4188
+ var BackendProxy_1 = require_BackendProxy();
4189
+ var MessageBatcher_1 = require_MessageBatcher();
4190
+ var replayQueue_1 = require_replayQueue();
4191
+ var LocalDiscoveryServer_1 = require_LocalDiscoveryServer();
4192
+ var AgentClient = class {
4193
+ config;
4194
+ state = "IDLE";
4195
+ ws = null;
4196
+ agentId = null;
4197
+ reconnectDelay = protocol_1.TIMING.RECONNECT_INITIAL_MS;
4198
+ reconnectTimer = null;
4199
+ stopped = false;
4200
+ queue;
4201
+ proxy;
4202
+ batcher;
4203
+ discovery;
4204
+ log;
4205
+ constructor(config) {
4206
+ this.config = config;
4207
+ this.log = config.logger ?? {
4208
+ info: (obj, msg) => console.info(msg ?? "", obj),
4209
+ warn: (obj, msg) => console.warn(msg ?? "", obj),
4210
+ error: (obj, msg) => console.error(msg ?? "", obj)
4211
+ };
4212
+ const queuePath = config.queuePath ?? path_1.default.join(os_1.default.homedir(), ".vhyxvoid", "queue.db");
4213
+ fs_1.default.mkdirSync(path_1.default.dirname(queuePath), { recursive: true });
4214
+ this.queue = new DurableQueue_1.DurableQueue(queuePath);
4215
+ this.proxy = new BackendProxy_1.BackendProxy(config.port);
4216
+ this.batcher = new MessageBatcher_1.MessageBatcher(
4217
+ // onFlush: send over WS
4218
+ (data) => this.sendRaw(data),
4219
+ // onQueueFallback: WS is down, persist to durable queue
4220
+ (msg) => this.queue.enqueueOutbound(msg),
4221
+ // isConnected: checked before every flush
4222
+ () => this.state === "CONNECTED"
4223
+ );
4224
+ const useDiscovery = config.localDiscovery !== false;
4225
+ this.discovery = useDiscovery ? new LocalDiscoveryServer_1.LocalDiscoveryServer({
4226
+ agentVersion: config.agentVersion,
4227
+ label: config.label,
4228
+ port: config.port,
4229
+ accountIdHash: ""
4230
+ // populated after hub:registered
4231
+ }) : null;
4232
+ }
4233
+ // ── Public API ──────────────────────────────────────────────────────────────
4234
+ start() {
4235
+ if (this.state !== "IDLE") {
4236
+ throw new Error("AgentClient already started. Create a new instance to restart.");
4237
+ }
4238
+ this.discovery?.start();
4239
+ this.connect();
4240
+ }
4241
+ stop() {
4242
+ this.stopped = true;
4243
+ this.setState("STOPPED");
4244
+ this.batcher.flushToQueue();
4245
+ if (this.reconnectTimer)
4246
+ clearTimeout(this.reconnectTimer);
4247
+ this.ws?.close(1e3, "agent_stopped");
4248
+ this.proxy.stop();
4249
+ this.discovery?.stop();
4250
+ this.queue.close();
4251
+ }
4252
+ getState() {
4253
+ return this.state;
4254
+ }
4255
+ getQueueStatus() {
4256
+ return this.queue.count();
4257
+ }
4258
+ getCacheStats() {
4259
+ return this.proxy.getCacheStats();
4260
+ }
4261
+ // ── WS connection lifecycle ─────────────────────────────────────────────────
4262
+ connect() {
4263
+ if (this.stopped)
4264
+ return;
4265
+ this.setState("CONNECTING");
4266
+ const ws = new ws_1.default(this.config.hubUrl, {
4267
+ perMessageDeflate: true,
4268
+ handshakeTimeout: 1e4
4269
+ });
4270
+ this.ws = ws;
4271
+ ws.on("open", () => this.onOpen());
4272
+ ws.on("message", (data) => this.onMessage(data));
4273
+ ws.on("close", (code, reason) => this.onClose(code, reason.toString()));
4274
+ ws.on("error", (err) => this.onError(err));
4275
+ }
4276
+ onOpen() {
4277
+ this.setState("AUTHENTICATING");
4278
+ this.reconnectDelay = protocol_1.TIMING.RECONNECT_INITIAL_MS;
4279
+ const msg = {
4280
+ v: protocol_1.PROTOCOL_VERSION,
4281
+ type: "agent:register",
4282
+ keyId: this.config.keyId,
4283
+ label: this.config.label,
4284
+ // agentVersion: this.config.agentVersion,
4285
+ rawSecret: this.config.secret,
4286
+ // ← raw secret, hub applies pepper
4287
+ agentVersion: this.config.agentVersion
4288
+ };
4289
+ this.sendRaw((0, protocol_1.serialize)(msg));
4290
+ this.log.info({ label: this.config.label, keyId: this.config.keyId }, "[agent] authenticating with hub");
4291
+ }
4292
+ onMessage(data) {
4293
+ let msg;
4294
+ try {
4295
+ msg = (0, protocol_1.parseMessage)(data);
4296
+ } catch (err) {
4297
+ if (err instanceof protocol_1.ProtocolError) {
4298
+ this.log.warn(
4299
+ {
4300
+ code: err.code,
4301
+ message: `Local backend on port ${this.config.port} is not responding: ${err.message}`
4302
+ },
4303
+ // ← this is fine, err IS ProtocolError here
4304
+ "[agent] protocol error from hub"
4305
+ );
4306
+ }
4307
+ return;
4308
+ }
4309
+ switch (msg.type) {
4310
+ case "hub:registered":
4311
+ return void this.onRegistered(msg);
4312
+ case "hub:ping":
4313
+ return this.onPing(msg);
4314
+ case "hub:error":
4315
+ return this.onHubError(msg);
4316
+ case "tunnel:forward":
4317
+ return void this.onForward(msg);
4318
+ default:
4319
+ this.log.warn({ type: msg.type }, "[agent] unknown message type from hub");
4320
+ }
4321
+ }
4322
+ async onRegistered(msg) {
4323
+ this.agentId = msg.agentId;
4324
+ this.setState("CONNECTED");
4325
+ console.log("");
4326
+ console.log(" \u2705 Tunnel active");
4327
+ console.log("");
4328
+ if (msg.tunnelUrl) {
4329
+ console.log(` Local: http://localhost:${this.config.port}`);
4330
+ console.log(` Public: ${msg.tunnelUrl}`);
4331
+ console.log("");
4332
+ console.log(" Share the Public URL \u2014 it is stable and never changes.");
4333
+ console.log(" Put it in webhooks, .env files, or share with teammates.");
4334
+ } else {
4335
+ console.log(` Local: http://localhost:${this.config.port}`);
4336
+ console.log(` Label: ${this.config.label}`);
4337
+ }
4338
+ console.log("");
4339
+ this.log.info({
4340
+ agentId: msg.agentId,
4341
+ accountId: msg.accountId,
4342
+ label: this.config.label,
4343
+ port: this.config.port
4344
+ }, "[agent] \u2705 tunnel is live");
4345
+ const counts = this.queue.count();
4346
+ if (counts.ready > 0) {
4347
+ this.log.info({ items: counts.ready }, "[agent] replaying queue");
4348
+ const result = await (0, replayQueue_1.replayQueue)(this.queue, (data) => this.sendRaw(data), this.proxy);
4349
+ this.log.info(result, "[agent] queue replay complete");
4350
+ }
4351
+ }
4352
+ onPing(msg) {
4353
+ if (!this.agentId)
4354
+ return;
4355
+ const pong = {
4356
+ v: protocol_1.PROTOCOL_VERSION,
4357
+ type: "agent:pong",
4358
+ agentId: this.agentId,
4359
+ ts: Date.now()
4360
+ };
4361
+ this.batcher.add(pong);
4362
+ }
4363
+ onHubError(msg) {
4364
+ this.log.error({ code: msg.code, message: msg.message, fatal: msg.fatal }, "[agent] hub error");
4365
+ if (msg.fatal) {
4366
+ if (msg.code === "AUTH_FAILED" || msg.code === "VERSION_UNSUPPORTED") {
4367
+ console.error(`
4368
+ \u274C Fatal error: ${msg.message}
4369
+ Check your API key and agent version, then restart.
4370
+ `);
4371
+ this.stop();
4372
+ }
4373
+ }
4374
+ }
4375
+ async onForward(msg) {
4376
+ this.proxy.invalidateCacheFor(msg.method, msg.path);
4377
+ try {
4378
+ const result = await this.proxy.forward(msg);
4379
+ const response = {
4380
+ v: protocol_1.PROTOCOL_VERSION,
4381
+ type: "tunnel:response",
4382
+ requestId: msg.requestId,
4383
+ ...result
4384
+ };
4385
+ this.batcher.add(response);
4386
+ } catch (err) {
4387
+ const agentError = {
4388
+ v: protocol_1.PROTOCOL_VERSION,
4389
+ type: "tunnel:agent-error",
4390
+ requestId: msg.requestId,
4391
+ code: "BACKEND_UNAVAILABLE",
4392
+ message: `Local backend on port ${this.config.port} is not responding: ${err.message}`
4393
+ };
4394
+ this.batcher.add(agentError);
4395
+ }
4396
+ }
4397
+ onClose(code, reason) {
4398
+ if (this.stopped)
4399
+ return;
4400
+ this.log.warn({ code, reason }, "[agent] WS closed \u2014 scheduling reconnect");
4401
+ this.batcher.flushToQueue();
4402
+ this.setState("RECONNECTING");
4403
+ this.scheduleReconnect();
4404
+ }
4405
+ onError(err) {
4406
+ this.log.warn({ message: err.message }, "[agent] WS error");
4407
+ }
4408
+ scheduleReconnect() {
4409
+ if (this.stopped)
4410
+ return;
4411
+ const delay = this.reconnectDelay;
4412
+ this.reconnectDelay = Math.min(delay * 2, protocol_1.TIMING.RECONNECT_MAX_MS);
4413
+ this.log.info({ delayMs: delay }, "[agent] reconnecting");
4414
+ this.reconnectTimer = setTimeout(() => {
4415
+ this.reconnectTimer = null;
4416
+ this.connect();
4417
+ }, delay);
4418
+ }
4419
+ // ── Helpers ─────────────────────────────────────────────────────────────────
4420
+ sendRaw(data) {
4421
+ if (this.ws?.readyState === ws_1.default.OPEN) {
4422
+ this.ws.send(data);
4423
+ }
4424
+ }
4425
+ setState(state) {
4426
+ if (this.state === state)
4427
+ return;
4428
+ this.state = state;
4429
+ this.config.onStateChange?.(state);
4430
+ }
4431
+ };
4432
+ exports2.AgentClient = AgentClient;
4433
+ }
4434
+ });
4435
+
4436
+ // package.json
4437
+ var require_package = __commonJS({
4438
+ "package.json"(exports2, module2) {
4439
+ module2.exports = {
4440
+ name: "@vhyxvoid/agent",
4441
+ version: "1.0.6",
4442
+ description: "Platform tunnel agent \u2014 connect your local server to the platform",
4443
+ keywords: [
4444
+ "tunnel",
4445
+ "proxy",
4446
+ "websocket",
4447
+ "ngrok-alternative"
4448
+ ],
4449
+ bin: {
4450
+ vhyxvoid: "dist/cli.js"
4451
+ },
4452
+ main: "dist/AgentClient.js",
4453
+ types: "dist/AgentClient.d.ts",
4454
+ files: [
4455
+ "dist/**/*"
4456
+ ],
4457
+ scripts: {
4458
+ build: "tsc -b && esbuild dist/cli.js --bundle --platform=node --external:better-sqlite3 --external:ws --external:axios --outfile=dist/cli.bundled.js && cp dist/cli.bundled.js dist/cli.js && chmod +x dist/cli.js",
4459
+ dev: "tsx src/cli.ts",
4460
+ typecheck: "tsc --noEmit",
4461
+ clean: "rm -rf dist tsconfig.tsbuildinfo",
4462
+ prepublishOnly: "npm run build"
4463
+ },
4464
+ dependencies: {
4465
+ axios: "^1.13.2",
4466
+ "better-sqlite3": "^12.8.0",
4467
+ commander: "^14.0.3",
4468
+ dotenv: "^17.2.3",
4469
+ ws: "^8.18.3"
4470
+ },
4471
+ devDependencies: {
4472
+ "@types/better-sqlite3": "^7.6.13",
4473
+ "@types/commander": "^2.12.5",
4474
+ "@types/node": "^24.10.1",
4475
+ "@types/ws": "^8.18.1",
4476
+ "@vhyxvoid/protocol": "workspace:*",
4477
+ esbuild: "^0.28.0"
4478
+ }
4479
+ };
4480
+ }
4481
+ });
4482
+
4483
+ // ../../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/package.json
4484
+ var require_package2 = __commonJS({
4485
+ "../../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/package.json"(exports2, module2) {
4486
+ module2.exports = {
4487
+ name: "dotenv",
4488
+ version: "17.2.3",
4489
+ description: "Loads environment variables from .env file",
4490
+ main: "lib/main.js",
4491
+ types: "lib/main.d.ts",
4492
+ exports: {
4493
+ ".": {
4494
+ types: "./lib/main.d.ts",
4495
+ require: "./lib/main.js",
4496
+ default: "./lib/main.js"
4497
+ },
4498
+ "./config": "./config.js",
4499
+ "./config.js": "./config.js",
4500
+ "./lib/env-options": "./lib/env-options.js",
4501
+ "./lib/env-options.js": "./lib/env-options.js",
4502
+ "./lib/cli-options": "./lib/cli-options.js",
4503
+ "./lib/cli-options.js": "./lib/cli-options.js",
4504
+ "./package.json": "./package.json"
4505
+ },
4506
+ scripts: {
4507
+ "dts-check": "tsc --project tests/types/tsconfig.json",
4508
+ lint: "standard",
4509
+ pretest: "npm run lint && npm run dts-check",
4510
+ test: "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
4511
+ "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
4512
+ prerelease: "npm test",
4513
+ release: "standard-version"
4514
+ },
4515
+ repository: {
4516
+ type: "git",
4517
+ url: "git://github.com/motdotla/dotenv.git"
4518
+ },
4519
+ homepage: "https://github.com/motdotla/dotenv#readme",
4520
+ funding: "https://dotenvx.com",
4521
+ keywords: [
4522
+ "dotenv",
4523
+ "env",
4524
+ ".env",
4525
+ "environment",
4526
+ "variables",
4527
+ "config",
4528
+ "settings"
4529
+ ],
4530
+ readmeFilename: "README.md",
4531
+ license: "BSD-2-Clause",
4532
+ devDependencies: {
4533
+ "@types/node": "^18.11.3",
4534
+ decache: "^4.6.2",
4535
+ sinon: "^14.0.1",
4536
+ standard: "^17.0.0",
4537
+ "standard-version": "^9.5.0",
4538
+ tap: "^19.2.0",
4539
+ typescript: "^4.8.4"
4540
+ },
4541
+ engines: {
4542
+ node: ">=12"
4543
+ },
4544
+ browser: {
4545
+ fs: false
4546
+ }
4547
+ };
4548
+ }
4549
+ });
4550
+
4551
+ // ../../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/lib/main.js
4552
+ var require_main = __commonJS({
4553
+ "../../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/lib/main.js"(exports2, module2) {
4554
+ var fs = require("fs");
4555
+ var path = require("path");
4556
+ var os = require("os");
4557
+ var crypto = require("crypto");
4558
+ var packageJson = require_package2();
4559
+ var version = packageJson.version;
4560
+ var TIPS = [
4561
+ "\u{1F510} encrypt with Dotenvx: https://dotenvx.com",
4562
+ "\u{1F510} prevent committing .env to code: https://dotenvx.com/precommit",
4563
+ "\u{1F510} prevent building .env in docker: https://dotenvx.com/prebuild",
4564
+ "\u{1F4E1} add observability to secrets: https://dotenvx.com/ops",
4565
+ "\u{1F465} sync secrets across teammates & machines: https://dotenvx.com/ops",
4566
+ "\u{1F5C2}\uFE0F backup and recover secrets: https://dotenvx.com/ops",
4567
+ "\u2705 audit secrets and track compliance: https://dotenvx.com/ops",
4568
+ "\u{1F504} add secrets lifecycle management: https://dotenvx.com/ops",
4569
+ "\u{1F511} add access controls to secrets: https://dotenvx.com/ops",
4570
+ "\u{1F6E0}\uFE0F run anywhere with `dotenvx run -- yourcommand`",
4571
+ "\u2699\uFE0F specify custom .env file path with { path: '/custom/path/.env' }",
4572
+ "\u2699\uFE0F enable debug logging with { debug: true }",
4573
+ "\u2699\uFE0F override existing env vars with { override: true }",
4574
+ "\u2699\uFE0F suppress all logs with { quiet: true }",
4575
+ "\u2699\uFE0F write to custom object with { processEnv: myObject }",
4576
+ "\u2699\uFE0F load multiple .env files with { path: ['.env.local', '.env'] }"
4577
+ ];
4578
+ function _getRandomTip() {
4579
+ return TIPS[Math.floor(Math.random() * TIPS.length)];
4580
+ }
4581
+ function parseBoolean(value) {
4582
+ if (typeof value === "string") {
4583
+ return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
4584
+ }
4585
+ return Boolean(value);
4586
+ }
4587
+ function supportsAnsi() {
4588
+ return process.stdout.isTTY;
4589
+ }
4590
+ function dim(text) {
4591
+ return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
4592
+ }
4593
+ var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
4594
+ function parse(src) {
4595
+ const obj = {};
4596
+ let lines = src.toString();
4597
+ lines = lines.replace(/\r\n?/mg, "\n");
4598
+ let match;
4599
+ while ((match = LINE.exec(lines)) != null) {
4600
+ const key = match[1];
4601
+ let value = match[2] || "";
4602
+ value = value.trim();
4603
+ const maybeQuote = value[0];
4604
+ value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
4605
+ if (maybeQuote === '"') {
4606
+ value = value.replace(/\\n/g, "\n");
4607
+ value = value.replace(/\\r/g, "\r");
4608
+ }
4609
+ obj[key] = value;
4610
+ }
4611
+ return obj;
4612
+ }
4613
+ function _parseVault(options) {
4614
+ options = options || {};
4615
+ const vaultPath = _vaultPath(options);
4616
+ options.path = vaultPath;
4617
+ const result = DotenvModule.configDotenv(options);
4618
+ if (!result.parsed) {
4619
+ const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
4620
+ err.code = "MISSING_DATA";
4621
+ throw err;
4622
+ }
4623
+ const keys = _dotenvKey(options).split(",");
4624
+ const length = keys.length;
4625
+ let decrypted;
4626
+ for (let i = 0; i < length; i++) {
4627
+ try {
4628
+ const key = keys[i].trim();
4629
+ const attrs = _instructions(result, key);
4630
+ decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
4631
+ break;
4632
+ } catch (error) {
4633
+ if (i + 1 >= length) {
4634
+ throw error;
4635
+ }
4636
+ }
4637
+ }
4638
+ return DotenvModule.parse(decrypted);
4639
+ }
4640
+ function _warn(message) {
4641
+ console.error(`[dotenv@${version}][WARN] ${message}`);
4642
+ }
4643
+ function _debug(message) {
4644
+ console.log(`[dotenv@${version}][DEBUG] ${message}`);
4645
+ }
4646
+ function _log(message) {
4647
+ console.log(`[dotenv@${version}] ${message}`);
4648
+ }
4649
+ function _dotenvKey(options) {
4650
+ if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
4651
+ return options.DOTENV_KEY;
4652
+ }
4653
+ if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
4654
+ return process.env.DOTENV_KEY;
4655
+ }
4656
+ return "";
4657
+ }
4658
+ function _instructions(result, dotenvKey) {
4659
+ let uri;
4660
+ try {
4661
+ uri = new URL(dotenvKey);
4662
+ } catch (error) {
4663
+ if (error.code === "ERR_INVALID_URL") {
4664
+ const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
4665
+ err.code = "INVALID_DOTENV_KEY";
4666
+ throw err;
4667
+ }
4668
+ throw error;
4669
+ }
4670
+ const key = uri.password;
4671
+ if (!key) {
4672
+ const err = new Error("INVALID_DOTENV_KEY: Missing key part");
4673
+ err.code = "INVALID_DOTENV_KEY";
4674
+ throw err;
4675
+ }
4676
+ const environment = uri.searchParams.get("environment");
4677
+ if (!environment) {
4678
+ const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
4679
+ err.code = "INVALID_DOTENV_KEY";
4680
+ throw err;
4681
+ }
4682
+ const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
4683
+ const ciphertext = result.parsed[environmentKey];
4684
+ if (!ciphertext) {
4685
+ const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
4686
+ err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
4687
+ throw err;
4688
+ }
4689
+ return { ciphertext, key };
4690
+ }
4691
+ function _vaultPath(options) {
4692
+ let possibleVaultPath = null;
4693
+ if (options && options.path && options.path.length > 0) {
4694
+ if (Array.isArray(options.path)) {
4695
+ for (const filepath of options.path) {
4696
+ if (fs.existsSync(filepath)) {
4697
+ possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
4698
+ }
4699
+ }
4700
+ } else {
4701
+ possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
4702
+ }
4703
+ } else {
4704
+ possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
4705
+ }
4706
+ if (fs.existsSync(possibleVaultPath)) {
4707
+ return possibleVaultPath;
4708
+ }
4709
+ return null;
4710
+ }
4711
+ function _resolveHome(envPath) {
4712
+ return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
4713
+ }
4714
+ function _configVault(options) {
4715
+ const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
4716
+ const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
4717
+ if (debug || !quiet) {
4718
+ _log("Loading env from encrypted .env.vault");
4719
+ }
4720
+ const parsed = DotenvModule._parseVault(options);
4721
+ let processEnv = process.env;
4722
+ if (options && options.processEnv != null) {
4723
+ processEnv = options.processEnv;
4724
+ }
4725
+ DotenvModule.populate(processEnv, parsed, options);
4726
+ return { parsed };
4727
+ }
4728
+ function configDotenv(options) {
4729
+ const dotenvPath = path.resolve(process.cwd(), ".env");
4730
+ let encoding = "utf8";
4731
+ let processEnv = process.env;
4732
+ if (options && options.processEnv != null) {
4733
+ processEnv = options.processEnv;
4734
+ }
4735
+ let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
4736
+ let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
4737
+ if (options && options.encoding) {
4738
+ encoding = options.encoding;
4739
+ } else {
4740
+ if (debug) {
4741
+ _debug("No encoding is specified. UTF-8 is used by default");
4742
+ }
4743
+ }
4744
+ let optionPaths = [dotenvPath];
4745
+ if (options && options.path) {
4746
+ if (!Array.isArray(options.path)) {
4747
+ optionPaths = [_resolveHome(options.path)];
4748
+ } else {
4749
+ optionPaths = [];
4750
+ for (const filepath of options.path) {
4751
+ optionPaths.push(_resolveHome(filepath));
4752
+ }
4753
+ }
4754
+ }
4755
+ let lastError;
4756
+ const parsedAll = {};
4757
+ for (const path2 of optionPaths) {
4758
+ try {
4759
+ const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
4760
+ DotenvModule.populate(parsedAll, parsed, options);
4761
+ } catch (e) {
4762
+ if (debug) {
4763
+ _debug(`Failed to load ${path2} ${e.message}`);
4764
+ }
4765
+ lastError = e;
4766
+ }
4767
+ }
4768
+ const populated = DotenvModule.populate(processEnv, parsedAll, options);
4769
+ debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
4770
+ quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
4771
+ if (debug || !quiet) {
4772
+ const keysCount = Object.keys(populated).length;
4773
+ const shortPaths = [];
4774
+ for (const filePath of optionPaths) {
4775
+ try {
4776
+ const relative = path.relative(process.cwd(), filePath);
4777
+ shortPaths.push(relative);
4778
+ } catch (e) {
4779
+ if (debug) {
4780
+ _debug(`Failed to load ${filePath} ${e.message}`);
4781
+ }
4782
+ lastError = e;
4783
+ }
4784
+ }
4785
+ _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
4786
+ }
4787
+ if (lastError) {
4788
+ return { parsed: parsedAll, error: lastError };
4789
+ } else {
4790
+ return { parsed: parsedAll };
4791
+ }
4792
+ }
4793
+ function config(options) {
4794
+ if (_dotenvKey(options).length === 0) {
4795
+ return DotenvModule.configDotenv(options);
4796
+ }
4797
+ const vaultPath = _vaultPath(options);
4798
+ if (!vaultPath) {
4799
+ _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
4800
+ return DotenvModule.configDotenv(options);
4801
+ }
4802
+ return DotenvModule._configVault(options);
4803
+ }
4804
+ function decrypt(encrypted, keyStr) {
4805
+ const key = Buffer.from(keyStr.slice(-64), "hex");
4806
+ let ciphertext = Buffer.from(encrypted, "base64");
4807
+ const nonce = ciphertext.subarray(0, 12);
4808
+ const authTag = ciphertext.subarray(-16);
4809
+ ciphertext = ciphertext.subarray(12, -16);
4810
+ try {
4811
+ const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
4812
+ aesgcm.setAuthTag(authTag);
4813
+ return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
4814
+ } catch (error) {
4815
+ const isRange = error instanceof RangeError;
4816
+ const invalidKeyLength = error.message === "Invalid key length";
4817
+ const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
4818
+ if (isRange || invalidKeyLength) {
4819
+ const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
4820
+ err.code = "INVALID_DOTENV_KEY";
4821
+ throw err;
4822
+ } else if (decryptionFailed) {
4823
+ const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
4824
+ err.code = "DECRYPTION_FAILED";
4825
+ throw err;
4826
+ } else {
4827
+ throw error;
4828
+ }
4829
+ }
4830
+ }
4831
+ function populate(processEnv, parsed, options = {}) {
4832
+ const debug = Boolean(options && options.debug);
4833
+ const override = Boolean(options && options.override);
4834
+ const populated = {};
4835
+ if (typeof parsed !== "object") {
4836
+ const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
4837
+ err.code = "OBJECT_REQUIRED";
4838
+ throw err;
4839
+ }
4840
+ for (const key of Object.keys(parsed)) {
4841
+ if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
4842
+ if (override === true) {
4843
+ processEnv[key] = parsed[key];
4844
+ populated[key] = parsed[key];
4845
+ }
4846
+ if (debug) {
4847
+ if (override === true) {
4848
+ _debug(`"${key}" is already defined and WAS overwritten`);
4849
+ } else {
4850
+ _debug(`"${key}" is already defined and was NOT overwritten`);
4851
+ }
4852
+ }
4853
+ } else {
4854
+ processEnv[key] = parsed[key];
4855
+ populated[key] = parsed[key];
4856
+ }
4857
+ }
4858
+ return populated;
4859
+ }
4860
+ var DotenvModule = {
4861
+ configDotenv,
4862
+ _configVault,
4863
+ _parseVault,
4864
+ config,
4865
+ decrypt,
4866
+ parse,
4867
+ populate
4868
+ };
4869
+ module2.exports.configDotenv = DotenvModule.configDotenv;
4870
+ module2.exports._configVault = DotenvModule._configVault;
4871
+ module2.exports._parseVault = DotenvModule._parseVault;
4872
+ module2.exports.config = DotenvModule.config;
4873
+ module2.exports.decrypt = DotenvModule.decrypt;
4874
+ module2.exports.parse = DotenvModule.parse;
4875
+ module2.exports.populate = DotenvModule.populate;
4876
+ module2.exports = DotenvModule;
4877
+ }
4878
+ });
4879
+
4880
+ // dist/cli.js
4881
+ Object.defineProperty(exports, "__esModule", { value: true });
4882
+ var commander_1 = require_commander();
4883
+ var AgentClient_1 = require_AgentClient();
4884
+ var package_json_1 = require_package();
4885
+ var dotenv_1 = require_main();
4886
+ (0, dotenv_1.config)();
4887
+ var program = new commander_1.Command();
4888
+ program.name("vhyxvoid").description("Platform tunnel agent.\nConnects your local server to the platform so the frontend SDK can reach it.").version(package_json_1.version).option("-k, --key <keyId>", "API key ID (e.g. vhyxvoid_dev_abc123). Env: VHYXVOID_API_KEY", process.env.VHYXVOID_API_KEY).option("-s, --secret <secret>", "API key secret (shown once at creation). Env: VHYXVOID_SECRET", process.env.VHYXVOID_SECRET).option("-p, --port <port>", "Local backend port to tunnel (e.g. 3000). Env: VHYXVOID_PORT", process.env.VHYXVOID_PORT ?? "3000").option("-l, --label <label>", "Tunnel label \u2014 identifies this agent if you run multiple. Env: VHYXVOID_LABEL", process.env.VHYXVOID_LABEL ?? "default").option("--hub <url>", "Hub WebSocket URL. Env: VHYXVOID_HUB_URL", process.env.VHYXVOID_HUB_URL ?? "wss://hub.vhyxvoid.com/agent").option("--queue-path <path>", "SQLite queue file path. Default: ~/.vhyxvoid/queue.db", process.env.VHYXVOID_QUEUE_PATH).option("--no-local-discovery", "Disable local discovery server on port 4242").parse(process.argv);
4889
+ var opts = program.opts();
4890
+ if (!opts.key) {
4891
+ console.error("\u274C --key is required. Get your API key from the platform dashboard.");
4892
+ console.error(" Usage: vhyxvoid --key vhyxvoid_dev_xxx --secret xxx --port 3000");
4893
+ process.exit(1);
4894
+ }
4895
+ if (!opts.secret) {
4896
+ console.error("\u274C --secret is required. It was shown once when you created the API key.");
4897
+ console.error(" If you lost it, rotate the key from the dashboard to get a new secret.");
4898
+ process.exit(1);
4899
+ }
4900
+ var port = parseInt(opts.port, 10);
4901
+ if (isNaN(port) || port < 1 || port > 65535) {
4902
+ console.error(`\u274C Invalid port: "${opts.port}"`);
4903
+ process.exit(1);
4904
+ }
4905
+ console.log(`
4906
+ vhyxvoid-agent v${package_json_1.version}`);
4907
+ console.log(` Key: ${opts.key}`);
4908
+ console.log(` Label: ${opts.label}`);
4909
+ console.log(` Port: ${port}`);
4910
+ console.log(` Hub: ${opts.hub}`);
4911
+ console.log(` Queue: ${opts.queuePath ?? "~/.vhyxvoid/queue.db"}`);
4912
+ console.log(` Local discovery: ${opts.localDiscovery ? "enabled" : "disabled"}`);
4913
+ console.log("");
4914
+ var agent = new AgentClient_1.AgentClient({
4915
+ hubUrl: opts.hub,
4916
+ keyId: opts.key,
4917
+ secret: opts.secret,
4918
+ label: opts.label,
4919
+ port,
4920
+ agentVersion: package_json_1.version,
4921
+ queuePath: opts.queuePath,
4922
+ localDiscovery: opts.localDiscovery,
4923
+ onStateChange: (state) => {
4924
+ if (state === "CONNECTED") {
4925
+ console.log(`\u2705 Tunnel active \u2014 label "${opts.label}" \u2192 localhost:${port}`);
4926
+ console.log(` SDK requests with label "${opts.label}" will reach your backend.
4927
+ `);
4928
+ }
4929
+ if (state === "RECONNECTING") {
4930
+ console.log("\u26A0 Disconnected from hub \u2014 reconnecting automatically...");
4931
+ }
4932
+ if (state === "STOPPED") {
4933
+ console.log("\u{1F6D1} Agent stopped.");
4934
+ }
4935
+ }
4936
+ });
4937
+ agent.start();
4938
+ process.on("SIGTERM", () => {
4939
+ console.log("\nReceived SIGTERM \u2014 shutting down gracefully...");
4940
+ agent.stop();
4941
+ process.exit(0);
4942
+ });
4943
+ process.on("SIGINT", () => {
4944
+ console.log("\nReceived SIGINT \u2014 shutting down gracefully...");
4945
+ agent.stop();
4946
+ process.exit(0);
4947
+ });
4948
+ process.on("uncaughtException", (err) => {
4949
+ console.error("Uncaught exception:", err);
4950
+ agent.stop();
4951
+ process.exit(1);
4952
+ });