politty 0.6.0 → 0.8.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.
Files changed (41) hide show
  1. package/dist/{arg-registry-BoqVZRFO.d.ts → arg-registry-DDJpsUea.d.cts} +24 -2
  2. package/dist/arg-registry-DDJpsUea.d.cts.map +1 -0
  3. package/dist/{arg-registry-BoqVZRFO.d.cts → arg-registry-DDJpsUea.d.ts} +24 -2
  4. package/dist/arg-registry-DDJpsUea.d.ts.map +1 -0
  5. package/dist/augment.d.cts +1 -1
  6. package/dist/augment.d.ts +1 -1
  7. package/dist/cli.cjs +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/completion/index.d.cts +2 -2
  10. package/dist/completion/index.d.ts +2 -2
  11. package/dist/docs/index.cjs +827 -43
  12. package/dist/docs/index.cjs.map +1 -1
  13. package/dist/docs/index.d.cts +45 -3
  14. package/dist/docs/index.d.cts.map +1 -1
  15. package/dist/docs/index.d.ts +45 -3
  16. package/dist/docs/index.d.ts.map +1 -1
  17. package/dist/docs/index.js +827 -43
  18. package/dist/docs/index.js.map +1 -1
  19. package/dist/{index-Csk1VFou.d.ts → index-DKGn3lIl.d.ts} +2 -2
  20. package/dist/{index-Csk1VFou.d.ts.map → index-DKGn3lIl.d.ts.map} +1 -1
  21. package/dist/{index-Ct48_myg.d.cts → index-WyViqW59.d.cts} +2 -2
  22. package/dist/{index-Ct48_myg.d.cts.map → index-WyViqW59.d.cts.map} +1 -1
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.d.cts +3 -3
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js +1 -1
  27. package/dist/prompt/clack/index.d.cts +1 -1
  28. package/dist/prompt/clack/index.d.ts +1 -1
  29. package/dist/prompt/index.d.cts +1 -1
  30. package/dist/prompt/index.d.ts +1 -1
  31. package/dist/prompt/inquirer/index.d.cts +1 -1
  32. package/dist/prompt/inquirer/index.d.ts +1 -1
  33. package/dist/{runner--Zn4KN9B.js → runner-D43SkHt5.js} +119 -18
  34. package/dist/runner-D43SkHt5.js.map +1 -0
  35. package/dist/{runner-BloFWJEB.cjs → runner-DvFvokV6.cjs} +119 -18
  36. package/dist/runner-DvFvokV6.cjs.map +1 -0
  37. package/package.json +6 -6
  38. package/dist/arg-registry-BoqVZRFO.d.cts.map +0 -1
  39. package/dist/arg-registry-BoqVZRFO.d.ts.map +0 -1
  40. package/dist/runner--Zn4KN9B.js.map +0 -1
  41. package/dist/runner-BloFWJEB.cjs.map +0 -1
@@ -1832,28 +1832,61 @@ const BUILTIN_FLAGS = new Set([
1832
1832
  "--version"
1833
1833
  ]);
1834
1834
  /**
1835
- * Find the first positional argument in argv, properly skipping global flag values.
1836
- * Without globalExtracted, falls back to the first non-flag token.
1837
- */
1838
- function findFirstPositional(argv, globalExtracted) {
1839
- if (!globalExtracted) return argv.find((arg) => !arg.startsWith("-"));
1840
- const lookup = buildGlobalFlagLookup(globalExtracted);
1835
+ * Find the index of the first positional argument in argv, properly skipping
1836
+ * global flag values. Returns -1 when no positional is present.
1837
+ *
1838
+ * Mirrors `scanForSubcommand`'s conservative stop conditions: the scan stops
1839
+ * (returning -1) on a `--` terminator, a builtin flag (`--help`/`--version`),
1840
+ * an unknown long flag, or an unknown/combined short flag. Past such tokens we
1841
+ * can't tell a flag *value* from a positional, so continuing would misclassify
1842
+ * e.g. `--help plugin` or `--unknown value` and wrongly trip plugin dispatch.
1843
+ *
1844
+ * Without globalExtracted, no flag is global, so any leading flag halts the
1845
+ * scan and a positional is only found when it precedes every flag.
1846
+ */
1847
+ function findFirstPositionalIndex(argv, globalExtracted) {
1848
+ const lookup = globalExtracted ? buildGlobalFlagLookup(globalExtracted) : {
1849
+ aliasMap: /* @__PURE__ */ new Map(),
1850
+ booleanFlags: /* @__PURE__ */ new Set(),
1851
+ flagNames: /* @__PURE__ */ new Set(),
1852
+ cliNames: /* @__PURE__ */ new Set(),
1853
+ aliases: /* @__PURE__ */ new Set(),
1854
+ negationMap: /* @__PURE__ */ new Map(),
1855
+ customNegatedFields: /* @__PURE__ */ new Set()
1856
+ };
1841
1857
  for (let i = 0; i < argv.length; i++) {
1842
1858
  const arg = argv[i];
1843
- if (!arg.startsWith("-")) return arg;
1844
- if (arg === "--") return void 0;
1859
+ if (!arg.startsWith("-")) return i;
1860
+ if (arg === "--" || BUILTIN_FLAGS.has(arg)) return -1;
1845
1861
  if (arg.startsWith("--")) {
1846
- const { resolvedName, isNegated, isGlobal } = resolveGlobalLongOption(arg, lookup);
1847
- if (isGlobal && shouldConsumeValue(arg, resolvedName, isNegated, argv[i + 1], lookup.booleanFlags)) i++;
1848
- continue;
1862
+ const { resolvedName, isNegated, isGlobal, isSuppressedNegation } = resolveGlobalLongOption(arg, lookup);
1863
+ if (isGlobal) {
1864
+ if (shouldConsumeValue(arg, resolvedName, isNegated, argv[i + 1], lookup.booleanFlags)) i++;
1865
+ continue;
1866
+ }
1867
+ if (isSuppressedNegation) continue;
1868
+ return -1;
1849
1869
  }
1850
- if (arg.length === 2) {
1851
- const ch = arg[1];
1852
- if (lookup.aliases.has(ch)) {
1853
- if (shouldConsumeValue(arg, lookup.aliasMap.get(ch) ?? ch, false, argv[i + 1], lookup.booleanFlags)) i++;
1870
+ const withoutDash = arg.includes("=") ? arg.slice(1, arg.indexOf("=")) : arg.slice(1);
1871
+ if (withoutDash.length === 1) {
1872
+ const resolvedName = lookup.aliasMap.get(withoutDash) ?? withoutDash;
1873
+ if (lookup.aliases.has(withoutDash) || lookup.flagNames.has(resolvedName)) {
1874
+ if (shouldConsumeValue(arg, resolvedName, false, argv[i + 1], lookup.booleanFlags)) i++;
1875
+ continue;
1854
1876
  }
1855
1877
  }
1878
+ return -1;
1856
1879
  }
1880
+ return -1;
1881
+ }
1882
+ /**
1883
+ * Find the first positional argument in argv, properly skipping global flag
1884
+ * values. Thin wrapper over {@link findFirstPositionalIndex} — see that
1885
+ * function for the scan and stop conditions. Returns `undefined` when none.
1886
+ */
1887
+ function findFirstPositional(argv, globalExtracted) {
1888
+ const index = findFirstPositionalIndex(argv, globalExtracted);
1889
+ return index >= 0 ? argv[index] : void 0;
1857
1890
  }
1858
1891
 
1859
1892
  //#endregion
@@ -2315,6 +2348,25 @@ async function runMain(command, options = {}) {
2315
2348
  effectiveOptions = rest;
2316
2349
  }
2317
2350
  const globalExtracted = extractAndValidateGlobal(effectiveOptions);
2351
+ if (effectiveOptions.onUnknownSubcommand && !isInternalSubcommandInvocation(command, argv, globalExtractedForBypass)) {
2352
+ const knownSubCommands = require_schema_extractor.listSubCommandNamesWithAliases(command);
2353
+ if (knownSubCommands.size > 0) {
2354
+ const positionalIndex = findFirstPositionalIndex(argv, globalExtracted);
2355
+ const name = positionalIndex >= 0 ? argv[positionalIndex] : void 0;
2356
+ if (name && !knownSubCommands.has(name)) {
2357
+ const forwardArgs = argv.slice(positionalIndex + 1);
2358
+ const exitCode = await effectiveOptions.onUnknownSubcommand({
2359
+ commandPath: [],
2360
+ name,
2361
+ args: forwardArgs
2362
+ });
2363
+ if (typeof exitCode === "number") {
2364
+ await flushStandardStreams();
2365
+ return process.exit(exitCode);
2366
+ }
2367
+ }
2368
+ }
2369
+ }
2318
2370
  if (effectiveOptions.setup) try {
2319
2371
  await effectiveOptions.setup({});
2320
2372
  } catch (e) {
@@ -2332,6 +2384,7 @@ async function runMain(command, options = {}) {
2332
2384
  logger: effectiveOptions.logger,
2333
2385
  globalArgs: effectiveOptions.globalArgs,
2334
2386
  prompt: effectiveOptions.prompt,
2387
+ onUnknownSubcommand: effectiveOptions.onUnknownSubcommand,
2335
2388
  _globalExtracted: globalExtracted,
2336
2389
  _globalCleanup: effectiveOptions.cleanup,
2337
2390
  _context: {
@@ -2348,11 +2401,22 @@ async function runMain(command, options = {}) {
2348
2401
  await effectiveOptions.cleanup(cleanupCtx);
2349
2402
  } catch {}
2350
2403
  }
2351
- if (process.stdout.writableLength > 0) await new Promise((resolve) => process.stdout.once("drain", resolve));
2352
- if (process.stderr.writableLength > 0) await new Promise((resolve) => process.stderr.once("drain", resolve));
2404
+ await flushStandardStreams();
2353
2405
  process.exit(result.exitCode);
2354
2406
  }
2355
2407
  /**
2408
+ * Flush stdout/stderr before exit to prevent truncated output when piped
2409
+ * (pipe writes are buffered asynchronously, so exiting early loses data).
2410
+ *
2411
+ * We await a zero-byte write's callback rather than a `drain` event: `drain`
2412
+ * only fires after a `write()` returned `false` (backpressure), so buffered
2413
+ * writes that never tripped it would hang. The write callback is ordered after
2414
+ * all pending writes, so it resolves once the buffer is flushed.
2415
+ */
2416
+ async function flushStandardStreams() {
2417
+ await Promise.all([process.stdout, process.stderr].map((stream) => stream.writableLength > 0 ? new Promise((resolve) => stream.write("", () => resolve())) : Promise.resolve()));
2418
+ }
2419
+ /**
2356
2420
  * Internal implementation of command running
2357
2421
  */
2358
2422
  async function runCommandInternal(command, argv, options = {}) {
@@ -2376,6 +2440,43 @@ async function runCommandInternal(command, argv, options = {}) {
2376
2440
  ...options._parsedGlobalArgs,
2377
2441
  ...parseResult.rawGlobalArgs
2378
2442
  };
2443
+ const nestedCommandPath = context.commandPath ?? [];
2444
+ if (options.onUnknownSubcommand && nestedCommandPath.length > 0) {
2445
+ const knownSubCommands = require_schema_extractor.listSubCommandNamesWithAliases(command);
2446
+ if (knownSubCommands.size > 0) {
2447
+ const positionalIndex = findFirstPositionalIndex(argv, options._globalExtracted);
2448
+ const name = positionalIndex >= 0 ? argv[positionalIndex] : void 0;
2449
+ if (name && !knownSubCommands.has(name)) {
2450
+ const forwardArgs = argv.slice(positionalIndex + 1);
2451
+ const exitCode = await options.onUnknownSubcommand({
2452
+ commandPath: nestedCommandPath,
2453
+ name,
2454
+ args: forwardArgs
2455
+ });
2456
+ if (typeof exitCode === "number") {
2457
+ collector?.stop();
2458
+ if (options.handleSignals) {
2459
+ if (options._globalCleanup) try {
2460
+ await options._globalCleanup({ error: void 0 });
2461
+ } catch {}
2462
+ await flushStandardStreams();
2463
+ process.exit(exitCode);
2464
+ }
2465
+ return exitCode === 0 ? {
2466
+ success: true,
2467
+ result: void 0,
2468
+ exitCode: 0,
2469
+ logs: getCurrentLogs()
2470
+ } : {
2471
+ success: false,
2472
+ error: /* @__PURE__ */ new Error(`Plugin "${[...nestedCommandPath, name].join(" ")}" exited with code ${exitCode}`),
2473
+ exitCode,
2474
+ logs: getCurrentLogs()
2475
+ };
2476
+ }
2477
+ }
2478
+ }
2479
+ }
2379
2480
  if (parseResult.helpRequested || parseResult.helpAllRequested) {
2380
2481
  let hasUnknownSubcommand = false;
2381
2482
  const subCmdNames = require_schema_extractor.listSubCommands(command);
@@ -2761,4 +2862,4 @@ Object.defineProperty(exports, 'validateReservedAliases', {
2761
2862
  return validateReservedAliases;
2762
2863
  }
2763
2864
  });
2764
- //# sourceMappingURL=runner-BloFWJEB.cjs.map
2865
+ //# sourceMappingURL=runner-DvFvokV6.cjs.map