File size: 2,803 Bytes
eb3f11e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Commander subclass that preserves the exact failing command for parse-error guidance.
import { Command, CommanderError, type ErrorOptions } from "commander";
import { applyResolvedCommandOutputMode, isJsonOutputModeActive } from "../json-output-mode.js";
import {
  getCommanderErrorCommandNames,
  getCommanderErrorCommandPath,
  getCommanderSubcommandFact,
  hasCommanderOptionToken,
  setCommanderErrorCommand,
} from "./commander-parse-facts.js";
import { createCliParseError } from "./error-output.js";
import { isCommandJsonOutputMode } from "./json-mode.js";

// Commander 15 declares this help hook only in its runtime class, not its types.
// Declaring it here lets the subclass override and delegate through `super`
// instead of re-binding a captured prototype method.
declare module "commander" {
  interface Command {
    _outputHelpIfRequested(args: string[]): void;
  }
}

export class OpenClawCommand extends Command {
  override createCommand(name?: string): Command {
    return new OpenClawCommand(name);
  }

  override error(message: string, errorOptions?: ErrorOptions): never {
    const restoreErrorCommand = setCommanderErrorCommand(this);
    try {
      return super.error(message, errorOptions);
    } catch (error) {
      if (
        error instanceof CommanderError &&
        error.exitCode !== 0 &&
        (isJsonOutputModeActive(process.argv) || isCommandJsonOutputMode(this, process.argv))
      ) {
        if (
          !isCommandJsonOutputMode(this, process.argv) &&
          !hasCommanderOptionToken(this, process.argv, new Set(["--json"]), "flag")
        ) {
          applyResolvedCommandOutputMode(false);
          throw error;
        }
        applyResolvedCommandOutputMode(true);
        throw createCliParseError(
          message,
          {
            argv: process.argv,
            commandPath: getCommanderErrorCommandPath(this),
            commandNames: getCommanderErrorCommandNames(this),
          },
          { humanOutputWritten: true },
        );
      }
      throw error;
    } finally {
      restoreErrorCommand();
    }
  }

  // Commander 15 checks this internal hook before dispatching actions.
  // Defer only marked lazy placeholders so their real command tree can decide.
  override _outputHelpIfRequested(args: string[]): void {
    const subcommandFact = getCommanderSubcommandFact(this, args);
    if (subcommandFact?.kind === "defer") {
      return;
    }
    if (subcommandFact?.kind === "unknown") {
      this.error(`error: unknown command '${subcommandFact.name}'`, {
        code: "commander.unknownCommand",
      });
    }
    // oxlint-disable-next-line eslint/no-underscore-dangle -- Commander 15.0.0 owns this hook name; package.json pins that exact version.
    super._outputHelpIfRequested(args);
  }
}