/ utils / cliArgs.ts
cliArgs.ts
 1  /**
 2   * Parse a CLI flag value early, before Commander.js processes arguments.
 3   * Supports both space-separated (--flag value) and equals-separated (--flag=value) syntax.
 4   *
 5   * This function is intended for flags that must be parsed before init() runs,
 6   * such as --settings which affects configuration loading. For normal flag parsing,
 7   * rely on Commander.js which handles this automatically.
 8   *
 9   * @param flagName The flag name including dashes (e.g., '--settings')
10   * @param argv Optional argv array to parse (defaults to process.argv)
11   * @returns The value if found, undefined otherwise
12   */
13  export function eagerParseCliFlag(
14    flagName: string,
15    argv: string[] = process.argv,
16  ): string | undefined {
17    for (let i = 0; i < argv.length; i++) {
18      const arg = argv[i]
19      // Handle --flag=value syntax
20      if (arg?.startsWith(`${flagName}=`)) {
21        return arg.slice(flagName.length + 1)
22      }
23      // Handle --flag value syntax
24      if (arg === flagName && i + 1 < argv.length) {
25        return argv[i + 1]
26      }
27    }
28    return undefined
29  }
30  
31  /**
32   * Handle the standard Unix `--` separator convention in CLI arguments.
33   *
34   * When using Commander.js with `.passThroughOptions()`, the `--` separator
35   * is passed through as a positional argument rather than being consumed.
36   * This means when a user runs:
37   *   `cmd --opt value name -- subcmd --flag arg`
38   *
39   * Commander parses it as:
40   *   positional1 = "name", positional2 = "--", rest = ["subcmd", "--flag", "arg"]
41   *
42   * This function corrects the parsing by extracting the actual command from
43   * the rest array when the positional is `--`.
44   *
45   * @param commandOrValue - The parsed positional that may be "--"
46   * @param args - The remaining arguments array
47   * @returns Object with corrected command and args
48   */
49  export function extractArgsAfterDoubleDash(
50    commandOrValue: string,
51    args: string[] = [],
52  ): { command: string; args: string[] } {
53    if (commandOrValue === '--' && args.length > 0) {
54      return {
55        command: args[0]!,
56        args: args.slice(1),
57      }
58    }
59    return { command: commandOrValue, args }
60  }