Migrate forge_cli to clap derive + re-point cli-command drift rule (P5.2)#31
Conversation
…5.2)
Replace the hand-rolled `env::args()` parser in forge_cli with clap derive:
a `#[derive(Parser)] Cli` + `#[derive(Subcommand)] enum Commands` model.
This yields generated `--help`/`--version`, real error messages, and per-
subcommand help, while preserving the exact command/flag/positional contract
(dev/build/bundle/smelt/sign/icon/docs; `-o/--out`, `--embed`, `-i/--identity`,
the artifact positional, icon create/validate). The hand-written usage extras
are carried over via clap `after_help`. `docs` keeps trailing-var-arg
pass-through so its sub-flags still forward to the docs generator unchanged.
Because the clap migration removed the `forge <a|b|c>` usage banner that the
`cli-command` documentation-drift rule parsed, re-point that rule at the new
source of truth: the clap `Commands` enum. The rule now brace-matches the
`enum Commands { .. }` body, harvests top-level variant names, and applies
clap's default PascalCase->kebab-case rename to recover the exact subcommand
names the CLI exposes. This keeps `forge smelt`-style "real subcommand but
undocumented" detection working post-migration.
- forge_cli/src/main.rs: clap Parser/Subcommand model; dispatch in main().
- forge_cli/Cargo.toml: add clap with the derive feature.
- forge_cli/tests/cli_characterization.rs: rewrite P5.1 snapshots to clap's
contract (edge cases now exit non-zero with clap errors) + assert the
preserved command/flag/alias/positional surface.
- forge-docs-check/src/checks/cli_commands.rs: source subcommands from the
clap enum instead of the deleted usage banner.
- forge-docs-check/tests/rules.rs: update the fixture to the clap-enum shape.
Verification: drift gate in sync; forge-docs-check 15/15; forge_cli 15+10
tests; fmt + clippy clean on both crates.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @LayerDynamics, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
There was a problem hiding this comment.
Code Review
This pull request migrates the forge CLI from a hand-rolled argument parser to a clap-derive model, updating command-line parsing, help generation, and error handling across the application. It also updates the documentation-checking tool (forge-docs-check) to extract subcommands directly from the Commands enum in the source code rather than a hand-written usage banner. Feedback on the pull request highlights that the custom brace-matching parser used in the documentation checker could fail if braces are present within comments or string literals, and suggests stripping comments and literals before parsing to ensure robustness.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
… output
`every_subcommand_has_help` panicked only on windows-latest: clap renders its
`Usage:` line from the real binary file name, which is `forge.exe` on Windows.
The assertion `contains("forge {cmd}")` then failed because the infix `.exe`
splits `forge` from the subcommand (`Usage: forge.exe dev ...`).
Normalize `forge.exe` -> `forge` once in the shared `combined()` helper so all
string assertions hold across platforms. No-op on Unix (the suffix never
appears). The CLI itself was always correct; this was a unix-only test
assumption.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Note that the PascalCase->kebab split matches clap/heck only for single-word variants (all current forge subcommands); multi-word acronyms would diverge. Documentation-only; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `v8` crate's build script downloads a large prebuilt static lib from
GitHub releases (denoland/rusty_v8) into ~/.cargo/.rusty_v8 at build time.
That directory was not covered by any cache, so every cold build re-downloaded
it — and an intermittent `HTTP Error 504: Gateway Time-out` from the releases
endpoint panicked v8's build.rs (assertion failed: status.success()), failing
Clippy/Check/Test/cross-platform jobs even though the code was sound.
Cache ~/.cargo/.rusty_v8 explicitly:
- ci.yml (check, test matrix, clippy): a dedicated actions/cache step keyed on
Cargo.lock with a `${{ runner.os }}-rusty_v8-` restore-keys prefix, so the
binary is restored even when Cargo.lock changes (the v8 version rarely moves)
and is downloaded at most once per OS.
- cross-platform.yml: add `cache-directories: ~/.cargo/.rusty_v8` to the
Swatinem/rust-cache step (rust-cache doesn't cover it by default).
docs.yml is unchanged: forge-docs-check's dependency graph contains no
deno_core/v8 (verified via cargo tree), so that job never performs the download.
Validated with actionlint (exit 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#32) ## Summary Phase **P5.3** (final phase) of the docs-autogeneration pipeline: generate the `forge` CLI reference **directly from the clap command model** and gate it against drift. The published docs and the binary's argument parser are now derived from the *same* model and cannot diverge. > **Stacked on #31 (P5.2).** This PR's base is the P5.2 branch, so the diff shows only the single P5.3 commit. Once #31 merges to `main`, retarget this PR to `main` (`gh pr edit --base main`). ## What changed **`forge_cli` → lib + bin split** - The clap model (`Cli`/`Commands`/`IconCommand` + `AFTER_HELP`) moves to `src/lib.rs`, which exposes `pub fn cli() -> clap::Command`. The binary imports it and dispatches as before; command handlers stay in the bin. Smallest lib surface that lets tooling introspect the real CLI. **`forge-docs-check`** - New `clidoc` module: introspects `forge_cli::cli()` and renders an authoritative reference (synopsis, arguments, options, nested `icon` subcommands) into the `<!-- forge:cli -->` region of `crates/forge.md`. Authored prose in the narrative `## Commands` section sits outside the markers and is never touched. - New **`cli-doc`** rule (wired into `run_all_checks`): fails when the region is stale. `make docs-cli` / `--write-cli` regenerates it. Mirrors the `api-block`/`example-block` marker-hybrid pattern (and inherits its CRLF-safe comparison). - **`cli-command`** rule refactored from regex source-parsing to clap introspection — deletes ~120 lines of brace/heck-mangling and the source-move fragility. The clap model is now the literal source of truth. **Docs/config** - `forge.md`: new generated `## CLI reference` section + a `lib.rs` entry in the file-structure tree. - `DOCUMENTATION.md`: documents the `cli-doc` (and previously-undocumented `ext-index`) rules and `make docs-cli`. - `Makefile`: adds the `docs-cli` target. ## Test plan - [x] Drift gate: **in sync, 0 issues** (new `cli-doc` rule passes) - [x] `forge-docs-check`: 18 fixture rules + `docs_sync` ratchet + 3 `clidoc` unit tests + new `cli-doc` fixture (stale flagged / fresh passes / un-opted skipped) - [x] `forge_cli`: 15 unit + 10 characterization - [x] `cargo fmt --all --check` + `clippy -D warnings` clean - [ ] Windows CI green on the drift gate (the new surface) — watched on this PR ## Notes - `clidoc::render_block_body()` prefixes the literal `"forge"` (not the binary name), so the `.exe` issue that bit P5.2's test cannot leak into the generated docs. - No dependency cycle: `forge-docs-check → forge_cli → forge-etch/forge-smelt`, nothing back. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
Phase P5.2 of the docs-autogeneration pipeline: migrate the
forgeCLI from a hand-rolledenv::args()parser to clap derive, and update the documentation-drift gate to track the new command model.CLI migration
forge_cli/src/main.rsnow uses#[derive(Parser)] Cli+#[derive(Subcommand)] enum Commands, with dispatch inmain().--help/--version, real clap error messages, and per-subcommand help.dev/build/bundle/smelt/sign/icon/docs;-o/--out,--embed,-i/--identity, theartifactpositional,icon create/validate. Hand-written usage extras carried over via clapafter_help.docskeepstrailing_var_argpass-through so its sub-flags still forward to the docs generator unchanged.Drift-rule follow-through
The migration deleted the
forge <a|b|c>usage banner that thecli-commanddrift rule parsed. That rule is re-pointed at the clapCommandsenum (the new single source of truth): it brace-matches the enum body, harvests top-level variant names, and applies clap's default PascalCase→kebab-case rename to recover the exact subcommand names.forge smelt-style "real subcommand but undocumented" detection keeps working.Test plan
forge-docs-check: 15/15 (incl. updated clap-enum fixture)forge_cli: 15 unit + 10 characterization passcargo fmt --check+cargo clippy -D warningsclean on both cratesNotes
feat-forge-branded-icon); the two main.rs changesets touch disjoint regions.🤖 Generated with Claude Code