politty 0.4.14 → 0.4.16

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.
Files changed (80) hide show
  1. package/README.md +7 -1
  2. package/dist/{arg-registry-CkPDokIu.d.ts → arg-registry-Cd6xnjHa.d.ts} +118 -4
  3. package/dist/arg-registry-Cd6xnjHa.d.ts.map +1 -0
  4. package/dist/{arg-registry-r5wYN6qd.d.cts → arg-registry-MVWOAcvw.d.cts} +118 -4
  5. package/dist/arg-registry-MVWOAcvw.d.cts.map +1 -0
  6. package/dist/augment.d.cts +1 -1
  7. package/dist/augment.d.cts.map +1 -1
  8. package/dist/augment.d.ts +1 -1
  9. package/dist/augment.d.ts.map +1 -1
  10. package/dist/completion/index.cjs +2 -1
  11. package/dist/completion/index.d.cts +2 -2
  12. package/dist/completion/index.d.ts +2 -2
  13. package/dist/completion/index.js +2 -2
  14. package/dist/{completion-yHz8Pdr7.js → completion-B04iiki9.js} +580 -31
  15. package/dist/completion-B04iiki9.js.map +1 -0
  16. package/dist/{completion-CAekGYS4.cjs → completion-BlZxMSeU.cjs} +598 -43
  17. package/dist/completion-BlZxMSeU.cjs.map +1 -0
  18. package/dist/docs/index.cjs +121 -65
  19. package/dist/docs/index.cjs.map +1 -1
  20. package/dist/docs/index.d.cts +5 -1
  21. package/dist/docs/index.d.cts.map +1 -1
  22. package/dist/docs/index.d.ts +5 -1
  23. package/dist/docs/index.d.ts.map +1 -1
  24. package/dist/docs/index.js +124 -67
  25. package/dist/docs/index.js.map +1 -1
  26. package/dist/{index-DPswv0Vt.d.cts → index-CPebddth.d.cts} +58 -4
  27. package/dist/index-CPebddth.d.cts.map +1 -0
  28. package/dist/{index-BLySW_2k.d.ts → index-DR9HLxIP.d.ts} +58 -4
  29. package/dist/index-DR9HLxIP.d.ts.map +1 -0
  30. package/dist/index.cjs +12 -10
  31. package/dist/index.d.cts +39 -4
  32. package/dist/index.d.cts.map +1 -1
  33. package/dist/index.d.ts +39 -4
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +4 -4
  36. package/dist/{subcommand-router-C9ONv6Nq.cjs → log-collector-Cd2_mv87.cjs} +1 -59
  37. package/dist/log-collector-Cd2_mv87.cjs.map +1 -0
  38. package/dist/{subcommand-router--EUt6ftA.js → log-collector-Cu6MCtAx.js} +2 -43
  39. package/dist/log-collector-Cu6MCtAx.js.map +1 -0
  40. package/dist/prompt/clack/index.cjs +1 -1
  41. package/dist/prompt/clack/index.cjs.map +1 -1
  42. package/dist/prompt/clack/index.d.cts +1 -1
  43. package/dist/prompt/clack/index.d.cts.map +1 -1
  44. package/dist/prompt/clack/index.d.ts +1 -1
  45. package/dist/prompt/clack/index.d.ts.map +1 -1
  46. package/dist/prompt/clack/index.js.map +1 -1
  47. package/dist/prompt/index.d.cts +1 -1
  48. package/dist/prompt/index.d.cts.map +1 -1
  49. package/dist/prompt/index.d.ts +1 -1
  50. package/dist/prompt/index.d.ts.map +1 -1
  51. package/dist/prompt/inquirer/index.cjs +1 -1
  52. package/dist/prompt/inquirer/index.cjs.map +1 -1
  53. package/dist/prompt/inquirer/index.d.cts +1 -1
  54. package/dist/prompt/inquirer/index.d.cts.map +1 -1
  55. package/dist/prompt/inquirer/index.d.ts +1 -1
  56. package/dist/prompt/inquirer/index.d.ts.map +1 -1
  57. package/dist/prompt/inquirer/index.js.map +1 -1
  58. package/dist/prompt-BKHqGrFw.js.map +1 -1
  59. package/dist/prompt-aXfSf27y.cjs.map +1 -1
  60. package/dist/{runner-DSZw1AsW.js → runner-BHeCMEa5.js} +383 -57
  61. package/dist/runner-BHeCMEa5.js.map +1 -0
  62. package/dist/{runner-CY5fOsSh.cjs → runner-BcyR6Z8r.cjs} +434 -96
  63. package/dist/runner-BcyR6Z8r.cjs.map +1 -0
  64. package/dist/{lazy-AGV9Pkt5.cjs → subcommand-router-DQy0KZU-.cjs} +148 -4
  65. package/dist/subcommand-router-DQy0KZU-.cjs.map +1 -0
  66. package/dist/{lazy-DiMJSDMB.js → subcommand-router-XZBWe8HN.js} +118 -4
  67. package/dist/subcommand-router-XZBWe8HN.js.map +1 -0
  68. package/package.json +16 -16
  69. package/dist/arg-registry-CkPDokIu.d.ts.map +0 -1
  70. package/dist/arg-registry-r5wYN6qd.d.cts.map +0 -1
  71. package/dist/completion-CAekGYS4.cjs.map +0 -1
  72. package/dist/completion-yHz8Pdr7.js.map +0 -1
  73. package/dist/index-BLySW_2k.d.ts.map +0 -1
  74. package/dist/index-DPswv0Vt.d.cts.map +0 -1
  75. package/dist/lazy-AGV9Pkt5.cjs.map +0 -1
  76. package/dist/lazy-DiMJSDMB.js.map +0 -1
  77. package/dist/runner-CY5fOsSh.cjs.map +0 -1
  78. package/dist/runner-DSZw1AsW.js.map +0 -1
  79. package/dist/subcommand-router--EUt6ftA.js.map +0 -1
  80. package/dist/subcommand-router-C9ONv6Nq.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
- import { a as getAllAliases, c as toCamelCase, i as extractFields, l as toKebabCase, o as getExtractedFields, r as resolveSubCommandMeta } from "./lazy-DiMJSDMB.js";
2
- import { a as emptyLogs, i as createLogCollector, n as resolveLazyCommand, o as mergeLogs, r as resolveSubcommand, t as listSubCommands } from "./subcommand-router--EUt6ftA.js";
1
+ import { a as resolveSubcommandWithAlias, c as resolveSubCommandMeta, d as getExtractedFields, l as extractFields, m as toKebabCase, n as listSubCommands, o as isLazyCommand, p as toCamelCase, r as resolveLazyCommand, t as listSubCommandNamesWithAliases, u as getAllAliases } from "./subcommand-router-XZBWe8HN.js";
2
+ import { n as emptyLogs, r as mergeLogs, t as createLogCollector } from "./log-collector-Cu6MCtAx.js";
3
3
  import { styleText } from "node:util";
