@lovrabet/cli-framework 0.1.1-beta.0

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,152 @@
1
+ /**
2
+ * @fileoverview Flag parsing and validation helpers.
3
+ *
4
+ * Provides the {@link createFlagHelpers} factory which returns `parseFlags`
5
+ * and `validateFlags` — the two-phase pipeline used by the runner adapter.
6
+ *
7
+ * Phase 1 (`parseFlags`): coerce raw CLI inputs into typed values using
8
+ * {@link FlagDef} metadata.
9
+ *
10
+ * Phase 2 (`validateFlags`): enforce `required`, `enum`, and `pattern`
11
+ * constraints and throw typed {@link CliError} on violation.
12
+ */
13
+ /**
14
+ * Creates a paired set of flag helpers used by the framework runner.
15
+ *
16
+ * @param cliErrors - Subset of the error factory providing `flagMissing` and `validation`.
17
+ * @returns An object with `parseFlags` and `validateFlags` functions.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const { parseFlags, validateFlags } = createFlagHelpers(cliErrors);
22
+ * const flags = parseFlags(flagDefs, rawInput);
23
+ * validateFlags(flagDefs, flags, "api list");
24
+ * ```
25
+ */
26
+ export function createFlagHelpers(cliErrors) {
27
+ /**
28
+ * Phase 1 — converts raw flag values (from meow / yargs / raw object) into
29
+ * their declared types using the definitions in `defs`.
30
+ *
31
+ * - Boolean flags: `true` when the raw value is `true` or `"true"`.
32
+ * - Number flags: coerces via `Number()`; throws on `NaN`.
33
+ * - String flags: all other values stringified.
34
+ * - Unset flags with a `default` are populated automatically.
35
+ *
36
+ * @param defs - Ordered list of flag definitions.
37
+ * @param rawFlags - Raw key-value map from the CLI parser.
38
+ * @returns A {@link ParsedFlags} map with all defined flags present.
39
+ */
40
+ function parseFlags(defs, rawFlags) {
41
+ const result = {};
42
+ for (const def of defs) {
43
+ const raw = getRawFlagValue(def, rawFlags);
44
+ if (raw === undefined || raw === null) {
45
+ if (def.default !== undefined) {
46
+ result[def.name] = def.default;
47
+ }
48
+ continue;
49
+ }
50
+ result[def.name] = coerce(def, raw, cliErrors);
51
+ }
52
+ return result;
53
+ }
54
+ /**
55
+ * Phase 2 — validates a set of parsed flags against their definitions.
56
+ * Throws a typed {@link CliError} for the first violation encountered.
57
+ *
58
+ * Checks (in order):
59
+ * 1. **Required** — throws `flagMissing` if a required flag is absent or empty.
60
+ * 2. **Enum** — throws `validation` if the value is not in the allowed list.
61
+ * 3. **Pattern** — throws `validation` if the regex does not match.
62
+ *
63
+ * @param defs - Ordered list of flag definitions.
64
+ * @param parsed - Result of {@link parseFlags}.
65
+ * @param commandLabel - Human-readable command label used in error messages.
66
+ * @throws {@link CliError} on the first validation failure.
67
+ */
68
+ function validateFlags(defs, parsed, commandLabel) {
69
+ for (const def of defs) {
70
+ const val = parsed[def.name];
71
+ if (def.required && (val === undefined || val === "")) {
72
+ throw cliErrors.flagMissing(def.name, `--${def.name} is required for \`${commandLabel}\`.`);
73
+ }
74
+ if (def.enum && def.enum.length > 0 && val !== undefined && val !== "") {
75
+ if (!def.enum.includes(String(val))) {
76
+ throw cliErrors.validation(`Invalid value "${val}" for --${def.name}. Allowed: ${def.enum.join(", ")}`);
77
+ }
78
+ }
79
+ if (def.pattern && val !== undefined && val !== "") {
80
+ if (!def.pattern.regex.test(String(val))) {
81
+ throw cliErrors.validation(`Invalid --${def.name}: expected ${def.pattern.description}, got "${val}".`);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return { parseFlags, validateFlags };
87
+ }
88
+ /**
89
+ * Looks up a raw flag value by trying multiple name variants.
90
+ * Checks, in order: `def.name`, camelCase of `def.name`, `def.alias`,
91
+ * camelCase of `def.alias`.
92
+ *
93
+ * @param def - Flag definition providing name and optional alias.
94
+ * @param rawFlags - Raw key-value map from the CLI parser.
95
+ * @returns The first matching raw value, or `undefined`.
96
+ */
97
+ function getRawFlagValue(def, rawFlags) {
98
+ const candidates = [
99
+ def.name,
100
+ toCamelCase(def.name),
101
+ def.alias,
102
+ def.alias ? toCamelCase(def.alias) : undefined,
103
+ ];
104
+ for (const candidate of candidates) {
105
+ if (!candidate)
106
+ continue;
107
+ const raw = rawFlags[candidate];
108
+ if (raw !== undefined && raw !== null) {
109
+ return raw;
110
+ }
111
+ }
112
+ return undefined;
113
+ }
114
+ /**
115
+ * Coerces a raw flag value to the type declared in `def`.
116
+ *
117
+ * @param def - Flag definition specifying the target type.
118
+ * @param raw - Raw value from the CLI parser.
119
+ * @param cliErrors - Error factory for throwing on invalid number input.
120
+ * @returns The coerced typed value.
121
+ * @throws {@link CliError} with code `"validation_error"` if a number flag
122
+ * receives a non-numeric value.
123
+ */
124
+ function coerce(def, raw, cliErrors) {
125
+ switch (def.type) {
126
+ case "boolean":
127
+ return raw === true || raw === "true";
128
+ case "number": {
129
+ const n = Number(raw);
130
+ if (Number.isNaN(n)) {
131
+ throw cliErrors.validation(`--${def.name} expects a number, got "${raw}"`);
132
+ }
133
+ return n;
134
+ }
135
+ default:
136
+ return String(raw);
137
+ }
138
+ }
139
+ /**
140
+ * Converts a kebab-case string to camelCase.
141
+ *
142
+ * @param s - Input string, e.g. `"dry-run"`.
143
+ * @returns camelCase equivalent, e.g. `"dryRun"`.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * toCamelCase("app-code") // "appCode"
148
+ * ```
149
+ */
150
+ function toCamelCase(s) {
151
+ return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
152
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @fileoverview Help text generation for the CLI.
3
+ *
4
+ * Produces structured plain-text help for:
5
+ * - Single commands (`<service> <command> --help`)
6
+ * - Entire services (`<service> --help`)
7
+ * - Full CLI overview (`--help`)
8
+ *
9
+ * All output follows the same section-based layout (USAGE / FLAGS / ARGS etc.)
10
+ * so callers can compose consistent help strings without reimplementing formatting.
11
+ */
12
+ import type { CommandDefinition, FlagDef } from "./types.js";
13
+ /**
14
+ * A global (top-level) flag definition used in the main `--help` output.
15
+ */
16
+ export interface GlobalHelpFlag {
17
+ /** Flag name (without leading `--`). */
18
+ name: string;
19
+ /** Value type. */
20
+ type: "string" | "boolean";
21
+ /** Description shown in the GLOBAL OPTIONS block. */
22
+ description: string;
23
+ /**
24
+ * Short hint appended to the flag name in the usage line
25
+ * (e.g. `<env>` for `--env daily`).
26
+ */
27
+ hint?: string;
28
+ /**
29
+ * When `true`, the flag is omitted from the help text.
30
+ */
31
+ hidden?: boolean;
32
+ }
33
+ /**
34
+ * A command summary entry in a service's command list.
35
+ */
36
+ export interface HelpCommandListing {
37
+ /** Subcommand name (e.g. `"list"`). */
38
+ command: string;
39
+ /** One-line description. */
40
+ description: string;
41
+ /**
42
+ * Optional tag appended to the command name in listings
43
+ * (e.g. `" beta"`).
44
+ */
45
+ tag?: string;
46
+ }
47
+ /**
48
+ * A service entry used to render service-level and full CLI help.
49
+ */
50
+ export interface HelpServiceEntry {
51
+ /** Service name as used in the CLI (e.g. `"api"`). */
52
+ service: string;
53
+ /** Display label shown in help headings (e.g. `"API"`). */
54
+ label: string;
55
+ /** Flat list of subcommand listings. */
56
+ commands: HelpCommandListing[];
57
+ /**
58
+ * For single-command services, the name of the default subcommand
59
+ * (which is omitted from the invocation path).
60
+ */
61
+ defaultCommand?: string;
62
+ /**
63
+ * `true` when `service === command` for this service — the whole
64
+ * service acts as a single command with no subcommands.
65
+ */
66
+ isSingleCommand?: boolean;
67
+ /**
68
+ * Present when the service supports a wildcard command pattern
69
+ * (e.g. `<script>` for `codegen <script>`).
70
+ */
71
+ wildcardDef?: CommandDefinition;
72
+ }
73
+ /**
74
+ * Dependencies required by {@link createHelpGenerators}.
75
+ */
76
+ export interface HelpGeneratorOptions {
77
+ /** CLI binary name (e.g. `"rabetbase"`). Used in usage strings. */
78
+ cliBinName: string;
79
+ /** Display name shown in the full help header (e.g. `"Rabetbase CLI"`). */
80
+ cliDisplayName: string;
81
+ /** Global flags to list under GLOBAL OPTIONS. */
82
+ globalFlags: GlobalHelpFlag[];
83
+ /** All registered service entries. */
84
+ serviceRegistry: HelpServiceEntry[];
85
+ /**
86
+ * Resolves a {@link HelpServiceEntry} by service name, or `undefined`
87
+ * if the service does not exist.
88
+ */
89
+ getServiceEntry(service: string): HelpServiceEntry | undefined;
90
+ /**
91
+ * Resolves the ordered array of {@link CommandDefinition} objects for
92
+ * a given service, or `undefined` if the service has no definitions.
93
+ */
94
+ getServiceDefinitions(service: string): CommandDefinition[] | undefined;
95
+ /**
96
+ * Function that builds the complete effective flag list for a command.
97
+ * Passed in so the help generator can display the correct flag set
98
+ * without re-implementing the built-in flag injection logic.
99
+ */
100
+ buildAllFlags(def: CommandDefinition): FlagDef[];
101
+ /**
102
+ * Text shown as a prerequisite hint for commands that require an app-code.
103
+ * Used in the PREREQUISITES section.
104
+ */
105
+ appPrerequisiteText: string;
106
+ /**
107
+ * Suffix appended to the service usage line (e.g. `" [--env <env>]"`).
108
+ */
109
+ serviceUsageSuffix?: string;
110
+ /**
111
+ * When `true`, the `helpExtra` content of wildcard definitions is
112
+ * included in the full help output.
113
+ * @default false
114
+ */
115
+ includeWildcardExtraInFullHelp?: boolean;
116
+ }
117
+ /**
118
+ * Creates a set of help generators for commands, services, and the full CLI.
119
+ *
120
+ * @param options - Resolver functions and metadata needed to render help.
121
+ * @returns An object with `generateCommandHelp`, `generateServiceHelp`,
122
+ * and `generateFullHelp`.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * const { generateCommandHelp } = createHelpGenerators({
127
+ * // ... options
128
+ * });
129
+ * console.log(generateCommandHelp(someCommandDef));
130
+ * ```
131
+ */
132
+ export declare function createHelpGenerators(options: HelpGeneratorOptions): {
133
+ generateCommandHelp: (def: CommandDefinition) => string;
134
+ generateServiceHelp: (service: string) => string;
135
+ generateFullHelp: () => string;
136
+ };
@@ -0,0 +1,244 @@
1
+ /**
2
+ * @fileoverview Help text generation for the CLI.
3
+ *
4
+ * Produces structured plain-text help for:
5
+ * - Single commands (`<service> <command> --help`)
6
+ * - Entire services (`<service> --help`)
7
+ * - Full CLI overview (`--help`)
8
+ *
9
+ * All output follows the same section-based layout (USAGE / FLAGS / ARGS etc.)
10
+ * so callers can compose consistent help strings without reimplementing formatting.
11
+ */
12
+ /**
13
+ * Creates a set of help generators for commands, services, and the full CLI.
14
+ *
15
+ * @param options - Resolver functions and metadata needed to render help.
16
+ * @returns An object with `generateCommandHelp`, `generateServiceHelp`,
17
+ * and `generateFullHelp`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const { generateCommandHelp } = createHelpGenerators({
22
+ * // ... options
23
+ * });
24
+ * console.log(generateCommandHelp(someCommandDef));
25
+ * ```
26
+ */
27
+ export function createHelpGenerators(options) {
28
+ /**
29
+ * Generates the full help text for a single command.
30
+ * Includes: description, usage, risk level, arguments, flags, and prerequisites.
31
+ *
32
+ * @param def - Command definition.
33
+ * @returns A formatted plain-text help string.
34
+ */
35
+ function generateCommandHelp(def) {
36
+ const lines = [];
37
+ const entry = options.getServiceEntry(def.service);
38
+ const cmd = entry?.isSingleCommand && entry.defaultCommand === def.command
39
+ ? `${options.cliBinName} ${def.service}`
40
+ : def.service === def.command
41
+ ? `${options.cliBinName} ${def.service}`
42
+ : `${options.cliBinName} ${def.service} ${def.command}`;
43
+ const argsSig = def.args
44
+ ? def.args.map((a) => (a.required !== false ? `<${a.name}>` : `[${a.name}]`)).join(" ")
45
+ : "";
46
+ const usageSig = argsSig ? `${cmd} ${argsSig} [flags]` : `${cmd} [flags]`;
47
+ lines.push("");
48
+ lines.push(` ${def.description}`);
49
+ lines.push("");
50
+ lines.push(" USAGE");
51
+ lines.push(` ${usageSig}`);
52
+ lines.push("");
53
+ lines.push(` RISK: ${def.risk}`);
54
+ if (def.risk === "high-risk-write") {
55
+ lines.push(" Requires --yes to confirm, or interactive prompt.");
56
+ }
57
+ lines.push("");
58
+ if (def.args && def.args.length > 0) {
59
+ lines.push(" ARGS");
60
+ const maxArgName = Math.max(...def.args.map((a) => a.name.length + 2));
61
+ for (const a of def.args) {
62
+ const label = `<${a.name}>`.padEnd(maxArgName + 2);
63
+ const req = a.required !== false ? " (required)" : "";
64
+ lines.push(` ${label}${a.description}${req}`);
65
+ }
66
+ lines.push("");
67
+ }
68
+ if (def.flags.length > 0 || def.dryRun || def.hasFormat !== false) {
69
+ const visibleFlags = options.buildAllFlags(def).filter((f) => !f.hidden);
70
+ if (visibleFlags.length > 0) {
71
+ lines.push(" FLAGS");
72
+ const maxName = Math.max(...visibleFlags.map((f) => formatFlagName(f).length));
73
+ for (const fl of visibleFlags) {
74
+ lines.push(` ${formatFlagName(fl).padEnd(maxName + 2)}${renderFlagDesc(fl)}`);
75
+ }
76
+ lines.push("");
77
+ }
78
+ }
79
+ const hints = [];
80
+ if (def.requiresAuth !== false) {
81
+ hints.push(`Requires authentication (run \`${options.cliBinName} auth\` first).`);
82
+ }
83
+ if (def.requiresAppCode !== false) {
84
+ hints.push(options.appPrerequisiteText);
85
+ }
86
+ if (hints.length > 0) {
87
+ lines.push(" PREREQUISITES");
88
+ for (const h of hints) {
89
+ lines.push(` • ${h}`);
90
+ }
91
+ lines.push("");
92
+ }
93
+ if (def.helpExtra) {
94
+ const extra = typeof def.helpExtra === "function" ? def.helpExtra() : def.helpExtra;
95
+ lines.push(extra);
96
+ lines.push("");
97
+ }
98
+ return lines.join("\n");
99
+ }
100
+ /**
101
+ * Generates help text for an entire service, listing all its subcommands.
102
+ *
103
+ * @param service - Service name.
104
+ * @returns A formatted plain-text help string, or an error line if unknown.
105
+ */
106
+ function generateServiceHelp(service) {
107
+ const entry = options.getServiceEntry(service);
108
+ if (!entry)
109
+ return ` Unknown service: ${service}\n`;
110
+ const defs = options.getServiceDefinitions(service);
111
+ if (entry.isSingleCommand && defs?.length === 1) {
112
+ return generateCommandHelp(defs[0]);
113
+ }
114
+ const lines = [];
115
+ lines.push("");
116
+ lines.push(` ${entry.label}`);
117
+ lines.push("");
118
+ lines.push(" USAGE");
119
+ lines.push(` ${options.cliBinName} ${service} <command>${options.serviceUsageSuffix ?? " [flags]"}`);
120
+ lines.push("");
121
+ lines.push(" COMMANDS");
122
+ for (const c of entry.commands) {
123
+ lines.push("");
124
+ const riskTag = c.tag ? ` ${c.tag.trim()}` : "";
125
+ lines.push(` ${c.command}${riskTag}`);
126
+ lines.push(` ${c.description}`);
127
+ const def = defs?.find((d) => d.command === c.command);
128
+ if (def?.args && def.args.length > 0) {
129
+ lines.push(" ARGS");
130
+ const maxArgName = Math.max(...def.args.map((a) => a.name.length + 2));
131
+ for (const a of def.args) {
132
+ const label = `<${a.name}>`.padEnd(maxArgName + 2);
133
+ const req = a.required !== false ? " (required)" : "";
134
+ lines.push(` ${label}${a.description}${req}`);
135
+ }
136
+ }
137
+ const flags = def ? options.buildAllFlags(def).filter((f) => !f.hidden) : [];
138
+ if (flags.length > 0) {
139
+ const maxName = Math.max(...flags.map((f) => formatFlagName(f).length));
140
+ for (const fl of flags) {
141
+ lines.push(` ${formatFlagName(fl).padEnd(maxName + 2)}${renderFlagDesc(fl)}`);
142
+ }
143
+ }
144
+ }
145
+ lines.push("");
146
+ return lines.join("\n");
147
+ }
148
+ /**
149
+ * Generates the top-level `--help` output showing global options and
150
+ * all services with their command summaries.
151
+ *
152
+ * @returns A formatted plain-text help string.
153
+ */
154
+ function generateFullHelp() {
155
+ const lines = [];
156
+ lines.push("");
157
+ lines.push(` ${options.cliDisplayName}`);
158
+ lines.push("");
159
+ lines.push(" USAGE");
160
+ lines.push(` $ ${options.cliBinName} [global-options] <service> <command> [flags]`);
161
+ lines.push("");
162
+ lines.push(" GLOBAL OPTIONS");
163
+ const visibleFlags = options.globalFlags.filter((f) => !f.hidden);
164
+ const maxFlagLen = Math.max(...visibleFlags.map((f) => {
165
+ const hint = f.hint ? ` ${f.hint}` : "";
166
+ return `--${f.name}${hint}`.length;
167
+ }));
168
+ for (const f of visibleFlags) {
169
+ const hint = f.hint ? ` ${f.hint}` : "";
170
+ const label = `--${f.name}${hint}`.padEnd(maxFlagLen + 2);
171
+ lines.push(` ${label}${f.description}`);
172
+ }
173
+ lines.push("");
174
+ lines.push(" COMMANDS");
175
+ lines.push("");
176
+ for (const entry of options.serviceRegistry) {
177
+ lines.push(` ${entry.label}`);
178
+ if (entry.isSingleCommand) {
179
+ const cmd = entry.commands[0];
180
+ lines.push(` ${entry.service.padEnd(18)}${cmd.description}${cmd.tag ?? ""}`);
181
+ }
182
+ else {
183
+ const fullNames = entry.commands.map((c) => `${entry.service} ${c.command}`);
184
+ const maxName = Math.max(...fullNames.map((n) => n.length));
185
+ for (let i = 0; i < entry.commands.length; i++) {
186
+ const cmd = entry.commands[i];
187
+ lines.push(` ${fullNames[i].padEnd(maxName + 2)}${cmd.description}${cmd.tag ?? ""}`);
188
+ }
189
+ }
190
+ if (options.includeWildcardExtraInFullHelp && entry.wildcardDef?.helpExtra) {
191
+ const extra = typeof entry.wildcardDef.helpExtra === "function"
192
+ ? entry.wildcardDef.helpExtra()
193
+ : entry.wildcardDef.helpExtra;
194
+ for (const line of extra.split("\n")) {
195
+ lines.push(` ${line}`);
196
+ }
197
+ }
198
+ lines.push("");
199
+ }
200
+ lines.push(` Run \`${options.cliBinName} <service> --help\` for service commands.`);
201
+ lines.push(` Run \`${options.cliBinName} <service> <command> --help\` for command flags.`);
202
+ lines.push("");
203
+ return lines.join("\n");
204
+ }
205
+ return { generateCommandHelp, generateServiceHelp, generateFullHelp };
206
+ }
207
+ /**
208
+ * Formats a flag definition into its CLI representation.
209
+ *
210
+ * Examples:
211
+ * - `--dry-run`
212
+ * - `-f, --format <value>`
213
+ * - `-e, --env <env>`
214
+ *
215
+ * @param fl - Flag definition.
216
+ * @returns Formatted flag string with type hint and optional alias.
217
+ */
218
+ function formatFlagName(fl) {
219
+ const typeSuffix = fl.type === "boolean" ? "" : fl.type === "number" ? " <n>" : " <value>";
220
+ const name = `--${fl.name}${typeSuffix}`;
221
+ if (!fl.alias)
222
+ return name;
223
+ return `-${fl.alias}, ${name}`;
224
+ }
225
+ /**
226
+ * Builds the description line for a flag, appending enum values, the
227
+ * default, and the `(required)` tag as applicable.
228
+ *
229
+ * @param fl - Flag definition.
230
+ * @returns Full description string with metadata annotations.
231
+ */
232
+ function renderFlagDesc(fl) {
233
+ let desc = fl.description;
234
+ if (fl.enum && fl.enum.length > 0) {
235
+ desc += ` (${fl.enum.join(" | ")})`;
236
+ }
237
+ if (fl.default !== undefined && fl.default !== "" && fl.default !== false) {
238
+ desc += ` [default: ${fl.default}]`;
239
+ }
240
+ if (fl.required && !desc.includes("(required)")) {
241
+ desc += " (required)";
242
+ }
243
+ return desc;
244
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @fileoverview Output formatting pipeline.
3
+ *
4
+ * Renders a {@link CommandResult} to stdout in one of three modes:
5
+ * - `json` — Full indented JSON envelope.
6
+ * - `compress` — Single-line JSON envelope (default).
7
+ * - `pretty` — Human-readable plain-text layout.
8
+ *
9
+ * Supports `--jq` post-filtering in `json` / `compress` modes via the
10
+ * bundled `node-jq` executable (or a `jq` binary on PATH).
11
+ */
12
+ import type { CommandResult, OutputFormat, Risk } from "./types.js";
13
+ /** Shared options passed through every internal print function. */
14
+ interface OutputOptions {
15
+ /** Full command label (e.g. `"api list"`). */
16
+ command: string;
17
+ /** Risk level for the envelope. */
18
+ risk: Risk;
19
+ /** Resolved output format. */
20
+ format: OutputFormat;
21
+ /** `true` when this is a dry-run result. */
22
+ dryRun?: boolean;
23
+ /** Optional jq expression for post-filtering (json/compress modes only). */
24
+ jqFilter?: string;
25
+ }
26
+ /**
27
+ * Central formatting entry point used by the runner adapter.
28
+ *
29
+ * Dispatches to the appropriate internal printer based on `options.format`:
30
+ * - `"json"` → {@link printJson}
31
+ * - `"compress"` → {@link printCompress}
32
+ * - `"pretty"` → {@link printPretty}
33
+ *
34
+ * All output is written to stdout. Errors are written to stderr.
35
+ *
36
+ * @param result - The command result to render.
37
+ * @param options - Formatting options including format, command label, risk, and jq filter.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * formatOutput({ ok: true, data: { id: 1 } }, { command: "app list", risk: "read", format: "compress" });
42
+ * ```
43
+ */
44
+ export declare function formatOutput<T>(result: CommandResult<T>, options: OutputOptions): void;
45
+ export {};