politty 0.9.1 → 0.10.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.
@@ -228,6 +228,8 @@ interface Logger {
228
228
  log(message: string): void;
229
229
  /** Log error message to stderr */
230
230
  error(message: string): void;
231
+ /** Log warning message to stderr */
232
+ warn?(message: string): void;
231
233
  }
232
234
  /**
233
235
  * Supported schema types for args
@@ -939,4 +941,4 @@ declare function arg<T extends z.ZodType>(schema: T): T;
939
941
  declare function arg<T extends z.ZodType, M extends ArgMeta<z.output<T>>>(schema: T, meta: ValidateArgMeta<M, z.output<T>>): T;
940
942
  //#endregion
941
943
  export { toKebabCase as $, LogStream as A, SetupContext as B, Example as C, IsEmpty as D, GlobalSetupContext as E, RunCommandOptions as F, isLazyCommand as G, SubCommandsRecord as H, RunResult as I, ResolvedFieldMeta as J, lazy as K, RunResultFailure as L, MainOptions as M, NonRunnableCommand as N, LogEntry as O, PromptResolver as P, toCamelCase as Q, RunResultSuccess as R, CommandBase as S, GlobalCleanupContext as T, UnknownSubcommandHandler as U, SubCommandValue as V, LazyCommand as W, extractFields as X, UnknownKeysMode as Y, getUnknownKeysMode as Z, AnyCommand as _, EffectContext as a, CollectedLogs as b, arg as c, ResolvedExpandCandidate as d, CompletionDirectiveMask as f, DynamicCompletionResult as g, DynamicCompletionResolver as h, CustomCompletion as i, Logger as j, LogLevel as k, ExpandCandidate as l, DynamicCompletionContext as m, CompletionMeta as n, PromptMeta as o, DynamicCompletionCandidate as p, ExtractedFields as q, CompletionType as r, PromptType as s, ArgMeta as t, ExpandCompletion as u, ArgsSchema as v, GlobalArgs as w, Command as x, CleanupContext as y, RunnableCommand as z };
942
- //# sourceMappingURL=arg-registry-DDJpsUea.d.ts.map
944
+ //# sourceMappingURL=arg-registry-BN3I-XON.d.ts.map
package/dist/augment.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as ArgMeta } from "./arg-registry-DDJpsUea.js";
1
+ import { t as ArgMeta } from "./arg-registry-BN3I-XON.js";
2
2
 
3
3
  //#region src/augment.d.ts
4
4
  declare module "zod" {
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as runMain } from "./runner-B-FZMN89.js";
2
+ import { n as runMain } from "./runner-DZOmYkN0.js";
3
3
  import { t as arg } from "./arg-registry-BeLLAW5-.js";
4
4
  import { n as defineCommand } from "./command-B4yA4LXX.js";
5
5
  import { p as generateBundledCompletionWorker } from "./completion-DwTFOtQk.js";
@@ -1,3 +1,3 @@
1
- import { f as CompletionDirectiveMask, g as DynamicCompletionResult, h as DynamicCompletionResolver, m as DynamicCompletionContext, p as DynamicCompletionCandidate } from "../arg-registry-DDJpsUea.js";
2
- import { A as BundledWorkerOptions, C as CandidateResult, D as CompletionContext, E as generateCandidates, F as CompletionMode, I as CompletionOptions, L as CompletionResult, M as CompletableSubcommand, N as CompletionData, O as CompletionType, P as CompletionGenerator, R as ShellType, S as hasCompleteCommand, T as CompletionDirective, _ as extractCompletionData, a as detectShell, b as formatForShell, c as withCompletionCommand, d as GenerateBundledCompletionWorkerOptions, f as GenerateBundledCompletionWorkerResult, g as validateBundledWorkerFile, h as generateBundledCompletionWorker, i as createRefreshCompletionCommand, j as CompletableOption, k as parseCompletionContext, l as ValueCompletionField, m as defaultBundledWorkerOutputPath, n as createCompletionCommand, o as generateCompletion, p as bundledWorkerShellExtension, r as createCompletionWorkerPathCommand, s as getSupportedShells, t as WithCompletionOptions, u as resolveValueCompletion, v as extractPositionals, w as CompletionCandidate, x as createDynamicCompleteCommand, y as ShellFormatOptions } from "../index-DKGn3lIl.js";
1
+ import { f as CompletionDirectiveMask, g as DynamicCompletionResult, h as DynamicCompletionResolver, m as DynamicCompletionContext, p as DynamicCompletionCandidate } from "../arg-registry-BN3I-XON.js";
2
+ import { A as BundledWorkerOptions, C as CandidateResult, D as CompletionContext, E as generateCandidates, F as CompletionMode, I as CompletionOptions, L as CompletionResult, M as CompletableSubcommand, N as CompletionData, O as CompletionType, P as CompletionGenerator, R as ShellType, S as hasCompleteCommand, T as CompletionDirective, _ as extractCompletionData, a as detectShell, b as formatForShell, c as withCompletionCommand, d as GenerateBundledCompletionWorkerOptions, f as GenerateBundledCompletionWorkerResult, g as validateBundledWorkerFile, h as generateBundledCompletionWorker, i as createRefreshCompletionCommand, j as CompletableOption, k as parseCompletionContext, l as ValueCompletionField, m as defaultBundledWorkerOutputPath, n as createCompletionCommand, o as generateCompletion, p as bundledWorkerShellExtension, r as createCompletionWorkerPathCommand, s as getSupportedShells, t as WithCompletionOptions, u as resolveValueCompletion, v as extractPositionals, w as CompletionCandidate, x as createDynamicCompleteCommand, y as ShellFormatOptions } from "../index-CtRrTVTL.js";
3
3
  export { type BundledWorkerOptions, type CandidateResult, type CompletableOption, type CompletableSubcommand, type CompletionCandidate, type CompletionContext, type CompletionData, CompletionDirective, type CompletionDirectiveMask, type CompletionGenerator, type CompletionMode, type CompletionOptions, type CompletionResult, type CompletionType, type DynamicCompletionCandidate, type DynamicCompletionContext, type DynamicCompletionResolver, type DynamicCompletionResult, type GenerateBundledCompletionWorkerOptions, type GenerateBundledCompletionWorkerResult, type ShellFormatOptions, type ShellType, type ValueCompletionField, WithCompletionOptions, bundledWorkerShellExtension, createCompletionCommand, createCompletionWorkerPathCommand, createDynamicCompleteCommand, createRefreshCompletionCommand, defaultBundledWorkerOutputPath, detectShell, extractCompletionData, extractPositionals, formatForShell, generateBundledCompletionWorker, generateCandidates, generateCompletion, getSupportedShells, hasCompleteCommand, parseCompletionContext, resolveValueCompletion, validateBundledWorkerFile, withCompletionCommand };
@@ -1,4 +1,4 @@
1
- import { C as Example, J as ResolvedFieldMeta, V as SubCommandValue, _ as AnyCommand, q as ExtractedFields, v as ArgsSchema } from "../arg-registry-DDJpsUea.js";
1
+ import { C as Example, J as ResolvedFieldMeta, V as SubCommandValue, _ as AnyCommand, q as ExtractedFields, v as ArgsSchema } from "../arg-registry-BN3I-XON.js";
2
2
  import { z } from "zod";
3
3
  import * as fs from "node:fs";
4
4
 
@@ -11,6 +11,12 @@ import * as fs from "node:fs";
11
11
  */
12
12
  declare function resolveLazyCommand(cmd: SubCommandValue): Promise<AnyCommand>;
13
13
  //#endregion
14
+ //#region src/docs/option-rows.d.ts
15
+ /**
16
+ * Column identifiers for the options markdown table, in their canonical order.
17
+ */
18
+ type ColumnId = "option" | "alias" | "description" | "required" | "default" | "env";
19
+ //#endregion
14
20
  //#region src/docs/render-args.d.ts