4
4
  import stringWidth from "string-width";
5
5
 
@@ -236,24 +236,45 @@ const symbols = {
236
236
  * Logger for CLI output
237
237
  */
238
238
  const logger = {
239
+ /**
240
+ * Log informational message
241
+ */
239
242
  info(message) {
240
243
  console.log(message);
241
244
  },
245
+ /**
246
+ * Log success message
247
+ */
242
248
  success(message) {
243
249
  console.log(`${symbols.success} ${styles.success(message)}`);
244
250
  },
251
+ /**
252
+ * Log warning message
253
+ */
245
254
  warn(message) {
246
255
  console.warn(`${symbols.warning} ${styles.warning(message)}`);
247
256
  },
257
+ /**
258
+ * Log error message
259
+ */
248
260
  error(message) {
249
261
  console.error(`${symbols.error} ${styles.error(message)}`);
250
262
  },
263
+ /**
264
+ * Log raw message without prefix
265
+ */
251
266
  log(message) {
252
267
  console.log(message);
253
268
  },
269
+ /**
270
+ * Log empty line
271
+ */
254
272
  newline() {
255
273
  console.log("");
256
274
  },
275
+ /**
276
+ * Log debug message with dim color
277
+ */
257
278
  debug(message) {
258
279
  console.log(styles.dim(message));
259
280
  }
@@ -650,10 +671,21 @@ function renderOptions(command, descriptions = {}, context) {
650
671
  const envInfo = formatEnvInfo(opt.env);
651
672
  if (envInfo) desc += ` ${envInfo}`;
652
673
  lines.push(formatOption(flags, desc));
674
+ const negationLine = formatNegationLine(opt);
675
+ if (negationLine) lines.push(negationLine);
653
676
  }
654
677
  return lines.join("\n");
655
678
  }
656
679
  /**
680
+ * Render a separate line for the custom negation option when a
681
+ * `negationDescription` is provided. When no description is given, the
682
+ * negation is shown inline by `formatFlags`.
683
+ */
684
+ function formatNegationLine(opt, indent = 0, extraDescPadding = 0) {
685
+ if (!opt.negationDisplay || !opt.negationDescription) return null;
686
+ return formatOption(styles.option(`--${opt.negationDisplay}`), `${opt.negationDescription} ${styles.dim(`(↔ --${opt.cliName})`)}`, indent, extraDescPadding);
687
+ }
688
+ /**
657
689
  * Render options for discriminated union with variants
658
690
  */
659
691
  function renderDiscriminatedUnionOptions(extracted, _command, lines) {
@@ -682,6 +714,8 @@ function renderDiscriminatedUnionOptions(extracted, _command, lines) {
682
714
  const envInfo = formatEnvInfo(field.env);
683
715
  if (envInfo) desc += ` ${envInfo}`;
684
716
  lines.push(formatOption(flags, desc));
717
+ const negationLine = formatNegationLine(field);
718
+ if (negationLine) lines.push(negationLine);
685
719
  }
686
720
  }
687
721
  for (const variant of variants) {
@@ -697,7 +731,9 @@ function renderDiscriminatedUnionOptions(extracted, _command, lines) {
697
731
  if (field.required) desc += ` ${styles.required("(required)")}`;
698
732
  const envInfo = formatEnvInfo(field.env);
699
733
  if (envInfo) desc += ` ${envInfo}`;
700
- lines.push(formatOption(` ${flags}`, desc));
734
+ lines.push(formatOption(flags, desc, 1));
735
+ const negationLine = formatNegationLine(field, 1);
736
+ if (negationLine) lines.push(negationLine);
701
737
  }
702
738
  }
703
739
  }
@@ -721,6 +757,8 @@ function renderUnionOptions(extracted, _command, lines) {
721
757
  const envInfo = formatEnvInfo(field.env);
722
758
  if (envInfo) desc += ` ${envInfo}`;
723
759
  lines.push(formatOption(flags, desc));
760
+ const negationLine = formatNegationLine(field);
761
+ if (negationLine) lines.push(negationLine);
724
762
  }
725
763
  }
