@guanghechen/commander 4.7.2 → 4.7.3

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/lib/esm/node.mjs CHANGED
@@ -305,6 +305,30 @@ function parsePrimitiveNumber(rawValue) {
305
305
  }
306
306
  return value;
307
307
  }
308
+ function normalizeSubcommandNameForDistance(name) {
309
+ return camelToKebabCase$1(name).toLowerCase();
310
+ }
311
+ function levenshteinDistance(left, right) {
312
+ if (left === right) {
313
+ return 0;
314
+ }
315
+ if (left.length === 0) {
316
+ return right.length;
317
+ }
318
+ if (right.length === 0) {
319
+ return left.length;
320
+ }
321
+ let prev = Array.from({ length: right.length + 1 }, (_, i) => i);
322
+ for (let i = 0; i < left.length; i += 1) {
323
+ const current = [i + 1];
324
+ for (let j = 0; j < right.length; j += 1) {
325
+ const substitutionCost = left[i] === right[j] ? 0 : 1;
326
+ current[j + 1] = Math.min(current[j] + 1, prev[j + 1] + 1, prev[j] + substitutionCost);
327
+ }
328
+ prev = current;
329
+ }
330
+ return prev[right.length];
331
+ }
308
332
  function tokenizeLongOption(arg, commandPath) {
309
333
  const eqIdx = arg.indexOf('=');
310
334
  const namePart = eqIdx !== -1 ? arg.slice(0, eqIdx) : arg;
@@ -707,7 +731,10 @@ class Command {
707
731
  const kebabLong = camelToKebabCase$1(opt.long);
708
732
  let sig = opt.short ? `-${opt.short}, ` : ' ';
709
733
  sig += `--${kebabLong}`;
710
- if (opt.args !== 'none') {
734
+ if (opt.args === 'optional') {
735
+ sig += ' [value]';
736
+ }
737
+ else if (opt.args !== 'none') {
711
738
  sig += ' <value>';
712
739
  }
713
740
  let desc = opt.desc;
@@ -1326,6 +1353,14 @@ class Command {
1326
1353
  consumed.push(tokens[i]);
1327
1354
  }
1328
1355
  }
1356
+ else if (opt.args === 'optional') {
1357
+ if (!token.resolved.includes('=') &&
1358
+ i + 1 < tokens.length &&
1359
+ tokens[i + 1].type === 'none') {
1360
+ i += 1;
1361
+ consumed.push(tokens[i]);
1362
+ }
1363
+ }
1329
1364
  else if (opt.args === 'variadic') {
1330
1365
  if (!token.resolved.includes('=')) {
1331
1366
  while (i + 1 < tokens.length && tokens[i + 1].type === 'none') {
@@ -1351,6 +1386,12 @@ class Command {
1351
1386
  consumed.push(tokens[i]);
1352
1387
  }
1353
1388
  }
1389
+ else if (opt.args === 'optional') {
1390
+ if (i + 1 < tokens.length && tokens[i + 1].type === 'none') {
1391
+ i += 1;
1392
+ consumed.push(tokens[i]);
1393
+ }
1394
+ }
1354
1395
  else if (opt.args === 'variadic') {
1355
1396
  while (i + 1 < tokens.length && tokens[i + 1].type === 'none') {
1356
1397
  i += 1;
@@ -1392,6 +1433,7 @@ class Command {
1392
1433
  leafLocalOpts[opt.long] = leafParsedOpts[opt.long];
1393
1434
  }
1394
1435
  }
1436
+ leafCommand.#assertUnknownSubcommand(ctx.sources.user.argv);
1395
1437
  const rawArgStrings = [...argTokens.map(t => t.original), ...restArgs];
1396
1438
  const { args, rawArgs } = leafCommand.#parseArguments(rawArgStrings);
1397
1439
  const parseCtx = {
@@ -1474,6 +1516,23 @@ class Command {
1474
1516
  i += 1;
1475
1517
  continue;
1476
1518
  }
1519
+ if (opt.args === 'optional') {
1520
+ const eqIdx = token.resolved.indexOf('=');
1521
+ if (eqIdx !== -1) {
1522
+ opts[opt.long] = this.#convertValue(opt, token.resolved.slice(eqIdx + 1));
1523
+ i += 1;
1524
+ continue;
1525
+ }
1526
+ if (i + 1 < tokens.length && tokens[i + 1].type === 'none') {
1527
+ opts[opt.long] = this.#convertValue(opt, tokens[i + 1].original);
1528
+ i += 1;
1529
+ }
1530
+ else {
1531
+ opts[opt.long] = undefined;
1532
+ }
1533
+ i += 1;
1534
+ continue;
1535
+ }
1477
1536
  if (opt.args === 'variadic') {
1478
1537
  const values = Array.isArray(opts[opt.long]) ? opts[opt.long] : [];
1479
1538
  const eqIdx = token.resolved.indexOf('=');
@@ -1493,7 +1552,7 @@ class Command {
1493
1552
  i += 1;
1494
1553
  }
1495
1554
  for (const opt of allOptions) {
1496
- if (opt.required && opts[opt.long] === undefined) {
1555
+ if (opt.required && !Object.prototype.hasOwnProperty.call(opts, opt.long)) {
1497
1556
  throw new CommanderError('MissingRequired', `missing required option "--${camelToKebabCase$1(opt.long)}"`, this.#getCommandPath());
1498
1557
  }
1499
1558
  }
@@ -1530,6 +1589,9 @@ class Command {
1530
1589
  #parseArguments(rawArgs) {
1531
1590
  const argumentDefs = this.#arguments;
1532
1591
  const args = {};
1592
+ if (argumentDefs.length === 0 && rawArgs.length > 0) {
1593
+ throw new CommanderError('UnexpectedArgument', `unexpected argument "${rawArgs[0]}"`, this.#getCommandPath());
1594
+ }
1533
1595
  const missing = [];
1534
1596
  let remaining = rawArgs.length;
1535
1597
  for (const def of argumentDefs) {
@@ -1570,25 +1632,23 @@ class Command {
1570
1632
  }
1571
1633
  if (def.kind === 'some') {
1572
1634
  const rest = rawArgs.slice(index);
1573
- if (rest.length === 0) {
1574
- throw new CommanderError('MissingRequiredArgument', `missing required argument(s): ${def.name}`, this.#getCommandPath());
1575
- }
1576
1635
  args[def.name] = rest.map(raw => this.#convertArgument(def, raw));
1577
1636
  index = rawArgs.length;
1578
1637
  break;
1579
1638
  }
1580
- const raw = rawArgs[index];
1581
- if (raw === undefined) {
1582
- if (def.kind === 'optional') {
1639
+ if (def.kind === 'optional') {
1640
+ const raw = rawArgs[index];
1641
+ if (raw === undefined) {
1583
1642
  args[def.name] = def.default ?? undefined;
1584
1643
  continue;
1585
1644
  }
1586
- throw new CommanderError('MissingRequiredArgument', `missing required argument(s): ${def.name}`, this.#getCommandPath());
1587
- }
1588
- else {
1589
1645
  args[def.name] = this.#convertArgument(def, raw);
1590
1646
  index += 1;
1647
+ continue;
1591
1648
  }
1649
+ const raw = rawArgs[index];
1650
+ args[def.name] = this.#convertArgument(def, raw);
1651
+ index += 1;
1592
1652
  }
1593
1653
  const hasRestArgument = argumentDefs.some(a => a.kind === 'variadic' || a.kind === 'some');
1594
1654
  if (!hasRestArgument && index < rawArgs.length) {
@@ -1622,6 +1682,50 @@ class Command {
1622
1682
  }
1623
1683
  return value;
1624
1684
  }
1685
+ #assertUnknownSubcommand(userTailArgv) {
1686
+ if (this.#subcommandsList.length === 0) {
1687
+ return;
1688
+ }
1689
+ const token = userTailArgv[0];
1690
+ if (token === undefined || token.startsWith('-') || token === 'help') {
1691
+ return;
1692
+ }
1693
+ if (this.#findSubcommandEntry(token) !== undefined) {
1694
+ return;
1695
+ }
1696
+ const hints = [];
1697
+ if (this.#arguments.length === 0) {
1698
+ hints.push(`Hint: command "${this.#getCommandPath()}" does not accept positional arguments.`);
1699
+ }
1700
+ const candidate = this.#resolveDidYouMeanSubcommandName(token);
1701
+ if (candidate !== undefined) {
1702
+ hints.push(`Hint: did you mean "${candidate}"?`);
1703
+ }
1704
+ const details = hints.length > 0 ? `\n${hints.join('\n')}` : '';
1705
+ throw new CommanderError('UnknownSubcommand', `unknown subcommand "${token}" for command "${this.#getCommandPath()}"${details}`, this.#getCommandPath());
1706
+ }
1707
+ #resolveDidYouMeanSubcommandName(token) {
1708
+ const source = normalizeSubcommandNameForDistance(token);
1709
+ let minDistance = Number.POSITIVE_INFINITY;
1710
+ let bestName;
1711
+ let isUniqueBest = false;
1712
+ for (const entry of this.#subcommandsList) {
1713
+ const target = normalizeSubcommandNameForDistance(entry.name);
1714
+ const distance = levenshteinDistance(source, target);
1715
+ if (distance < minDistance) {
1716
+ minDistance = distance;
1717
+ bestName = entry.name;
1718
+ isUniqueBest = true;
1719
+ }
1720
+ else if (distance === minDistance) {
1721
+ isUniqueBest = false;
1722
+ }
1723
+ }
1724
+ if (minDistance <= 2 && isUniqueBest) {
1725
+ return bestName;
1726
+ }
1727
+ return undefined;
1728
+ }
1625
1729
  #hasUserOption(long) {
1626
1730
  return this.#options.some(option => option.long === long);
1627
1731
  }
@@ -1665,11 +1769,9 @@ class Command {
1665
1769
  return optionPolicyMap;
1666
1770
  }
1667
1771
  #mustGetOptionPolicy(optionPolicyMap, cmd) {
1668
- const policy = optionPolicyMap.get(cmd);
1669
- if (policy !== undefined) {
1670
- return policy;
1671
- }
1672
- throw new CommanderError('ConfigurationError', `missing option policy for command "${cmd.#getCommandPath()}"`, this.#getCommandPath());
1772
+ const policy = optionPolicyMap.get(cmd) ?? cmd.#resolveOptionPolicy();
1773
+ optionPolicyMap.set(cmd, policy);
1774
+ return policy;
1673
1775
  }
1674
1776
  #validateMergedShortOptions(chain, optionPolicyMap) {
1675
1777
  const mergedByLong = new Map();
@@ -1698,7 +1800,10 @@ class Command {
1698
1800
  throw new CommanderError('ConfigurationError', `boolean option "--${opt.long}" must have args: 'none'`, this.#getCommandPath());
1699
1801
  }
1700
1802
  if ((opt.type === 'string' || opt.type === 'number') && opt.args === 'none') {
1701
- throw new CommanderError('ConfigurationError', `${opt.type} option "--${opt.long}" must have args: 'required' or 'variadic'`, this.#getCommandPath());
1803
+ throw new CommanderError('ConfigurationError', `${opt.type} option "--${opt.long}" must have args: 'required', 'optional', or 'variadic'`, this.#getCommandPath());
1804
+ }
1805
+ if (opt.type === 'number' && opt.args === 'optional') {
1806
+ throw new CommanderError('ConfigurationError', `number option "--${opt.long}" does not support args: 'optional'`, this.#getCommandPath());
1702
1807
  }
1703
1808
  if (opt.long.startsWith('no')) {
1704
1809
  throw new CommanderError('ConfigurationError', `option long name cannot start with "no": "${opt.long}"`, this.#getCommandPath());
@@ -1715,6 +1820,9 @@ class Command {
1715
1820
  if (opt.type === 'boolean' && opt.required) {
1716
1821
  throw new CommanderError('ConfigurationError', `boolean option "--${opt.long}" cannot be required`, this.#getCommandPath());
1717
1822
  }
1823
+ if (opt.required && opt.args !== 'required') {
1824
+ throw new CommanderError('ConfigurationError', `required option "--${opt.long}" must use args: 'required'`, this.#getCommandPath());
1825
+ }
1718
1826
  }
1719
1827
  #checkOptionUniqueness(opt) {
1720
1828
  if (this.#options.some(o => o.long === opt.long)) {
@@ -2023,6 +2131,35 @@ class Coerce {
2023
2131
  function camelToKebabCase(str) {
2024
2132
  return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
2025
2133
  }
2134
+ const COMPLETION_SHELL_STATE = Symbol('completion-shell-state');
2135
+ function getCommandPath(ctx) {
2136
+ const names = ctx.chain
2137
+ .map(command => command.name)
2138
+ .filter((name) => Boolean(name));
2139
+ if (names.length > 0) {
2140
+ return names.join(' ');
2141
+ }
2142
+ return ctx.cmd.name ?? 'command';
2143
+ }
2144
+ function getCompletionShellState(ctx) {
2145
+ const host = ctx;
2146
+ host[COMPLETION_SHELL_STATE] ??= {};
2147
+ return host[COMPLETION_SHELL_STATE];
2148
+ }
2149
+ function registerCompletionShell(ctx, shell) {
2150
+ const state = getCompletionShellState(ctx);
2151
+ if (state.shell !== undefined && state.shell !== shell) {
2152
+ throw new CommanderError('OptionConflict', 'options "--bash", "--fish", and "--pwsh" are mutually exclusive', getCommandPath(ctx));
2153
+ }
2154
+ state.shell = shell;
2155
+ }
2156
+ function mustGetCompletionShell(ctx) {
2157
+ const state = getCompletionShellState(ctx);
2158
+ if (state.shell === undefined) {
2159
+ throw new CommanderError('MissingRequired', 'missing required option: one of "--bash", "--fish", or "--pwsh"', getCommandPath(ctx));
2160
+ }
2161
+ return state.shell;
2162
+ }
2026
2163
  class CompletionCommand extends Command {
2027
2164
  constructor(root, config = {}) {
2028
2165
  const programName = config.programName ?? root.name ?? 'program';
@@ -2036,45 +2173,45 @@ class CompletionCommand extends Command {
2036
2173
  type: 'boolean',
2037
2174
  args: 'none',
2038
2175
  desc: 'Generate Bash completion script',
2176
+ apply: (value, ctx) => {
2177
+ if (value === true) {
2178
+ registerCompletionShell(ctx, 'bash');
2179
+ }
2180
+ },
2039
2181
  })
2040
2182
  .option({
2041
2183
  long: 'fish',
2042
2184
  type: 'boolean',
2043
2185
  args: 'none',
2044
2186
  desc: 'Generate Fish completion script',
2187
+ apply: (value, ctx) => {
2188
+ if (value === true) {
2189
+ registerCompletionShell(ctx, 'fish');
2190
+ }
2191
+ },
2045
2192
  })
2046
2193
  .option({
2047
2194
  long: 'pwsh',
2048
2195
  type: 'boolean',
2049
2196
  args: 'none',
2050
2197
  desc: 'Generate PowerShell completion script',
2198
+ apply: (value, ctx) => {
2199
+ if (value === true) {
2200
+ registerCompletionShell(ctx, 'pwsh');
2201
+ }
2202
+ mustGetCompletionShell(ctx);
2203
+ },
2051
2204
  })
2052
2205
  .option({
2053
2206
  long: 'write',
2054
2207
  short: 'w',
2055
2208
  type: 'string',
2056
- args: 'required',
2057
- desc: 'Write to file (use shell default path if empty)',
2058
- default: undefined,
2209
+ args: 'optional',
2210
+ desc: 'Write to file (use shell default path when value is omitted or empty)',
2059
2211
  })
2060
- .action(({ opts }) => {
2212
+ .action(({ opts, ctx }) => {
2061
2213
  const meta = root.getCompletionMeta();
2062
- const selectedShells = [
2063
- opts['bash'] && 'bash',
2064
- opts['fish'] && 'fish',
2065
- opts['pwsh'] && 'pwsh',
2066
- ].filter(Boolean);
2067
- if (selectedShells.length === 0) {
2068
- console.error('Please specify a shell: --bash, --fish, or --pwsh');
2069
- process.exit(1);
2070
- return;
2071
- }
2072
- if (selectedShells.length > 1) {
2073
- console.error('Please specify only one shell option');
2074
- process.exit(1);
2075
- return;
2076
- }
2077
- const shell = selectedShells[0];
2214
+ const shell = mustGetCompletionShell(ctx);
2078
2215
  let script;
2079
2216
  switch (shell) {
2080
2217
  case 'bash':
@@ -2087,8 +2224,9 @@ class CompletionCommand extends Command {
2087
2224
  script = new PwshCompletion(meta, programName).generate();
2088
2225
  break;
2089
2226
  }
2090
- const writeOpt = opts['write'];
2091
- if (writeOpt !== undefined) {
2227
+ const hasWrite = Object.prototype.hasOwnProperty.call(opts, 'write');
2228
+ if (hasWrite) {
2229
+ const writeOpt = opts['write'];
2092
2230
  const filePath = typeof writeOpt === 'string' && writeOpt !== '' ? writeOpt : paths[shell];
2093
2231
  const expandedPath = expandHome(filePath);
2094
2232
  const dir = path.dirname(expandedPath);
@@ -29,13 +29,14 @@ interface ICommandToken {
29
29
  /** Option value type */
30
30
  type ICommandOptionType = 'boolean' | 'number' | 'string';
31
31
  /** Option argument mode */
32
- type ICommandOptionArgs = 'none' | 'required' | 'variadic';
32
+ type ICommandOptionArgs = 'none' | 'required' | 'optional' | 'variadic';
33
33
  /**
34
34
  * Option configuration.
35
35
  *
36
36
  * `type` and `args` must be specified together. Valid combinations:
37
37
  * - boolean + none → boolean
38
38
  * - string + required → string
39
+ * - string + optional → string | undefined
39
40
  * - number + required → number
40
41
  * - string + variadic → string[]
41
42
  * - number + variadic → number[]
@@ -92,54 +92,16 @@ interface ICommandArgumentConfig<T = unknown> {
92
92
  /** Custom value transformation (takes precedence over type conversion) */
93
93
  coerce?: (rawValue: string) => T;
94
94
  }
95
- interface ICommandBuiltinOptionConfig {
96
- /** Enable built-in --version option (root only, requires configured version) */
97
- version?: boolean;
98
- /** Enable built-in --color/--no-color option for help rendering (defaults respect NO_COLOR) */
99
- color?: boolean;
100
- /** Enable built-in --log-level option */
101
- logLevel?: boolean;
102
- /** Enable built-in --silent option */
103
- silent?: boolean;
104
- /** Enable built-in --log-date/--no-log-date option */
105
- logDate?: boolean;
106
- /** Enable built-in --log-colorful/--no-log-colorful option */
107
- logColorful?: boolean;
108
- }
109
- interface ICommandBuiltinConfig {
110
- /** Built-in options configuration */
111
- option?: boolean | ICommandBuiltinOptionConfig;
112
- }
113
- /** Command example configuration */
114
- interface ICommandExample {
115
- /** Example title */
116
- title: string;
117
- /** Usage fragment relative to command path */
118
- usage: string;
119
- /** Example description */
120
- desc: string;
121
- }
122
- /** Command preset defaults */
123
- interface ICommandPresetConfig {
124
- /** Preset root directory (absolute path) */
125
- root?: string;
126
- /** Default preset options file */
127
- opt?: string;
128
- /** Default preset envs file */
129
- env?: string;
130
- }
131
95
  /** Command configuration */
132
96
  interface ICommandConfig {
133
97
  /** Command name (only for root command) */
134
98
  name?: string;
135
99
  /** Command description */
136
100
  desc: string;
137
- /** Version (for built-in --version on this command) */
101
+ /** Version (for root --version) */
138
102
  version?: string;
139
- /** Built-in features configuration */
140
- builtin?: boolean | ICommandBuiltinConfig;
141
- /** Command-level preset defaults */
142
- preset?: ICommandPresetConfig;
103
+ /** Enable built-in "help" subcommand */
104
+ help?: boolean;
143
105
  /** Default reporter for this command */
144
106
  reporter?: IReporter;
145
107
  }
@@ -148,28 +110,21 @@ interface ICommand {
148
110
  readonly name: string | undefined;
149
111
  readonly description: string;
150
112
  readonly version: string | undefined;
151
- readonly builtin: ICommandConfig['builtin'] | undefined;
152
- readonly preset: ICommandPresetConfig | undefined;
153
113
  readonly parent: ICommand | undefined;
154
114
  readonly options: ICommandOptionConfig[];
155
115
  readonly arguments: ICommandArgumentConfig[];
156
- readonly examples: ICommandExample[];
157
116
  readonly subcommands: Map<string, ICommand>;
158
117
  }
159
118
  /** Execution context */
160
119
  interface ICommandContext {
161
120
  /** Current command node */
162
121
  cmd: ICommand;
163
- /** Command chain from root to leaf */
164
- chain: ICommand[];
165
- /** Effective environment variables */
122
+ /** Environment variables */
166
123
  envs: Record<string, string | undefined>;
167
- /** Built-in control hit status */
168
- controls: ICommandControls;
169
- /** Input source snapshots */
170
- sources: ICommandInputSources;
171
124
  /** Reporter instance */
172
125
  reporter: IReporter;
126
+ /** Original argv */
127
+ argv: string[];
173
128
  }
174
129
  /** Action callback parameters */
175
130
  interface ICommandActionParams {
@@ -198,29 +153,11 @@ type ICommandParsedOpts = Record<string, unknown>;
198
153
  /** Parsed arguments record */
199
154
  type ICommandParsedArgs = Record<string, unknown>;
200
155
  /** Route stage result */
201
- interface ICommandRouteResult<TCommand = ICommand> {
156
+ interface ICommandRouteResult {
202
157
  /** Command chain from root to leaf */
203
- chain: TCommand[];
158
+ chain: ICommand[];
204
159
  /** Remaining argv after routing */
205
160
  remaining: string[];
206
- /** Routed command tokens from user argv (name/alias) */
207
- cmds: string[];
208
- }
209
- /** Control-scan stage result */
210
- interface ICommandControlScanResult {
211
- /** Built-in control hit status */
212
- controls: ICommandControls;
213
- /** Remaining argv after stripping control tokens */
214
- remaining: string[];
215
- /** Optional target token from `help <child>` syntax */
216
- helpTarget?: string;
217
- }
218
- /** Preset stage result */
219
- interface ICommandPresetResult {
220
- /** Effective tail argv after preset merge */
221
- tailArgv: string[];
222
- /** Effective envs after preset merge */
223
- envs: Record<string, string | undefined>;
224
161
  }
225
162
  /** Tokenize stage result */
226
163
  interface ICommandTokenizeResult {
@@ -254,71 +191,8 @@ interface ICommandParseResult {
254
191
  /** Raw argument strings */
255
192
  rawArgs: string[];
256
193
  }
257
- /** Input source snapshots for debugging/tracing */
258
- interface ICommandInputSources {
259
- preset: {
260
- argv: string[];
261
- envs: Record<string, string>;
262
- };
263
- user: {
264
- /** Routed command tokens (name/alias as entered by user) */
265
- cmds: string[];
266
- /** Clean user tail argv after removing command chain/control/preset directives */
267
- argv: string[];
268
- /** Raw env snapshot from run/parse params */
269
- envs: Record<string, string | undefined>;
270
- };
271
- }
272
- /** Built-in run controls */
273
- interface ICommandControls {
274
- help: boolean;
275
- version: boolean;
276
- }
277
- /** Built-in option resolution result (internal) */
278
- interface ICommandBuiltinOptionResolved {
279
- version: boolean;
280
- color: boolean;
281
- logLevel: boolean;
282
- silent: boolean;
283
- logDate: boolean;
284
- logColorful: boolean;
285
- }
286
- /** Built-in config resolution result (internal) */
287
- interface ICommandBuiltinResolved {
288
- option: ICommandBuiltinOptionResolved;
289
- }
290
- /** Subcommand registry entry (internal) */
291
- interface ISubcommandEntry<TCommand = ICommand> {
292
- name: string;
293
- aliases: string[];
294
- command: TCommand;
295
- }
296
- /** Help option line (internal) */
297
- interface IHelpOptionLine {
298
- sig: string;
299
- desc: string;
300
- }
301
- /** Help command line (internal) */
302
- interface IHelpCommandLine {
303
- name: string;
304
- desc: string;
305
- }
306
- /** Help example line (internal) */
307
- interface IHelpExampleLine {
308
- title: string;
309
- usage: string;
310
- desc: string;
311
- }
312
- /** Structured help data for rendering (internal) */
313
- interface IHelpData {
314
- desc: string;
315
- usage: string;
316
- options: IHelpOptionLine[];
317
- commands: IHelpCommandLine[];
318
- examples: IHelpExampleLine[];
319
- }
320
194
  /** Error kinds for command parsing */
321
- type ICommanderErrorKind = 'InvalidOptionFormat' | 'InvalidNegativeOption' | 'NegativeOptionWithValue' | 'NegativeOptionType' | 'UnknownOption' | 'UnknownSubcommand' | 'UnexpectedArgument' | 'MissingValue' | 'InvalidType' | 'UnsupportedShortSyntax' | 'OptionConflict' | 'MissingRequired' | 'InvalidChoice' | 'InvalidBooleanValue' | 'MissingRequiredArgument' | 'TooManyArguments' | 'ConfigurationError';
195
+ type ICommanderErrorKind = 'InvalidOptionFormat' | 'InvalidNegativeOption' | 'NegativeOptionWithValue' | 'NegativeOptionType' | 'UnknownOption' | 'UnexpectedArgument' | 'MissingValue' | 'InvalidType' | 'UnsupportedShortSyntax' | 'OptionConflict' | 'MissingRequired' | 'InvalidChoice' | 'InvalidBooleanValue' | 'MissingRequiredArgument' | 'TooManyArguments' | 'ConfigurationError';
322
196
  /** Commander error with structured information */
323
197
  declare class CommanderError extends Error {
324
198
  readonly kind: ICommanderErrorKind;
@@ -369,13 +243,13 @@ interface ICompletionCommandConfig {
369
243
  /** Program name for completion scripts (defaults to root.name) */
370
244
  programName?: string;
371
245
  /** Default completion file paths for each shell */
372
- paths?: Partial<ICompletionPaths>;
246
+ paths: ICompletionPaths;
373
247
  }
374
248
 
375
249
  /**
376
250
  * Command class - CLI command builder with fluent API
377
251
  *
378
- * Execution flow: route → control-scan → run-control(run) → preset → tokenize → resolve → parse → run
252
+ * Execution flow: route → tokenize → resolve → parse → run
379
253
  *
380
254
  * @module @guanghechen/commander
381
255
  */
@@ -386,48 +260,20 @@ declare class Command implements ICommand {
386
260
  get name(): string | undefined;
387
261
  get description(): string;
388
262
  get version(): string | undefined;
389
- get builtin(): ICommandConfig['builtin'] | undefined;
390
- get preset(): ICommandPresetConfig | undefined;
391
263
  get parent(): Command | undefined;
392
264
  get options(): ICommandOptionConfig[];
393
265
  get arguments(): ICommandArgumentConfig[];
394
- get examples(): ICommandExample[];
395
266
  get subcommands(): Map<string, ICommand>;
396
267
  option<T>(opt: ICommandOptionConfig<T>): this;
397
268
  argument<T>(arg: ICommandArgumentConfig<T>): this;
398
269
  action(fn: ICommandAction): this;
399
- example(title: string, usage: string, desc: string): this;
400
270
  subcommand(name: string, cmd: Command): this;
401
271
  run(params: ICommandRunParams): Promise<void>;
402
- parse(params: ICommandRunParams): Promise<ICommandParseResult>;
272
+ parse(params: ICommandRunParams): ICommandParseResult;
403
273
  formatHelp(): string;
404
274
  getCompletionMeta(): ICompletionMeta;
405
275
  }
406
276
 
407
- /**
408
- * Pre-defined coerce factory methods for @guanghechen/commander.
409
- *
410
- * @module @guanghechen/commander/coerce
411
- */
412
- declare class Coerce {
413
- private constructor();
414
- private static create;
415
- static choice<TValue extends string>(name: string, values: ReadonlyArray<TValue>, errorMessage?: string): (rawValue: string) => TValue;
416
- static domain(name: string, errorMessage?: string): (rawValue: string) => string;
417
- static host(name: string, errorMessage?: string): (rawValue: string) => string;
418
- static integer(name: string, errorMessage?: string): (rawValue: string) => number;
419
- static ip(name: string, errorMessage?: string): (rawValue: string) => string;
420
- static number(name: string, errorMessage?: string): (rawValue: string) => number;
421
- static port(name: string, errorMessage?: string): (rawValue: string) => number;
422
- static positiveInteger(name: string, errorMessage?: string): (rawValue: string) => number;
423
- static positiveNumber(name: string, errorMessage?: string): (rawValue: string) => number;
424
- }
425
-
426
- declare function isIpv4(rawValue: string): boolean;
427
- declare function isIpv6(rawValue: string): boolean;
428
- declare function isIp(rawValue: string): boolean;
429
- declare function isDomain(rawValue: string): boolean;
430
-
431
277
  /**
432
278
  * Shell completion generators
433
279
  *
@@ -455,7 +301,7 @@ declare function isDomain(rawValue: string): boolean;
455
301
  * ```
456
302
  */
457
303
  declare class CompletionCommand extends Command {
458
- constructor(root: Command, config?: ICompletionCommandConfig);
304
+ constructor(root: Command, config: ICompletionCommandConfig);
459
305
  }
460
306
  declare class BashCompletion {
461
307
  #private;
@@ -509,28 +355,6 @@ declare class PwshCompletion {
509
355
  * ```
510
356
  */
511
357
  declare const logLevelOption: ICommandOptionConfig<string>;
512
- /**
513
- * Pre-defined --log-date option for controlling timestamp output.
514
- *
515
- * | Property | Value |
516
- * | --------- | --------- |
517
- * | long | 'logDate' |
518
- * | type | 'boolean' |
519
- * | args | 'none' |
520
- * | default | true |
521
- */
522
- declare const logDateOption: ICommandOptionConfig<boolean>;
523
- /**
524
- * Pre-defined --log-colorful option for controlling colorful output.
525
- *
526
- * | Property | Value |
527
- * | --------- | ------------- |
528
- * | long | 'logColorful' |
529
- * | type | 'boolean' |
530
- * | args | 'none' |
531
- * | default | true |
532
- */
533
- declare const logColorfulOption: ICommandOptionConfig<boolean>;
534
358
  /**
535
359
  * Pre-defined --silent option for suppressing non-error output.
536
360
  *
@@ -556,5 +380,5 @@ declare const logColorfulOption: ICommandOptionConfig<boolean>;
556
380
  */
557
381
  declare const silentOption: ICommandOptionConfig<boolean>;
558
382
 
559
- export { BashCompletion, Coerce, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, isDomain, isIp, isIpv4, isIpv6, logColorfulOption, logDateOption, logLevelOption, silentOption };
560
- export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandBuiltinConfig, ICommandBuiltinOptionConfig, ICommandBuiltinOptionResolved, ICommandBuiltinResolved, ICommandConfig, ICommandContext, ICommandControlScanResult, ICommandControls, ICommandExample, ICommandInputSources, ICommandOptionArgs, ICommandOptionConfig, ICommandOptionType, ICommandParseResult, ICommandParsedArgs, ICommandParsedOpts, ICommandPresetConfig, ICommandPresetResult, ICommandResolveResult, ICommandRouteResult, ICommandRunParams, ICommandShiftResult, ICommandToken, ICommandTokenType, ICommandTokenizeResult, ICommanderErrorKind, ICompletionCommandConfig, ICompletionMeta, ICompletionOptionMeta, ICompletionPaths, ICompletionShellType, IHelpCommandLine, IHelpData, IHelpExampleLine, IHelpOptionLine, ISubcommandEntry };
383
+ export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logLevelOption, silentOption };
384
+ export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandConfig, ICommandContext, ICommandOptionArgs, ICommandOptionConfig, ICommandOptionType, ICommandParseResult, ICommandParsedArgs, ICommandParsedOpts, ICommandResolveResult, ICommandRouteResult, ICommandRunParams, ICommandShiftResult, ICommandToken, ICommandTokenType, ICommandTokenizeResult, ICommanderErrorKind, ICompletionCommandConfig, ICompletionMeta, ICompletionOptionMeta, ICompletionPaths, ICompletionShellType };