[PR #1175] [MERGED] fix(cli): advertise defaulted inputs as optional in --schema and help #2699

Closed
opened 2026-10-17 21:09:12 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1175
Author: @kaoru0822-kitauji
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @N0zoM1z0

Base: main ← Head: fix/cli-schema-omittable-defaults


📝 Commits (1)

  • 76d2829 fix(cli): advertise defaulted inputs as optional in --schema and help

📊 Changes

3 files changed (+182 additions, -0 deletions)

View changed files

📝 src/cli.ts (+2 -0)
➕ src/cli/omittableDefaults.ts (+66 -0)
➕ tests/boundary/cli/cliInputSchemaRequired.test.ts (+114 -0)

📄 Description

Summary

rea <command> --schema listed every defaulted argument and option under required, although the CLI accepts their omission and applies the default. The help synopsis also showed defaulted positional arguments as mandatory (<path> <archive>), and the --llms-full manifest marked them Required: yes. Schema-driven callers that validate before invoking rejected documented calls such as rea inspect-keyed-archive <plist>.

Fixes #1169

Cause

Incur converts command schemas with Zod's default output view (z.toJSONSchema without io: "input") and builds help synopses from optout. A .default() field always has a value on output, so it is reported as required even though input may omit it. Incur 0.7.0 has the same conversion.

Change

  • src/cli/omittableDefaults.ts: after all commands register, wrap each args/options/env field that accepts an omitted value but always produces one (optin: "optional", optout: undefined) as .optional(), copying its metadata. Parsing is unchanged: Zod still applies the inner default, Incur's coercion unwraps the wrapper, and descriptions, defaults, and constraints such as minimum remain in the schema.
  • src/cli.ts: apply it once at the end of createCli, so every current and future command gets the same presentation.

Across the catalog, 29 commands advertised defaulted inputs as required. Examples: inspect-keyed-archive (archive, offset, limit), inspect-artifact (integrityPolicy), setup (yes, dryRun, …), trace-native-values, and inspect-web-page.

Before / after (inspect-keyed-archive)

args.required     ['path', 'archive']  ->  ['path']
options.required  ['offset', 'limit']  ->  (none)
Usage: rea inspect-keyed-archive <path> <archive> [options]
    -> Usage: rea inspect-keyed-archive <path> [archive] [options]

archive keeps "default": ".". limit keeps "default": 20000, "minimum": 1, "maximum": 20000. The one-argument call still resolves archive to ., and --limit 0 still exits 1.

Tests

tests/boundary/cli/cliInputSchemaRequired.test.ts serves --schema --json in process for every primary command. It checks that required names exactly the fields whose omission the registered parser schema rejects. On unpatched main it reports the 29 mismatched commands. It also uses Ajv 2020 to validate the keyed-archive contract ({path} accepted, {} rejected, {limit: 0} rejected) and checks the help synopsis.

Verification

  • npm run check:fast
  • npm run jscpd (2.49%)
  • npm run docs:check
  • npm run test:focused -- tests/boundary/cli/{cliInputSchemaRequired,productCatalog,cliToolCoverage,skillSync,mcpDoctorHelp,mcpDoctorHelpCli,dispatcher,cliOutput,cliSetup,nativeUiScenarioInputCli,jsonOutput,scenarioCliInputDiagnostics,nativePlistCli,analysisSelectorCli,nativeSignatureCli}.test.ts
  • Built CLI: inspect-keyed-archive <plist> --json exits 0 with parameters.path: ".", --limit 1 --offset 1 is honored, and --limit 0 exits 1.

No Hopper/Ghidra verification was needed: this changes CLI schema presentation only. MCP tool schemas are unchanged, since they already convert with io: "input".

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1175 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/9/2026 **Status:** ✅ Merged **Merged:** 10/9/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `fix/cli-schema-omittable-defaults` --- ### 📝 Commits (1) - [`76d2829`](https://github.com/morluto/rea/commit/76d2829563adac328facb25664e613f58c93e579) fix(cli): advertise defaulted inputs as optional in --schema and help ### 📊 Changes **3 files changed** (+182 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `src/cli.ts` (+2 -0) ➕ `src/cli/omittableDefaults.ts` (+66 -0) ➕ `tests/boundary/cli/cliInputSchemaRequired.test.ts` (+114 -0) </details> ### 📄 Description ## Summary `rea <command> --schema` listed every defaulted argument and option under `required`, although the CLI accepts their omission and applies the default. The help synopsis also showed defaulted positional arguments as mandatory (`<path> <archive>`), and the `--llms-full` manifest marked them `Required: yes`. Schema-driven callers that validate before invoking rejected documented calls such as `rea inspect-keyed-archive <plist>`. Fixes #1169 ## Cause Incur converts command schemas with Zod's default output view (`z.toJSONSchema` without `io: "input"`) and builds help synopses from `optout`. A `.default()` field always has a value on output, so it is reported as required even though input may omit it. Incur 0.7.0 has the same conversion. ## Change - `src/cli/omittableDefaults.ts`: after all commands register, wrap each `args`/`options`/`env` field that accepts an omitted value but always produces one (`optin: "optional"`, `optout: undefined`) as `.optional()`, copying its metadata. Parsing is unchanged: Zod still applies the inner default, Incur's coercion unwraps the wrapper, and descriptions, defaults, and constraints such as `minimum` remain in the schema. - `src/cli.ts`: apply it once at the end of `createCli`, so every current and future command gets the same presentation. Across the catalog, 29 commands advertised defaulted inputs as required. Examples: `inspect-keyed-archive` (`archive`, `offset`, `limit`), `inspect-artifact` (`integrityPolicy`), `setup` (`yes`, `dryRun`, …), `trace-native-values`, and `inspect-web-page`. ## Before / after (`inspect-keyed-archive`) ``` args.required ['path', 'archive'] -> ['path'] options.required ['offset', 'limit'] -> (none) Usage: rea inspect-keyed-archive <path> <archive> [options] -> Usage: rea inspect-keyed-archive <path> [archive] [options] ``` `archive` keeps `"default": "."`. `limit` keeps `"default": 20000, "minimum": 1, "maximum": 20000`. The one-argument call still resolves `archive` to `.`, and `--limit 0` still exits 1. ## Tests `tests/boundary/cli/cliInputSchemaRequired.test.ts` serves `--schema --json` in process for every primary command. It checks that `required` names exactly the fields whose omission the registered parser schema rejects. On unpatched `main` it reports the 29 mismatched commands. It also uses Ajv 2020 to validate the keyed-archive contract (`{path}` accepted, `{}` rejected, `{limit: 0}` rejected) and checks the help synopsis. ## Verification - `npm run check:fast` - `npm run jscpd` (2.49%) - `npm run docs:check` - `npm run test:focused -- tests/boundary/cli/{cliInputSchemaRequired,productCatalog,cliToolCoverage,skillSync,mcpDoctorHelp,mcpDoctorHelpCli,dispatcher,cliOutput,cliSetup,nativeUiScenarioInputCli,jsonOutput,scenarioCliInputDiagnostics,nativePlistCli,analysisSelectorCli,nativeSignatureCli}.test.ts` - Built CLI: `inspect-keyed-archive <plist> --json` exits 0 with `parameters.path: "."`, `--limit 1 --offset 1` is honored, and `--limit 0` exits 1. No Hopper/Ghidra verification was needed: this changes CLI schema presentation only. MCP tool schemas are unchanged, since they already convert with `io: "input"`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:09:12 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2699
No description provided.