726
764
  for (let i = 0; i < unionOptions.length; i++) {
@@ -738,7 +776,9 @@ function renderUnionOptions(extracted, _command, lines) {
738
776
  if (field.required) desc += ` ${styles.required("(required)")}`;
739
777
  const envInfo = formatEnvInfo(field.env);
740
778
  if (envInfo) desc += ` ${envInfo}`;
741
- lines.push(formatOption(` ${flags}`, desc));
779
+ lines.push(formatOption(flags, desc, 1));
780
+ const negationLine = formatNegationLine(field, 1);
781
+ if (negationLine) lines.push(negationLine);
742
782
  }
743
783
  } else {
744
784
  lines.push("");
@@ -753,16 +793,16 @@ function renderUnionOptions(extracted, _command, lines) {
753
793
  * Uses cliName (kebab-case) for display
754
794
  */
755
795
  function formatFlags(opt) {
756
- const parts = [];
796
+ const aliasParts = [];
757
797
  if (opt.alias) {
758
- for (const alias of opt.alias) if (alias.length === 1) parts.push(styles.option(`-${alias}`));
798
+ for (const alias of opt.alias) if (alias.length === 1) aliasParts.push(styles.option(`-${alias}`));
759
799
  }
760
800
  let longFlag = styles.option(`--${opt.cliName}`);
761
801
  if (opt.type !== "boolean") {
762
802
  const placeholder = opt.placeholder ?? opt.cliName.toUpperCase();
763
803
  longFlag += ` ${styles.placeholder(`<${placeholder}>`)}`;
764
804
  }
765
- parts.push(longFlag);
805
+ aliasParts.push(longFlag);
766
806
  if (opt.alias) {
767
807
  for (const alias of opt.alias) if (alias.length > 1) {
768
808
  let longAlias = styles.option(`--${alias}`);
@@ -770,10 +810,12 @@ function formatFlags(opt) {
770
810
  const placeholder = opt.placeholder ?? opt.cliName.toUpperCase();
771
811
  longAlias += ` ${styles.placeholder(`<${placeholder}>`)}`;
772
812
  }
773
- parts.push(longAlias);
813
+ aliasParts.push(longAlias);
774
814
  }
775
815
  }
776
- return parts.join(", ");
816
+ const aliasStr = aliasParts.join(", ");
817
+ if (opt.type === "boolean" && opt.negationDisplay && !opt.negationDescription) return `${aliasStr} / ${styles.option(`--${opt.negationDisplay}`)}`;
818
+ return aliasStr;
777
819
  }
778
820
  /**
779
821
  * Format environment variable info for help display
@@ -825,7 +867,14 @@ function formatFieldLine(opt, indent = 0, extraDescPadding = 0) {
825
867
  * Render global options section
826
868
  */
827
869
  function renderGlobalOptions(globalExtracted) {
828
- return globalExtracted.fields.filter((a) => !a.positional).map((opt) => formatFieldLine(opt)).join("\n");
870
+ const lines = [];
871
+ for (const opt of globalExtracted.fields) {
872
+ if (opt.positional) continue;
873
+ lines.push(formatFieldLine(opt));
874
+ const negationLine = formatNegationLine(opt);
875
+ if (negationLine) lines.push(negationLine);
876
+ }
877
+ return lines.join("\n");
829
878
  }
830
879
  /**
831
880
  * Render options for a subcommand (used by showSubcommandOptions)
@@ -842,6 +891,8 @@ function renderSubcommandOptionsCompact(command, indent) {
842
891
  const envInfo = formatEnvInfo(opt.env);
843
892
  if (envInfo) desc += ` ${envInfo}`;
844
893
  lines.push(formatOption(flags, desc, indent, 2));
894
+ const negationLine = formatNegationLine(opt, indent, 2);
895
+ if (negationLine) lines.push(negationLine);
845
896
  }
846
897
  }
847
898
  return lines;
@@ -855,7 +906,9 @@ function renderSubcommandsWithOptions(subCommands, parentPath, baseIndent) {
855
906
  const cmd = resolveSubCommandMeta(subCmd);
856
907
  const fullPath = parentPath ? `${parentPath} ${name}` : name;
857
908
  const desc = cmd?.description ?? "";
858
- lines.push(formatOption(styles.command(fullPath), desc, baseIndent));
909
+ const aliases = cmd?.aliases;
910
+ const displayName = aliases && aliases.length > 0 ? `${fullPath}, ${aliases.join(", ")}` : fullPath;
911
+ lines.push(formatOption(styles.command(displayName), desc, baseIndent));
859
912
  if (cmd) {
860
913
  const optionLines = renderSubcommandOptionsCompact(cmd, baseIndent + 1);
861
914
  lines.push(...optionLines);
@@ -886,7 +939,9 @@ function generateHelp(command, options) {
886
939
  else if (context?.rootVersion) header += ` ${styles.version(`v${context.rootVersion}`)}`;
887
940
  sections.push(header);
888
941
  }
942
+ if (context?.aliasFor) sections.push(styles.dim(`Alias for ${styles.commandName(context.aliasFor)}`));
889
943
  if (command.description) sections.push(command.description);
944
+ if (!context?.aliasFor && command.aliases && command.aliases.length > 0) sections.push(`${styles.sectionHeader("Aliases:")} ${command.aliases.map((a) => styles.command(a)).join(", ")}`);
890
945
  sections.push(`${styles.sectionHeader("Usage:")} ${renderUsageLine(command, context)}`);
891
946
  const optionsText = renderOptions(command, options.descriptions, context);
892
947
  if (optionsText) sections.push(`${styles.sectionHeader("Options:")}\n${optionsText}`);
@@ -900,9 +955,12 @@ function generateHelp(command, options) {
900
955
  } else {
901
956
  const subLines = [];
902
957
  for (const [name, subCmd] of Object.entries(visibleSubCommands)) {
903
- const desc = resolveSubCommandMeta(subCmd)?.description ?? "";
958
+ const cmd = resolveSubCommandMeta(subCmd);
959
+ const desc = cmd?.description ?? "";
904
960
  const fullName = currentPath ? `${currentPath} ${name}` : name;
905
- subLines.push(formatOption(styles.command(fullName), desc));
961
+ const aliases = cmd?.aliases;
962
+ const displayName = aliases && aliases.length > 0 ? `${fullName}, ${aliases.join(", ")}` : fullName;
963
+ subLines.push(formatOption(styles.command(displayName), desc));
906
964
  }
907
965
  sections.push(`${styles.sectionHeader("Commands:")}\n${subLines.join("\n")}`);
908
966
  }
@@ -982,6 +1040,17 @@ var CaseVariantCollisionError = class extends Error {
982
1040
  this.name = "CaseVariantCollisionError";
983
1041
  }
984
1042
  };
1043
+ /**
1044
+ * Error thrown when a custom boolean negation name collides with another
1045
+ * field's name, cliName, alias, or another field's negation (including
1046
+ * derived camelCase variants).
1047
+ */
1048
+ var DuplicateNegationError = class extends Error {
1049
+ constructor(message) {
1050
+ super(message);
1051
+ this.name = "DuplicateNegationError";
1052
+ }
1053
+ };
985
1054
 
986
1055
  //#endregion
987
1056
  //#region src/validator/command-validator.ts
@@ -1062,6 +1131,79 @@ function checkDuplicateAliases(extracted, commandPath) {
1062
1131
  return errors;
1063
1132
  }
1064
1133
  /**
1134
+ * Check for collisions involving custom boolean `negation` names
1135
+ */
1136
+ function checkDuplicateNegations(extracted, commandPath) {
1137
+ const errors = [];
1138
+ const claimed = /* @__PURE__ */ new Map();
1139
+ const claim = (name, fieldName, kind) => {
1140
+ if (!claimed.has(name)) claimed.set(name, {
1141
+ field: fieldName,
1142
+ kind
1143
+ });
1144
+ };
1145
+ for (const field of extracted.fields) {
1146
+ claim(field.name, field.name, "field name");
1147
+ if (field.name.includes("-")) {
1148
+ const camelName = toCamelCase(field.name);
1149
+ if (camelName !== field.name) claim(camelName, field.name, "field name");
1150
+ }
1151
+ if (field.cliName !== field.name) claim(field.cliName, field.name, "CLI name");
1152
+ if (field.cliName.includes("-")) {
1153
+ const camelCli = toCamelCase(field.cliName);
1154
+ if (camelCli !== field.cliName) claim(camelCli, field.name, "CLI name");
1155
+ }
1156
+ for (const alias of getAllAliases(field)) {
1157
+ claim(alias, field.name, "alias");
1158
+ if (alias.length > 1 && alias.includes("-")) {
1159
+ const camelVariant = toCamelCase(alias);
1160
+ if (camelVariant !== alias) claim(camelVariant, field.name, "alias");
1161
+ }
1162
+ }
1163
+ if (field.type === "boolean" && field.negation !== false && typeof field.negation !== "string") {
1164
+ const defaultKebab = `no-${field.cliName}`;
1165
+ claim(defaultKebab, field.name, "default negation");
1166
+ const camelBase = toCamelCase(field.cliName);
1167
+ const defaultCamel = `no${camelBase[0]?.toUpperCase() ?? ""}${camelBase.slice(1)}`;
1168
+ if (defaultCamel !== defaultKebab) claim(defaultCamel, field.name, "default negation");
1169
+ }
1170
+ }
1171
+ const seenNegations = /* @__PURE__ */ new Map();
1172
+ const register = (name, fieldName, isDerived) => {
1173
+ const claim = claimed.get(name);
1174
+ if (claim) {
1175
+ const qualifier = isDerived ? " (derived camelCase variant)" : "";
1176
+ const conflict = claim.field === fieldName ? `the same field's own ${claim.kind} "${name}"` : `${claim.kind} "${name}" of field "${claim.field}"`;
1177
+ errors.push({
1178
+ commandPath,
1179
+ type: "duplicate_negation",
1180
+ message: `Negation "${name}"${qualifier} for field "${fieldName}" conflicts with ${conflict}.`,
1181
+ field: fieldName
1182
+ });
1183
+ }
1184
+ const existing = seenNegations.get(name);
1185
+ if (existing && existing !== fieldName) {
1186
+ const qualifier = isDerived ? " (derived camelCase variant)" : "";
1187
+ errors.push({
1188
+ commandPath,
1189
+ type: "duplicate_negation",
1190
+ message: `Duplicate negation "${name}"${qualifier} detected. Both "${existing}" and "${fieldName}" use the same negation name.`,
1191
+ field: fieldName
1192
+ });
1193
+ }
1194
+ seenNegations.set(name, fieldName);
1195
+ };
1196
+ for (const field of extracted.fields) {
1197
+ if (typeof field.negation !== "string") continue;
1198
+ register(field.negation, field.name, false);
1199
+ if (field.negation.includes("-")) {
1200
+ const camelVariant = toCamelCase(field.negation);
1201
+ if (camelVariant !== field.negation) register(camelVariant, field.name, true);
1202
+ }
1203
+ }
1204
+ return errors;
1205
+ }
1206
+ /**
1065
1207
  * Check positional argument configuration
1066
1208
  */
1067
1209
  function checkPositionalConfig(extracted, commandPath) {
@@ -1176,6 +1318,19 @@ function validateReservedAliases(extracted, _hasSubCommands) {
1176
1318
  }
1177
1319
  }
1178
1320
  /**
1321
+ * Validate that custom boolean negation names do not collide with anything
1322
+ *
1323
+ * @param extracted - Extracted fields from schema
1324
+ * @throws {DuplicateNegationError} If a colliding negation is found
1325
+ */
1326
+ function validateDuplicateNegations(extracted) {
1327
+ const errors = checkDuplicateNegations(extracted, []);
1328
+ if (errors.length > 0) {
1329
+ const err = errors[0];
1330
+ throw new DuplicateNegationError(err.message);
1331
+ }
1332
+ }
1333
+ /**
1179
1334
  * Validate that no case-variant collisions exist
1180
1335
  *
1181
1336
  * @param extracted - Extracted fields from schema
@@ -1213,11 +1368,63 @@ function collectSchemaErrors(extracted, _hasSubCommands, commandPath) {
1213
1368
  ...checkDuplicateFields(extracted, commandPath),
1214
1369
  ...checkCaseVariantCollisions(extracted, commandPath),
1215
1370
  ...checkDuplicateAliases(extracted, commandPath),
1371
+ ...checkDuplicateNegations(extracted, commandPath),
1216
1372
  ...checkPositionalConfig(extracted, commandPath),
1217
1373
  ...checkReservedAliases(extracted, commandPath)
1218
1374
  ];
1219
1375
  }
1220
1376
  /**
1377
+ * Check for alias conflicts within subcommands
1378
+ * - Aliases must not conflict with subcommand names
1379
+ * - Aliases must not conflict with other aliases
1380
+ */
1381
+ function checkSubCommandAliasConflicts(command, commandPath) {
1382
+ const errors = [];
1383
+ if (!command.subCommands) return errors;
1384
+ const nameToOwner = /* @__PURE__ */ new Map();
1385
+ for (const [name] of Object.entries(command.subCommands)) nameToOwner.set(name, name);
1386
+ for (const [name, subCmdValue] of Object.entries(command.subCommands)) {
1387
+ const resolved = isLazyCommand(subCmdValue) ? subCmdValue.meta : typeof subCmdValue !== "function" ? subCmdValue : null;
1388
+ if (!resolved?.aliases) continue;
1389
+ const subCommandPath = [...commandPath, name];
1390
+ for (const alias of resolved.aliases) {
1391
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(alias)) {
1392
+ errors.push({
1393
+ commandPath: subCommandPath,
1394
+ type: "invalid_alias",
1395
+ message: `Alias "${alias}" is invalid. Aliases must start with an alphanumeric character and contain only alphanumeric characters, hyphens, or underscores.`,
1396
+ field: name
1397
+ });
1398
+ continue;
1399
+ }
1400
+ if (alias === name) {
1401
+ errors.push({
1402
+ commandPath: subCommandPath,
1403
+ type: "duplicate_alias",
1404
+ message: `Alias "${alias}" conflicts with its own name.`,
1405
+ field: name
1406
+ });
1407
+ continue;
1408
+ }
1409
+ const existing = nameToOwner.get(alias);
1410
+ if (existing) if (existing === name) errors.push({
1411
+ commandPath: subCommandPath,
1412
+ type: "duplicate_alias",
1413
+ message: `Alias "${alias}" is duplicated within the alias list.`,
1414
+ field: name
1415
+ });
1416
+ else errors.push({
1417
+ commandPath: subCommandPath,
1418
+ type: "duplicate_alias",
1419
+ message: `Alias "${alias}" conflicts with existing subcommand or alias "${existing}".`,
1420
+ field: name
1421
+ });
1422
+ else nameToOwner.set(alias, name);
1423
+ }
1424
+ }
1425
+ return errors;
1426
+ }
1427
+ /**
1221
1428
  * Validate a command and all its subcommands recursively
1222
1429
  *
1223
1430
  * This function collects all validation errors without throwing,
@@ -1243,6 +1450,7 @@ async function validateCommand(command, options = {}) {
1243
1450
  const extracted = extractFields(command.args);
1244
1451
  errors.push(...collectSchemaErrors(extracted, hasSubCommands, commandPath));
1245
1452
  }
1453
+ errors.push(...checkSubCommandAliasConflicts(command, commandPath));
1246
1454
  if (command.subCommands) for (const [name, subCmd] of Object.entries(command.subCommands)) {
1247
1455
  const subResult = await validateCommand(await resolveLazyCommand(subCmd), { commandPath: [...commandPath, name] });
1248
1456
  if (!subResult.valid) errors.push(...subResult.errors);
@@ -1293,7 +1501,7 @@ function formatCommandValidationErrors(errors) {
1293
1501
  * @returns Parsed arguments
1294
1502
  */
1295
1503
  function parseArgv(argv, options = {}) {
1296
- const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), arrayFlags = /* @__PURE__ */ new Set(), definedNames = /* @__PURE__ */ new Set() } = options;
1504
+ const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), arrayFlags = /* @__PURE__ */ new Set(), definedNames = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = options;
1297
1505
  const result = {
1298
1506
  options: {},
1299
1507
  positionals: [],
@@ -1324,11 +1532,19 @@ function parseArgv(argv, options = {}) {
1324
1532
  }
1325
1533
  if (arg.startsWith("--")) {
1326
1534
  const withoutDashes = arg.slice(2);
1535
+ if (!withoutDashes.includes("=")) {
1536
+ const negatedField = negationMap.get(withoutDashes);
1537
+ if (negatedField && booleanFlags.has(negatedField)) {
1538
+ setOption(negatedField, false);
1539
+ i++;
1540
+ continue;
1541
+ }
1542
+ }
1327
1543
  if (withoutDashes.startsWith("no-")) {
1328
1544
  const flagName = withoutDashes.slice(3);
1329
1545
  if (flagName === flagName.toLowerCase()) {
1330
1546
  const resolvedName = aliasMap.get(flagName) ?? flagName;
1331
- if (booleanFlags.has(resolvedName)) {
1547
+ if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
1332
1548
  const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
1333
1549
  if (!definedNames.has(asIsResolved)) {
1334
1550
  setOption(flagName, false);
@@ -1341,7 +1557,7 @@ function parseArgv(argv, options = {}) {
1341
1557
  if (withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2])) {
1342
1558
  const camelFlagName = withoutDashes[2].toLowerCase() + withoutDashes.slice(3);
1343
1559
  const resolvedName = aliasMap.get(camelFlagName) ?? camelFlagName;
1344
- if (booleanFlags.has(resolvedName)) {
1560
+ if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
1345
1561
  const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
1346
1562
  if (!definedNames.has(asIsResolved)) {
1347
1563
  setOption(camelFlagName, false);
@@ -1414,6 +1630,8 @@ function buildParserOptions(extracted) {
1414
1630
  const booleanFlags = /* @__PURE__ */ new Set();
1415
1631
  const arrayFlags = /* @__PURE__ */ new Set();
1416
1632
  const definedNames = /* @__PURE__ */ new Set();
1633
+ const negationMap = /* @__PURE__ */ new Map();
1634
+ const customNegatedFields = /* @__PURE__ */ new Set();
1417
1635
  for (const field of extracted.fields) definedNames.add(field.name);
1418
1636
  for (const field of extracted.fields) {
1419
1637
  if (field.cliName !== field.name) aliasMap.set(field.cliName, field.name);
@@ -1428,12 +1646,24 @@ function buildParserOptions(extracted) {
1428
1646
  if (camelVariant !== field.name && !definedNames.has(camelVariant) && !aliasMap.has(camelVariant)) aliasMap.set(camelVariant, field.name);
1429
1647
  if (field.type === "boolean") booleanFlags.add(field.name);
1430
1648
  if (field.type === "array") arrayFlags.add(field.name);
1649
+ if (field.type === "boolean" && (typeof field.negation === "string" || field.negation === false)) {
1650
+ customNegatedFields.add(field.name);
1651
+ if (typeof field.negation === "string") {
1652
+ negationMap.set(field.negation, field.name);
1653
+ if (field.negation.includes("-")) {
1654
+ const camelNegation = toCamelCase(field.negation);
1655
+ if (camelNegation !== field.negation) negationMap.set(camelNegation, field.name);
1656
+ }
1657
+ }
1658
+ }
1431
1659
  }
1432
1660
  return {
1433
1661
  aliasMap,
1434
1662
  booleanFlags,
1435
1663
  arrayFlags,
1436
- definedNames
1664
+ definedNames,
1665
+ negationMap,
1666
+ customNegatedFields
1437
1667
  };
1438
1668
  }
1439
1669
  /**
@@ -1464,7 +1694,7 @@ function mergeWithPositionals(parsed, extracted) {
1464
1694
  * Shared by scanForSubcommand, separateGlobalArgs, and findFirstPositional.
1465
1695
  */
1466
1696
  function buildGlobalFlagLookup(globalExtracted) {
1467
- const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
1697
+ const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
1468
1698
  const shortAliases = /* @__PURE__ */ new Set();
1469
1699
  for (const field of globalExtracted.fields) for (const alias of getAllAliases(field)) if (alias.length === 1) shortAliases.add(alias);
1470
1700
  return {
@@ -1472,23 +1702,53 @@ function buildGlobalFlagLookup(globalExtracted) {
1472
1702
  booleanFlags,
1473
1703
  flagNames: new Set(globalExtracted.fields.map((f) => f.name)),
1474
1704
  cliNames: new Set(globalExtracted.fields.map((f) => f.cliName)),
1475
- aliases: shortAliases
1705
+ aliases: shortAliases,
1706
+ negationMap,
1707
+ customNegatedFields
1476
1708
  };
1477
1709
  }
1478
1710
  /**
1479
- * Resolve a long option (--flag, --flag=value, --no-flag) against global flag lookup.
1480
- * Returns the resolved camelCase name and whether it is a known global flag.
1711
+ * Resolve a long option (--flag, --flag=value, --no-flag, --custom-negation)
1712
+ * against global flag lookup. Returns the resolved camelCase name and whether
1713
+ * it is a known global flag.
1714
+ *
1715
+ * `isSuppressedNegation` is true when the token matches a default `--no-X`
1716
+ * form that has been suppressed by a custom `negation` on the target field.
1717
+ * The caller may use this to keep argv scanning past such tokens (so a
1718
+ * trailing subcommand is still detected) even though they no longer negate.
1481
1719
  */
1482
1720
  function resolveGlobalLongOption(arg, lookup) {
1483
1721
  const withoutDashes = arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2);
1484
- const isNegated = withoutDashes.startsWith("no-");
1485
- const flagName = isNegated ? withoutDashes.slice(3) : withoutDashes;
1722
+ const customNegated = !arg.includes("=") ? lookup.negationMap.get(withoutDashes) : void 0;
1723
+ if (customNegated) return {
1724
+ resolvedName: customNegated,
1725
+ withoutDashes,
1726
+ isNegated: true,
1727
+ isGlobal: lookup.flagNames.has(customNegated),
1728
+ isSuppressedNegation: false
1729
+ };
1730
+ const kebabNegated = withoutDashes.startsWith("no-");
1731
+ const camelNegated = !kebabNegated && withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2]);
1732
+ if (kebabNegated || camelNegated) {
1733
+ const literalResolved = lookup.aliasMap.get(withoutDashes) ?? withoutDashes;
1734
+ if (lookup.flagNames.has(literalResolved) || lookup.cliNames.has(withoutDashes)) return {
1735
+ resolvedName: literalResolved,
1736
+ withoutDashes,
1737
+ isNegated: false,
1738
+ isGlobal: true,
1739
+ isSuppressedNegation: false
1740
+ };
1741
+ }
1742
+ const defaultIsNegated = kebabNegated || camelNegated;
1743
+ const flagName = kebabNegated ? withoutDashes.slice(3) : camelNegated ? withoutDashes[2].toLowerCase() + withoutDashes.slice(3) : withoutDashes;
1486
1744
  const resolvedName = lookup.aliasMap.get(flagName) ?? flagName;
1745
+ const suppressDefaultNegation = defaultIsNegated && lookup.customNegatedFields.has(resolvedName);
1487
1746
  return {
1488
1747
  resolvedName,
1489
1748
  withoutDashes,
1490
- isNegated,
1491
- isGlobal: lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName)
1749
+ isNegated: defaultIsNegated && !suppressDefaultNegation,
1750
+ isGlobal: !suppressDefaultNegation && (lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName)),
1751
+ isSuppressedNegation: suppressDefaultNegation
1492
1752
  };
1493
1753
  }
1494
1754
  /**
@@ -1536,6 +1796,7 @@ function scanForSubcommand(argv, subCommandNames, globalExtracted) {
1536
1796
  const lookup = buildGlobalFlagLookup(globalExtracted);
1537
1797
  const subCommandNameSet = new Set(subCommandNames);
1538
1798
  const globalTokensBefore = [];
1799
+ const suppressedTokens = [];
1539
1800
  let i = 0;
1540
1801
  while (i < argv.length) {
1541
1802
  const arg = argv[i];
@@ -1543,14 +1804,20 @@ function scanForSubcommand(argv, subCommandNames, globalExtracted) {
1543
1804
  if (!arg.startsWith("-") && subCommandNameSet.has(arg)) return {
1544
1805
  subCommandIndex: i,
1545
1806
  globalTokensBefore,
1546
- tokensAfterSubcommand: argv.slice(i + 1)
1807
+ tokensAfterSubcommand: argv.slice(i + 1),
1808
+ suppressedTokens
1547
1809
  };
1548
1810
  if (arg.startsWith("--")) {
1549
- const { resolvedName, isNegated, isGlobal } = resolveGlobalLongOption(arg, lookup);
1811
+ const { resolvedName, isNegated, isGlobal, isSuppressedNegation } = resolveGlobalLongOption(arg, lookup);
1550
1812
  if (isGlobal) {
1551
1813
  i += collectGlobalFlag(argv, i, resolvedName, isNegated, lookup.booleanFlags, globalTokensBefore);
1552
1814
  continue;
1553
1815
  }
1816
+ if (isSuppressedNegation) {
1817
+ suppressedTokens.push(arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2));
1818
+ i++;
1819
+ continue;
1820
+ }
1554
1821
  break;
1555
1822
  }
1556
1823
  if (arg.startsWith("-") && arg.length > 1) {
@@ -1569,7 +1836,8 @@ function scanForSubcommand(argv, subCommandNames, globalExtracted) {
1569
1836
  return {
1570
1837
  subCommandIndex: -1,
1571
1838
  globalTokensBefore,
1572
- tokensAfterSubcommand: []
1839
+ tokensAfterSubcommand: [],
1840
+ suppressedTokens
1573
1841
  };
1574
1842
  }
1575
1843
  const BUILTIN_FLAGS = new Set([
@@ -1615,7 +1883,8 @@ function findFirstPositional(argv, globalExtracted) {
1615
1883
  * @returns Parse result
1616
1884
  */
1617
1885
  function parseArgs(argv, command, options = {}) {
1618
- const subCommandNames = command.subCommands ? Object.keys(command.subCommands) : [];
1886
+ const subCommandNameSet = listSubCommandNamesWithAliases(command);
1887
+ const subCommandNames = [...subCommandNameSet];
1619
1888
  const hasSubCommands = subCommandNames.length > 0;
1620
1889
  if (hasSubCommands && argv.length > 0) if (options.globalExtracted) {
1621
1890
  const scanResult = scanForSubcommand(argv, subCommandNames, options.globalExtracted);
@@ -1629,13 +1898,13 @@ function parseArgs(argv, command, options = {}) {
1629
1898
  remainingArgs: scanResult.tokensAfterSubcommand,
1630
1899
  rawArgs: {},
1631
1900
  positionals: [],
1632
- unknownFlags: [],
1901
+ unknownFlags: scanResult.suppressedTokens,
1633
1902
  rawGlobalArgs
1634
1903
  };
1635
1904
  }
1636
1905
  } else {
1637
1906
  const firstArg = argv[0];
1638
- if (firstArg && !firstArg.startsWith("-") && subCommandNames.includes(firstArg)) return {
1907
+ if (firstArg && !firstArg.startsWith("-") && subCommandNameSet.has(firstArg)) return {
1639
1908
  helpRequested: false,
1640
1909
  helpAllRequested: false,
1641
1910
  versionRequested: false,
@@ -1653,6 +1922,7 @@ function parseArgs(argv, command, options = {}) {
1653
1922
  validateDuplicateFields(extracted);
1654
1923
  validateCaseVariantCollisions(extracted);
1655
1924
  validateDuplicateAliases(extracted);
1925
+ validateDuplicateNegations(extracted);
1656
1926
  validatePositionalConfig(extracted);
1657
1927
  validateReservedAliases(extracted, hasSubCommands);
1658
1928
  if (options.globalExtracted) validateCrossSchemaCollisions(options.globalExtracted, extracted);
@@ -1762,7 +2032,7 @@ function separateGlobalArgs(argv, globalExtracted, localExtracted) {
1762
2032
  }
1763
2033
  if (arg.startsWith("--")) {
1764
2034
  const { resolvedName, withoutDashes, isNegated, isGlobal } = resolveGlobalLongOption(arg, lookup);
1765
- const flagName = isNegated ? withoutDashes.slice(3) : withoutDashes;
2035
+ const flagName = resolvedName;
1766
2036
  const isLocalCollision = localFieldNames.has(withoutDashes) || localFieldNames.has(flagName) || localCliNames.has(withoutDashes) || localCliNames.has(flagName) || localAliasMapKeys.has(withoutDashes) || localAliasMapKeys.has(flagName);
1767
2037
  if (isGlobal && !isLocalCollision) {
1768
2038
  i += collectGlobalFlag(argv, i, resolvedName, isNegated, lookup.booleanFlags, globalTokens) - 1;
@@ -1998,12 +2268,36 @@ async function runCommand(command, argv, options = {}) {
1998
2268
  return result;
1999
2269
  }
2000
2270
  /**
2271
+ * Hidden internal subcommands (e.g. `__refresh-completion`) are spawned
2272
+ * by background hooks and must not run user-provided
2273
+ * `setup`/`cleanup`/`prompt` or required `globalArgs`. Those exist for
2274
+ * the foreground CLI run; replaying them in a detached child causes
2275
+ * duplicate side effects, stuck prompts, and validation failures the
2276
+ * user never opted into.
2277
+ *
2278
+ * We treat any registered subcommand whose name starts with `__` as
2279
+ * internal. We use `findFirstPositional` (schema-aware) instead of the
2280
+ * naive "first non-flag token" so an option *value* like
2281
+ * `--name __refresh-completion` doesn't trip the bypass — that would
2282
+ * silently skip lifecycle hooks for ordinary invocations.
2283
+ */
2284
+ function isInternalSubcommandInvocation(command, argv, globalExtracted) {
2285
+ const firstPositional = findFirstPositional(argv, globalExtracted);
2286
+ if (!firstPositional || !firstPositional.startsWith("__")) return false;
2287
+ return Boolean(command.subCommands?.[firstPositional]);
2288
+ }
2289
+ /**
2001
2290
  * Run a CLI command as the main entry point
2002
2291
  *
2003
2292
  * This function:
2004
2293
  * - Uses process.argv for arguments
2005
2294
  * - Handles SIGINT/SIGTERM signals
2006
2295
  * - Calls process.exit with the appropriate exit code
2296
+ * - Invokes `command.runMainHook` once before parsing if set, so plug-ins
2297
+ * like `withCompletionCommand` can fire detached background work
2298
+ * - Bypasses user `setup`/`cleanup`/`prompt` and required `globalArgs`
2299
+ * for registered hidden subcommands whose name starts with `__`
2300
+ * (e.g. `__refresh-completion`)
2007
2301
  *
2008
2302
  * @param command - The command to run
2009
2303
  * @param options - Main options (version, debug)
@@ -2021,38 +2315,51 @@ async function runCommand(command, argv, options = {}) {
2021
2315
  * ```
2022
2316
  */
2023
2317
  async function runMain(command, options = {}) {
2024
- const globalExtracted = extractAndValidateGlobal(options);
2025
- if (options.setup) try {
2026
- await options.setup({});
2318
+ if (command.runMainHook) try {
2319
+ command.runMainHook(process.argv.slice(2));
2320
+ } catch {}
2321
+ const argv = process.argv.slice(2);
2322
+ let globalExtractedForBypass;
2323
+ if (options.globalArgs) try {
2324
+ globalExtractedForBypass = extractFields(options.globalArgs);
2325
+ } catch {}
2326
+ let effectiveOptions = options;
2327
+ if (isInternalSubcommandInvocation(command, argv, globalExtractedForBypass)) {
2328
+ const { setup: _s, cleanup: _c, prompt: _p, globalArgs: _g, ...rest } = options;
2329
+ effectiveOptions = rest;
2330
+ }
2331
+ const globalExtracted = extractAndValidateGlobal(effectiveOptions);
2332
+ if (effectiveOptions.setup) try {
2333
+ await effectiveOptions.setup({});
2027
2334
  } catch (e) {
2028
2335
  const error = e instanceof Error ? e : new Error(String(e));
2029
- if (options.cleanup) try {
2030
- await options.cleanup({ error });
2336
+ if (effectiveOptions.cleanup) try {
2337
+ await effectiveOptions.cleanup({ error });
2031
2338
  } catch {}
2032
2339
  process.exit(1);
2033
2340
  }
2034
- const result = await runCommandInternal(command, process.argv.slice(2), {
2035
- debug: options.debug,
2036
- captureLogs: options.captureLogs,
2037
- skipValidation: options.skipValidation,
2341
+ const result = await runCommandInternal(command, argv, {
2342
+ debug: effectiveOptions.debug,
2343
+ captureLogs: effectiveOptions.captureLogs,
2344
+ skipValidation: effectiveOptions.skipValidation,
2038
2345
  handleSignals: true,
2039
- logger: options.logger,
2040
- globalArgs: options.globalArgs,
2041
- prompt: options.prompt,
2346
+ logger: effectiveOptions.logger,
2347
+ globalArgs: effectiveOptions.globalArgs,
2348
+ prompt: effectiveOptions.prompt,
2042
2349
  _globalExtracted: globalExtracted,
2043
- _globalCleanup: options.cleanup,
2350
+ _globalCleanup: effectiveOptions.cleanup,
2044
2351
  _context: {
2045
2352
  commandPath: [],
2046
2353
  rootName: command.name,
2047
- rootVersion: options.version,
2354
+ rootVersion: effectiveOptions.version,
2048
2355
  globalExtracted
2049
2356
  }
2050
2357
  });
2051
- if ((options.displayErrors ?? true) && !result.success && result.error) (options.logger ?? defaultLogger).error(formatRuntimeError(result.error, options.debug ?? false));
2052
- if (options.cleanup) {
2358
+ if ((effectiveOptions.displayErrors ?? true) && !result.success && result.error) (effectiveOptions.logger ?? defaultLogger).error(formatRuntimeError(result.error, effectiveOptions.debug ?? false));
2359
+ if (effectiveOptions.cleanup) {
2053
2360
  const cleanupCtx = { error: !result.success ? result.error : void 0 };
2054
2361
  try {
2055
- await options.cleanup(cleanupCtx);
2362
+ await effectiveOptions.cleanup(cleanupCtx);
2056
2363
  } catch {}
2057
2364
  }
2058
2365
  if (process.stdout.writableLength > 0) await new Promise((resolve) => process.stdout.once("drain", resolve));
@@ -2086,9 +2393,10 @@ async function runCommandInternal(command, argv, options = {}) {
2086
2393
  if (parseResult.helpRequested || parseResult.helpAllRequested) {
2087
2394
  let hasUnknownSubcommand = false;
2088
2395
  const subCmdNames = listSubCommands(command);
2396
+ const allSubCmdNameSet = listSubCommandNamesWithAliases(command);
2089
2397
  if (subCmdNames.length > 0) {
2090
2398
  const potentialSubCmd = findFirstPositional(argv, context.globalExtracted);
2091
- if (potentialSubCmd && !subCmdNames.includes(potentialSubCmd)) hasUnknownSubcommand = true;
2399
+ if (potentialSubCmd && !allSubCmdNameSet.has(potentialSubCmd)) hasUnknownSubcommand = true;
2092
2400
  }
2093
2401
  const help = generateHelp(command, {
2094
2402
  showSubcommands: options.showSubcommands ?? true,
@@ -2099,7 +2407,7 @@ async function runCommandInternal(command, argv, options = {}) {
2099
2407
  collector?.stop();
2100
2408
  if (hasUnknownSubcommand) {
2101
2409
  const unknownCmd = findFirstPositional(argv, context.globalExtracted) ?? "";
2102
- const similar = findSimilar(unknownCmd, subCmdNames);
2410
+ const similar = findSimilar(unknownCmd, [...allSubCmdNameSet]);
2103
2411
  const suggestion = similar.length > 0 ? ` Did you mean: ${similar.join(", ")}?` : "";
2104
2412
  return {
2105
2413
  success: false,
@@ -2127,16 +2435,33 @@ async function runCommandInternal(command, argv, options = {}) {
2127
2435
  };
2128
2436
  }
2129
2437
  if (parseResult.subCommand) {
2130
- const subCmd = await resolveSubcommand(command, parseResult.subCommand);
2131
- if (subCmd) {
2438
+ if (parseResult.unknownFlags.length > 0) {
2439
+ const globalMode = context.globalExtracted?.unknownKeysMode ?? "strip";
2440
+ if (globalMode === "strict") {
2441
+ collector?.stop();
2442
+ return {
2443
+ success: false,
2444
+ error: /* @__PURE__ */ new Error(`Unknown flags: ${parseResult.unknownFlags.join(", ")}`),
2445
+ exitCode: 1,
2446
+ logs: getCurrentLogs()
2447
+ };
2448
+ }
2449
+ if (globalMode === "strip") {
2450
+ const knownGlobalFlags = context.globalExtracted?.fields.map((f) => f.name) ?? [];
2451
+ for (const flag of parseResult.unknownFlags) logger.error(formatUnknownFlagWarning(flag, knownGlobalFlags));
2452
+ }
2453
+ }
2454
+ const resolved = await resolveSubcommandWithAlias(command, parseResult.subCommand);
2455
+ if (resolved) {
2132
2456
  const subContext = {
2133
2457
  commandPath: [...context.commandPath ?? [], parseResult.subCommand],
2134
2458
  rootName: context.rootName,
2135
2459
  rootVersion: context.rootVersion,
2136
- globalExtracted: context.globalExtracted
2460
+ globalExtracted: context.globalExtracted,
2461
+ aliasFor: resolved.aliasFor
2137
2462
  };
2138
2463
  collector?.stop();
2139
- return runCommandInternal(subCmd, parseResult.remainingArgs, {
2464
+ return runCommandInternal(resolved.command, parseResult.remainingArgs, {
2140
2465
  ...options,
2141
2466
  _context: subContext,
2142
2467
  _existingLogs: getCurrentLogs(),
@@ -2266,6 +2591,7 @@ function extractAndValidateGlobal(options) {
2266
2591
  validateDuplicateFields(extracted);
2267
2592
  validateCaseVariantCollisions(extracted);
2268
2593
  validateDuplicateAliases(extracted);
2594
+ validateDuplicateNegations(extracted);
2269
2595
  validateReservedAliases(extracted, true);
2270
2596
  const positionalNames = extracted.fields.filter((f) => f.positional).map((f) => f.name);
2271
2597
  if (positionalNames.length > 0) throw new Error(`Global options schema must not contain positional arguments. Found: ${positionalNames.join(", ")}`);
@@ -2274,5 +2600,5 @@ function extractAndValidateGlobal(options) {
2274
2600
  }
2275
2601
 
2276
2602
  //#endregion
2277
- export { logger as C, createDualCaseProxy as D, symbols as E, isColorEnabled as S, styles as T, PositionalConfigError as _, parseArgv as a, renderInline as b, validateCommand as c, validateDuplicateFields as d, validatePositionalConfig as f, DuplicateFieldError as g, DuplicateAliasError as h, formatValidationErrors as i, validateCrossSchemaCollisions as l, CaseVariantCollisionError as m, runMain as n, formatCommandValidationErrors as o, validateReservedAliases as p, runner_exports as r, validateCaseVariantCollisions as s, runCommand as t, validateDuplicateAliases as u, ReservedAliasError as v, setColorEnabled as w, renderMarkdown as x, generateHelp as y };
2278
- //# sourceMappingURL=runner-DSZw1AsW.js.map
2603
+ export { renderMarkdown as C, styles as D, setColorEnabled as E, symbols as O, renderInline as S, logger as T, DuplicateFieldError as _, parseArgv as a, ReservedAliasError as b, validateCommand as c, validateDuplicateFields as d, validateDuplicateNegations as f, DuplicateAliasError as g, CaseVariantCollisionError as h, formatValidationErrors as i, createDualCaseProxy as k, validateCrossSchemaCollisions as l, validateReservedAliases as m, runMain as n, formatCommandValidationErrors as o, validatePositionalConfig as p, runner_exports as r, validateCaseVariantCollisions as s, runCommand as t, validateDuplicateAliases as u, DuplicateNegationError as v, isColorEnabled as w, generateHelp as x, PositionalConfigError as y };
2604
+ //# sourceMappingURL=runner-BHeCMEa5.js.map