burgee 0.3.0 → 0.5.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/LICENSE +21 -0
- package/README.md +61 -9
- package/dist/brand.d.ts +62 -1
- package/dist/brand.js +73 -7
- package/dist/{commander-argument.js → commander/argument.js} +4 -1
- package/dist/{commander-command.d.ts → commander/command.d.ts} +5 -5
- package/dist/{commander-command.js → commander/command.js} +159 -22
- package/dist/{commander-error.js → commander/error.js} +2 -0
- package/dist/{commander-help.d.ts → commander/help.d.ts} +3 -3
- package/dist/{commander-help.js → commander/help.js} +18 -1
- package/dist/{commander-option.d.ts → commander/option.d.ts} +1 -1
- package/dist/{commander-option.js → commander/option.js} +15 -1
- package/dist/commander.d.ts +8 -8
- package/dist/commander.js +8 -8
- package/dist/completions.js +15 -4
- package/dist/contrast.d.ts +9 -11
- package/dist/contrast.js +2 -33
- package/dist/execute.js +39 -24
- package/dist/schema.d.ts +34 -0
- package/dist/schema.js +12 -0
- package/dist/unknown-option.d.ts +9 -0
- package/dist/unknown-option.js +27 -0
- package/dist/{yargs-burgee.d.ts → yargs/burgee.d.ts} +2 -2
- package/dist/{yargs-burgee.js → yargs/burgee.js} +15 -1
- package/dist/{yargs-cliui.js → yargs/cliui.js} +8 -0
- package/dist/{yargs-command.d.ts → yargs/command.d.ts} +5 -5
- package/dist/{yargs-command.js → yargs/command.js} +9 -2
- package/dist/{yargs-completion.d.ts → yargs/completion.d.ts} +3 -3
- package/dist/{yargs-completion.js → yargs/completion.js} +7 -2
- package/dist/{yargs-factory.d.ts → yargs/factory.d.ts} +8 -8
- package/dist/{yargs-factory.js → yargs/factory.js} +63 -13
- package/dist/{yargs-middleware.js → yargs/middleware.js} +6 -1
- package/dist/{yargs-shim.d.ts → yargs/shim.d.ts} +3 -3
- package/dist/{yargs-shim.js → yargs/shim.js} +24 -5
- package/dist/{yargs-usage.d.ts → yargs/usage.d.ts} +1 -1
- package/dist/{yargs-usage.js → yargs/usage.js} +9 -1
- package/dist/{yargs-utils.js → yargs/utils.js} +11 -0
- package/dist/{yargs-validation.d.ts → yargs/validation.d.ts} +1 -1
- package/dist/{yargs-validation.js → yargs/validation.js} +7 -1
- package/dist/{yargs-y18n.js → yargs/y18n.js} +6 -0
- package/dist/yargs-helpers.d.ts +1 -1
- package/dist/yargs-helpers.js +1 -1
- package/dist/yargs.d.ts +4 -4
- package/dist/yargs.js +5 -5
- package/package.json +5 -1
- /package/dist/{commander-argument.d.ts → commander/argument.d.ts} +0 -0
- /package/dist/{commander-error.d.ts → commander/error.d.ts} +0 -0
- /package/dist/{commander-suggest.d.ts → suggest.d.ts} +0 -0
- /package/dist/{commander-suggest.js → suggest.js} +0 -0
- /package/dist/{yargs-cliui.d.ts → yargs/cliui.d.ts} +0 -0
- /package/dist/{yargs-middleware.d.ts → yargs/middleware.d.ts} +0 -0
- /package/dist/{yargs-utils.d.ts → yargs/utils.d.ts} +0 -0
- /package/dist/{yargs-y18n.d.ts → yargs/y18n.d.ts} +0 -0
|
@@ -1,18 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commander's `Command`, ported method for method from commander 15 and graded by
|
|
3
|
+
* commander's own suite through `compat-oracle`. The parse pipeline, the option
|
|
4
|
+
* grammar, every error string and exit code are commander's — that is what makes a
|
|
5
|
+
* user's existing program run unchanged (J2).
|
|
6
|
+
*
|
|
7
|
+
* burgee's additions sit beside it and never alter the default behaviour:
|
|
8
|
+
* - `manifest` projects the command tree, so plugins (`use`) and the generated
|
|
9
|
+
* surfaces read commander-syntax programs exactly like native ones (J7, J8);
|
|
10
|
+
* - `--json`, when the program has not declared that option itself, wraps the
|
|
11
|
+
* action's return value in the envelope (N-family);
|
|
12
|
+
* - `parse(argv, { stdout, stderr, exit })` injects the streams and the exit, and
|
|
13
|
+
* then reports through the E1 taxonomy — the harness's seam (T1).
|
|
14
|
+
*/
|
|
1
15
|
import childProcess from 'node:child_process';
|
|
2
16
|
import { EventEmitter } from 'node:events';
|
|
3
17
|
import fs from 'node:fs';
|
|
4
18
|
import path from 'node:path';
|
|
5
19
|
import process from 'node:process';
|
|
6
20
|
import { stripVTControlCharacters } from 'node:util';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { suggestSimilar } from '
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
21
|
+
import { ExitCode } from '../exit-code.js';
|
|
22
|
+
import { Manifest } from '../manifest.js';
|
|
23
|
+
import { serveMcp } from '../mcp.js';
|
|
24
|
+
import { machineJson, schemaOf } from '../schema.js';
|
|
25
|
+
import { suggestSimilar } from '../suggest.js';
|
|
26
|
+
import { Argument, humanReadableArgName } from './argument.js';
|
|
27
|
+
import { CommanderError } from './error.js';
|
|
28
|
+
import { Help } from './help.js';
|
|
29
|
+
import { DualOptions, Option } from './option.js';
|
|
30
|
+
/** Names that would reach Object.prototype if used as an option key. */
|
|
16
31
|
const POLLUTING = new Set(['__proto__', 'constructor', 'prototype']);
|
|
17
32
|
const ENV_SOURCES = ['default', 'config', 'env'];
|
|
18
33
|
const IMPLIED_SOURCES = ['default', 'implied'];
|
|
@@ -20,10 +35,12 @@ const HOOK_EVENTS = ['preSubcommand', 'preAction', 'postAction'];
|
|
|
20
35
|
const HELP_POSITIONS = ['beforeAll', 'before', 'after', 'afterAll'];
|
|
21
36
|
const SOURCE_EXT = ['.js', '.ts', '.tsx', '.mjs', '.cjs'];
|
|
22
37
|
const FORWARDED_SIGNALS = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
38
|
+
/** 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. */
|
|
23
39
|
const quoted = (s) => `'${s}'`;
|
|
24
40
|
function isThenable(value) {
|
|
25
41
|
return typeof value?.then === 'function';
|
|
26
42
|
}
|
|
43
|
+
/** commander's exit codes, read through burgee's taxonomy when the exit is injected (E1). */
|
|
27
44
|
function e1(err) {
|
|
28
45
|
switch (err.code) {
|
|
29
46
|
case 'commander.helpDisplayed':
|
|
@@ -38,6 +55,7 @@ function e1(err) {
|
|
|
38
55
|
return err.exitCode === 1 ? ExitCode.USAGE : err.exitCode;
|
|
39
56
|
}
|
|
40
57
|
}
|
|
58
|
+
/** What a run prints for an action's return value when the streams are injected. */
|
|
41
59
|
function render(value) {
|
|
42
60
|
if (value === undefined || value === null)
|
|
43
61
|
return '';
|
|
@@ -55,9 +73,12 @@ export class Command extends EventEmitter {
|
|
|
55
73
|
options = [];
|
|
56
74
|
parent = null;
|
|
57
75
|
registeredArguments = [];
|
|
76
|
+
/** @deprecated old name for registeredArguments */
|
|
58
77
|
_args;
|
|
78
|
+
/** cli args with options removed */
|
|
59
79
|
args = [];
|
|
60
80
|
rawArgs = [];
|
|
81
|
+
/** like .args but after custom processing and collecting variadic */
|
|
61
82
|
processedArgs = [];
|
|
62
83
|
runningCommand = undefined;
|
|
63
84
|
_allowUnknownOption = false;
|
|
@@ -86,6 +107,7 @@ export class Command extends EventEmitter {
|
|
|
86
107
|
_savedState = null;
|
|
87
108
|
_outputConfiguration;
|
|
88
109
|
_hidden = false;
|
|
110
|
+
/** Lazy created on demand; null once disabled. */
|
|
89
111
|
_helpOption = undefined;
|
|
90
112
|
_addImplicitHelpCommand = undefined;
|
|
91
113
|
_helpCommand = undefined;
|
|
@@ -96,10 +118,14 @@ export class Command extends EventEmitter {
|
|
|
96
118
|
_version = undefined;
|
|
97
119
|
_versionOptionName = undefined;
|
|
98
120
|
_usage = undefined;
|
|
121
|
+
/** burgee: the root's projection, created on first use. */
|
|
99
122
|
_manifest = undefined;
|
|
123
|
+
/** burgee: what this command does to the world (N6); declaring it exposes the command as an MCP tool. */
|
|
100
124
|
_effects = undefined;
|
|
125
|
+
/** burgee: `true`, or the replacement's name (M5). Shown in help, schema and a one-line warning on use. */
|
|
101
126
|
_deprecated = undefined;
|
|
102
127
|
_deprecationWarned = false;
|
|
128
|
+
/** burgee: set for the duration of a parse that injected the streams or the exit. */
|
|
103
129
|
_burgee = undefined;
|
|
104
130
|
constructor(name) {
|
|
105
131
|
super();
|
|
@@ -116,6 +142,7 @@ export class Command extends EventEmitter {
|
|
|
116
142
|
stripColor: (str) => stripVTControlCharacters(str),
|
|
117
143
|
};
|
|
118
144
|
}
|
|
145
|
+
/** Copy settings useful to share between the root and its subcommands. */
|
|
119
146
|
copyInheritedSettings(sourceCommand) {
|
|
120
147
|
this._outputConfiguration = sourceCommand._outputConfiguration;
|
|
121
148
|
this._helpOption = sourceCommand._helpOption;
|
|
@@ -163,6 +190,7 @@ export class Command extends EventEmitter {
|
|
|
163
190
|
return this;
|
|
164
191
|
return cmd;
|
|
165
192
|
}
|
|
193
|
+
/** Factory for an unattached command; override to customise subcommands. */
|
|
166
194
|
createCommand(name) {
|
|
167
195
|
return new Command(name);
|
|
168
196
|
}
|
|
@@ -234,6 +262,7 @@ export class Command extends EventEmitter {
|
|
|
234
262
|
this.registeredArguments.push(argument);
|
|
235
263
|
return this;
|
|
236
264
|
}
|
|
265
|
+
/** Customise or disable the default help command (added by default when there are subcommands). */
|
|
237
266
|
helpCommand(enableOrNameAndArgs, description) {
|
|
238
267
|
if (typeof enableOrNameAndArgs === 'boolean') {
|
|
239
268
|
this._addImplicitHelpCommand = enableOrNameAndArgs;
|
|
@@ -290,21 +319,25 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
290
319
|
this._lifeCycleHooks[event] = [listener];
|
|
291
320
|
return this;
|
|
292
321
|
}
|
|
322
|
+
/** Replace the call to process.exit; defaults to throwing the CommanderError. */
|
|
293
323
|
exitOverride(fn) {
|
|
294
324
|
this._exitCallback =
|
|
295
325
|
fn ??
|
|
296
326
|
((err) => {
|
|
297
327
|
if (err.code !== 'commander.executeSubCommandAsync')
|
|
298
328
|
throw err;
|
|
329
|
+
// Async callback from spawn events, not useful to throw.
|
|
299
330
|
});
|
|
300
331
|
return this;
|
|
301
332
|
}
|
|
302
333
|
_exit(exitCode, code, message) {
|
|
303
334
|
if (this._exitCallback) {
|
|
304
335
|
this._exitCallback(new CommanderError(exitCode, code, message));
|
|
336
|
+
// Expecting this line is not reached.
|
|
305
337
|
}
|
|
306
338
|
process.exit(exitCode);
|
|
307
339
|
}
|
|
340
|
+
// commander's contract: the positional args, then the options, then the command itself.
|
|
308
341
|
action(fn) {
|
|
309
342
|
const listener = (args) => {
|
|
310
343
|
const expectedArgsCount = this.registeredArguments.length;
|
|
@@ -319,6 +352,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
319
352
|
createOption(flags, description) {
|
|
320
353
|
return new Option(flags, description);
|
|
321
354
|
}
|
|
355
|
+
/** Wrap parseArg to turn `commander.invalidArgument` into an error with context. */
|
|
322
356
|
_callParseArg(target, value, previous, invalidArgumentMessage) {
|
|
323
357
|
try {
|
|
324
358
|
return target.parseArg?.(value, previous);
|
|
@@ -366,6 +400,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
366
400
|
if (option.defaultValue !== undefined) {
|
|
367
401
|
this.setOptionValueWithSource(name, option.defaultValue, 'default');
|
|
368
402
|
}
|
|
403
|
+
// val is null for an optional option used without its argument, undefined for boolean and negated.
|
|
369
404
|
const handleOptionValue = (val, invalidValueMessage, valueSource) => {
|
|
370
405
|
let value = val;
|
|
371
406
|
if (value == null && option.presetArg !== undefined)
|
|
@@ -383,7 +418,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
383
418
|
else if (option.isBoolean() || option.optional)
|
|
384
419
|
value = true;
|
|
385
420
|
else
|
|
386
|
-
value = '';
|
|
421
|
+
value = ''; // not normal, parseArg might have failed or be a mock function for testing
|
|
387
422
|
}
|
|
388
423
|
this.setOptionValueWithSource(name, value, valueSource);
|
|
389
424
|
};
|
|
@@ -407,6 +442,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
407
442
|
option.default(defaultValue).argParser(fn);
|
|
408
443
|
}
|
|
409
444
|
else if (fn instanceof RegExp) {
|
|
445
|
+
// deprecated
|
|
410
446
|
const regex = fn;
|
|
411
447
|
option.default(defaultValue).argParser((val, def) => {
|
|
412
448
|
const m = regex.exec(val);
|
|
@@ -424,6 +460,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
424
460
|
requiredOption(flags, description, parseArg, defaultValue) {
|
|
425
461
|
return this._optionEx({ mandatory: true }, flags, description, parseArg, defaultValue);
|
|
426
462
|
}
|
|
463
|
+
/** `-f80` as `--flag=80` (default) versus `-fb` as `-f -b`. */
|
|
427
464
|
combineFlagAndOptionalValue(combine = true) {
|
|
428
465
|
this._combineFlagAndOptionalValue = !!combine;
|
|
429
466
|
return this;
|
|
@@ -436,10 +473,12 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
436
473
|
this._allowExcessArguments = !!allowExcess;
|
|
437
474
|
return this;
|
|
438
475
|
}
|
|
476
|
+
/** Global options before subcommands only, so subcommands may reuse option names. */
|
|
439
477
|
enablePositionalOptions(positional = true) {
|
|
440
478
|
this._enablePositionalOptions = !!positional;
|
|
441
479
|
return this;
|
|
442
480
|
}
|
|
481
|
+
/** Options after the first command-argument are passed through, not parsed. */
|
|
443
482
|
passThroughOptions(passThrough = true) {
|
|
444
483
|
this._passThroughOptions = !!passThrough;
|
|
445
484
|
this._checkForBrokenPassThrough();
|
|
@@ -466,6 +505,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
466
505
|
setOptionValue(key, value) {
|
|
467
506
|
return this.setOptionValueWithSource(key, value, undefined);
|
|
468
507
|
}
|
|
508
|
+
/** `source` is default | config | env | cli | implied. */
|
|
469
509
|
setOptionValueWithSource(key, value, source) {
|
|
470
510
|
if (this._storeOptionsAsProperties)
|
|
471
511
|
this[key] = value;
|
|
@@ -477,6 +517,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
477
517
|
getOptionValueSource(key) {
|
|
478
518
|
return this._optionValueSources[key];
|
|
479
519
|
}
|
|
520
|
+
/** Globals overwrite locals, like optsWithGlobals. */
|
|
480
521
|
getOptionValueSourceWithGlobals(key) {
|
|
481
522
|
let source;
|
|
482
523
|
for (const cmd of this._getCommandAndAncestors()) {
|
|
@@ -485,6 +526,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
485
526
|
}
|
|
486
527
|
return source;
|
|
487
528
|
}
|
|
529
|
+
/** User args from argv per `from`; sets `_scriptPath` and the default program name. */
|
|
488
530
|
_prepareUserArgs(argv, parseOptions) {
|
|
489
531
|
if (argv !== undefined && !Array.isArray(argv))
|
|
490
532
|
throw new Error('first parameter to parse must be array or undefined');
|
|
@@ -494,7 +536,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
494
536
|
parseOptions.from = 'electron';
|
|
495
537
|
const execArgv = process.execArgv ?? [];
|
|
496
538
|
if (execArgv.includes('-e') || execArgv.includes('--eval') || execArgv.includes('-p') || execArgv.includes('--print')) {
|
|
497
|
-
parseOptions.from = 'eval';
|
|
539
|
+
parseOptions.from = 'eval'; // internal usage, not documented
|
|
498
540
|
}
|
|
499
541
|
}
|
|
500
542
|
if (argv === undefined)
|
|
@@ -530,10 +572,17 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
530
572
|
this._name = this._name || 'program';
|
|
531
573
|
return userArgs;
|
|
532
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Parse argv, set options and run commands. Use `parseAsync` when an action is async.
|
|
577
|
+
* With no arguments, parses process.argv and auto-detects Electron and `node --eval`.
|
|
578
|
+
*/
|
|
533
579
|
parse(argv, parseOptions) {
|
|
534
580
|
const from = this._prepareBurgee(parseOptions);
|
|
535
581
|
this._prepareForParse();
|
|
536
582
|
const userArgs = this._prepareUserArgs(argv, from);
|
|
583
|
+
// The surface check is synchronous unless a surface is actually served (completions,
|
|
584
|
+
// --mcp), so a synchronous action has run by the time parse() returns — commander's
|
|
585
|
+
// contract, which its suite asserts on after every parse(). commander-sync.test.ts.
|
|
537
586
|
this._runBurgee(() => {
|
|
538
587
|
const served = this._burgeeSurface(userArgs);
|
|
539
588
|
if (isThenable(served))
|
|
@@ -546,6 +595,8 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
546
595
|
const from = this._prepareBurgee(parseOptions);
|
|
547
596
|
this._prepareForParse();
|
|
548
597
|
const userArgs = this._prepareUserArgs(argv, from);
|
|
598
|
+
// Same synchronous start as parse(): a preAction hook has run before the promise is
|
|
599
|
+
// handed back, which commander's hook tests assert on.
|
|
549
600
|
await this._runBurgee(() => {
|
|
550
601
|
const served = this._burgeeSurface(userArgs);
|
|
551
602
|
if (isThenable(served))
|
|
@@ -556,6 +607,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
556
607
|
}
|
|
557
608
|
_prepareForParse() {
|
|
558
609
|
if (this._savedState === null) {
|
|
610
|
+
// Lone negated option (--no-foo without --foo) defaults to true, now that all options are known.
|
|
559
611
|
for (const option of this.options) {
|
|
560
612
|
if (option.negate && option.defaultValue === undefined && this.getOptionValue(option.attributeName()) === undefined) {
|
|
561
613
|
const positiveLongFlag = (option.long ?? '').replace(/^--no-/, '--');
|
|
@@ -569,6 +621,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
569
621
|
this.restoreStateBeforeParse();
|
|
570
622
|
}
|
|
571
623
|
}
|
|
624
|
+
/** Called lazily on first parse; available for subclasses to save custom state. */
|
|
572
625
|
saveStateBeforeParse() {
|
|
573
626
|
this._savedState = {
|
|
574
627
|
_name: this._name,
|
|
@@ -614,6 +667,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
614
667
|
const foundExt = SOURCE_EXT.find((ext) => fs.existsSync(`${localBin}${ext}`));
|
|
615
668
|
return foundExt ? `${localBin}${foundExt}` : undefined;
|
|
616
669
|
};
|
|
670
|
+
// Not checking for help first: can't robustly test for help flags in an external command.
|
|
617
671
|
this._checkForMissingMandatoryOptions();
|
|
618
672
|
this._checkForConflictingOptions();
|
|
619
673
|
let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
|
|
@@ -630,6 +684,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
630
684
|
}
|
|
631
685
|
if (executableDir) {
|
|
632
686
|
let localFile = findFile(executableDir, executableFile);
|
|
687
|
+
// Legacy search using the script name as prefix instead of the command name.
|
|
633
688
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
634
689
|
const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
|
|
635
690
|
if (legacyName !== this._name)
|
|
@@ -656,6 +711,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
656
711
|
proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });
|
|
657
712
|
}
|
|
658
713
|
if (!proc.killed) {
|
|
714
|
+
// Testing mainly to avoid leak warnings during unit tests with mocked spawn.
|
|
659
715
|
for (const signal of FORWARDED_SIGNALS) {
|
|
660
716
|
process.on(signal, () => {
|
|
661
717
|
if (proc.killed === false && proc.exitCode === null)
|
|
@@ -665,7 +721,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
665
721
|
}
|
|
666
722
|
const exitCallback = this._exitCallback;
|
|
667
723
|
proc.on('close', (code) => {
|
|
668
|
-
code = code ?? 1;
|
|
724
|
+
code = code ?? 1; // null when the spawned process terminated due to a signal
|
|
669
725
|
if (!exitCallback)
|
|
670
726
|
process.exit(code);
|
|
671
727
|
else
|
|
@@ -705,12 +761,14 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
705
761
|
});
|
|
706
762
|
return promiseChain;
|
|
707
763
|
}
|
|
764
|
+
/** `help foo`: invoke help directly if possible, or dispatch if necessary. */
|
|
708
765
|
_dispatchHelpCommand(subcommandName) {
|
|
709
766
|
if (!subcommandName)
|
|
710
767
|
this.help();
|
|
711
768
|
const subCommand = this._findCommand(subcommandName);
|
|
712
769
|
if (subCommand && !subCommand._executableHandler)
|
|
713
770
|
subCommand.help();
|
|
771
|
+
// Fallback to parsing the help flag to invoke the help.
|
|
714
772
|
return this._dispatchSubcommand(subcommandName ?? '', [], [
|
|
715
773
|
this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? '--help',
|
|
716
774
|
]);
|
|
@@ -726,6 +784,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
726
784
|
if (this.args.length > this.registeredArguments.length)
|
|
727
785
|
this._excessArguments(this.args);
|
|
728
786
|
}
|
|
787
|
+
/** Process this.args against registeredArguments into this.processedArgs. */
|
|
729
788
|
_processArguments() {
|
|
730
789
|
const myParseArg = (argument, value, previous) => {
|
|
731
790
|
let parsedValue = value;
|
|
@@ -758,6 +817,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
758
817
|
});
|
|
759
818
|
this.processedArgs = processedArgs;
|
|
760
819
|
}
|
|
820
|
+
/** Chain once we have a promise; call synchronously until then. */
|
|
761
821
|
_chainOrCall(promise, fn) {
|
|
762
822
|
if (isThenable(promise))
|
|
763
823
|
return promise.then(() => fn());
|
|
@@ -784,9 +844,10 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
784
844
|
}
|
|
785
845
|
return result;
|
|
786
846
|
}
|
|
847
|
+
/** Process arguments in the context of this command; returns the action result in case it is a promise. */
|
|
787
848
|
_parseCommand(operands, unknown) {
|
|
788
849
|
const parsed = this.parseOptions(unknown);
|
|
789
|
-
this._parseOptionsEnv();
|
|
850
|
+
this._parseOptionsEnv(); // after cli, so parseArg not called on both cli and env
|
|
790
851
|
this._parseOptionsImplied();
|
|
791
852
|
operands = operands.concat(parsed.operands);
|
|
792
853
|
unknown = parsed.unknown;
|
|
@@ -801,15 +862,17 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
801
862
|
return this._dispatchHelpCommand(operands[1]);
|
|
802
863
|
}
|
|
803
864
|
if (this._defaultCommandName) {
|
|
804
|
-
this._outputHelpIfRequested(unknown);
|
|
865
|
+
this._outputHelpIfRequested(unknown); // help for the default command comes from the parent
|
|
805
866
|
return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
|
|
806
867
|
}
|
|
807
868
|
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
|
|
869
|
+
// probably missing subcommand and no handler, user needs help (and exit)
|
|
808
870
|
this.help({ error: true });
|
|
809
871
|
}
|
|
810
872
|
this._outputHelpIfRequested(parsed.unknown);
|
|
811
873
|
this._checkForMissingMandatoryOptions();
|
|
812
874
|
this._checkForConflictingOptions();
|
|
875
|
+
// Not always called, to avoid masking a "better" error like unknown command.
|
|
813
876
|
const checkForUnknownOptions = () => {
|
|
814
877
|
if (parsed.unknown.length > 0)
|
|
815
878
|
this.unknownOption(parsed.unknown[0] ?? '');
|
|
@@ -823,7 +886,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
823
886
|
promiseChain = this._chainOrCall(promiseChain, () => this._runAction());
|
|
824
887
|
if (this.parent) {
|
|
825
888
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
826
|
-
this.parent?.emit(commandEvent, operands, unknown);
|
|
889
|
+
this.parent?.emit(commandEvent, operands, unknown); // legacy
|
|
827
890
|
});
|
|
828
891
|
}
|
|
829
892
|
promiseChain = this._chainOrCallHooks(promiseChain, 'postAction');
|
|
@@ -832,13 +895,15 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
832
895
|
if (this.parent?.listenerCount(commandEvent)) {
|
|
833
896
|
checkForUnknownOptions();
|
|
834
897
|
this._processArguments();
|
|
835
|
-
this.parent.emit(commandEvent, operands, unknown);
|
|
898
|
+
this.parent.emit(commandEvent, operands, unknown); // legacy
|
|
836
899
|
}
|
|
837
900
|
else if (operands.length) {
|
|
838
901
|
if (this._findCommand('*')) {
|
|
902
|
+
// legacy default command
|
|
839
903
|
return this._dispatchSubcommand('*', operands, unknown);
|
|
840
904
|
}
|
|
841
905
|
if (this.listenerCount('command:*')) {
|
|
906
|
+
// skip option check, emit event for possible misspelling suggestion
|
|
842
907
|
this.emit('command:*', operands, unknown);
|
|
843
908
|
}
|
|
844
909
|
else if (this.commands.length) {
|
|
@@ -851,11 +916,13 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
851
916
|
}
|
|
852
917
|
else if (this.commands.length) {
|
|
853
918
|
checkForUnknownOptions();
|
|
919
|
+
// This command has subcommands and nothing hooked up at this level, so display help (and exit).
|
|
854
920
|
this.help({ error: true });
|
|
855
921
|
}
|
|
856
922
|
else {
|
|
857
923
|
checkForUnknownOptions();
|
|
858
924
|
this._processArguments();
|
|
925
|
+
// fall through for caller to handle after calling .parse()
|
|
859
926
|
}
|
|
860
927
|
return undefined;
|
|
861
928
|
}
|
|
@@ -867,6 +934,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
867
934
|
_findOption(arg) {
|
|
868
935
|
return this.options.find((option) => option.is(arg));
|
|
869
936
|
}
|
|
937
|
+
/** Walks up the hierarchy so a subcommand can check after displaying help. */
|
|
870
938
|
_checkForMissingMandatoryOptions() {
|
|
871
939
|
for (const cmd of this._getCommandAndAncestors()) {
|
|
872
940
|
for (const anOption of cmd.options) {
|
|
@@ -894,6 +962,15 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
894
962
|
for (const cmd of this._getCommandAndAncestors())
|
|
895
963
|
cmd._checkForConflictingLocalOptions();
|
|
896
964
|
}
|
|
965
|
+
/**
|
|
966
|
+
* Parse options from `args`, removing known options, and return argv split into
|
|
967
|
+
* operands and unknown arguments. Side effect: stores option values on the command.
|
|
968
|
+
*
|
|
969
|
+
* --known kkk op => [op], []
|
|
970
|
+
* op --known kkk => [op], []
|
|
971
|
+
* sub --unknown uuu op => [sub], [--unknown uuu op]
|
|
972
|
+
* sub -- --unknown uuu op => [sub --unknown uuu op], []
|
|
973
|
+
*/
|
|
897
974
|
parseOptions(args) {
|
|
898
975
|
const operands = [];
|
|
899
976
|
const unknown = [];
|
|
@@ -902,10 +979,11 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
902
979
|
const negativeNumberArg = (arg) => {
|
|
903
980
|
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
|
|
904
981
|
return false;
|
|
982
|
+
// a negative number is ok unless a digit is used as an option in the command hierarchy
|
|
905
983
|
return !this._getCommandAndAncestors().some((cmd) => cmd.options.some((opt) => /^-\d$/.test(opt.short ?? '')));
|
|
906
984
|
};
|
|
907
985
|
let activeVariadicOption = null;
|
|
908
|
-
let activeGroup = null;
|
|
986
|
+
let activeGroup = null; // working through a group of short options, like -abc
|
|
909
987
|
let i = 0;
|
|
910
988
|
while (i < args.length || activeGroup) {
|
|
911
989
|
const arg = activeGroup ?? args[i++] ?? '';
|
|
@@ -932,6 +1010,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
932
1010
|
}
|
|
933
1011
|
else if (option.optional) {
|
|
934
1012
|
let value = null;
|
|
1013
|
+
// historical behaviour: the optional value is the following arg unless it is an option
|
|
935
1014
|
const next = args[i];
|
|
936
1015
|
if (i < args.length && next !== undefined && (!maybeOption(next) || negativeNumberArg(next))) {
|
|
937
1016
|
value = next;
|
|
@@ -946,6 +1025,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
946
1025
|
continue;
|
|
947
1026
|
}
|
|
948
1027
|
}
|
|
1028
|
+
// Combined short options: eat the first one if known.
|
|
949
1029
|
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
950
1030
|
const option = this._findOption(`-${arg[1]}`);
|
|
951
1031
|
if (option) {
|
|
@@ -959,6 +1039,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
959
1039
|
continue;
|
|
960
1040
|
}
|
|
961
1041
|
}
|
|
1042
|
+
// Known long flag with value, like --foo=bar
|
|
962
1043
|
if (/^--[^=]+=/.test(arg)) {
|
|
963
1044
|
const index = arg.indexOf('=');
|
|
964
1045
|
const option = this._findOption(arg.slice(0, index));
|
|
@@ -967,9 +1048,13 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
967
1048
|
continue;
|
|
968
1049
|
}
|
|
969
1050
|
}
|
|
1051
|
+
// Not recognised by this command: command-argument, subcommand option, unknown option, or help.
|
|
1052
|
+
// An unknown option makes everything after it unknown too, for a subcommand to reprocess.
|
|
1053
|
+
// A negative number in a leaf command is not an unknown option.
|
|
970
1054
|
if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
|
|
971
1055
|
dest = unknown;
|
|
972
1056
|
}
|
|
1057
|
+
// Positional options: stop processing our options at a subcommand.
|
|
973
1058
|
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
|
|
974
1059
|
if (this._findCommand(arg)) {
|
|
975
1060
|
operands.push(arg);
|
|
@@ -985,6 +1070,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
985
1070
|
break;
|
|
986
1071
|
}
|
|
987
1072
|
}
|
|
1073
|
+
// Pass-through options: stop processing options at the first command-argument.
|
|
988
1074
|
if (this._passThroughOptions) {
|
|
989
1075
|
dest.push(arg, ...args.slice(i));
|
|
990
1076
|
break;
|
|
@@ -993,6 +1079,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
993
1079
|
}
|
|
994
1080
|
return { operands, unknown };
|
|
995
1081
|
}
|
|
1082
|
+
/** Local option values as key-value pairs. */
|
|
996
1083
|
opts() {
|
|
997
1084
|
if (this._storeOptionsAsProperties) {
|
|
998
1085
|
const result = {};
|
|
@@ -1004,9 +1091,11 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1004
1091
|
}
|
|
1005
1092
|
return this._optionValues;
|
|
1006
1093
|
}
|
|
1094
|
+
/** Merged local and global option values; globals overwrite locals. */
|
|
1007
1095
|
optsWithGlobals() {
|
|
1008
1096
|
return this._getCommandAndAncestors().reduce((combined, cmd) => Object.assign(combined, cmd.opts()), {});
|
|
1009
1097
|
}
|
|
1098
|
+
/** Display an error message and exit (or call exitOverride). */
|
|
1010
1099
|
error(message, errorOptions) {
|
|
1011
1100
|
this._outputConfiguration.outputError(`${message}\n`, this._outputConfiguration.writeErr);
|
|
1012
1101
|
if (typeof this._showHelpAfterError === 'string') {
|
|
@@ -1021,10 +1110,12 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1021
1110
|
const code = config.code || 'commander.error';
|
|
1022
1111
|
this._exit(exitCode, code, message);
|
|
1023
1112
|
}
|
|
1113
|
+
/** Apply environment variables to options that have no value from the cli or client code. */
|
|
1024
1114
|
_parseOptionsEnv() {
|
|
1025
1115
|
for (const option of this.options) {
|
|
1026
1116
|
if (option.envVar && option.envVar in process.env) {
|
|
1027
1117
|
const optionKey = option.attributeName();
|
|
1118
|
+
// Do not overwrite cli values or values from an unknown (client-code) source.
|
|
1028
1119
|
if (this.getOptionValue(optionKey) === undefined || ENV_SOURCES.includes(this.getOptionValueSource(optionKey) ?? '')) {
|
|
1029
1120
|
if (option.required || option.optional)
|
|
1030
1121
|
this.emit(`optionEnv:${option.name()}`, process.env[option.envVar]);
|
|
@@ -1034,6 +1125,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1034
1125
|
}
|
|
1035
1126
|
}
|
|
1036
1127
|
}
|
|
1128
|
+
/** Apply implied option values where the option is undefined or at its default. */
|
|
1037
1129
|
_parseOptionsImplied() {
|
|
1038
1130
|
const dualHelper = new DualOptions(this.options);
|
|
1039
1131
|
const hasCustomOptionValue = (optionKey) => this.getOptionValue(optionKey) !== undefined && !IMPLIED_SOURCES.includes(this.getOptionValueSource(optionKey) ?? '');
|
|
@@ -1057,6 +1149,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1057
1149
|
this.error(`error: required option '${option.flags}' not specified`, { code: 'commander.missingMandatoryOptionValue' });
|
|
1058
1150
|
}
|
|
1059
1151
|
_conflictingOption(option, conflictingOption) {
|
|
1152
|
+
// The caller does not know whether a negated option is the source of the value; take an educated guess.
|
|
1060
1153
|
const findBestOptionFromValue = (candidate) => {
|
|
1061
1154
|
const optionKey = candidate.attributeName();
|
|
1062
1155
|
const optionValue = this.getOptionValue(optionKey);
|
|
@@ -1084,6 +1177,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1084
1177
|
return;
|
|
1085
1178
|
let suggestion = '';
|
|
1086
1179
|
if (flag.startsWith('--') && this._showSuggestionAfterError) {
|
|
1180
|
+
// Looping to pick up the global options too.
|
|
1087
1181
|
let candidateFlags = [];
|
|
1088
1182
|
let command = this;
|
|
1089
1183
|
do {
|
|
@@ -1160,6 +1254,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1160
1254
|
let command = this;
|
|
1161
1255
|
const last = this.commands[this.commands.length - 1];
|
|
1162
1256
|
if (this.commands.length !== 0 && last?._executableHandler) {
|
|
1257
|
+
// assume adding an alias for the last added executable subcommand, rather than this
|
|
1163
1258
|
command = last;
|
|
1164
1259
|
}
|
|
1165
1260
|
if (alias === command._name)
|
|
@@ -1223,6 +1318,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1223
1318
|
if (this._defaultCommandGroup && !cmd.helpGroup())
|
|
1224
1319
|
cmd.helpGroup(this._defaultCommandGroup);
|
|
1225
1320
|
}
|
|
1321
|
+
/** Name the command from a script filename, such as process.argv[1] or import.meta.filename. */
|
|
1226
1322
|
nameFromFilename(filename) {
|
|
1227
1323
|
this._name = path.basename(filename, path.extname(filename));
|
|
1228
1324
|
return this;
|
|
@@ -1269,6 +1365,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1269
1365
|
};
|
|
1270
1366
|
return { error, write, hasColors, helpWidth };
|
|
1271
1367
|
}
|
|
1368
|
+
/** Output built-in help plus any text added with `addHelpText`. */
|
|
1272
1369
|
outputHelp(contextOptions) {
|
|
1273
1370
|
let deprecatedCallback;
|
|
1274
1371
|
if (typeof contextOptions === 'function') {
|
|
@@ -1290,16 +1387,17 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1290
1387
|
outputContext.write(String(helpInformation));
|
|
1291
1388
|
const helpLong = this._getHelpOption()?.long;
|
|
1292
1389
|
if (helpLong)
|
|
1293
|
-
this.emit(helpLong);
|
|
1390
|
+
this.emit(helpLong); // deprecated
|
|
1294
1391
|
this.emit('afterHelp', eventContext);
|
|
1295
1392
|
for (const command of this._getCommandAndAncestors())
|
|
1296
1393
|
command.emit('afterAllHelp', eventContext);
|
|
1297
1394
|
}
|
|
1395
|
+
/** Customise the built-in help option, or pass false to disable it. */
|
|
1298
1396
|
helpOption(flags, description) {
|
|
1299
1397
|
if (typeof flags === 'boolean') {
|
|
1300
1398
|
if (flags) {
|
|
1301
1399
|
if (this._helpOption === null)
|
|
1302
|
-
this._helpOption = undefined;
|
|
1400
|
+
this._helpOption = undefined; // reenable
|
|
1303
1401
|
if (this._defaultOptionGroup) {
|
|
1304
1402
|
const helpOption = this._getHelpOption();
|
|
1305
1403
|
if (helpOption)
|
|
@@ -1307,7 +1405,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1307
1405
|
}
|
|
1308
1406
|
}
|
|
1309
1407
|
else {
|
|
1310
|
-
this._helpOption = null;
|
|
1408
|
+
this._helpOption = null; // disable
|
|
1311
1409
|
}
|
|
1312
1410
|
return this;
|
|
1313
1411
|
}
|
|
@@ -1316,6 +1414,7 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1316
1414
|
this._initOptionGroup(this._helpOption);
|
|
1317
1415
|
return this;
|
|
1318
1416
|
}
|
|
1417
|
+
/** Lazily created; null once disabled with `helpOption(false)`. */
|
|
1319
1418
|
_getHelpOption() {
|
|
1320
1419
|
if (this._helpOption === undefined)
|
|
1321
1420
|
this.helpOption(undefined, undefined);
|
|
@@ -1326,13 +1425,16 @@ Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
|
1326
1425
|
this._initOptionGroup(option);
|
|
1327
1426
|
return this;
|
|
1328
1427
|
}
|
|
1428
|
+
/** Output help and exit. */
|
|
1329
1429
|
help(contextOptions) {
|
|
1330
1430
|
this.outputHelp(contextOptions);
|
|
1331
1431
|
let exitCode = Number(process.exitCode ?? 0);
|
|
1332
1432
|
if (exitCode === 0 && contextOptions && typeof contextOptions !== 'function' && contextOptions.error)
|
|
1333
1433
|
exitCode = 1;
|
|
1434
|
+
// message: not all displayed text is available, so only a placeholder is passed.
|
|
1334
1435
|
this._exit(exitCode, 'commander.help', '(outputHelp)');
|
|
1335
1436
|
}
|
|
1437
|
+
/** Extra help text: 'before'/'after' for this command, 'beforeAll'/'afterAll' for its subcommands too. */
|
|
1336
1438
|
addHelpText(position, text) {
|
|
1337
1439
|
if (!HELP_POSITIONS.includes(position)) {
|
|
1338
1440
|
throw new Error(`Unexpected value for position to addHelpText.
|
|
@@ -1352,12 +1454,17 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1352
1454
|
this._exit(0, 'commander.helpDisplayed', '(outputHelp)');
|
|
1353
1455
|
}
|
|
1354
1456
|
}
|
|
1457
|
+
// ───── burgee: the manifest projection, plugins, `--json` and the injected seam ─────
|
|
1355
1458
|
_root() {
|
|
1356
1459
|
let command = this;
|
|
1357
1460
|
while (command.parent)
|
|
1358
1461
|
command = command.parent;
|
|
1359
1462
|
return command;
|
|
1360
1463
|
}
|
|
1464
|
+
/**
|
|
1465
|
+
* The manifest every surface reads. Projected from the command tree on each access,
|
|
1466
|
+
* so it is never stale; plugin-contributed nodes are kept across projections.
|
|
1467
|
+
*/
|
|
1361
1468
|
get manifest() {
|
|
1362
1469
|
const root = this._root();
|
|
1363
1470
|
root._manifest ??= new Manifest();
|
|
@@ -1389,6 +1496,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1389
1496
|
};
|
|
1390
1497
|
visit(this, [rootName]);
|
|
1391
1498
|
}
|
|
1499
|
+
/** Options as the manifest describes them, on a null-prototype record. */
|
|
1392
1500
|
_optionSpecs() {
|
|
1393
1501
|
const specs = Object.create(null);
|
|
1394
1502
|
for (const option of this.options) {
|
|
@@ -1407,21 +1515,33 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1407
1515
|
}
|
|
1408
1516
|
return specs;
|
|
1409
1517
|
}
|
|
1518
|
+
/** burgee: declare what the command does to the world (N6). This is what exposes it as an MCP tool (N2). */
|
|
1410
1519
|
effects(value) {
|
|
1411
1520
|
this._effects = value;
|
|
1412
1521
|
return this;
|
|
1413
1522
|
}
|
|
1523
|
+
/**
|
|
1524
|
+
* burgee: mark the command deprecated (M5). Help and `--schema` show it; running it prints
|
|
1525
|
+
* `warning: 'old' is deprecated, use 'new'` on stderr once and goes on, exit unchanged.
|
|
1526
|
+
*/
|
|
1414
1527
|
deprecate(use) {
|
|
1415
1528
|
this._deprecated = use ?? true;
|
|
1416
1529
|
return this;
|
|
1417
1530
|
}
|
|
1531
|
+
/**
|
|
1532
|
+
* burgee: `--schema` and `--mcp` on a commander-syntax program, from its manifest (J2).
|
|
1533
|
+
* Only when the program declares neither option itself; `--mcp` runs commands through
|
|
1534
|
+
* this very program with the streams captured, so tool results are the `--json` envelope.
|
|
1535
|
+
*/
|
|
1418
1536
|
_burgeeSurface(userArgs) {
|
|
1419
1537
|
const root = this._root();
|
|
1538
|
+
// Any command in the tree that declares the flag keeps it: the surface is additive only.
|
|
1420
1539
|
const declared = (flag, at = root) => at._findOption(flag) !== undefined || at.commands.some((sub) => declared(flag, sub));
|
|
1421
1540
|
const terminator = userArgs.indexOf('--');
|
|
1422
1541
|
const head = terminator === -1 ? userArgs : userArgs.slice(0, terminator);
|
|
1423
1542
|
if (head[0] === 'completion' && root._findCommand('completion') === undefined) {
|
|
1424
|
-
|
|
1543
|
+
// Loaded on this command only (K6), exactly as the engine does.
|
|
1544
|
+
return import('../completions.js').then(({ renderCompletion, renderFigSpec, SHELLS }) => {
|
|
1425
1545
|
const shell = head[1] ?? '';
|
|
1426
1546
|
if (shell === 'fig') {
|
|
1427
1547
|
root._outputConfiguration.writeOut(`${JSON.stringify(renderFigSpec(this.manifest), null, 2)}\n`);
|
|
@@ -1437,10 +1557,13 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1437
1557
|
}
|
|
1438
1558
|
return this._burgeeSurfaceRest(head, declared);
|
|
1439
1559
|
}
|
|
1560
|
+
/** The surfaces after `completion`: `--schema` is synchronous, `--mcp` serves until stdin closes. */
|
|
1440
1561
|
_burgeeSurfaceRest(head, declared) {
|
|
1441
1562
|
const root = this._root();
|
|
1442
1563
|
if (head.includes('--schema') && !declared('--schema')) {
|
|
1443
|
-
|
|
1564
|
+
// R1, and the same escape hatch the engine has: `--schema` is burgee's surface, not
|
|
1565
|
+
// commander's, so it answers to E-floor byte discipline rather than to the host.
|
|
1566
|
+
root._outputConfiguration.writeOut(`${machineJson(schemaOf(this.manifest), head)}\n`);
|
|
1444
1567
|
return true;
|
|
1445
1568
|
}
|
|
1446
1569
|
if (head[0] === '--mcp' && !declared('--mcp')) {
|
|
@@ -1455,10 +1578,12 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1455
1578
|
}
|
|
1456
1579
|
return false;
|
|
1457
1580
|
}
|
|
1581
|
+
/** Additive, and the point of the whole exercise: plugins commander has never had (#2505, unlanded). */
|
|
1458
1582
|
use(plugin) {
|
|
1459
1583
|
this.manifest.use(plugin);
|
|
1460
1584
|
return this;
|
|
1461
1585
|
}
|
|
1586
|
+
/** Inject the streams and the exit for one parse; returns commander's own parse options. */
|
|
1462
1587
|
_prepareBurgee(parseOptions) {
|
|
1463
1588
|
if (parseOptions === undefined)
|
|
1464
1589
|
return undefined;
|
|
@@ -1485,6 +1610,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1485
1610
|
visit(root);
|
|
1486
1611
|
return from;
|
|
1487
1612
|
}
|
|
1613
|
+
/** In burgee mode the whole run settles to one E1 exit; otherwise commander's behaviour, untouched. */
|
|
1488
1614
|
_runBurgee(run) {
|
|
1489
1615
|
const root = this._root();
|
|
1490
1616
|
const burgee = root._burgee;
|
|
@@ -1521,6 +1647,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1521
1647
|
return undefined;
|
|
1522
1648
|
}
|
|
1523
1649
|
}
|
|
1650
|
+
/** `--json` that no command in the chain declared is burgee's envelope, not an unknown option. */
|
|
1524
1651
|
_takeJson(unknown) {
|
|
1525
1652
|
const terminator = unknown.indexOf('--');
|
|
1526
1653
|
const index = unknown.indexOf('--json');
|
|
@@ -1533,6 +1660,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1533
1660
|
root._burgee ??= { exit: undefined, json: false };
|
|
1534
1661
|
root._burgee.json = true;
|
|
1535
1662
|
}
|
|
1663
|
+
/** The action, wrapped in the plugin hooks and followed by the envelope or the rendering. */
|
|
1536
1664
|
_runAction() {
|
|
1537
1665
|
const handler = this._actionHandler;
|
|
1538
1666
|
if (handler === null)
|
|
@@ -1555,6 +1683,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1555
1683
|
settle(value);
|
|
1556
1684
|
});
|
|
1557
1685
|
}
|
|
1686
|
+
/** burgee (M5): once per process, on stderr; only for a command that asked, so commander's own output is untouched. */
|
|
1558
1687
|
_warnDeprecated() {
|
|
1559
1688
|
if (this._deprecated === undefined || this._deprecated === false || this._deprecationWarned)
|
|
1560
1689
|
return;
|
|
@@ -1562,6 +1691,7 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1562
1691
|
const use = typeof this._deprecated === 'string' ? `, use '${this._deprecated}'` : '';
|
|
1563
1692
|
this._outputConfiguration.writeErr(`warning: '${this.name()}' is deprecated${use}\n`);
|
|
1564
1693
|
}
|
|
1694
|
+
/** burgee: where every option value came from, from commander's own value sources (V3). */
|
|
1565
1695
|
_provenance() {
|
|
1566
1696
|
const out = {};
|
|
1567
1697
|
const names = { cli: 'flag', env: 'env', config: 'config', default: 'default', implied: 'implied' };
|
|
@@ -1584,7 +1714,9 @@ Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
|
1584
1714
|
this._outputConfiguration.writeOut(text);
|
|
1585
1715
|
}
|
|
1586
1716
|
}
|
|
1717
|
+
/** Bump inspector ports so a spawned subcommand does not collide with the parent. */
|
|
1587
1718
|
function incrementNodeInspectorPort(args) {
|
|
1719
|
+
// --inspect[=[host:]port], --inspect-brk[=[host:]port], --inspect-port=[host:]port
|
|
1588
1720
|
return args.map((arg) => {
|
|
1589
1721
|
if (!arg.startsWith('--inspect'))
|
|
1590
1722
|
return arg;
|
|
@@ -1612,6 +1744,10 @@ function incrementNodeInspectorPort(args) {
|
|
|
1612
1744
|
return arg;
|
|
1613
1745
|
});
|
|
1614
1746
|
}
|
|
1747
|
+
/**
|
|
1748
|
+
* The common colour conventions: NO_COLOR and FORCE_COLOR=0/false disable, FORCE_COLOR
|
|
1749
|
+
* and CLICOLOR_FORCE enable, otherwise undecided (the stream's TTY-ness decides).
|
|
1750
|
+
*/
|
|
1615
1751
|
export function useColor() {
|
|
1616
1752
|
if (process.env['NO_COLOR'] || process.env['FORCE_COLOR'] === '0' || process.env['FORCE_COLOR'] === 'false')
|
|
1617
1753
|
return false;
|
|
@@ -1619,3 +1755,4 @@ export function useColor() {
|
|
|
1619
1755
|
return true;
|
|
1620
1756
|
return undefined;
|
|
1621
1757
|
}
|
|
1758
|
+
//# sourceMappingURL=command.js.map
|