15
21
  /**
16
22
  * Args shape type (Record of string keys to Zod schemas)
@@ -21,7 +27,7 @@ type ArgsShape = Record<string, z.ZodType>;
21
27
  * Options for rendering args table
22
28
  */
23
29
  type ArgsTableOptions = {
24
- /** Columns to include in the table (default: all columns) */columns?: ("option" | "alias" | "description" | "required" | "default" | "env")[];
30
+ /** Columns to include in the table (default: all columns) */columns?: ColumnId[];
25
31
  };
26
32
  /**
27
33
  * Render args definition as a markdown options table
@@ -6,6 +6,204 @@ import * as path$1 from "node:path";
6
6
  import path from "node:path";
7
7
  import { isDeepStrictEqual } from "node:util";
8
8
 
9
+ //#region src/docs/option-rows.ts
10
+ /** Canonical column order used when no explicit column subset is requested. */
11
+ const DEFAULT_COLUMNS = [
12
+ "option",
13
+ "alias",
14
+ "description",
15
+ "required",
16
+ "default"
17
+ ];
18
+ /**
19
+ * Marker appended to a custom negation row/line so readers can see which
20
+ * positive flag it negates (e.g. `--monochrome` → ``(↔ `--color`)``).
21
+ */
22
+ function negationRelationMarker(opt) {
23
+ return `(↔ \`--${opt.cliName}\`)`;
24
+ }
25
+ /**
26
+ * Resolve placeholder for an option (uses kebab-case cliName).
27
+ */
28
+ function resolvePlaceholder(opt) {
29
+ return opt.placeholder ?? opt.cliName.toUpperCase().replace(/-/g, "_");
30
+ }
31
+ /**
32
+ * Normalize a single {@link ResolvedFieldMeta} into an {@link OptionRow}.
33
+ */
34
+ function toOptionRow(opt) {
35
+ const longFlag = opt.type === "boolean" ? `--${opt.cliName}` : `--${opt.cliName} <${resolvePlaceholder(opt)}>`;
36
+ const aliases = [];
37
+ if (opt.alias) for (const a of opt.alias) aliases.push(a.length === 1 ? `-${a}` : `--${a}`);
38
+ const hasNegationDisplay = opt.type === "boolean" && !!opt.negationDisplay;
39
+ const inlineNegation = hasNegationDisplay && !opt.negationDescription ? `--${opt.negationDisplay}` : void 0;
40
+ const negationRow = hasNegationDisplay && opt.negationDescription ? {
41
+ flag: `--${opt.negationDisplay}`,
42
+ description: opt.negationDescription,
43
+ relationMarker: negationRelationMarker(opt),
44
+ required: opt.required
45
+ } : void 0;
46
+ return {
47
+ longFlag,
48
+ aliases,
49
+ inlineNegation,
50
+ description: opt.description,
51
+ required: opt.required,
52
+ hasDefault: opt.defaultValue !== void 0,
53
+ defaultValue: opt.defaultValue,
54
+ env: opt.env,
55
+ negationRow
56
+ };
57
+ }
58
+ /**
59
+ * Build the normalized intermediate representation for a list of options.
60
+ * This is the single source of truth for per-option display decisions; the
61
+ * emitters below ({@link emitMarkdownTable}, {@link emitMarkdownList}) are pure
62
+ * formatting.
63
+ */
64
+ function toOptionRows(options) {
65
+ return options.map(toOptionRow);
66
+ }
67
+ /**
68
+ * Escape markdown special characters in table cells.
69
+ */
70
+ function escapeTableCell$2(str) {
71
+ return str.replace(/\|/g, "\\|").replace(/\n/g, " ");
72
+ }
73
+ function backtick(value) {
74
+ return `\`${value}\``;
75
+ }
76
+ /**
77
+ * Format default value for table display.
78
+ */
79
+ function formatDefaultValue(row) {
80
+ if (!row.hasDefault) return "-";
81
+ return `\`${JSON.stringify(row.defaultValue)}\``;
82
+ }
83
+ /**
84
+ * Format env variable names for a markdown table cell.
85
+ */
86
+ function formatEnvNames(env) {
87
+ if (!env) return "-";
88
+ if (Array.isArray(env)) return env.map((e) => `\`${e}\``).join(", ");
89
+ return `\`${env}\``;
90
+ }
91
+ /**
92
+ * Format env variable info for a markdown list item (e.g. `[env: PORT, SERVER_PORT]`).
93
+ */
94
+ function formatEnvInfo(env) {
95
+ if (!env) return "";
96
+ return ` [env: ${(Array.isArray(env) ? env : [env]).join(", ")}]`;
97
+ }
98
+ /** Header label + separator dashes for each column, matching legacy widths. */
99
+ const COLUMN_META = {
100
+ option: {
101
+ header: "Option",
102
+ separator: "--------"
103
+ },
104
+ alias: {
105
+ header: "Alias",
106
+ separator: "-------"
107
+ },
108
+ description: {
109
+ header: "Description",
110
+ separator: "-------------"
111
+ },
112
+ required: {
113
+ header: "Required",
114
+ separator: "----------"
115
+ },
116
+ default: {
117
+ header: "Default",
118
+ separator: "---------"
119
+ },
120
+ env: {
121
+ header: "Env",
122
+ separator: "-----"
123
+ }
124
+ };
125
+ /**
126
+ * Render the table cell for a base option row in the given column.
127
+ */
128
+ function tableCell(row, col) {
129
+ switch (col) {
130
+ case "option": {
131
+ const name = backtick(row.longFlag);
132
+ return row.inlineNegation ? `${name} / ${backtick(row.inlineNegation)}` : name;
133
+ }
134
+ case "alias": return row.aliases.length > 0 ? row.aliases.map(backtick).join(", ") : "-";
135
+ case "description": return escapeTableCell$2(row.description ?? "");
136
+ case "required": return row.required ? "Yes" : "No";
137
+ case "default": return formatDefaultValue(row);
138
+ case "env": return formatEnvNames(row.env);
139
+ }
140
+ }
141
+ /**
142
+ * Render the table cell for a negation row in the given column.
143
+ */
144
+ function negationTableCell(neg, col) {
145
+ switch (col) {
146
+ case "option": return backtick(neg.flag);
147
+ case "description": return `${escapeTableCell$2(neg.description)} ${neg.relationMarker}`;
148
+ case "required": return neg.required ? "Yes" : "No";
149
+ case "alias":
150
+ case "default":
151
+ case "env": return "-";
152
+ }
153
+ }
154
+ /**
155
+ * Emit option rows as a markdown table.
156
+ *
157
+ * When `columns` is omitted, the canonical column set is used and the `Env`
158
+ * column is appended automatically iff any row has env configured. When
159
+ * `columns` is provided, exactly those columns are emitted, in that order.
160
+ *
161
+ * The separator row always uses the canonical fixed-width dashes from
162
+ * {@link COLUMN_META}, so every table — default or column-filtered — shares a
163
+ * single, consistent format.
164
+ */
165
+ function emitMarkdownTable(rows, columns) {
166
+ if (rows.length === 0) return "";
167
+ const cols = columns ?? (rows.some((r) => r.env) ? [...DEFAULT_COLUMNS, "env"] : DEFAULT_COLUMNS);
168
+ const lines = [];
169
+ lines.push(`| ${cols.map((c) => COLUMN_META[c].header).join(" | ")} |`);
170
+ lines.push(`|${cols.map((c) => COLUMN_META[c].separator).join("|")}|`);
171
+ for (const row of rows) {
172
+ lines.push(`| ${cols.map((c) => tableCell(row, c)).join(" | ")} |`);
173
+ if (row.negationRow) lines.push(`| ${cols.map((c) => negationTableCell(row.negationRow, c)).join(" | ")} |`);
174
+ }
175
+ return lines.join("\n");
176
+ }
177
+ /**
178
+ * Emit option rows as a markdown list.
179
+ *
180
+ * Aliases are joined with `, ` (short flags first, then the long flag, then
181
+ * long aliases); the inline negation is appended with ` / ` so it stays
182
+ * visually distinct from aliases.
183
+ */
184
+ function emitMarkdownList(rows) {
185
+ if (rows.length === 0) return "";
186
+ const lines = [];
187
+ for (const row of rows) {
188
+ const shortAliases = row.aliases.filter((a) => !a.startsWith("--"));
189
+ const longAliases = row.aliases.filter((a) => a.startsWith("--"));
190
+ let flags = [
191
+ ...shortAliases,
192
+ row.longFlag,
193
+ ...longAliases
194
+ ].map(backtick).join(", ");
195
+ if (row.inlineNegation) flags += ` / ${backtick(row.inlineNegation)}`;
196
+ const desc = row.description ? ` - ${row.description}` : "";
197
+ const required = row.required ? " (required)" : "";
198
+ const defaultVal = row.hasDefault ? ` (default: ${JSON.stringify(row.defaultValue)})` : "";
199
+ const envInfo = formatEnvInfo(row.env);
200
+ lines.push(`- ${flags}${desc}${required}${defaultVal}${envInfo}`);
201
+ if (row.negationRow) lines.push(`- ${backtick(row.negationRow.flag)} - ${row.negationRow.description} ${row.negationRow.relationMarker}`);
202
+ }
203
+ return lines.join("\n");
204
+ }
205
+
206
+ //#endregion
9
207
  //#region src/docs/types.ts
