Skip to content

Fix Commander parser for real-world CLI output#3

Merged
kitschpatrol merged 3 commits into
mainfrom
claude/fix-commander-wrapping-and-recursion
Apr 7, 2026
Merged

Fix Commander parser for real-world CLI output#3
kitschpatrol merged 3 commits into
mainfrom
claude/fix-commander-wrapping-and-recursion

Conversation

@kitschpatrol
Copy link
Copy Markdown
Owner

Summary

  • Multi-line wrapping: Add unwrapContinuationLines() pre-processing that joins Commander's wrapped continuation lines (4+ spaces indent) before lexing. Real-world Commander CLIs like @kitschpatrol/snip wrap descriptions and (default: ...) values across multiple lines even with COLUMNS=200. The lexer's ROW_MODE exits on \n, so continuation lines caused parse failures.
  • Help command recursion: Filter out Commander's built-in help [command] from parsed commands. Recursing into it re-outputs the full top-level help, causing duplicate content and wasted recursion depth.
  • Arguments section: Add Arguments: section support for Commander subcommands (e.g. snip add --help emits Arguments: filename name of snippet). Maps to ProgramInfo.positionals.

Test plan

  • All 42 tests pass (including existing normalization, rule, and snip subcommand tests)
  • snip --help.txt fixture updated to use real wrapped output — parses correctly
  • snip add --help output with Arguments: section parses correctly
  • Build succeeds
  • ESLint passes

https://claude.ai/code/session_013xxgkuT1DBoaJ5MxQmrNuc

claude added 3 commits April 7, 2026 00:24
Three issues fixed:

1. Multi-line wrapping: Commander wraps long descriptions/defaults across
   multiple lines (even with COLUMNS=200). Add unwrapContinuationLines()
   pre-processing that joins continuation lines (4+ spaces indent, not a
   new row) before lexing. Tested with real snip --help wrapped output.

2. Help command recursion: Commander always lists a "help [command]"
   subcommand. Recursing into it re-outputs the top-level help, causing
   duplicate content and wasted depth. Filter it out during post-processing.

3. Arguments section: Commander subcommands emit an "Arguments:" section
   for positional args (e.g. "snip add --help" shows "Arguments: filename").
   Add startArgumentsSection token, argumentsSection parser rule, and
   visitor method mapping to ProgramInfo.positionals.

Also updates snip --help.txt fixture to use real wrapped output instead
of the manually unwrapped version.

https://claude.ai/code/session_013xxgkuT1DBoaJ5MxQmrNuc
Add unwrapContinuationLines() to the Yargs parser, mirroring the
Commander fix. Yargs wraps long descriptions and metadata ([string],
[default:], [choices:]) across multiple lines at narrow terminal widths.

The Yargs unwrap is section-aware: only joins continuation lines within
Options/Commands/Positionals sections, preventing false matches on
non-Yargs formats (e.g. meow's indented usage examples).

Key differences from Commander unwrap:
- Uses /^ *-/ to detect new option rows (Yargs uses variable indent:
  2 spaces for aliased options, 6+ for long-only)
- Section-aware: tracks Options:/Commands:/Positionals: headers,
  resets on blank lines
- Does not attempt to unwrap command argument wrapping (e.g.
  <arg> at 2-space indent) as this creates ambiguous output

New test fixture: yargs-wrapped-cli.js with .wrap(60) generating
10 options with long descriptions, choices, and defaults that wrap
heavily across multiple lines.

https://claude.ai/code/session_013xxgkuT1DBoaJ5MxQmrNuc
Document supported CLI frameworks with specific notes:
- Yargs: .wrap() pattern for reliable piped output, known
  limitation with command argument wrapping at narrow widths
- Commander: parenthesized defaults, env annotations, help
  command filtering
- Meow: options-only support

https://claude.ai/code/session_013xxgkuT1DBoaJ5MxQmrNuc
@kitschpatrol kitschpatrol merged commit 1597d12 into main Apr 7, 2026
0 of 3 checks passed
@kitschpatrol kitschpatrol self-assigned this Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants