Skip to content

fix(args): warn when positionals overwrite an explicit --_ flag#39

Merged
beogip merged 1 commit into
mainfrom
claude/issue-19-20260608-0304
Jun 8, 2026
Merged

fix(args): warn when positionals overwrite an explicit --_ flag#39
beogip merged 1 commit into
mainfrom
claude/issue-19-20260608-0304

Conversation

@claude

@claude claude Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the footgun reported in #19: in validateInput (src/args.ts) positional args are attached under the reserved _ key, silently overwriting any user-declared --_ flag.

This PR addresses both remedies suggested in the issue:

  • Warns loudly — when an explicit --_ flag and positional args are both present, a warning is written to stderr (stdout stays reserved for the JSON envelope, per the always-exit-0 / loud-failure contract).
  • Documents _ as reserved — in the JSDoc for validateInput, ParsedArgs, and SubcommandSpec.input.

Behavior is unchanged and backward compatible — positionals still win the collision; only a warning is added.

Changes

  • src/args.ts — emit stderr warning when both --_ and positionals are present; document reserved _.
  • src/types.ts — document _ as reserved in ParsedArgs and SubcommandSpec.input.
  • tests/args.test.ts — unit tests (spy on process.stderr.write): warns only when both present, silent otherwise.
  • tests/fixtures/dummy-tool.ts — new echoArgs subcommand declaring the reserved _ key.
  • tests/cli.test.ts — black-box test asserting the warning reaches stderr and positionals win on stdout.
  • docs/specs/issue-19-...md — implementation plan artifact.

Verification

  • bun test118 pass / 0 fail
  • bunx tsc --noEmit — clean
  • bunx biome check . — clean

Closes #19

Generated with Claude Code

The reserved `_` key silently clobbered a user-declared `--_` flag in
validateInput. Emit a loud stderr warning when both an explicit `--_`
flag and positional args are present, and document `_` as reserved in
ParsedArgs and SubcommandSpec.input. Behavior is unchanged — positionals
still win; stdout stays reserved for the JSON envelope.

Closes #19

Co-authored-by: Juan Ignacio Gipponi <beogip@users.noreply.github.com>
@greptile-apps

greptile-apps Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the silent _ key overwrite footgun in validateInput by emitting a process.stderr.write warning whenever both an explicit --_ flag and positional args are present. The underlying overwrite behavior is unchanged — positionals continue to win — so the change is fully backward-compatible.

  • src/args.ts: adds the Object.hasOwn(parsed.flags, "_") guard and process.stderr.write warning before the toValidate._ = parsed.positional assignment.
  • src/types.ts: documents _ as reserved across ParsedArgs.flags, ParsedArgs interface, and SubcommandSpec.input JSDoc.
  • Tests: three unit tests (spy on process.stderr.write) cover all three edge cases (collision, positionals-only, flag-only), and two CLI black-box tests confirm end-to-end warning behavior and the correct stdout output.

Confidence Score: 5/5

Safe to merge — the change is a pure additive warning on stderr with no mutation of the existing overwrite logic.

The implementation is a small, focused addition of a single Object.hasOwn guard and a process.stderr.write call inside the existing if (parsed.positional.length > 0) branch. Existing behavior (positionals win, stdout carries only the JSON envelope) is entirely unchanged. All three edge cases are covered by unit tests with proper spy/restore, and end-to-end subprocess tests confirm the warning reaches stderr without corrupting stdout.

No files require special attention.

Important Files Changed

Filename Overview
src/args.ts Adds a precise Object.hasOwn guard and process.stderr.write warning before the existing toValidate._ = parsed.positional assignment; logic is correct and the overwrite behavior is unchanged.
src/types.ts JSDoc-only changes: accurately documents _ as reserved across ParsedArgs.flags, the ParsedArgs interface, and SubcommandSpec.input.
tests/args.test.ts Adds three unit tests using spyOn(process.stderr, 'write') covering all three edge cases (collision, positionals-only, flag-only), all with proper mockRestore in finally blocks.
tests/cli.test.ts Adds two black-box subprocess tests asserting the warning reaches stderr and positionals win on stdout; correctly asserts exit code 0 in both cases.
tests/fixtures/dummy-tool.ts Adds the echoArgs fixture subcommand with _: z.array(z.string()).optional() schema and a _ ?? [] handler, correctly supporting the CLI collision tests.
docs/specs/issue-19-reserved-key-positionals-silently-overwrite.md Implementation plan artifact; matches the delivered changes and acceptance criteria exactly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["CLI: argv"] --> B["parseArgs(argv)"]
    B --> C{"positional.length > 0?"}
    C -- No --> E["safeParse(flags only)"]
    C -- Yes --> D{"Object.hasOwn(flags, '_')?"}
    D -- No --> F["toValidate._ = positional"]
    D -- Yes --> G["process.stderr.write(warning)"]
    G --> F
    F --> E
    E --> H["Zod safeParse result"]
Loading

Reviews (1): Last reviewed commit: "fix(args): warn when positionals overwri..." | Re-trigger Greptile

@beogip beogip merged commit 366b422 into main Jun 8, 2026
5 checks passed
@beogip beogip deleted the claude/issue-19-20260608-0304 branch June 8, 2026 03:27
beogip pushed a commit that referenced this pull request Jun 8, 2026
## [0.1.5](v0.1.4...v0.1.5) (2026-06-08)

### Bug Fixes

* **args:** warn when positionals overwrite an explicit --_ flag ([#39](#39)) ([366b422](366b422)), closes [#19](#19)
* emit extension-free bundled declarations for published types ([#33](#33)) ([3841ab1](3841ab1)), closes [#18](#18)
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 0.1.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reserved _ key: positionals silently overwrite an explicit --_ flag

1 participant