10
208
  /**
11
209
  * Environment variable name for update mode
@@ -108,30 +306,17 @@ function indexEndMarker(scope) {
108
306
  /**
109
307
  * Escape markdown special characters in table cells
110
308
  */
111
- function escapeTableCell$2(str) {
309
+ function escapeTableCell$1(str) {
112
310
  return str.replace(/\|/g, "\\|").replace(/\n/g, " ");
113
311
  }
114
312
  /**
115
- * Marker appended to a custom negation row/line so readers can see which
116
- * positive flag it negates (e.g. `--monochrome` → `(↔ \`--color\`)`).
117
- */
118
- function negationRelationMarker(opt) {
119
- return `(↔ \`--${opt.cliName}\`)`;
120
- }
121
- /**
122
- * Format default value for display
123
- */
124
- function formatDefaultValue$1(value) {
125
- if (value === void 0) return "-";
126
- return `\`${JSON.stringify(value)}\``;
127
- }
128
- /**
129
313
  * Render usage line
130
314
  */
131
315
  function renderUsage(info) {
132
316
  const parts = [info.fullCommandPath];
133
317
  if (info.options.length > 0) parts.push("[options]");
134
- if (info.subCommands.length > 0) parts.push("[command]");
318
+ if (info.subCommands.length > 0) if (info.command.run) parts.push("[command]");
319
+ else parts.push("<command>");
135
320
  for (const arg of info.positionalArgs) if (arg.required) parts.push(`<${arg.name}>`);
136
321
  else parts.push(`[${arg.name}]`);
137
322
  return parts.join(" ");
@@ -145,7 +330,7 @@ function renderArgumentsTable(info) {
145
330
  lines.push("| Argument | Description | Required |");
146
331
  lines.push("|----------|-------------|----------|");
147
332
  for (const arg of info.positionalArgs) {
148
- const desc = escapeTableCell$2(arg.description ?? "");
333
+ const desc = escapeTableCell$1(arg.description ?? "");
149
334
  const required = arg.required ? "Yes" : "No";
150
335
  lines.push(`| \`${arg.name}\` | ${desc} | ${required} |`);
151
336
  }
@@ -165,70 +350,6 @@ function renderArgumentsList(info) {
165
350
  return lines.join("\n");
166
351
  }
167
352
  /**
168
- * Format environment variable info for display
169
- */
170
- function formatEnvInfo(env) {
171
- if (!env) return "";
172
- return ` [env: ${(Array.isArray(env) ? env : [env]).join(", ")}]`;
173
- }
174
- /**
175
- * Resolve placeholder for an option (uses kebab-case cliName)
176
- */
177
- function resolvePlaceholder(opt) {
178
- return opt.placeholder ?? opt.cliName.toUpperCase().replace(/-/g, "_");
179
- }
180
- /**
181
- * Format option name for table display (e.g., `--dry-run` or `--port <PORT>`)
182
- *
183
- * Boolean fields with a custom inline `negation` (no separate description) are
184
- * shown as `\`--cache\` / \`--disable-cache\``.
185
- */
186
- function formatOptionName(opt) {
187
- const placeholder = resolvePlaceholder(opt);
188
- if (opt.type === "boolean") {
189
- const positive = `\`--${opt.cliName}\``;
190
- if (opt.negationDisplay && !opt.negationDescription) return `${positive} / \`--${opt.negationDisplay}\``;
191
- return positive;
192
- }
193
- return `\`--${opt.cliName} <${placeholder}>\``;
194
- }
195
- /**
196
- * Format option flags for list display (uses kebab-case cliName).
197
- * Aliases are joined with `, `; the inline negation (when no separate
198
- * `negationDescription` is set) is appended with ` / ` so it stays
199
- * visually distinct from aliases, matching help and table output.
200
- */
201
- function formatOptionFlags(opt) {
202
- const placeholder = resolvePlaceholder(opt);
203
- const longFlag = opt.type === "boolean" ? `--${opt.cliName}` : `--${opt.cliName} <${placeholder}>`;
204
- const parts = [];
205
- if (opt.alias) {
206
- for (const a of opt.alias) if (a.length === 1) parts.push(`\`-${a}\``);
207
- }
208
- parts.push(`\`${longFlag}\``);
209
- if (opt.alias) {
210
- for (const a of opt.alias) if (a.length > 1) parts.push(`\`--${a}\``);
211
- }
212
- const aliasJoined = parts.join(", ");
213
- if (opt.type === "boolean" && opt.negationDisplay && !opt.negationDescription) return `${aliasJoined} / \`--${opt.negationDisplay}\``;
214
- return aliasJoined;
215
- }
216
- /**
217
- * Format aliases for a markdown table cell
218
- */
219
- function formatAliasCell(alias) {
220
- if (!alias || alias.length === 0) return "-";
221
- return alias.map((a) => `\`${a.length === 1 ? `-${a}` : `--${a}`}\``).join(", ");
222
- }
223
- /**
224
- * Format env variable names for table display
225
- */
226
- function formatEnvNames(env) {
227
- if (!env) return "-";
228
- if (Array.isArray(env)) return env.map((e) => `\`${e}\``).join(", ");
229
- return `\`${env}\``;
230
- }
231
- /**
232
353
  * Render options as markdown table
233
354
  *
234
355
  * Features:
@@ -243,34 +364,7 @@ function formatEnvNames(env) {
243
364
  * | `--port <PORT>` | - | Server port | Yes | - | `PORT`, `SERVER_PORT` |
244
365
  */
245
366
  function renderOptionsTable(info) {
246
- if (info.options.length === 0) return "";
247
- const hasEnv = info.options.some((opt) => opt.env);
248
- const lines = [];
249
- if (hasEnv) {
250
- lines.push("| Option | Alias | Description | Required | Default | Env |");
251
- lines.push("|--------|-------|-------------|----------|---------|-----|");
252
- } else {
253
- lines.push("| Option | Alias | Description | Required | Default |");
254
- lines.push("|--------|-------|-------------|----------|---------|");
255
- }
256
- for (const opt of info.options) {
257
- const optionName = formatOptionName(opt);
258
- const alias = formatAliasCell(opt.alias);
259
- const desc = escapeTableCell$2(opt.description ?? "");
260
- const required = opt.required ? "Yes" : "No";
261
- const defaultVal = formatDefaultValue$1(opt.defaultValue);
262
- if (hasEnv) {
263
- const envNames = formatEnvNames(opt.env);
264
- lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} | ${envNames} |`);
265
- } else lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} |`);
266
- if (opt.type === "boolean" && opt.negationDisplay && opt.negationDescription) {
267
- const negName = `\`--${opt.negationDisplay}\``;
268
- const negDesc = `${escapeTableCell$2(opt.negationDescription)} ${negationRelationMarker(opt)}`;
269
- if (hasEnv) lines.push(`| ${negName} | - | ${negDesc} | ${required} | - | - |`);
270
- else lines.push(`| ${negName} | - | ${negDesc} | ${required} | - |`);
271
- }
272
- }
273
- return lines.join("\n");
367
+ return emitMarkdownTable(toOptionRows(info.options));
274
368
  }
275
369
  /**
276
370
  * Render options as markdown list
@@ -284,18 +378,7 @@ function renderOptionsTable(info) {
284
378
  * - `--port <PORT>` - Server port (required) [env: PORT, SERVER_PORT]
285
379
  */
286
380
  function renderOptionsList(info) {
287
- if (info.options.length === 0) return "";
288
- const lines = [];
289
- for (const opt of info.options) {
290
- const flags = formatOptionFlags(opt);
291
- const desc = opt.description ? ` - ${opt.description}` : "";
292
- const required = opt.required ? " (required)" : "";
293
- const defaultVal = opt.defaultValue !== void 0 ? ` (default: ${JSON.stringify(opt.defaultValue)})` : "";
294
- const envInfo = formatEnvInfo(opt.env);
295
- lines.push(`- ${flags}${desc}${required}${defaultVal}${envInfo}`);
296
- if (opt.type === "boolean" && opt.negationDisplay && opt.negationDescription) lines.push(`- \`--${opt.negationDisplay}\` - ${opt.negationDescription} ${negationRelationMarker(opt)}`);
297
- }
298
- return lines.join("\n");
381
+ return emitMarkdownList(toOptionRows(info.options));
299
382
  }
300
383
  /**
301
384
  * Generate anchor from command path
@@ -322,34 +405,7 @@ function renderSubcommandsTable(info, generateAnchors = true) {
322
405
  * Render options from array as table
323
406
  */
324
407
  function renderOptionsTableFromArray(options) {
325
- if (options.length === 0) return "";
326
- const hasEnv = options.some((opt) => opt.env);
327
- const lines = [];
328
- if (hasEnv) {
329
- lines.push("| Option | Alias | Description | Required | Default | Env |");
330
- lines.push("|--------|-------|-------------|----------|---------|-----|");
331
- } else {
332
- lines.push("| Option | Alias | Description | Required | Default |");
333
- lines.push("|--------|-------|-------------|----------|---------|");
334
- }
335
- for (const opt of options) {
336
- const optionName = formatOptionName(opt);
337
- const alias = formatAliasCell(opt.alias);
338
- const desc = escapeTableCell$2(opt.description ?? "");
339
- const required = opt.required ? "Yes" : "No";
340
- const defaultVal = formatDefaultValue$1(opt.defaultValue);
341
- if (hasEnv) {
342
- const envNames = formatEnvNames(opt.env);
343
- lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} | ${envNames} |`);
344
- } else lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} |`);
345
- if (opt.type === "boolean" && opt.negationDisplay && opt.negationDescription) {
346
- const negName = `\`--${opt.negationDisplay}\``;
347
- const negDesc = `${escapeTableCell$2(opt.negationDescription)} ${negationRelationMarker(opt)}`;
348
- if (hasEnv) lines.push(`| ${negName} | - | ${negDesc} | ${required} | - | - |`);
349
- else lines.push(`| ${negName} | - | ${negDesc} | ${required} | - |`);
350
- }
351
- }
352
- return lines.join("\n");
408
+ return emitMarkdownTable(toOptionRows(options));
353
409
  }
354
410
  /**
355
411
  * Render union/xor options as markdown with variant grouping
@@ -420,18 +476,7 @@ function renderDiscriminatedUnionOptionsMarkdown(extracted, style = "table") {
420
476
  * Render options from array as list
421
477
  */
422
478
  function renderOptionsListFromArray(options) {
423
- if (options.length === 0) return "";
424
- const lines = [];
425
- for (const opt of options) {
426
- const flags = formatOptionFlags(opt);
427
- const desc = opt.description ? ` - ${opt.description}` : "";
428
- const required = opt.required ? " (required)" : "";
429
- const defaultVal = opt.defaultValue !== void 0 ? ` (default: ${JSON.stringify(opt.defaultValue)})` : "";
430
- const envInfo = formatEnvInfo(opt.env);
431
- lines.push(`- ${flags}${desc}${required}${defaultVal}${envInfo}`);
432
- if (opt.type === "boolean" && opt.negationDisplay && opt.negationDescription) lines.push(`- \`--${opt.negationDisplay}\` - ${opt.negationDescription} ${negationRelationMarker(opt)}`);
433
- }
434
- return lines.join("\n");
479
+ return emitMarkdownList(toOptionRows(options));
435
480
  }
436
481
  /**
437
482
  * Render arguments from array as table
@@ -442,7 +487,7 @@ function renderArgumentsTableFromArray(args) {
442
487
  lines.push("| Argument | Description | Required |");
443
488
  lines.push("|----------|-------------|----------|");
444
489
  for (const arg of args) {
445
- const desc = escapeTableCell$2(arg.description ?? "");
490
+ const desc = escapeTableCell$1(arg.description ?? "");
446
491
  const required = arg.required ? "Yes" : "No";
447
492
  lines.push(`| \`${arg.name}\` | ${desc} | ${required} |`);
448
493
  }
@@ -479,9 +524,9 @@ function renderSubcommandsTableFromArray(subcommands, info, generateAnchors = tr
479
524
  const fileMap = info.fileMap;
480
525
  for (const sub of subcommands) {
481
526
  const fullName = sub.fullPath.join(" ");
482
- const desc = escapeTableCell$2(sub.description ?? "");
527
+ const desc = escapeTableCell$1(sub.description ?? "");
483
528
  const subCommandPath = sub.fullPath.join(" ");
484
- const aliasCell = hasAliases ? sub.aliases && sub.aliases.length > 0 ? sub.aliases.map((a) => `\`${escapeTableCell$2(a)}\``).join(", ") : "-" : "";
529
+ const aliasCell = hasAliases ? sub.aliases && sub.aliases.length > 0 ? sub.aliases.map((a) => `\`${escapeTableCell$1(a)}\``).join(", ") : "-" : "";
485
530
  let cmdCell;
486
531
  if (generateAnchors) {
487
532
  const anchor = generateAnchor$1(sub.fullPath);
@@ -874,7 +919,7 @@ async function executeSingleExample(example, rootCommand, commandPath) {
874
919
  collector.start();
875
920
  let success = true;
876
921
  try {
877
- const { runCommand } = await import("../runner-B-FZMN89.js").then((n) => n.r);
922
+ const { runCommand } = await import("../runner-DZOmYkN0.js").then((n) => n.r);
878
923
  const result = await runCommand(rootCommand, argv);
879
924
  success = result.success;
880
925
  if (!result.success && result.error) console.error(result.error.message);
@@ -966,111 +1011,7 @@ function extractArgsFields(args) {
966
1011
  function renderArgsTable(args, options) {
967
1012
  const optionFields = extractArgsFields(args).filter((f) => !f.positional);
968
1013
  if (optionFields.length === 0) return "";
969
- if (options?.columns) return renderFilteredTable(optionFields, options.columns);
970
- return renderOptionsTableFromArray(optionFields);
971
- }
972
- /**
973
- * Escape markdown special characters in table cells
974
- */
975
- function escapeTableCell$1(str) {
976
- return str.replace(/\|/g, "\\|").replace(/\n/g, " ");
977
- }
978
- /**
979
- * Format default value for display
980
- */
981
- function formatDefaultValue(value) {
982
- if (value === void 0) return "-";
983
- return `\`${JSON.stringify(value)}\``;
984
- }
985
- /**
986
- * Render table with filtered columns
987
- */
988
- function renderFilteredTable(options, columns) {
989
- const lines = [];
990
- const headerCells = [];
991
- const separatorCells = [];
992
- for (const col of columns) switch (col) {
993
- case "option":
994
- headerCells.push("Option");
995
- separatorCells.push("------");
996
- break;
997
- case "alias":
998
- headerCells.push("Alias");
999
- separatorCells.push("-----");
1000
- break;
1001
- case "description":
1002
- headerCells.push("Description");
1003
- separatorCells.push("-----------");
1004
- break;
1005
- case "required":
1006
- headerCells.push("Required");
1007
- separatorCells.push("--------");
1008
- break;
1009
- case "default":
1010
- headerCells.push("Default");
1011
- separatorCells.push("-------");
1012
- break;
1013
- case "env":
1014
- headerCells.push("Env");
1015
- separatorCells.push("---");
1016
- break;
1017
- }
1018
- lines.push(`| ${headerCells.join(" | ")} |`);
1019
- lines.push(`| ${separatorCells.join(" | ")} |`);
1020
- for (const opt of options) {
1021
- const cells = [];
1022
- for (const col of columns) switch (col) {
1023
- case "option": {
1024
- const placeholder = opt.placeholder ?? opt.cliName.toUpperCase().replace(/-/g, "_");
1025
- let optionName;
1026
- if (opt.type === "boolean") {
1027
- optionName = `\`--${opt.cliName}\``;
1028
- if (opt.negationDisplay && !opt.negationDescription) optionName += ` / \`--${opt.negationDisplay}\``;
1029
- } else optionName = `\`--${opt.cliName} <${placeholder}>\``;
1030
- cells.push(optionName);
1031
- break;
1032
- }
1033
- case "alias":
1034
- cells.push(opt.alias && opt.alias.length > 0 ? opt.alias.map((a) => `\`${a.length === 1 ? `-${a}` : `--${a}`}\``).join(", ") : "-");
1035
- break;
1036
- case "description":
1037
- cells.push(escapeTableCell$1(opt.description ?? ""));
1038
- break;
1039
- case "required":
1040
- cells.push(opt.required ? "Yes" : "No");
1041
- break;
1042
- case "default":
1043
- cells.push(formatDefaultValue(opt.defaultValue));
1044
- break;
1045
- case "env": {
1046
- const envNames = opt.env ? Array.isArray(opt.env) ? opt.env.map((e) => `\`${e}\``).join(", ") : `\`${opt.env}\`` : "-";
1047
- cells.push(envNames);
1048
- break;
1049
- }
1050
- }
1051
- lines.push(`| ${cells.join(" | ")} |`);
1052
- if (opt.type === "boolean" && opt.negationDisplay && opt.negationDescription) {
1053
- const negCells = [];
1054
- for (const col of columns) switch (col) {
1055
- case "option":
1056
- negCells.push(`\`--${opt.negationDisplay}\``);
1057
- break;
1058
- case "description":
1059
- negCells.push(`${escapeTableCell$1(opt.negationDescription)} ${negationRelationMarker(opt)}`);
1060
- break;
1061
- case "required":
1062
- negCells.push(opt.required ? "Yes" : "No");
1063
- break;
1064
- case "alias":
1065
- case "default":
1066
- case "env":
1067
- negCells.push("-");
1068
- break;
1069
- }
1070
- lines.push(`| ${negCells.join(" | ")} |`);
1071
- }
1072
- }
1073
- return lines.join("\n");
1014
+ return emitMarkdownTable(toOptionRows(optionFields), options?.columns);
1074
1015
  }
1075
1016
 
1076
1017
  //#endregion
@@ -1,4 +1,4 @@
1
- import { J as ResolvedFieldMeta, _ as AnyCommand, d as ResolvedExpandCandidate, h as DynamicCompletionResolver, u as ExpandCompletion, v as ArgsSchema, x as Command } from "./arg-registry-DDJpsUea.js";
1
+ import { J as ResolvedFieldMeta, _ as AnyCommand, d as ResolvedExpandCandidate, h as DynamicCompletionResolver, u as ExpandCompletion, v as ArgsSchema, x as Command } from "./arg-registry-BN3I-XON.js";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/completion/types.d.ts
@@ -660,4 +660,4 @@ interface WithCompletionOptions {
660
660
  declare function withCompletionCommand<T extends AnyCommand>(command: T, options?: string | WithCompletionOptions): T;
661
661
  //#endregion
662
662
  export { BundledWorkerOptions as A, CandidateResult as C, CompletionContext as D, generateCandidates as E, CompletionMode as F, CompletionOptions as I, CompletionResult as L, CompletableSubcommand as M, CompletionData as N, CompletionType as O, CompletionGenerator as P, ShellType as R, hasCompleteCommand as S, CompletionDirective as T, extractCompletionData as _, detectShell as a, formatForShell as b, withCompletionCommand as c, GenerateBundledCompletionWorkerOptions as d, GenerateBundledCompletionWorkerResult as f, validateBundledWorkerFile as g, generateBundledCompletionWorker as h, createRefreshCompletionCommand as i, CompletableOption as j, parseCompletionContext as k, ValueCompletionField as l, defaultBundledWorkerOutputPath as m, createCompletionCommand as n, generateCompletion as o, bundledWorkerShellExtension as p, createCompletionWorkerPathCommand as r, getSupportedShells as s, WithCompletionOptions as t, resolveValueCompletion as u, extractPositionals as v, CompletionCandidate as w, createDynamicCompleteCommand as x, ShellFormatOptions as y };
663
- //# sourceMappingURL=index-DKGn3lIl.d.ts.map
663
+ //# sourceMappingURL=index-CtRrTVTL.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { $ as toKebabCase, A as LogStream, B as SetupContext, C as Example, D as IsEmpty, E as GlobalSetupContext, F as RunCommandOptions, G as isLazyCommand, H as SubCommandsRecord, I as RunResult, J as ResolvedFieldMeta, K as lazy, L as RunResultFailure, M as MainOptions, N as NonRunnableCommand, O as LogEntry, P as PromptResolver, Q as toCamelCase, R as RunResultSuccess, S as CommandBase, T as GlobalCleanupContext, U as UnknownSubcommandHandler, V as SubCommandValue, W as LazyCommand, X as extractFields, Y as UnknownKeysMode, Z as getUnknownKeysMode, _ as AnyCommand, a as EffectContext, b as CollectedLogs, c as arg, d as ResolvedExpandCandidate, f as CompletionDirectiveMask, g as DynamicCompletionResult, h as DynamicCompletionResolver, i as CustomCompletion, j as Logger, k as LogLevel, l as ExpandCandidate, m as DynamicCompletionContext, n as CompletionMeta, o as PromptMeta, p as DynamicCompletionCandidate, q as ExtractedFields, r as CompletionType, s as PromptType, t as ArgMeta, u as ExpandCompletion, v as ArgsSchema, w as GlobalArgs, x as Command, y as CleanupContext, z as RunnableCommand } from "./arg-registry-DDJpsUea.js";
2
- import { I as CompletionOptions, L as CompletionResult, c as withCompletionCommand, d as GenerateBundledCompletionWorkerOptions, f as GenerateBundledCompletionWorkerResult, h as generateBundledCompletionWorker, o as generateCompletion, t as WithCompletionOptions } from "./index-DKGn3lIl.js";
1
+ import { $ as toKebabCase, A as LogStream, B as SetupContext, C as Example, D as IsEmpty, E as GlobalSetupContext, F as RunCommandOptions, G as isLazyCommand, H as SubCommandsRecord, I as RunResult, J as ResolvedFieldMeta, K as lazy, L as RunResultFailure, M as MainOptions, N as NonRunnableCommand, O as LogEntry, P as PromptResolver, Q as toCamelCase, R as RunResultSuccess, S as CommandBase, T as GlobalCleanupContext, U as UnknownSubcommandHandler, V as SubCommandValue, W as LazyCommand, X as extractFields, Y as UnknownKeysMode, Z as getUnknownKeysMode, _ as AnyCommand, a as EffectContext, b as CollectedLogs, c as arg, d as ResolvedExpandCandidate, f as CompletionDirectiveMask, g as DynamicCompletionResult, h as DynamicCompletionResolver, i as CustomCompletion, j as Logger, k as LogLevel, l as ExpandCandidate, m as DynamicCompletionContext, n as CompletionMeta, o as PromptMeta, p as DynamicCompletionCandidate, q as ExtractedFields, r as CompletionType, s as PromptType, t as ArgMeta, u as ExpandCompletion, v as ArgsSchema, w as GlobalArgs, x as Command, y as CleanupContext, z as RunnableCommand } from "./arg-registry-BN3I-XON.js";
2
+ import { I as CompletionOptions, L as CompletionResult, c as withCompletionCommand, d as GenerateBundledCompletionWorkerOptions, f as GenerateBundledCompletionWorkerResult, h as generateBundledCompletionWorker, o as generateCompletion, t as WithCompletionOptions } from "./index-CtRrTVTL.js";
3
3
  import { z } from "zod";
4
4
 
5
5
  //#region src/core/case-types.d.ts
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as renderMarkdown, S as renderInline, _ as DuplicateFieldError, a as parseArgv, b as ReservedAliasError, c as validateCommand, d as validateDuplicateFields, f as validateDuplicateNegations, g as DuplicateAliasError, h as CaseVariantCollisionError, i as formatValidationErrors, l as validateCrossSchemaCollisions, m as validateReservedAliases, n as runMain, o as formatCommandValidationErrors, p as validatePositionalConfig, s as validateCaseVariantCollisions, t as runCommand, u as validateDuplicateAliases, v as DuplicateNegationError, w as createDualCaseProxy, x as generateHelp, y as PositionalConfigError } from "./runner-B-FZMN89.js";
1
+ import { C as renderMarkdown, S as renderInline, _ as DuplicateFieldError, a as parseArgv, b as ReservedAliasError, c as validateCommand, d as validateDuplicateFields, f as validateDuplicateNegations, g as DuplicateAliasError, h as CaseVariantCollisionError, i as formatValidationErrors, l as validateCrossSchemaCollisions, m as validateReservedAliases, n as runMain, o as formatCommandValidationErrors, p as validatePositionalConfig, s as validateCaseVariantCollisions, t as runCommand, u as validateDuplicateAliases, v as DuplicateNegationError, w as createDualCaseProxy, x as generateHelp, y as PositionalConfigError } from "./runner-DZOmYkN0.js";
2
2
  import { t as arg } from "./arg-registry-BeLLAW5-.js";
3
3
  import { n as defineCommand, t as createDefineCommand } from "./command-B4yA4LXX.js";
4
4
  import { a as toCamelCase, f as isLazyCommand, i as getUnknownKeysMode, o as toKebabCase, p as lazy, t as extractFields } from "./schema-extractor-CVHWm23M.js";
@@ -1,4 +1,4 @@
1
- import { P as PromptResolver } from "../../arg-registry-DDJpsUea.js";
1
+ import { P as PromptResolver } from "../../arg-registry-BN3I-XON.js";
2
2
 
3
3
  //#region src/prompt/clack/index.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { J as ResolvedFieldMeta, q as ExtractedFields } from "../arg-registry-DDJpsUea.js";
1
+ import { J as ResolvedFieldMeta, q as ExtractedFields } from "../arg-registry-BN3I-XON.js";
2
2
 
3
3
  //#region src/prompt/types.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { P as PromptResolver } from "../../arg-registry-DDJpsUea.js";
1
+ import { P as PromptResolver } from "../../arg-registry-BN3I-XON.js";
2
2
 
3
3
  //#region src/prompt/inquirer/index.d.ts
4
4
  /**
@@ -576,10 +576,12 @@ function renderUsageLine(command, context) {
576
576
  if (extracted) {
577
577
  const positionals = extracted.fields.filter((a) => a.positional);
578
578
  if (extracted.fields.filter((a) => !a.positional).length > 0) parts.push(styles.placeholder("[options]"));
579
- if (command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) parts.push(styles.placeholder("[command]"));
579
+ if (command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) if (command.run) parts.push(styles.placeholder("[command]"));
580
+ else parts.push(styles.option("<command>"));
580
581
  for (const arg of positionals) if (arg.required) parts.push(styles.option(`<${arg.name}>`));
581
582
  else parts.push(styles.placeholder(`[${arg.name}]`));
582
- } else if (command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) parts.push(styles.placeholder("[command]"));
583
+ } else if (command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) if (command.run) parts.push(styles.placeholder("[command]"));
584
+ else parts.push(styles.option("<command>"));
583
585
  return parts.join(" ");
584
586
  }
585
587
  /**
@@ -1419,6 +1421,78 @@ function formatCommandValidationErrors(errors) {
1419
1421
  return lines.join("\n");
1420
1422
  }
1421
1423
 
1424
+ //#endregion
1425
+ //#region src/parser/long-option-resolver.ts
1426
+ function resolveLongOption(arg, lookup) {
1427
+ const withoutDashes = arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2);
1428
+ if (!arg.includes("=")) {
1429
+ const negatedField = lookup.negationMap.get(withoutDashes);
1430
+ if (negatedField && lookup.booleanFlags.has(negatedField)) return {
1431
+ resolvedName: negatedField,
1432
+ withoutDashes,
1433
+ isNegated: true,
1434
+ isCustomNegation: true,
1435
+ isSuppressedNegation: false
1436
+ };
1437
+ }
1438
+ const hasEquals = arg.includes("=");
1439
+ if (!hasEquals && withoutDashes.startsWith("no-")) {
1440
+ const flagName = withoutDashes.slice(3);
1441
+ if (flagName === flagName.toLowerCase()) {
1442
+ const resolvedName = lookup.aliasMap.get(flagName) ?? flagName;
1443
+ if (lookup.booleanFlags.has(resolvedName)) {
1444
+ const asIsResolved = lookup.aliasMap.get(withoutDashes) ?? withoutDashes;
1445
+ if (!lookup.definedNames.has(asIsResolved)) {
1446
+ if (lookup.customNegatedFields.has(resolvedName)) return {
1447
+ resolvedName,
1448
+ withoutDashes,
1449
+ isNegated: false,
1450
+ isCustomNegation: false,
1451
+ isSuppressedNegation: true
1452
+ };
1453
+ return {
1454
+ resolvedName,
1455
+ withoutDashes,
1456
+ isNegated: true,
1457
+ isCustomNegation: false,
1458
+ isSuppressedNegation: false
1459
+ };
1460
+ }
1461
+ }
1462
+ }
1463
+ }
1464
+ if (!hasEquals && withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2])) {
1465
+ const camelFlagName = withoutDashes[2].toLowerCase() + withoutDashes.slice(3);
1466
+ const resolvedName = lookup.aliasMap.get(camelFlagName) ?? camelFlagName;
1467
+ if (lookup.booleanFlags.has(resolvedName)) {
1468
+ const asIsResolved = lookup.aliasMap.get(withoutDashes) ?? withoutDashes;
1469
+ if (!lookup.definedNames.has(asIsResolved)) {
1470
+ if (lookup.customNegatedFields.has(resolvedName)) return {
1471
+ resolvedName,
1472
+ withoutDashes,
1473
+ isNegated: false,
1474
+ isCustomNegation: false,
1475
+ isSuppressedNegation: true
1476
+ };
1477
+ return {
1478
+ resolvedName,
1479
+ withoutDashes,
1480
+ isNegated: true,
1481
+ isCustomNegation: false,
1482
+ isSuppressedNegation: false
1483
+ };
1484
+ }
1485
+ }
1486
+ }
1487
+ return {
1488
+ resolvedName: lookup.aliasMap.get(withoutDashes) ?? withoutDashes,
1489
+ withoutDashes,
1490
+ isNegated: false,
1491
+ isCustomNegation: false,
1492
+ isSuppressedNegation: false
1493
+ };
1494
+ }
1495
+
1422
1496
  //#endregion
1423
1497
  //#region src/parser/argv-parser.ts
1424
1498
  /**
@@ -1444,6 +1518,13 @@ function formatCommandValidationErrors(errors) {
1444
1518
  */
1445
1519
  function parseArgv(argv, options = {}) {
1446
1520
  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;
1521
+ const longOptionLookup = {
1522
+ aliasMap,
1523
+ booleanFlags,
1524
+ definedNames,
1525
+ negationMap,
1526
+ customNegatedFields
1527
+ };
1447
1528
  const result = {
1448
1529
  options: {},
1449
1530
  positionals: [],
@@ -1474,39 +1555,11 @@ function parseArgv(argv, options = {}) {
1474
1555
  }
1475
1556
  if (arg.startsWith("--")) {
1476
1557
  const withoutDashes = arg.slice(2);
1477
- if (!withoutDashes.includes("=")) {
1478
- const negatedField = negationMap.get(withoutDashes);
1479
- if (negatedField && booleanFlags.has(negatedField)) {
1480
- setOption(negatedField, false);
1481
- i++;
1482
- continue;
1483
- }
1484
- }
1485
- if (withoutDashes.startsWith("no-")) {
1486
- const flagName = withoutDashes.slice(3);
1487
- if (flagName === flagName.toLowerCase()) {
1488
- const resolvedName = aliasMap.get(flagName) ?? flagName;
1489
- if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
1490
- const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
1491
- if (!definedNames.has(asIsResolved)) {
1492
- setOption(flagName, false);
1493
- i++;
1494
- continue;
1495
- }
1496
- }
1497
- }
1498
- }
1499
- if (withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2])) {
1500
- const camelFlagName = withoutDashes[2].toLowerCase() + withoutDashes.slice(3);
1501
- const resolvedName = aliasMap.get(camelFlagName) ?? camelFlagName;
1502
- if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
1503
- const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
1504
- if (!definedNames.has(asIsResolved)) {
1505
- setOption(camelFlagName, false);
1506
- i++;
1507
- continue;
1508
- }
1509
- }
1558
+ const resolution = resolveLongOption(arg, longOptionLookup);
1559
+ if (resolution.isNegated) {
1560
+ setOption(resolution.resolvedName, false);
1561
+ i++;
1562
+ continue;
1510
1563
  }
1511
1564
  const eqIndex = withoutDashes.indexOf("=");
1512
1565
  if (eqIndex !== -1) {
@@ -1636,12 +1689,13 @@ function mergeWithPositionals(parsed, extracted) {
1636
1689
  * Shared by scanForSubcommand, separateGlobalArgs, and findFirstPositional.
1637
1690
  */
1638
1691
  function buildGlobalFlagLookup(globalExtracted) {
1639
- const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
1692
+ const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), definedNames = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
1640
1693
  const shortAliases = /* @__PURE__ */ new Set();
1641
1694
  for (const field of globalExtracted.fields) for (const alias of getAllAliases(field)) if (alias.length === 1) shortAliases.add(alias);
1642
1695
  return {
1643
1696
  aliasMap,
1644
1697
  booleanFlags,
1698
+ definedNames,
1645
1699
  flagNames: new Set(globalExtracted.fields.map((f) => f.name)),
1646
1700
  cliNames: new Set(globalExtracted.fields.map((f) => f.cliName)),
1647
1701
  aliases: shortAliases,
@@ -1660,37 +1714,21 @@ function buildGlobalFlagLookup(globalExtracted) {
1660
1714
  * trailing subcommand is still detected) even though they no longer negate.
1661
1715
  */
1662
1716
  function resolveGlobalLongOption(arg, lookup) {
1663
- const withoutDashes = arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2);
1664
- const customNegated = !arg.includes("=") ? lookup.negationMap.get(withoutDashes) : void 0;
1665
- if (customNegated) return {
1666
- resolvedName: customNegated,
1717
+ const { resolvedName, withoutDashes, isNegated, isCustomNegation, isSuppressedNegation } = resolveLongOption(arg, lookup);
1718
+ if (isSuppressedNegation) return {
1719
+ resolvedName,
1667
1720
  withoutDashes,
1668
- isNegated: true,
1669
- isGlobal: lookup.flagNames.has(customNegated),
1670
- isSuppressedNegation: false
1721
+ isNegated: false,
1722
+ isGlobal: false,
1723
+ isSuppressedNegation
1671
1724
  };
1672
- const kebabNegated = withoutDashes.startsWith("no-");
1673
- const camelNegated = !kebabNegated && withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2]);
1674
- if (kebabNegated || camelNegated) {
1675
- const literalResolved = lookup.aliasMap.get(withoutDashes) ?? withoutDashes;
1676
- if (lookup.flagNames.has(literalResolved) || lookup.cliNames.has(withoutDashes)) return {
1677
- resolvedName: literalResolved,
1678
- withoutDashes,
1679
- isNegated: false,
1680
- isGlobal: true,
1681
- isSuppressedNegation: false
1682
- };
1683
- }
1684
- const defaultIsNegated = kebabNegated || camelNegated;
1685
- const flagName = kebabNegated ? withoutDashes.slice(3) : camelNegated ? withoutDashes[2].toLowerCase() + withoutDashes.slice(3) : withoutDashes;
1686
- const resolvedName = lookup.aliasMap.get(flagName) ?? flagName;
1687
- const suppressDefaultNegation = defaultIsNegated && lookup.customNegatedFields.has(resolvedName);
1725
+ const flagName = isNegated && !isCustomNegation ? withoutDashes.startsWith("no-") ? withoutDashes.slice(3) : withoutDashes[2].toLowerCase() + withoutDashes.slice(3) : withoutDashes;
1688
1726
  return {
1689
1727
  resolvedName,
1690
1728
  withoutDashes,
1691
- isNegated: defaultIsNegated && !suppressDefaultNegation,
1692
- isGlobal: !suppressDefaultNegation && (lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName)),
1693
- isSuppressedNegation: suppressDefaultNegation
1729
+ isNegated,
1730
+ isGlobal: lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName),
1731
+ isSuppressedNegation: false
1694
1732
  };
1695
1733
  }
