burgee 0.7.1 → 0.9.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.
- package/README.md +1 -0
- package/dist/check.d.ts +22 -0
- package/dist/check.js +35 -0
- package/dist/cli.d.ts +31 -3
- package/dist/cli.js +36 -7
- package/dist/commander/argument.js +0 -3
- package/dist/commander/command.d.ts +7 -3
- package/dist/commander/command.js +54 -187
- package/dist/commander/error.js +0 -2
- package/dist/commander/help.js +0 -17
- package/dist/commander/option.js +0 -14
- package/dist/compat.d.ts +30 -0
- package/dist/compat.js +4 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +2 -0
- package/dist/definition.d.ts +24 -6
- package/dist/definition.js +18 -14
- package/dist/execute.d.ts +1 -0
- package/dist/execute.js +45 -27
- package/dist/exit-code.d.ts +17 -1
- package/dist/exit-code.js +1 -0
- package/dist/help-entry.d.ts +2 -0
- package/dist/help-entry.js +1 -0
- package/dist/help.d.ts +12 -0
- package/dist/help.js +6 -0
- package/dist/index.d.ts +32 -7
- package/dist/index.js +1 -7
- package/dist/mcp-entry.d.ts +2 -0
- package/dist/mcp-entry.js +1 -0
- package/dist/mcp.d.ts +33 -13
- package/dist/mcp.js +4 -3
- package/dist/meow/parse.d.ts +21 -0
- package/dist/meow/parse.js +43 -0
- package/dist/meow/present.d.ts +35 -0
- package/dist/meow/present.js +58 -0
- package/dist/meow/types.d.ts +47 -0
- package/dist/meow/types.js +3 -0
- package/dist/meow/validate.d.ts +35 -0
- package/dist/meow/validate.js +144 -0
- package/dist/meow.d.ts +6 -0
- package/dist/meow.js +146 -0
- package/dist/migrate.d.ts +142 -0
- package/dist/migrate.js +284 -0
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.js +1 -1
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +3 -0
- package/dist/schema-entry.d.ts +3 -0
- package/dist/schema-entry.js +2 -0
- package/dist/schema.json +1 -1
- package/dist/testing-helpers.js +3 -1
- package/dist/validate.d.ts +15 -0
- package/dist/validate.js +10 -0
- package/dist/yargs/burgee.js +0 -14
- package/dist/yargs/cliui.js +0 -53
- package/dist/yargs/command.js +0 -7
- package/dist/yargs/completion.js +0 -5
- package/dist/yargs/factory.js +7 -57
- package/dist/yargs/middleware.js +0 -5
- package/dist/yargs/shim.js +0 -20
- package/dist/yargs/usage.js +0 -8
- package/dist/yargs/utils.js +0 -11
- package/dist/yargs/validation.js +0 -6
- package/dist/yargs/y18n.js +0 -6
- package/package.json +32 -7
|
@@ -2,25 +2,9 @@ import { EventEmitter } from 'node:events';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { stripVTControlCharacters } from 'node:util';
|
|
5
|
-
/**
|
|
6
|
-
* commander's `Command`, ported method for method from commander 15 and graded by
|
|
7
|
-
* commander's own suite through `compat-oracle`. The parse pipeline, the option
|
|
8
|
-
* grammar, every error string and exit code are commander's — that is what makes a
|
|
9
|
-
* user's existing program run unchanged (J2).
|
|
10
|
-
*
|
|
11
|
-
* burgee's additions sit beside it and never alter the default behaviour:
|
|
12
|
-
* - `manifest` projects the command tree, so plugins (`use`) and the generated
|
|
13
|
-
* surfaces read commander-syntax programs exactly like native ones (J7, J8);
|
|
14
|
-
* - `--json`, when the program has not declared that option itself, wraps the
|
|
15
|
-
* action's return value in the envelope (N-family);
|
|
16
|
-
* - `parse(argv, { stdout, stderr, exit })` injects the streams and the exit, and
|
|
17
|
-
* then reports through the E1 taxonomy — the harness's seam (T1).
|
|
18
|
-
*/
|
|
19
|
-
// eslint-disable-next-line import-next/no-namespace -- `spawn` is read off the namespace at the call site and never captured into a local. commander's own suite mocks `childProcess.spawn` in roughly 23 `executableSubcommand` cases, and a binding captured at import never re-syncs; bellpull's `cross-spawn.ts` reads `spawn` off its default import for this exact consumer, so a named import here would undo that and take the row from 1360 / 1360 to ungradeable.
|
|
20
5
|
import * as crossSpawn from 'bellpull/cross-spawn';
|
|
21
6
|
import { ExitCode } from '../exit-code.js';
|
|
22
7
|
import { Manifest } from '../manifest.js';
|
|
23
|
-
import { serveMcp } from '../mcp.js';
|
|
24
8
|
import { host } from '../runtime.js';
|
|
25
9
|
import { machineJson, schemaOf } from '../schema.js';
|
|
26
10
|
import { suggestSimilar } from '../suggest.js';
|
|
@@ -28,7 +12,6 @@ import { Argument, humanReadableArgName } from './argument.js';
|
|
|
28
12
|
import { CommanderError } from './error.js';
|
|
29
13
|
import { Help } from './help.js';
|
|
30
14
|
import { DualOptions, Option } from './option.js';
|
|
31
|
-
/** Names that would reach Object.prototype if used as an option key. */
|
|
32
15
|
const POLLUTING = new Set(['__proto__', 'constructor', 'prototype']);
|
|
33
16
|
const ENV_SOURCES = ['default', 'config', 'env'];
|
|
34
17
|
const IMPLIED_SOURCES = ['default', 'implied'];
|
|
@@ -36,12 +19,10 @@ const HOOK_EVENTS = ['preSubcommand', 'preAction', 'postAction'];
|
|
|
36
19
|
const HELP_POSITIONS = ['beforeAll', 'before', 'after', 'afterAll'];
|
|
37
20
|
const SOURCE_EXT = ['.js', '.ts', '.tsx', '.mjs', '.cjs'];
|
|
38
21
|
const FORWARDED_SIGNALS = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
39
|
-
/** Wraps in single quotes. Used where a message says "from" right before a quoted method name, which a static import scanner would otherwise read as a specifier. */
|
|
40
22
|
const quoted = (s) => `'${s}'`;
|
|
41
23
|
function isThenable(value) {
|
|
42
24
|
return typeof value?.then === 'function';
|
|
43
25
|
}
|
|
44
|
-
/** commander's exit codes, read through burgee's taxonomy when the exit is injected (E1). */
|
|
45
26
|
function e1(err) {
|
|
46
27
|
switch (err.code) {
|
|
47
28
|
case 'commander.helpDisplayed':
|
|
@@ -56,7 +37,6 @@ function e1(err) {
|
|
|
56
37
|
return err.exitCode === 1 ? ExitCode.USAGE : err.exitCode;
|
|
57
38
|
}
|
|
58
39
|
}
|
|
59
|
-
/** What a run prints for an action's return value when the streams are injected. */
|
|
60
40
|
function render(value) {
|
|
61
41
|
if (value === undefined || value === null)
|
|
62
42
|
return '';
|
|
@@ -74,12 +54,9 @@ export class Command extends EventEmitter {
|
|
|
74
54
|
options = [];
|
|
75
55
|
parent = null;
|
|
76
56
|
registeredArguments = [];
|
|
77
|
-
/** @deprecated old name for registeredArguments */
|
|
78
57
|
_args;
|
|
79
|
-
/** cli args with options removed */
|
|
80
58
|
args = [];
|
|
81
59
|
rawArgs = [];
|
|
82
|
-
/** like .args but after custom processing and collecting variadic */
|
|
83
60
|
processedArgs = [];
|
|
84
61
|
runningCommand = undefined;
|
|
85
62
|
_allowUnknownOption = false;
|
|
@@ -108,7 +85,6 @@ export class Command extends EventEmitter {
|
|
|
108
85
|
_savedState = null;
|
|
109
86
|
_outputConfiguration;
|
|
110
87
|
_hidden = false;
|
|
111
|
-
/** Lazy created on demand; null once disabled. */
|
|
112
88
|
_helpOption = undefined;
|
|
113
89
|
_addImplicitHelpCommand = undefined;
|
|
114
90
|
_helpCommand = undefined;
|
|
@@ -119,14 +95,10 @@ export class Command extends EventEmitter {
|
|
|
119
95
|
_version = undefined;
|
|
120
96
|
_versionOptionName = undefined;
|
|
121
97
|
_usage = undefined;
|
|
122
|
-
/** burgee: the root's projection, created on first use. */
|
|
123
98
|
_manifest = undefined;
|
|
124
|
-
/** burgee: what this command does to the world (N6); declaring it exposes the command as an MCP tool. */
|
|
125
99
|
_effects = undefined;
|
|
126
|
-
/** burgee: `true`, or the replacement's name (M5). Shown in help, schema and a one-line warning on use. */
|
|
127
100
|
_deprecated = undefined;
|
|
128
101
|
_deprecationWarned = false;
|
|
129
|
-
/** burgee: set for the duration of a parse that injected the streams or the exit. */
|
|
130
102
|
_burgee = undefined;
|
|
131
103
|
constructor(name) {
|
|
132
104
|
super();
|
|
@@ -143,7 +115,6 @@ export class Command extends EventEmitter {
|
|
|
143
115
|
stripColor: (str) => stripVTControlCharacters(str),
|
|
144
116
|
};
|
|
145
117
|
}
|
|
146
|
-
/** Copy settings useful to share between the root and its subcommands. */
|
|
147
118
|
copyInheritedSettings(sourceCommand) {
|
|
148
119
|
this._outputConfiguration = sourceCommand._outputConfiguration;
|
|
149
120
|
this._helpOption = sourceCommand._helpOption;
|
|
@@ -191,7 +162,6 @@ export class Command extends EventEmitter {
|
|
|
191
162
|
return this;
|
|
192
163
|
return cmd;
|
|
193
164
|
}
|
|
194
|
-
/** Factory for an unattached command; override to customise subcommands. */
|
|
195
165
|
createCommand(name) {
|
|
196
166
|
return new Command(name);
|
|
197
167
|
}
|
|
@@ -263,7 +233,6 @@ export class Command extends EventEmitter {
|
|
|
263
233
|
this.registeredArguments.push(argument);
|
|
264
234
|
return this;
|
|
265
235
|
}
|
|
266
|
-
/** Customise or disable the default help command (added by default when there are subcommands). */
|
|
267
236
|
helpCommand(enableOrNameAndArgs, description) {
|
|
268
237
|
if (typeof enableOrNameAndArgs === 'boolean') {
|
|
269
238
|
this._addImplicitHelpCommand = enableOrNameAndArgs;
|
|
@@ -320,25 +289,21 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
320
289
|
this._lifeCycleHooks[event] = [listener];
|
|
321
290
|
return this;
|
|
322
291
|
}
|
|
323
|
-
/** Replace the call to process.exit; defaults to throwing the CommanderError. */
|
|
324
292
|
exitOverride(fn) {
|
|
325
293
|
this._exitCallback =
|
|
326
294
|
fn ??
|
|
327
295
|
((err) => {
|
|
328
296
|
if (err.code !== 'commander.executeSubCommandAsync')
|
|
329
297
|
throw err;
|
|
330
|
-
// Async callback from spawn events, not useful to throw.
|
|
331
298
|
});
|
|
332
299
|
return this;
|
|
333
300
|
}
|
|
334
301
|
_exit(exitCode, code, message) {
|
|
335
302
|
if (this._exitCallback) {
|
|
336
303
|
this._exitCallback(new CommanderError(exitCode, code, message));
|
|
337
|
-
// Expecting this line is not reached.
|
|
338
304
|
}
|
|
339
305
|
return host.exit(exitCode);
|
|
340
306
|
}
|
|
341
|
-
// commander's contract: the positional args, then the options, then the command itself.
|
|
342
307
|
action(fn) {
|
|
343
308
|
const listener = (args) => {
|
|
344
309
|
const expectedArgsCount = this.registeredArguments.length;
|
|
@@ -353,7 +318,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
353
318
|
createOption(flags, description) {
|
|
354
319
|
return new Option(flags, description);
|
|
355
320
|
}
|
|
356
|
-
/** Wrap parseArg to turn `commander.invalidArgument` into an error with context. */
|
|
357
321
|
_callParseArg(target, value, previous, invalidArgumentMessage) {
|
|
358
322
|
try {
|
|
359
323
|
return target.parseArg?.(value, previous);
|
|
@@ -401,7 +365,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
401
365
|
if (option.defaultValue !== undefined) {
|
|
402
366
|
this.setOptionValueWithSource(name, option.defaultValue, 'default');
|
|
403
367
|
}
|
|
404
|
-
// val is null for an optional option used without its argument, undefined for boolean and negated.
|
|
405
368
|
const handleOptionValue = (val, invalidValueMessage, valueSource) => {
|
|
406
369
|
let value = val;
|
|
407
370
|
if (value == null && option.presetArg !== undefined)
|
|
@@ -419,7 +382,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
419
382
|
else if (option.isBoolean() || option.optional)
|
|
420
383
|
value = true;
|
|
421
384
|
else
|
|
422
|
-
value = '';
|
|
385
|
+
value = '';
|
|
423
386
|
}
|
|
424
387
|
this.setOptionValueWithSource(name, value, valueSource);
|
|
425
388
|
};
|
|
@@ -443,7 +406,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
443
406
|
option.default(defaultValue).argParser(fn);
|
|
444
407
|
}
|
|
445
408
|
else if (fn instanceof RegExp) {
|
|
446
|
-
// deprecated
|
|
447
409
|
const regex = fn;
|
|
448
410
|
option.default(defaultValue).argParser((val, def) => {
|
|
449
411
|
const m = regex.exec(val);
|
|
@@ -461,7 +423,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
461
423
|
requiredOption(flags, description, parseArg, defaultValue) {
|
|
462
424
|
return this._optionEx({ mandatory: true }, flags, description, parseArg, defaultValue);
|
|
463
425
|
}
|
|
464
|
-
/** `-f80` as `--flag=80` (default) versus `-fb` as `-f -b`. */
|
|
465
426
|
combineFlagAndOptionalValue(combine = true) {
|
|
466
427
|
this._combineFlagAndOptionalValue = !!combine;
|
|
467
428
|
return this;
|
|
@@ -474,12 +435,10 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
474
435
|
this._allowExcessArguments = !!allowExcess;
|
|
475
436
|
return this;
|
|
476
437
|
}
|
|
477
|
-
/** Global options before subcommands only, so subcommands may reuse option names. */
|
|
478
438
|
enablePositionalOptions(positional = true) {
|
|
479
439
|
this._enablePositionalOptions = !!positional;
|
|
480
440
|
return this;
|
|
481
441
|
}
|
|
482
|
-
/** Options after the first command-argument are passed through, not parsed. */
|
|
483
442
|
passThroughOptions(passThrough = true) {
|
|
484
443
|
this._passThroughOptions = !!passThrough;
|
|
485
444
|
this._checkForBrokenPassThrough();
|
|
@@ -506,7 +465,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
506
465
|
setOptionValue(key, value) {
|
|
507
466
|
return this.setOptionValueWithSource(key, value, undefined);
|
|
508
467
|
}
|
|
509
|
-
/** `source` is default | config | env | cli | implied. */
|
|
510
468
|
setOptionValueWithSource(key, value, source) {
|
|
511
469
|
if (this._storeOptionsAsProperties)
|
|
512
470
|
this[key] = value;
|
|
@@ -518,7 +476,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
518
476
|
getOptionValueSource(key) {
|
|
519
477
|
return this._optionValueSources[key];
|
|
520
478
|
}
|
|
521
|
-
/** Globals overwrite locals, like optsWithGlobals. */
|
|
522
479
|
getOptionValueSourceWithGlobals(key) {
|
|
523
480
|
let source;
|
|
524
481
|
for (const cmd of this._getCommandAndAncestors()) {
|
|
@@ -527,7 +484,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
527
484
|
}
|
|
528
485
|
return source;
|
|
529
486
|
}
|
|
530
|
-
/** User args from argv per `from`; sets `_scriptPath` and the default program name. */
|
|
531
487
|
_prepareUserArgs(argv, parseOptions) {
|
|
532
488
|
if (argv !== undefined && !Array.isArray(argv))
|
|
533
489
|
throw new Error('first parameter to parse must be array or undefined');
|
|
@@ -537,7 +493,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
537
493
|
parseOptions.from = 'electron';
|
|
538
494
|
const execArgv = host.execArgv ?? [];
|
|
539
495
|
if (execArgv.includes('-e') || execArgv.includes('--eval') || execArgv.includes('-p') || execArgv.includes('--print')) {
|
|
540
|
-
parseOptions.from = 'eval';
|
|
496
|
+
parseOptions.from = 'eval';
|
|
541
497
|
}
|
|
542
498
|
}
|
|
543
499
|
if (argv === undefined)
|
|
@@ -573,17 +529,10 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
573
529
|
this._name = this._name || 'program';
|
|
574
530
|
return userArgs;
|
|
575
531
|
}
|
|
576
|
-
/**
|
|
577
|
-
* Parse argv, set options and run commands. Use `parseAsync` when an action is async.
|
|
578
|
-
* With no arguments, parses process.argv and auto-detects Electron and `node --eval`.
|
|
579
|
-
*/
|
|
580
532
|
parse(argv, parseOptions) {
|
|
581
533
|
const from = this._prepareBurgee(parseOptions);
|
|
582
534
|
this._prepareForParse();
|
|
583
535
|
const userArgs = this._prepareUserArgs(argv, from);
|
|
584
|
-
// The surface check is synchronous unless a surface is actually served (completions,
|
|
585
|
-
// --mcp), so a synchronous action has run by the time parse() returns — commander's
|
|
586
|
-
// contract, which its suite asserts on after every parse(). commander-sync.test.ts.
|
|
587
536
|
this._runBurgee(() => {
|
|
588
537
|
const served = this._burgeeSurface(userArgs);
|
|
589
538
|
if (isThenable(served))
|
|
@@ -596,8 +545,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
596
545
|
const from = this._prepareBurgee(parseOptions);
|
|
597
546
|
this._prepareForParse();
|
|
598
547
|
const userArgs = this._prepareUserArgs(argv, from);
|
|
599
|
-
// Same synchronous start as parse(): a preAction hook has run before the promise is
|
|
600
|
-
// handed back, which commander's hook tests assert on.
|
|
601
548
|
await this._runBurgee(() => {
|
|
602
549
|
const served = this._burgeeSurface(userArgs);
|
|
603
550
|
if (isThenable(served))
|
|
@@ -608,7 +555,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
608
555
|
}
|
|
609
556
|
_prepareForParse() {
|
|
610
557
|
if (this._savedState === null) {
|
|
611
|
-
// Lone negated option (--no-foo without --foo) defaults to true, now that all options are known.
|
|
612
558
|
for (const option of this.options) {
|
|
613
559
|
if (option.negate && option.defaultValue === undefined && this.getOptionValue(option.attributeName()) === undefined) {
|
|
614
560
|
const positiveLongFlag = (option.long ?? '').replace(/^--no-/, '--');
|
|
@@ -622,7 +568,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
622
568
|
this.restoreStateBeforeParse();
|
|
623
569
|
}
|
|
624
570
|
}
|
|
625
|
-
/** Called lazily on first parse; available for subclasses to save custom state. */
|
|
626
571
|
saveStateBeforeParse() {
|
|
627
572
|
this._savedState = {
|
|
628
573
|
_name: this._name,
|
|
@@ -668,7 +613,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
668
613
|
const foundExt = SOURCE_EXT.find((ext) => fs.existsSync(`${localBin}${ext}`));
|
|
669
614
|
return foundExt ? `${localBin}${foundExt}` : undefined;
|
|
670
615
|
};
|
|
671
|
-
// Not checking for help first: can't robustly test for help flags in an external command.
|
|
672
616
|
this._checkForMissingMandatoryOptions();
|
|
673
617
|
this._checkForConflictingOptions();
|
|
674
618
|
let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
|
|
@@ -685,7 +629,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
685
629
|
}
|
|
686
630
|
if (executableDir) {
|
|
687
631
|
let localFile = findFile(executableDir, executableFile);
|
|
688
|
-
// Legacy search using the script name as prefix instead of the command name.
|
|
689
632
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
690
633
|
const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
|
|
691
634
|
if (legacyName !== this._name)
|
|
@@ -694,10 +637,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
694
637
|
executableFile = localFile || executableFile;
|
|
695
638
|
}
|
|
696
639
|
const launchWithNode = SOURCE_EXT.includes(path.extname(executableFile));
|
|
697
|
-
// Through `bellpull`, not `node:child_process`: it resolves the executable properly on
|
|
698
|
-
// Windows, where upstream sends every spawn through `node` to dodge `PATHEXT`. The
|
|
699
|
-
// reasoning, the measurement and the mock constraint are in `weight.test.ts`'s
|
|
700
|
-
// `./commander` entry — they are prose, and prose in this file ships.
|
|
701
640
|
let proc;
|
|
702
641
|
if (host.platform !== 'win32') {
|
|
703
642
|
if (launchWithNode) {
|
|
@@ -717,12 +656,10 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
717
656
|
proc = crossSpawn.spawn(host.execPath, args, { stdio: 'inherit' });
|
|
718
657
|
}
|
|
719
658
|
else {
|
|
720
|
-
// The case upstream cannot reach: a `.cmd`, a `.bat`, or a shebang that is not node.
|
|
721
659
|
proc = crossSpawn.spawn(executableFile, args, { stdio: 'inherit' });
|
|
722
660
|
}
|
|
723
661
|
}
|
|
724
662
|
if (!proc.killed) {
|
|
725
|
-
// Testing mainly to avoid leak warnings during unit tests with mocked spawn.
|
|
726
663
|
for (const signal of FORWARDED_SIGNALS) {
|
|
727
664
|
host.on(signal, () => {
|
|
728
665
|
if (proc.killed === false && proc.exitCode === null)
|
|
@@ -732,7 +669,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
732
669
|
}
|
|
733
670
|
const exitCallback = this._exitCallback;
|
|
734
671
|
proc.on('close', (code) => {
|
|
735
|
-
code = code ?? 1;
|
|
672
|
+
code = code ?? 1;
|
|
736
673
|
if (!exitCallback)
|
|
737
674
|
host.exit(code);
|
|
738
675
|
else
|
|
@@ -772,14 +709,12 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
772
709
|
});
|
|
773
710
|
return promiseChain;
|
|
774
711
|
}
|
|
775
|
-
/** `help foo`: invoke help directly if possible, or dispatch if necessary. */
|
|
776
712
|
_dispatchHelpCommand(subcommandName) {
|
|
777
713
|
if (!subcommandName)
|
|
778
714
|
this.help();
|
|
779
715
|
const subCommand = this._findCommand(subcommandName);
|
|
780
716
|
if (subCommand && !subCommand._executableHandler)
|
|
781
717
|
subCommand.help();
|
|
782
|
-
// Fallback to parsing the help flag to invoke the help.
|
|
783
718
|
return this._dispatchSubcommand(subcommandName ?? '', [], [
|
|
784
719
|
this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? '--help',
|
|
785
720
|
]);
|
|
@@ -795,7 +730,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
795
730
|
if (this.args.length > this.registeredArguments.length)
|
|
796
731
|
this._excessArguments(this.args);
|
|
797
732
|
}
|
|
798
|
-
/** Process this.args against registeredArguments into this.processedArgs. */
|
|
799
733
|
_processArguments() {
|
|
800
734
|
const myParseArg = (argument, value, previous) => {
|
|
801
735
|
let parsedValue = value;
|
|
@@ -828,7 +762,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
828
762
|
});
|
|
829
763
|
this.processedArgs = processedArgs;
|
|
830
764
|
}
|
|
831
|
-
/** Chain once we have a promise; call synchronously until then. */
|
|
832
765
|
_chainOrCall(promise, fn) {
|
|
833
766
|
if (isThenable(promise))
|
|
834
767
|
return promise.then(() => fn());
|
|
@@ -855,15 +788,12 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
855
788
|
}
|
|
856
789
|
return result;
|
|
857
790
|
}
|
|
858
|
-
/** Process arguments in the context of this command; returns the action result in case it is a promise. */
|
|
859
791
|
_parseCommand(operands, unknown) {
|
|
860
792
|
const parsed = this.parseOptions(unknown);
|
|
861
|
-
this._parseOptionsEnv();
|
|
793
|
+
this._parseOptionsEnv();
|
|
862
794
|
this._parseOptionsImplied();
|
|
863
795
|
operands = operands.concat(parsed.operands);
|
|
864
796
|
unknown = parsed.unknown;
|
|
865
|
-
if (this._actionHandler && !this._findCommand(operands[0]) && !this._defaultCommandName)
|
|
866
|
-
this._takeJson(unknown);
|
|
867
797
|
this.args = operands.concat(unknown);
|
|
868
798
|
if (operands && this._findCommand(operands[0])) {
|
|
869
799
|
return this._dispatchSubcommand(operands[0] ?? '', operands.slice(1), unknown);
|
|
@@ -873,17 +803,15 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
873
803
|
return this._dispatchHelpCommand(operands[1]);
|
|
874
804
|
}
|
|
875
805
|
if (this._defaultCommandName) {
|
|
876
|
-
this._outputHelpIfRequested(unknown);
|
|
806
|
+
this._outputHelpIfRequested(unknown);
|
|
877
807
|
return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
|
|
878
808
|
}
|
|
879
809
|
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
|
|
880
|
-
// probably missing subcommand and no handler, user needs help (and exit)
|
|
881
810
|
this.help({ error: true });
|
|
882
811
|
}
|
|
883
812
|
this._outputHelpIfRequested(parsed.unknown);
|
|
884
813
|
this._checkForMissingMandatoryOptions();
|
|
885
814
|
this._checkForConflictingOptions();
|
|
886
|
-
// Not always called, to avoid masking a "better" error like unknown command.
|
|
887
815
|
const checkForUnknownOptions = () => {
|
|
888
816
|
if (parsed.unknown.length > 0)
|
|
889
817
|
this.unknownOption(parsed.unknown[0] ?? '');
|
|
@@ -897,7 +825,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
897
825
|
promiseChain = this._chainOrCall(promiseChain, () => this._runAction());
|
|
898
826
|
if (this.parent) {
|
|
899
827
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
900
|
-
this.parent?.emit(commandEvent, operands, unknown);
|
|
828
|
+
this.parent?.emit(commandEvent, operands, unknown);
|
|
901
829
|
});
|
|
902
830
|
}
|
|
903
831
|
promiseChain = this._chainOrCallHooks(promiseChain, 'postAction');
|
|
@@ -906,15 +834,13 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
906
834
|
if (this.parent?.listenerCount(commandEvent)) {
|
|
907
835
|
checkForUnknownOptions();
|
|
908
836
|
this._processArguments();
|
|
909
|
-
this.parent.emit(commandEvent, operands, unknown);
|
|
837
|
+
this.parent.emit(commandEvent, operands, unknown);
|
|
910
838
|
}
|
|
911
839
|
else if (operands.length) {
|
|
912
840
|
if (this._findCommand('*')) {
|
|
913
|
-
// legacy default command
|
|
914
841
|
return this._dispatchSubcommand('*', operands, unknown);
|
|
915
842
|
}
|
|
916
843
|
if (this.listenerCount('command:*')) {
|
|
917
|
-
// skip option check, emit event for possible misspelling suggestion
|
|
918
844
|
this.emit('command:*', operands, unknown);
|
|
919
845
|
}
|
|
920
846
|
else if (this.commands.length) {
|
|
@@ -927,13 +853,11 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
927
853
|
}
|
|
928
854
|
else if (this.commands.length) {
|
|
929
855
|
checkForUnknownOptions();
|
|
930
|
-
// This command has subcommands and nothing hooked up at this level, so display help (and exit).
|
|
931
856
|
this.help({ error: true });
|
|
932
857
|
}
|
|
933
858
|
else {
|
|
934
859
|
checkForUnknownOptions();
|
|
935
860
|
this._processArguments();
|
|
936
|
-
// fall through for caller to handle after calling .parse()
|
|
937
861
|
}
|
|
938
862
|
return undefined;
|
|
939
863
|
}
|
|
@@ -945,7 +869,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
945
869
|
_findOption(arg) {
|
|
946
870
|
return this.options.find((option) => option.is(arg));
|
|
947
871
|
}
|
|
948
|
-
/** Walks up the hierarchy so a subcommand can check after displaying help. */
|
|
949
872
|
_checkForMissingMandatoryOptions() {
|
|
950
873
|
for (const cmd of this._getCommandAndAncestors()) {
|
|
951
874
|
for (const anOption of cmd.options) {
|
|
@@ -973,15 +896,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
973
896
|
for (const cmd of this._getCommandAndAncestors())
|
|
974
897
|
cmd._checkForConflictingLocalOptions();
|
|
975
898
|
}
|
|
976
|
-
/**
|
|
977
|
-
* Parse options from `args`, removing known options, and return argv split into
|
|
978
|
-
* operands and unknown arguments. Side effect: stores option values on the command.
|
|
979
|
-
*
|
|
980
|
-
* --known kkk op => [op], []
|
|
981
|
-
* op --known kkk => [op], []
|
|
982
|
-
* sub --unknown uuu op => [sub], [--unknown uuu op]
|
|
983
|
-
* sub -- --unknown uuu op => [sub --unknown uuu op], []
|
|
984
|
-
*/
|
|
985
899
|
parseOptions(args) {
|
|
986
900
|
const operands = [];
|
|
987
901
|
const unknown = [];
|
|
@@ -990,11 +904,10 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
990
904
|
const negativeNumberArg = (arg) => {
|
|
991
905
|
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
|
|
992
906
|
return false;
|
|
993
|
-
// a negative number is ok unless a digit is used as an option in the command hierarchy
|
|
994
907
|
return !this._getCommandAndAncestors().some((cmd) => cmd.options.some((opt) => /^-\d$/.test(opt.short ?? '')));
|
|
995
908
|
};
|
|
996
909
|
let activeVariadicOption = null;
|
|
997
|
-
let activeGroup = null;
|
|
910
|
+
let activeGroup = null;
|
|
998
911
|
let i = 0;
|
|
999
912
|
while (i < args.length || activeGroup) {
|
|
1000
913
|
const arg = activeGroup ?? args[i++] ?? '';
|
|
@@ -1021,7 +934,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1021
934
|
}
|
|
1022
935
|
else if (option.optional) {
|
|
1023
936
|
let value = null;
|
|
1024
|
-
// historical behaviour: the optional value is the following arg unless it is an option
|
|
1025
937
|
const next = args[i];
|
|
1026
938
|
if (i < args.length && next !== undefined && (!maybeOption(next) || negativeNumberArg(next))) {
|
|
1027
939
|
value = next;
|
|
@@ -1035,8 +947,13 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1035
947
|
activeVariadicOption = option.variadic ? option : null;
|
|
1036
948
|
continue;
|
|
1037
949
|
}
|
|
950
|
+
if (arg === '--json' && !this._root()._declares('--json')) {
|
|
951
|
+
const root = this._root();
|
|
952
|
+
root._burgee ??= { exit: undefined, json: false };
|
|
953
|
+
root._burgee.json = true;
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
1038
956
|
}
|
|
1039
|
-
// Combined short options: eat the first one if known.
|
|
1040
957
|
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
1041
958
|
const option = this._findOption(`-${arg[1]}`);
|
|
1042
959
|
if (option) {
|
|
@@ -1050,7 +967,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1050
967
|
continue;
|
|
1051
968
|
}
|
|
1052
969
|
}
|
|
1053
|
-
// Known long flag with value, like --foo=bar
|
|
1054
970
|
if (/^--[^=]+=/.test(arg)) {
|
|
1055
971
|
const index = arg.indexOf('=');
|
|
1056
972
|
const option = this._findOption(arg.slice(0, index));
|
|
@@ -1059,13 +975,9 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1059
975
|
continue;
|
|
1060
976
|
}
|
|
1061
977
|
}
|
|
1062
|
-
// Not recognised by this command: command-argument, subcommand option, unknown option, or help.
|
|
1063
|
-
// An unknown option makes everything after it unknown too, for a subcommand to reprocess.
|
|
1064
|
-
// A negative number in a leaf command is not an unknown option.
|
|
1065
978
|
if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
|
|
1066
979
|
dest = unknown;
|
|
1067
980
|
}
|
|
1068
|
-
// Positional options: stop processing our options at a subcommand.
|
|
1069
981
|
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
|
|
1070
982
|
if (this._findCommand(arg)) {
|
|
1071
983
|
operands.push(arg);
|
|
@@ -1081,7 +993,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1081
993
|
break;
|
|
1082
994
|
}
|
|
1083
995
|
}
|
|
1084
|
-
// Pass-through options: stop processing options at the first command-argument.
|
|
1085
996
|
if (this._passThroughOptions) {
|
|
1086
997
|
dest.push(arg, ...args.slice(i));
|
|
1087
998
|
break;
|
|
@@ -1090,7 +1001,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1090
1001
|
}
|
|
1091
1002
|
return { operands, unknown };
|
|
1092
1003
|
}
|
|
1093
|
-
/** Local option values as key-value pairs. */
|
|
1094
1004
|
opts() {
|
|
1095
1005
|
if (this._storeOptionsAsProperties) {
|
|
1096
1006
|
const result = {};
|
|
@@ -1102,31 +1012,40 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1102
1012
|
}
|
|
1103
1013
|
return this._optionValues;
|
|
1104
1014
|
}
|
|
1105
|
-
/** Merged local and global option values; globals overwrite locals. */
|
|
1106
1015
|
optsWithGlobals() {
|
|
1107
1016
|
return this._getCommandAndAncestors().reduce((combined, cmd) => Object.assign(combined, cmd.opts()), {});
|
|
1108
1017
|
}
|
|
1109
|
-
/** Display an error message and exit (or call exitOverride). */
|
|
1110
1018
|
error(message, errorOptions) {
|
|
1111
|
-
this._outputConfiguration.outputError(`${message}\n`, this._outputConfiguration.writeErr);
|
|
1112
|
-
if (typeof this._showHelpAfterError === 'string') {
|
|
1113
|
-
this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
|
|
1114
|
-
}
|
|
1115
|
-
else if (this._showHelpAfterError) {
|
|
1116
|
-
this._outputConfiguration.writeErr('\n');
|
|
1117
|
-
this.outputHelp({ error: true });
|
|
1118
|
-
}
|
|
1119
1019
|
const config = errorOptions ?? {};
|
|
1120
1020
|
const exitCode = config.exitCode || 1;
|
|
1121
1021
|
const code = config.code || 'commander.error';
|
|
1022
|
+
if (this._root()._burgee?.json === true)
|
|
1023
|
+
this._reportJson(code, message);
|
|
1024
|
+
else {
|
|
1025
|
+
this._outputConfiguration.outputError(`${message}\n`, this._outputConfiguration.writeErr);
|
|
1026
|
+
if (typeof this._showHelpAfterError === 'string') {
|
|
1027
|
+
this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
|
|
1028
|
+
}
|
|
1029
|
+
else if (this._showHelpAfterError) {
|
|
1030
|
+
this._outputConfiguration.writeErr('\n');
|
|
1031
|
+
this.outputHelp({ error: true });
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1122
1034
|
this._exit(exitCode, code, message);
|
|
1123
1035
|
}
|
|
1124
|
-
|
|
1036
|
+
_reportJson(code, message) {
|
|
1037
|
+
const burgee = this._root()._burgee;
|
|
1038
|
+
if (burgee === undefined || !burgee.json || burgee.reported)
|
|
1039
|
+
return;
|
|
1040
|
+
burgee.reported = true;
|
|
1041
|
+
const [first = '', ...rest] = message.replace(/^error: /, '').split('\n');
|
|
1042
|
+
const guess = /\(Did you mean (\S+)\?\)/.exec(rest.join(''));
|
|
1043
|
+
this._outputConfiguration.writeOut(`${JSON.stringify({ ok: false, error: { code, message: first, ...(guess === null ? {} : { fix: guess[1] }) } })}\n`);
|
|
1044
|
+
}
|
|
1125
1045
|
_parseOptionsEnv() {
|
|
1126
1046
|
for (const option of this.options) {
|
|
1127
1047
|
if (option.envVar && option.envVar in host.env) {
|
|
1128
1048
|
const optionKey = option.attributeName();
|
|
1129
|
-
// Do not overwrite cli values or values from an unknown (client-code) source.
|
|
1130
1049
|
if (this.getOptionValue(optionKey) === undefined || ENV_SOURCES.includes(this.getOptionValueSource(optionKey) ?? '')) {
|
|
1131
1050
|
if (option.required || option.optional)
|
|
1132
1051
|
this.emit(`optionEnv:${option.name()}`, host.env[option.envVar]);
|
|
@@ -1136,7 +1055,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1136
1055
|
}
|
|
1137
1056
|
}
|
|
1138
1057
|
}
|
|
1139
|
-
/** Apply implied option values where the option is undefined or at its default. */
|
|
1140
1058
|
_parseOptionsImplied() {
|
|
1141
1059
|
const dualHelper = new DualOptions(this.options);
|
|
1142
1060
|
const hasCustomOptionValue = (optionKey) => this.getOptionValue(optionKey) !== undefined && !IMPLIED_SOURCES.includes(this.getOptionValueSource(optionKey) ?? '');
|
|
@@ -1160,7 +1078,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1160
1078
|
this.error(`error: required option '${option.flags}' not specified`, { code: 'commander.missingMandatoryOptionValue' });
|
|
1161
1079
|
}
|
|
1162
1080
|
_conflictingOption(option, conflictingOption) {
|
|
1163
|
-
// The caller does not know whether a negated option is the source of the value; take an educated guess.
|
|
1164
1081
|
const findBestOptionFromValue = (candidate) => {
|
|
1165
1082
|
const optionKey = candidate.attributeName();
|
|
1166
1083
|
const optionValue = this.getOptionValue(optionKey);
|
|
@@ -1188,7 +1105,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1188
1105
|
return;
|
|
1189
1106
|
let suggestion = '';
|
|
1190
1107
|
if (flag.startsWith('--') && this._showSuggestionAfterError) {
|
|
1191
|
-
// Looping to pick up the global options too.
|
|
1192
1108
|
let candidateFlags = [];
|
|
1193
1109
|
let command = this;
|
|
1194
1110
|
do {
|
|
@@ -1265,7 +1181,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1265
1181
|
let command = this;
|
|
1266
1182
|
const last = this.commands[this.commands.length - 1];
|
|
1267
1183
|
if (this.commands.length !== 0 && last?._executableHandler) {
|
|
1268
|
-
// assume adding an alias for the last added executable subcommand, rather than this
|
|
1269
1184
|
command = last;
|
|
1270
1185
|
}
|
|
1271
1186
|
if (alias === command._name)
|
|
@@ -1329,7 +1244,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1329
1244
|
if (this._defaultCommandGroup && !cmd.helpGroup())
|
|
1330
1245
|
cmd.helpGroup(this._defaultCommandGroup);
|
|
1331
1246
|
}
|
|
1332
|
-
/** Name the command from a script filename, such as process.argv[1] or import.meta.filename. */
|
|
1333
1247
|
nameFromFilename(filename) {
|
|
1334
1248
|
this._name = path.basename(filename, path.extname(filename));
|
|
1335
1249
|
return this;
|
|
@@ -1376,7 +1290,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1376
1290
|
};
|
|
1377
1291
|
return { error, write, hasColors, helpWidth };
|
|
1378
1292
|
}
|
|
1379
|
-
/** Output built-in help plus any text added with `addHelpText`. */
|
|
1380
1293
|
outputHelp(contextOptions) {
|
|
1381
1294
|
let deprecatedCallback;
|
|
1382
1295
|
if (typeof contextOptions === 'function') {
|
|
@@ -1398,17 +1311,16 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1398
1311
|
outputContext.write(String(helpInformation));
|
|
1399
1312
|
const helpLong = this._getHelpOption()?.long;
|
|
1400
1313
|
if (helpLong)
|
|
1401
|
-
this.emit(helpLong);
|
|
1314
|
+
this.emit(helpLong);
|
|
1402
1315
|
this.emit('afterHelp', eventContext);
|
|
1403
1316
|
for (const command of this._getCommandAndAncestors())
|
|
1404
1317
|
command.emit('afterAllHelp', eventContext);
|
|
1405
1318
|
}
|
|
1406
|
-
/** Customise the built-in help option, or pass false to disable it. */
|
|
1407
1319
|
helpOption(flags, description) {
|
|
1408
1320
|
if (typeof flags === 'boolean') {
|
|
1409
1321
|
if (flags) {
|
|
1410
1322
|
if (this._helpOption === null)
|
|
1411
|
-
this._helpOption = undefined;
|
|
1323
|
+
this._helpOption = undefined;
|
|
1412
1324
|
if (this._defaultOptionGroup) {
|
|
1413
1325
|
const helpOption = this._getHelpOption();
|
|
1414
1326
|
if (helpOption)
|
|
@@ -1416,7 +1328,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1416
1328
|
}
|
|
1417
1329
|
}
|
|
1418
1330
|
else {
|
|
1419
|
-
this._helpOption = null;
|
|
1331
|
+
this._helpOption = null;
|
|
1420
1332
|
}
|
|
1421
1333
|
return this;
|
|
1422
1334
|
}
|
|
@@ -1425,7 +1337,6 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1425
1337
|
this._initOptionGroup(this._helpOption);
|
|
1426
1338
|
return this;
|
|
1427
1339
|
}
|
|
1428
|
-
/** Lazily created; null once disabled with `helpOption(false)`. */
|
|
1429
1340
|
_getHelpOption() {
|
|
1430
1341
|
if (this._helpOption === undefined)
|
|
1431
1342
|
this.helpOption(undefined, undefined);
|
|
@@ -1436,16 +1347,13 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1436
1347
|
this._initOptionGroup(option);
|
|
1437
1348
|
return this;
|
|
1438
1349
|
}
|
|
1439
|
-
/** Output help and exit. */
|
|
1440
1350
|
help(contextOptions) {
|
|
1441
1351
|
this.outputHelp(contextOptions);
|
|
1442
1352
|
let exitCode = Number(host.exitCode ?? 0);
|
|
1443
1353
|
if (exitCode === 0 && contextOptions && typeof contextOptions !== 'function' && contextOptions.error)
|
|
1444
1354
|
exitCode = 1;
|
|
1445
|
-
// message: not all displayed text is available, so only a placeholder is passed.
|
|
1446
1355
|
this._exit(exitCode, 'commander.help', '(outputHelp)');
|
|
1447
1356
|
}
|
|
1448
|
-
/** Extra help text: 'before'/'after' for this command, 'beforeAll'/'afterAll' for its subcommands too. */
|
|
1449
1357
|
addHelpText(position, text) {
|
|
1450
1358
|
if (!HELP_POSITIONS.includes(position)) {
|
|
1451
1359
|
throw new Error(`Unexpected value for position to addHelpText.
|
|
@@ -1465,17 +1373,12 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1465
1373
|
this._exit(0, 'commander.helpDisplayed', '(outputHelp)');
|
|
1466
1374
|
}
|
|
1467
1375
|
}
|
|
1468
|
-
// ───── burgee: the manifest projection, plugins, `--json` and the injected seam ─────
|
|
1469
1376
|
_root() {
|
|
1470
1377
|
let command = this;
|
|
1471
1378
|
while (command.parent)
|
|
1472
1379
|
command = command.parent;
|
|
1473
1380
|
return command;
|
|
1474
1381
|
}
|
|
1475
|
-
/**
|
|
1476
|
-
* The manifest every surface reads. Projected from the command tree on each access,
|
|
1477
|
-
* so it is never stale; plugin-contributed nodes are kept across projections.
|
|
1478
|
-
*/
|
|
1479
1382
|
get manifest() {
|
|
1480
1383
|
const root = this._root();
|
|
1481
1384
|
root._manifest ??= new Manifest();
|
|
@@ -1507,7 +1410,6 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1507
1410
|
};
|
|
1508
1411
|
visit(this, [rootName]);
|
|
1509
1412
|
}
|
|
1510
|
-
/** Options as the manifest describes them, on a null-prototype record. */
|
|
1511
1413
|
_optionSpecs() {
|
|
1512
1414
|
const specs = Object.create(null);
|
|
1513
1415
|
for (const option of this.options) {
|
|
@@ -1526,32 +1428,19 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1526
1428
|
}
|
|
1527
1429
|
return specs;
|
|
1528
1430
|
}
|
|
1529
|
-
/** burgee: declare what the command does to the world (N6). This is what exposes it as an MCP tool (N2). */
|
|
1530
1431
|
effects(value) {
|
|
1531
1432
|
this._effects = value;
|
|
1532
1433
|
return this;
|
|
1533
1434
|
}
|
|
1534
|
-
/**
|
|
1535
|
-
* burgee: mark the command deprecated (M5). Help and `--schema` show it; running it prints
|
|
1536
|
-
* `warning: 'old' is deprecated, use 'new'` on stderr once and goes on, exit unchanged.
|
|
1537
|
-
*/
|
|
1538
1435
|
deprecate(use) {
|
|
1539
1436
|
this._deprecated = use ?? true;
|
|
1540
1437
|
return this;
|
|
1541
1438
|
}
|
|
1542
|
-
/**
|
|
1543
|
-
* burgee: `--schema` and `--mcp` on a commander-syntax program, from its manifest (J2).
|
|
1544
|
-
* Only when the program declares neither option itself; `--mcp` runs commands through
|
|
1545
|
-
* this very program with the streams captured, so tool results are the `--json` envelope.
|
|
1546
|
-
*/
|
|
1547
1439
|
_burgeeSurface(userArgs) {
|
|
1548
1440
|
const root = this._root();
|
|
1549
|
-
// Any command in the tree that declares the flag keeps it: the surface is additive only.
|
|
1550
|
-
const declared = (flag, at = root) => at._findOption(flag) !== undefined || at.commands.some((sub) => declared(flag, sub));
|
|
1551
1441
|
const terminator = userArgs.indexOf('--');
|
|
1552
1442
|
const head = terminator === -1 ? userArgs : userArgs.slice(0, terminator);
|
|
1553
1443
|
if (head[0] === 'completion' && root._findCommand('completion') === undefined) {
|
|
1554
|
-
// Loaded on this command only (K6), exactly as the engine does.
|
|
1555
1444
|
return import('../completions.js').then(({ renderCompletion, renderFigSpec, SHELLS }) => {
|
|
1556
1445
|
const shell = head[1] ?? '';
|
|
1557
1446
|
if (shell === 'fig') {
|
|
@@ -1563,21 +1452,19 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1563
1452
|
root._outputConfiguration.writeOut(renderCompletion(this.manifest, known));
|
|
1564
1453
|
return true;
|
|
1565
1454
|
}
|
|
1566
|
-
return this._burgeeSurfaceRest(head
|
|
1455
|
+
return this._burgeeSurfaceRest(head);
|
|
1567
1456
|
});
|
|
1568
1457
|
}
|
|
1569
|
-
return this._burgeeSurfaceRest(head
|
|
1458
|
+
return this._burgeeSurfaceRest(head);
|
|
1570
1459
|
}
|
|
1571
|
-
|
|
1572
|
-
_burgeeSurfaceRest(head, declared) {
|
|
1460
|
+
_burgeeSurfaceRest(head) {
|
|
1573
1461
|
const root = this._root();
|
|
1574
|
-
if (head.includes('--schema') && !
|
|
1575
|
-
// R1, and the same escape hatch the engine has: `--schema` is burgee's surface, not
|
|
1576
|
-
// commander's, so it answers to E-floor byte discipline rather than to the host.
|
|
1462
|
+
if (head.includes('--schema') && !root._declares('--schema')) {
|
|
1577
1463
|
root._outputConfiguration.writeOut(`${machineJson(schemaOf(this.manifest), head)}\n`);
|
|
1578
1464
|
return true;
|
|
1579
1465
|
}
|
|
1580
|
-
if (head[0] === '--mcp' && !
|
|
1466
|
+
if (head[0] === '--mcp' && !root._declares('--mcp')) {
|
|
1467
|
+
const writeOut = root._outputConfiguration.writeOut;
|
|
1581
1468
|
const invoke = async (args) => {
|
|
1582
1469
|
const out = [];
|
|
1583
1470
|
const err = [];
|
|
@@ -1585,16 +1472,14 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1585
1472
|
await root.parseAsync(args, { from: 'user', stdout: { write: (s) => out.push(s) }, stderr: { write: (s) => err.push(s) }, exit: (c) => void (code = c) });
|
|
1586
1473
|
return { stdout: out.join(''), stderr: err.join(''), code };
|
|
1587
1474
|
};
|
|
1588
|
-
return serveMcp(this.manifest, { input: host.stdin, output: { write:
|
|
1475
|
+
return import('../mcp.js').then(async ({ serveMcp }) => serveMcp(this.manifest, { input: host.stdin, output: { write: writeOut }, invoke })).then(() => true);
|
|
1589
1476
|
}
|
|
1590
1477
|
return false;
|
|
1591
1478
|
}
|
|
1592
|
-
/** Additive, and the point of the whole exercise: plugins commander has never had (#2505, unlanded). */
|
|
1593
1479
|
use(plugin) {
|
|
1594
1480
|
this.manifest.use(plugin);
|
|
1595
1481
|
return this;
|
|
1596
1482
|
}
|
|
1597
|
-
/** Inject the streams and the exit for one parse; returns commander's own parse options. */
|
|
1598
1483
|
_prepareBurgee(parseOptions) {
|
|
1599
1484
|
if (parseOptions === undefined)
|
|
1600
1485
|
return undefined;
|
|
@@ -1621,7 +1506,6 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1621
1506
|
visit(root);
|
|
1622
1507
|
return from;
|
|
1623
1508
|
}
|
|
1624
|
-
/** In burgee mode the whole run settles to one E1 exit; otherwise commander's behaviour, untouched. */
|
|
1625
1509
|
_runBurgee(run) {
|
|
1626
1510
|
const root = this._root();
|
|
1627
1511
|
const burgee = root._burgee;
|
|
@@ -1633,15 +1517,14 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1633
1517
|
};
|
|
1634
1518
|
const fail = (err) => {
|
|
1635
1519
|
if (err instanceof CommanderError) {
|
|
1636
|
-
if (
|
|
1637
|
-
root.
|
|
1638
|
-
}
|
|
1520
|
+
if (err.code !== 'commander.helpDisplayed' && err.code !== 'commander.version')
|
|
1521
|
+
root._reportJson(err.code, err.message);
|
|
1639
1522
|
finish(e1(err));
|
|
1640
1523
|
return;
|
|
1641
1524
|
}
|
|
1642
1525
|
const message = err instanceof Error ? err.message : String(err);
|
|
1643
1526
|
if (burgee.json)
|
|
1644
|
-
root.
|
|
1527
|
+
root._reportJson('runtime', message);
|
|
1645
1528
|
else
|
|
1646
1529
|
root._outputConfiguration.writeErr(`error: ${message}\n`);
|
|
1647
1530
|
finish(ExitCode.RUNTIME);
|
|
@@ -1658,20 +1541,9 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1658
1541
|
return undefined;
|
|
1659
1542
|
}
|
|
1660
1543
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
const terminator = unknown.indexOf('--');
|
|
1664
|
-
const index = unknown.indexOf('--json');
|
|
1665
|
-
if (index === -1 || (terminator !== -1 && index > terminator))
|
|
1666
|
-
return;
|
|
1667
|
-
if (this._getCommandAndAncestors().some((cmd) => cmd._findOption('--json')))
|
|
1668
|
-
return;
|
|
1669
|
-
unknown.splice(index, 1);
|
|
1670
|
-
const root = this._root();
|
|
1671
|
-
root._burgee ??= { exit: undefined, json: false };
|
|
1672
|
-
root._burgee.json = true;
|
|
1544
|
+
_declares(flag) {
|
|
1545
|
+
return this._findOption(flag) !== undefined || this.commands.some((sub) => sub._declares(flag));
|
|
1673
1546
|
}
|
|
1674
|
-
/** The action, wrapped in the plugin hooks and followed by the envelope or the rendering. */
|
|
1675
1547
|
_runAction() {
|
|
1676
1548
|
const handler = this._actionHandler;
|
|
1677
1549
|
if (handler === null)
|
|
@@ -1692,9 +1564,12 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1692
1564
|
.then(async (value) => {
|
|
1693
1565
|
await manifest.fire('postRun', name, options);
|
|
1694
1566
|
settle(value);
|
|
1567
|
+
})
|
|
1568
|
+
.catch(async (cause) => {
|
|
1569
|
+
await manifest.fire('onError', name, options);
|
|
1570
|
+
throw cause;
|
|
1695
1571
|
});
|
|
1696
1572
|
}
|
|
1697
|
-
/** burgee (M5): once per process, on stderr; only for a command that asked, so commander's own output is untouched. */
|
|
1698
1573
|
_warnDeprecated() {
|
|
1699
1574
|
if (this._deprecated === undefined || this._deprecated === false || this._deprecationWarned)
|
|
1700
1575
|
return;
|
|
@@ -1702,7 +1577,6 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1702
1577
|
const use = typeof this._deprecated === 'string' ? `, use '${this._deprecated}'` : '';
|
|
1703
1578
|
this._outputConfiguration.writeErr(`warning: '${this.name()}' is deprecated${use}\n`);
|
|
1704
1579
|
}
|
|
1705
|
-
/** burgee: where every option value came from, from commander's own value sources (V3). */
|
|
1706
1580
|
_provenance() {
|
|
1707
1581
|
const out = {};
|
|
1708
1582
|
const names = { cli: 'flag', env: 'env', config: 'config', default: 'default', implied: 'implied' };
|
|
@@ -1725,9 +1599,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1725
1599
|
this._outputConfiguration.writeOut(text);
|
|
1726
1600
|
}
|
|
1727
1601
|
}
|
|
1728
|
-
/** Bump inspector ports so a spawned subcommand does not collide with the parent. */
|
|
1729
1602
|
function incrementNodeInspectorPort(args) {
|
|
1730
|
-
// --inspect[=[host:]port], --inspect-brk[=[host:]port], --inspect-port=[host:]port
|
|
1731
1603
|
return args.map((arg) => {
|
|
1732
1604
|
if (!arg.startsWith('--inspect'))
|
|
1733
1605
|
return arg;
|
|
@@ -1755,10 +1627,6 @@ function incrementNodeInspectorPort(args) {
|
|
|
1755
1627
|
return arg;
|
|
1756
1628
|
});
|
|
1757
1629
|
}
|
|
1758
|
-
/**
|
|
1759
|
-
* The common colour conventions: NO_COLOR and FORCE_COLOR=0/false disable, FORCE_COLOR
|
|
1760
|
-
* and CLICOLOR_FORCE enable, otherwise undecided (the stream's TTY-ness decides).
|
|
1761
|
-
*/
|
|
1762
1630
|
export function useColor() {
|
|
1763
1631
|
if (host.env['NO_COLOR'] || host.env['FORCE_COLOR'] === '0' || host.env['FORCE_COLOR'] === 'false')
|
|
1764
1632
|
return false;
|
|
@@ -1766,4 +1634,3 @@ export function useColor() {
|
|
|
1766
1634
|
return true;
|
|
1767
1635
|
return undefined;
|
|
1768
1636
|
}
|
|
1769
|
-
//# sourceMappingURL=command.js.map
|