feat(cua-driver): auto-generate CLI and MCP reference docs from source - #1418
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR adds automated documentation generation infrastructure for cua-driver by introducing doc extraction utilities, a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
libs/cua-driver/Sources/CuaDriverCLI/Docs/CLIDocExtractor.swift (1)
69-85: ⚡ Quick winAdd a drift guard for
allCommandDocsvs registered CLI subcommands.The command list is manually maintained; a small sync check (e.g., unit test/assertion) would prevent silent doc drift when commands are added/renamed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/cua-driver/Sources/CuaDriverCLI/Docs/CLIDocExtractor.swift` around lines 69 - 85, Add a drift guard that asserts the manually maintained allCommandDocs matches the actual registered CLI subcommands: implement a check (either in a unit test or a static validation run at startup) that compares allCommandDocs.map { $0.name } (or .identifier) against the runtime registry of subcommands and fails with a clear message if there's a mismatch; e.g., add a test or a small validation function that calls the CLI's subcommand registry (the codepath that registers/returns available subcommand names) and compares sets, rejecting on difference so renames/additions must update allCommandDocs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/ci-check-docs.yml:
- Around line 5-7: The workflow's paths list currently only includes the cua
driver source pattern ("libs/cua-driver/Sources/**") so edits directly to the
generated reference docs won't trigger the job; update the paths block to also
include the docs pattern "docs/content/docs/cua-driver/reference/**" by adding
that glob to the existing paths array so manual edits under the cua-driver
reference docs fire the ci-check-docs workflow.
In `@scripts/docs-generators/cua-driver.ts`:
- Around line 634-640: The current loop that builds exampleObj from
propertyNames and required only uses syntheticExampleValue and ignores
schema-level conditional constraints (oneOf/anyOf/allOf/dependencies/pattern of
paired fields), which produces invalid payloads for mutually exclusive or paired
inputs; update the generation to first inspect the schema for conditional rules
(check properties, required, schema.oneOf/anyOf/allOf, and schema.dependencies)
and if such constraints are present either (a) synthesize a consistent group by
selecting an applicable branch and including dependent fields together (extend
syntheticExampleValue to accept context and add sibling fields from properties
and dependencies), or (b) mark the schema as ambiguous and skip creating the
example (avoid adding to exampleObj) so no invalid partial payload is emitted;
reference the variables and functions exampleObj, propertyNames, properties,
required, and syntheticExampleValue when implementing this guard/behavior.
- Around line 404-409: The table row builders currently push raw help text into
Markdown table cells (see the loop over cmd.arguments that does lines.push(`|
\`<${arg.name}>\` | ${arg.type} | ${required} | ${arg.help} |`)), which allows
unescaped pipes/newlines to break columns; create or reuse a helper function
(e.g., escapeTableCell or sanitizeCell) to escape at least '|' and newline
characters and call it for every cell value (arg.name, arg.type, required,
arg.help and similar values) before composing the table string, and apply this
helper to the equivalent nested/subcommand table emitters elsewhere in the file
(the other loops that push rows) so all table cells are consistently escaped.
- Around line 624-630: The loop that builds property doc lines (iterating
propertyNames and using prop = properties[propName]) currently interpolates
prop.description directly, producing the literal "undefined" when a description
is missing; change the interpolation in the lines.push call to use a safe
fallback (e.g., const desc = prop.description ?? '' or a placeholder string) and
insert desc instead of prop.description so missing descriptions render as
empty/placeholder text; update the lines.push that references propName,
typeLabel, requiredLabel to use this fallback description.
- Around line 218-221: The code currently uses releasedVersion =
getLatestReleasedVersion() as the version passed into generateCLIReferenceMDX
and generateMCPToolsMDX, which yields stale metadata; instead capture the
source-provided versions from dumpDocs (dumpDocs.cli.version and
dumpDocs.mcp.version) as currentVersion and thread those into the generators
while leaving releasedVersion solely for discovery. Update calls to
generateCLIReferenceMDX and generateMCPToolsMDX to accept/use a currentVersion
argument (or an options object) derived from dumpDocs.cli.version and
dumpDocs.mcp.version respectively, so page content uses the extracted source
version while releasedVersion remains available for historical links.
---
Nitpick comments:
In `@libs/cua-driver/Sources/CuaDriverCLI/Docs/CLIDocExtractor.swift`:
- Around line 69-85: Add a drift guard that asserts the manually maintained
allCommandDocs matches the actual registered CLI subcommands: implement a check
(either in a unit test or a static validation run at startup) that compares
allCommandDocs.map { $0.name } (or .identifier) against the runtime registry of
subcommands and fails with a clear message if there's a mismatch; e.g., add a
test or a small validation function that calls the CLI's subcommand registry
(the codepath that registers/returns available subcommand names) and compares
sets, rejecting on difference so renames/additions must update allCommandDocs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f731fdad-1a0a-4860-8964-fd63b0831603
📒 Files selected for processing (12)
.github/workflows/ci-check-docs.ymldocs/content/docs/cua-driver/guide/getting-started/quickstart.mdxdocs/content/docs/cua-driver/reference/cli-reference.mdxdocs/content/docs/cua-driver/reference/mcp-tools.mdxlibs/cua-driver/Skills/cua-driver/SKILL.mdlibs/cua-driver/Skills/cua-driver/TESTS.mdlibs/cua-driver/Sources/CuaDriverCLI/CuaDriverCommand.swiftlibs/cua-driver/Sources/CuaDriverCLI/Docs/CLIDocExtractor.swiftlibs/cua-driver/Sources/CuaDriverCLI/DumpDocsCommand.swiftlibs/cua-driver/Sources/CuaDriverServer/Docs/MCPDocExtractor.swiftscripts/docs-generators/config.jsonscripts/docs-generators/cua-driver.ts
| paths: | ||
| # Cua Driver (Swift) | ||
| - "libs/cua-driver/Sources/**" |
There was a problem hiding this comment.
Add cua-driver reference docs to workflow path triggers.
This workflow now validates cua-driver docs sync, but direct edits under docs/content/docs/cua-driver/reference/** won’t trigger it. Please include that path so generated-doc drift checks run for manual doc edits too.
Suggested patch
# Documentation files themselves
+ - "docs/content/docs/cua-driver/reference/**"
- "docs/content/docs/cua/reference/**"
- "docs/content/docs/cuabot/reference/**"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/ci-check-docs.yml around lines 5 - 7, The workflow's paths
list currently only includes the cua driver source pattern
("libs/cua-driver/Sources/**") so edits directly to the generated reference docs
won't trigger the job; update the paths block to also include the docs pattern
"docs/content/docs/cua-driver/reference/**" by adding that glob to the existing
paths array so manual edits under the cua-driver reference docs fire the
ci-check-docs workflow.
| const releasedVersion = getLatestReleasedVersion(); | ||
|
|
||
| const cliMdx = generateCLIReferenceMDX(dumpDocs.cli, releasedVersion); | ||
| const mcpMdx = generateMCPToolsMDX(dumpDocs.mcp, releasedVersion); |
There was a problem hiding this comment.
Use the extracted source version for the current docs.
dump-docs already gives you cli.version / mcp.version, but these pages are stamped with the latest git tag instead. On an unreleased branch—or anywhere tags are unavailable—you'll generate current docs with stale version metadata (or 0.0.0) even though the content came from newer source. Keep git tags for historical links, but drive the current page version from dumpDocs.cli.version.
Suggested direction
- const releasedVersion = getLatestReleasedVersion();
-
- const cliMdx = generateCLIReferenceMDX(dumpDocs.cli, releasedVersion);
- const mcpMdx = generateMCPToolsMDX(dumpDocs.mcp, releasedVersion);
+ const releasedVersion = getLatestReleasedVersion();
+ const currentVersion = dumpDocs.cli.version;
+
+ const cliMdx = generateCLIReferenceMDX(dumpDocs.cli, currentVersion, releasedVersion);
+ const mcpMdx = generateMCPToolsMDX(dumpDocs.mcp, currentVersion);Then thread currentVersion through the generators and reserve releasedVersion for version discovery only.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/docs-generators/cua-driver.ts` around lines 218 - 221, The code
currently uses releasedVersion = getLatestReleasedVersion() as the version
passed into generateCLIReferenceMDX and generateMCPToolsMDX, which yields stale
metadata; instead capture the source-provided versions from dumpDocs
(dumpDocs.cli.version and dumpDocs.mcp.version) as currentVersion and thread
those into the generators while leaving releasedVersion solely for discovery.
Update calls to generateCLIReferenceMDX and generateMCPToolsMDX to accept/use a
currentVersion argument (or an options object) derived from dumpDocs.cli.version
and dumpDocs.mcp.version respectively, so page content uses the extracted source
version while releasedVersion remains available for historical links.
| lines.push('| Name | Type | Required | Description |'); | ||
| lines.push('| ---- | ---- | -------- | ----------- |'); | ||
| for (const arg of cmd.arguments) { | ||
| const required = arg.is_optional ? 'No' : 'Yes'; | ||
| lines.push(`| \`<${arg.name}>\` | ${arg.type} | ${required} | ${arg.help} |`); | ||
| } |
There was a problem hiding this comment.
Escape Markdown table cells before writing help text.
These row builders inject raw strings into Markdown tables. The generated mcp-config --client row already contains unescaped |, which will split the row into extra columns. Please escape table-cell content (| and newlines at least) and reuse the helper for the nested tables too.
Suggested fix
+function escapeTableCell(value: unknown): string {
+ return String(value ?? '—')
+ .replace(/\|/g, '\\|')
+ .replace(/\r?\n/g, '<br/>');
+}
+
// ...
- lines.push(`| \`<${arg.name}>\` | ${arg.type} | ${required} | ${arg.help} |`);
+ lines.push(
+ `| \`<${arg.name}>\` | ${escapeTableCell(arg.type)} | ${required} | ${escapeTableCell(arg.help)} |`
+ );
// ...
- lines.push(`| ${nameCell} | ${opt.type} | ${defaultVal} | ${opt.help} |`);
+ lines.push(
+ `| ${nameCell} | ${escapeTableCell(opt.type)} | ${escapeTableCell(defaultVal)} | ${escapeTableCell(opt.help)} |`
+ );
// ...
- lines.push(`| ${nameCell} | ${flag.help} |`);
+ lines.push(`| ${nameCell} | ${escapeTableCell(flag.help)} |`);Apply the same helper to the repeated subcommand/nested-subcommand table emitters below.
Also applies to: 417-425, 433-439, 460-465, 472-480, 487-493, 514-519, 526-534, 541-547
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/docs-generators/cua-driver.ts` around lines 404 - 409, The table row
builders currently push raw help text into Markdown table cells (see the loop
over cmd.arguments that does lines.push(`| \`<${arg.name}>\` | ${arg.type} |
${required} | ${arg.help} |`)), which allows unescaped pipes/newlines to break
columns; create or reuse a helper function (e.g., escapeTableCell or
sanitizeCell) to escape at least '|' and newline characters and call it for
every cell value (arg.name, arg.type, required, arg.help and similar values)
before composing the table string, and apply this helper to the equivalent
nested/subcommand table emitters elsewhere in the file (the other loops that
push rows) so all table cells are consistently escaped.
| for (const propName of propertyNames) { | ||
| const prop = properties[propName]; | ||
| const isRequired = required.has(propName); | ||
| const requiredLabel = isRequired ? 'required' : 'optional'; | ||
| const typeLabel = formatPropertyType(prop); | ||
| lines.push(`- \`${propName}\` (${typeLabel}, ${requiredLabel}): ${prop.description}`); | ||
| } |
There was a problem hiding this comment.
Don't publish literal undefined for missing property docs.
Some extracted properties currently have no description, and this interpolation turns that into user-visible undefined in the generated page (scroll.direction, set_config.value, set_value.pid, etc.). Please fall back to an empty string or placeholder here.
Suggested fix
- lines.push(`- \`${propName}\` (${typeLabel}, ${requiredLabel}): ${prop.description}`);
+ const description = prop.description?.trim() || '—';
+ lines.push(`- \`${propName}\` (${typeLabel}, ${requiredLabel}): ${description}`);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (const propName of propertyNames) { | |
| const prop = properties[propName]; | |
| const isRequired = required.has(propName); | |
| const requiredLabel = isRequired ? 'required' : 'optional'; | |
| const typeLabel = formatPropertyType(prop); | |
| lines.push(`- \`${propName}\` (${typeLabel}, ${requiredLabel}): ${prop.description}`); | |
| } | |
| for (const propName of propertyNames) { | |
| const prop = properties[propName]; | |
| const isRequired = required.has(propName); | |
| const requiredLabel = isRequired ? 'required' : 'optional'; | |
| const typeLabel = formatPropertyType(prop); | |
| const description = prop.description?.trim() || '—'; | |
| lines.push(`- \`${propName}\` (${typeLabel}, ${requiredLabel}): ${description}`); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/docs-generators/cua-driver.ts` around lines 624 - 630, The loop that
builds property doc lines (iterating propertyNames and using prop =
properties[propName]) currently interpolates prop.description directly,
producing the literal "undefined" when a description is missing; change the
interpolation in the lines.push call to use a safe fallback (e.g., const desc =
prop.description ?? '' or a placeholder string) and insert desc instead of
prop.description so missing descriptions render as empty/placeholder text;
update the lines.push that references propName, typeLabel, requiredLabel to use
this fallback description.
| // Synthesize a minimal JSON example from required params only | ||
| const exampleObj: Record<string, unknown> = {}; | ||
| for (const propName of propertyNames) { | ||
| if (required.has(propName)) { | ||
| exampleObj[propName] = syntheticExampleValue(propName, properties[propName]); | ||
| } | ||
| } |
There was a problem hiding this comment.
Required-only example synthesis is generating invalid payloads.
For tools with mutually exclusive or paired inputs, these examples are wrong. The current output already shows click, double_click, and right_click as {"pid":844}, even though one of element_index or x+y is mandatory. Either teach the generator about these constraints, or suppress the example when it can't derive a valid one.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/docs-generators/cua-driver.ts` around lines 634 - 640, The current
loop that builds exampleObj from propertyNames and required only uses
syntheticExampleValue and ignores schema-level conditional constraints
(oneOf/anyOf/allOf/dependencies/pattern of paired fields), which produces
invalid payloads for mutually exclusive or paired inputs; update the generation
to first inspect the schema for conditional rules (check properties, required,
schema.oneOf/anyOf/allOf, and schema.dependencies) and if such constraints are
present either (a) synthesize a consistent group by selecting an applicable
branch and including dependent fields together (extend syntheticExampleValue to
accept context and add sibling fields from properties and dependencies), or (b)
mark the schema as ambiguous and skip creating the example (avoid adding to
exampleObj) so no invalid partial payload is emitted; reference the variables
and functions exampleObj, propertyNames, properties, required, and
syntheticExampleValue when implementing this guard/behavior.
Adds a dump-docs subcommand and TypeScript generator following the same pattern as lume. The reference docs are now generated from Swift source rather than hand-maintained, eliminating drift. Swift: - DumpDocsCommand (--type cli|mcp|all, --pretty) - MCPDocExtractor: serializes all ToolRegistry tools to JSON - CLIDocExtractor: documents all 14 CLI subcommands with args/options/flags - Wired into CuaDriverCommand subcommands list TypeScript: - scripts/docs-generators/cua-driver.ts: reads dump-docs JSON, generates mcp-tools.mdx (29 tools) and cli-reference.mdx (14 commands) - --check flag for CI drift detection Config/CI: - cua-driver entry added to scripts/docs-generators/config.json - ci-check-docs.yml: triggers on libs/cua-driver/Sources/**, builds release binary, runs generator in --check mode Generated docs updated to match current source. To regenerate: npx tsx scripts/docs-generators/cua-driver.ts Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fa57814 to
2b6e79c
Compare
- ci-check-docs.yml: add docs/content/docs/cua-driver/reference/** to
path triggers so manual doc edits also fire the check
- cua-driver.ts: use binary-reported version as canonical current version
instead of git tag (correct on unreleased branches)
- cua-driver.ts: escape | and newlines in Markdown table cells
- cua-driver.ts: fallback to empty string for missing property descriptions
(prevents literal "undefined" in generated pages)
- cua-driver.ts: suppress JSON example block when no required params exist
(avoids invalid {} payloads for tools with optional-only schemas)
- Regenerated mcp-tools.mdx and cli-reference.mdx with fixes applied
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nerator only git diff HEAD~1 HEAD → git diff base...HEAD for full PR range. Individual generator script changes (cua-driver.ts, lume.ts, etc.) now only trigger their own generator instead of setting GENERATORS=all. Only runner.ts and config.json changes trigger all generators. Deduplicate GENERATORS to avoid running the same generator twice. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
config.json changes (e.g. adding a new generator entry) were incorrectly triggering all generators including lume and python-sdk which have pre-existing drift unrelated to the PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Wires cua-driver into the existing docs-generator pipeline (same pattern as lume), eliminating hand-maintained reference drift.
Swift side
DumpDocsCommand(cua-driver dump-docs --type cli|mcp|all --pretty) — new subcommandMCPDocExtractor— serializes all 29ToolRegistrytools to JSON (name, description, input schema)CLIDocExtractor— documents all 14 CLI subcommands with args/options/flagsTypeScript generator
scripts/docs-generators/cua-driver.ts— readsdump-docs --type allJSON, generatesmcp-tools.mdx(29 tools with full descriptions + arg tables + JSON examples) andcli-reference.mdx(14 commands grouped by category)--checkmode for CI drift detectionConfig / CI
cua-driverentry added toconfig.jsonwithenabled: trueci-check-docs.ymlnow triggers onlibs/cua-driver/Sources/**, builds the release binary, and runs--checkGenerated docs
Both reference files regenerated from current source — content is now auto-generated with
AUTO-GENERATED FILEheaders.To regenerate locally:
Test plan
swift build --configuration releaseinlibs/cua-driver✅cua-driver dump-docs --type all --prettyoutputs valid JSON with 14 CLI commands + 29 MCP tools ✅npx tsx scripts/docs-generators/cua-driver.tsgenerates both MDX files ✅npx tsx scripts/docs-generators/cua-driver.ts --checkexits 0 after generation ✅🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
dump-docsCLI command to export CLI and MCP tool documentation as JSON, with support for selecting documentation type and pretty-printing output.Documentation
--screenshot-out-file).