1696
1734
  /**
@@ -1806,6 +1844,7 @@ function findFirstPositionalIndex(argv, globalExtracted) {
1806
1844
  const lookup = globalExtracted ? buildGlobalFlagLookup(globalExtracted) : {
1807
1845
  aliasMap: /* @__PURE__ */ new Map(),
1808
1846
  booleanFlags: /* @__PURE__ */ new Set(),
1847
+ definedNames: /* @__PURE__ */ new Set(),
1809
1848
  flagNames: /* @__PURE__ */ new Set(),
1810
1849
  cliNames: /* @__PURE__ */ new Set(),
1811
1850
  aliases: /* @__PURE__ */ new Set(),
@@ -1873,6 +1912,7 @@ function parseArgs(argv, command, options = {}) {
1873
1912
  remainingArgs: scanResult.tokensAfterSubcommand,
1874
1913
  rawArgs: {},
1875
1914
  positionals: [],
1915
+ rest: [],
1876
1916
  unknownFlags: scanResult.suppressedTokens,
1877
1917
  rawGlobalArgs
1878
1918
  };
@@ -1887,6 +1927,7 @@ function parseArgs(argv, command, options = {}) {
1887
1927
  remainingArgs: argv.slice(1),
1888
1928
  rawArgs: {},
1889
1929
  positionals: [],
1930
+ rest: [],
1890
1931
  unknownFlags: []
1891
1932
  };
1892
1933
  }
@@ -1918,6 +1959,7 @@ function parseArgs(argv, command, options = {}) {
1918
1959
  remainingArgs: [],
1919
1960
  rawArgs: {},
1920
1961
  positionals: [],
1962
+ rest: [],
1921
1963
  unknownFlags: []
1922
1964
  };
1923
1965
  let commandArgv = argv;
@@ -1927,17 +1969,21 @@ function parseArgs(argv, command, options = {}) {
1927
1969
  commandArgv = separated;
1928
1970
  rawGlobalArgs = globalParsed;
1929
1971
  }
1930
- if (!extracted) return {
1931
- helpRequested: false,
1932
- helpAllRequested: false,
1933
- versionRequested: false,
1934
- subCommand: void 0,
1935
- remainingArgs: [],
1936
- rawArgs: {},
1937
- positionals: [],
1938
- unknownFlags: [],
1939
- rawGlobalArgs
1940
- };
1972
+ if (!extracted) {
1973
+ const ddIdx = commandArgv.indexOf("--");
1974
+ return {
1975
+ helpRequested: false,
1976
+ helpAllRequested: false,
1977
+ versionRequested: false,
1978
+ subCommand: void 0,
1979
+ remainingArgs: [],
1980
+ rawArgs: {},
1981
+ positionals: ddIdx >= 0 ? commandArgv.slice(0, ddIdx) : commandArgv,
1982
+ rest: ddIdx >= 0 ? commandArgv.slice(ddIdx + 1) : [],
1983
+ unknownFlags: [],
1984
+ rawGlobalArgs
1985
+ };
1986
+ }
1941
1987
  const parserOptions = buildParserOptions(extracted);
