File size: 2,335 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
// JSON-mode metadata for Commander commands; distinguishes JSON output from parse-only flags.
import type { Command } from "commander";
import { hasFlag } from "../argv.js";
import {
  isMachineOutputStdoutTTY,
  type MachineOutputResolverParams,
} from "../machine-output-argv.js";
import { hasCommanderOptionToken } from "./commander-parse-facts.js";

const jsonModeSymbol = Symbol("openclaw.cli.jsonMode");
const JSON_FLAG = new Set(["--json"]);

type CommandJsonMode = "output" | "parse-only";
type CommandJsonModeResolver = (
  params: {
    command: Command;
  } & MachineOutputResolverParams,
) => boolean;

type CommandJsonModeDeclaration = {
  mode: CommandJsonMode;
  resolve?: CommandJsonModeResolver;
};
type JsonModeCommand = Command & {
  [jsonModeSymbol]?: CommandJsonModeDeclaration;
};

function commandDefinesJsonOption(command: Command): boolean {
  return command.options.some((option) => option.long === "--json");
}

function getCommandJsonMode(
  command: Command,
  argv: string[] = process.argv,
): CommandJsonMode | null {
  const rawJsonFlag =
    hasFlag(argv, "--json") && !hasCommanderOptionToken(command, argv, JSON_FLAG, "value");
  const literalJsonMode =
    command.optsWithGlobals<{ json?: unknown }>().json === true || rawJsonFlag;
  for (let current: Command | null = command; current; current = current.parent ?? null) {
    const metadata = (current as JsonModeCommand)[jsonModeSymbol];
    if (metadata?.resolve?.({ command, argv, stdoutIsTTY: isMachineOutputStdoutTTY() })) {
      return metadata.mode;
    }
    if (metadata && !metadata.resolve && literalJsonMode) {
      return metadata.mode;
    }
    if (literalJsonMode && commandDefinesJsonOption(current)) {
      return "output";
    }
  }
  return null;
}

/** Mark a command as having a special JSON mode beyond ordinary `--json` output. */
export function setCommandJsonMode(
  command: Command,
  mode: CommandJsonMode,
  resolve?: CommandJsonModeResolver,
): Command {
  (command as JsonModeCommand)[jsonModeSymbol] = { mode, ...(resolve ? { resolve } : {}) };
  return command;
}

/** Return true when the command's active mode owns machine-readable JSON stdout. */
export function isCommandJsonOutputMode(command: Command, argv: string[] = process.argv): boolean {
  return getCommandJsonMode(command, argv) === "output";
}