1942
1988
  const parsed = parseArgv(commandArgv, parserOptions);
1943
1989
  const rawArgs = mergeWithPositionals(parsed, extracted);
@@ -1970,6 +2016,7 @@ function parseArgs(argv, command, options = {}) {
1970
2016
  remainingArgs: [],
1971
2017
  rawArgs,
1972
2018
  positionals: parsed.positionals,
2019
+ rest: parsed.rest,
1973
2020
  unknownFlags,
1974
2021
  extractedFields: extracted,
1975
2022
  rawGlobalArgs
@@ -2159,7 +2206,8 @@ var runner_exports = /* @__PURE__ */ __exportAll({
2159
2206
  */
2160
2207
  const defaultLogger = {
2161
2208
  log: (message) => console.log(message),
2162
- error: (message) => console.error(message)
2209
+ error: (message) => console.error(message),
2210
+ warn: (message) => console.warn(message)
2163
2211
  };
2164
2212
  /**
2165
2213
  * Run a command with the given arguments (programmatic/test usage)
@@ -2514,7 +2562,12 @@ async function runCommandInternal(command, argv, options = {}) {
2514
2562
  });
2515
2563
  }
2516
2564
  }
2517
- if (listSubCommands(command).length > 0 && !parseResult.subCommand && !command.run) {
2565
+ const positionalFields = parseResult.extractedFields?.fields.filter((f) => f.positional) ?? [];
2566
+ const hasArrayPositional = positionalFields.some((f) => f.type === "array");
2567
+ const allPositionals = [...parseResult.positionals, ...parseResult.rest];
2568
+ const extraPositionals = hasArrayPositional ? [] : allPositionals.slice(positionalFields.length);
2569
+ const unconsumedRegulars = hasArrayPositional ? [] : parseResult.positionals.slice(positionalFields.length);
2570
+ if (listSubCommands(command).length > 0 && !parseResult.subCommand && !command.run && extraPositionals.length === 0) {
2518
2571
  const help = generateHelp(command, {
2519
2572
  showSubcommands: options.showSubcommands ?? true,
2520
2573
  context
@@ -2541,6 +2594,33 @@ async function runCommandInternal(command, argv, options = {}) {
2541
2594
  };
2542
2595
  } else if (unknownKeysMode === "strip") for (const flag of parseResult.unknownFlags) logger.error(formatUnknownFlagWarning(flag, knownFlags));
2543
2596
  }
2597
+ if (extraPositionals.length > 0) {
2598
+ const subCmdNames = listSubCommandNamesWithAliases(command);
2599
+ if (subCmdNames.size > 0) {
2600
+ const unknownCmd = unconsumedRegulars.find((t) => !t.startsWith("-") && !subCmdNames.has(t));
2601
+ if (unknownCmd) {
2602
+ const similar = findSimilar(unknownCmd, [...subCmdNames]);
2603
+ const suggestion = similar.length > 0 ? ` Did you mean: ${similar.join(", ")}?` : "";
2604
+ collector?.stop();
2605
+ return {
2606
+ success: false,
2607
+ error: /* @__PURE__ */ new Error(`Unknown subcommand: ${unknownCmd}${suggestion ? `.${suggestion}` : ""}`),
2608
+ exitCode: 1,
2609
+ logs: getCurrentLogs()
2610
+ };
2611
+ }
2612
+ }
2613
+ const unknownKeysMode = parseResult.extractedFields?.unknownKeysMode ?? "strip";
2614
+ if (unknownKeysMode === "strict") {
2615
+ collector?.stop();
2616
+ return {
2617
+ success: false,
2618
+ error: /* @__PURE__ */ new Error(`Unexpected positional argument${extraPositionals.length > 1 ? "s" : ""}: ${extraPositionals.join(", ")}`),
2619
+ exitCode: 1,
2620
+ logs: getCurrentLogs()
2621
+ };
2622
+ } else if (unknownKeysMode === "strip") for (const positional of extraPositionals) (logger.warn ?? logger.error)(`Warning: Unexpected positional argument: ${positional}`);
2623
+ }
2544
2624
  let validatedGlobalArgs = {};
2545
2625
  const isCompletionInvocation = command.name === "__complete";
2546
2626
  if (options.globalArgs && options._globalExtracted && !isCompletionInvocation) {
@@ -2647,4 +2727,4 @@ function extractAndValidateGlobal(options) {
2647
2727
 
2648
2728
  //#endregion
2649
2729
  export { renderMarkdown as C, renderInline as S, 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, 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, createDualCaseProxy as w, generateHelp as x, PositionalConfigError as y };
2650
- //# sourceMappingURL=runner-B-FZMN89.js.map
2730
+ //# sourceMappingURL=runner-DZOmYkN0.js.map
@@ -1,4 +1,4 @@
1
- import { _ as AnyCommand } from "../arg-registry-DDJpsUea.js";
1
+ import { _ as AnyCommand } from "../arg-registry-BN3I-XON.js";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/skill/frontmatter.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "politty",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "A lightweight CLI framework inspired by citty with zod v4 registry integration for type-safe metadata management",
5
5
  "keywords": [
6
6
  "argument-parser",
@@ -69,18 +69,18 @@
69
69
  "@inquirer/prompts": "8.5.2",
70
70
  "@quansync/fs": "1.0.0",
71
71
  "@types/node": "25.9.3",
72
- "@typescript/native-preview": "7.0.0-dev.20260610.1",
73
- "@vitest/coverage-v8": "4.1.8",
72
+ "@typescript/native-preview": "7.0.0-dev.20260615.1",
73
+ "@vitest/coverage-v8": "4.1.9",
74
74
  "knip": "6.16.1",
75
75
  "lefthook": "2.1.9",
76
76
  "organize-imports-cli": "1.0.2",
77
- "oxfmt": "0.54.0",
78
- "oxlint": "1.69.0",
77
+ "oxfmt": "0.55.0",
78
+ "oxlint": "1.70.0",
79
79
  "quansync": "1.0.0",
80
80
  "tsdown": "0.22.2",
81
81
  "tsx": "4.22.4",
82
82
  "typescript": "6.0.3",
83
- "vitest": "4.1.8",
83
+ "vitest": "4.1.9",
84
84
  "zod": "4.4.3"
85
85
  },
86
86
  "peerDependencies": {