Files
webstudio/scripts/docs/generate-mcp-docs.ts
Oleg Isonen e6a29b5d36 fix: Show released CLI version in MCP docs (#5990)
## Summary

- make the MCP page generator render the CLI package version directly in
the page title
- publish `Webstudio MCP v<release>` from the exact generated page in
each successful release
- merge each successful release tag into the publication-only `docs`
branch
- serialize publication and ignore reruns or older release tags already
contained in `docs`

## Root cause

The first publication design advanced `docs` to the release commit
without putting the CLI package version into the generated page. The
repository uses `0.0.0-webstudio-version` until release time, so the
release workflow now replaces that existing version placeholder with the
successful tag version before publishing.

## Todo

- [x] Generate the CLI version in the MCP page title.
- [x] Publish the generated page from the exact release revision.
- [x] Make publication idempotent and prevent version downgrades.
- [x] Validate generation, formatting, linting, and release-branch
behavior.
- [ ] Merge this pull request.
- [ ] Publish `0.285.0` as the initial version on the existing `docs`
branch.

## Verification

- `pnpm docs:mcp:test`
- `pnpm docs:mcp:typecheck`
- `pnpm check:generated-docs`
- `pnpm lint`
- `pnpm oxfmt --check`
- `git diff --check`
- isolated Git simulation for release merge, exact generated-page
selection, version replacement, and rerun detection
- regression tests demonstrated failing without version rendering and
validation, then passing after restoration

Ref #5986
2026-08-03 18:32:59 +02:00

71 lines
2.1 KiB
TypeScript

import { execFileSync } from "node:child_process";
import { readFileSync, writeFileSync } from "node:fs";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
const manualTitle = "# Webstudio MCP Manual";
const manualPlaceholder = "{{manual}}";
const versionPlaceholder = "{{version}}";
const repositoryRoot = fileURLToPath(new URL("../..", import.meta.url));
const outputPath = resolve(repositoryRoot, "docs/university/mcp.md");
const template = readFileSync(new URL("mcp-page.md", import.meta.url), "utf8");
const { version: cliVersion } = JSON.parse(
readFileSync(resolve(repositoryRoot, "packages/cli/package.json"), "utf8")
) as { version: string };
const getMcpManual = () =>
execFileSync(
process.execPath,
[
resolve(repositoryRoot, "packages/cli/local.js"),
"man",
"mcp",
"--verbose",
],
{
encoding: "utf8",
cwd: repositoryRoot,
env: {
...process.env,
CI: "1",
FORCE_COLOR: "0",
NO_COLOR: "1",
},
maxBuffer: 10 * 1024 * 1024,
}
).trim();
export const renderMcpDocumentation = (manual: string, version: string) => {
const normalizedManual = manual.replaceAll("\r\n", "\n").trim();
if (normalizedManual.startsWith(`${manualTitle}\n`) === false) {
throw new Error(
`Expected the CLI manual to begin with ${JSON.stringify(manualTitle)}.`
);
}
const manualBody = normalizedManual.slice(manualTitle.length).trimStart();
const placeholderCount = template.split(manualPlaceholder).length - 1;
if (placeholderCount !== 1) {
throw new Error(
`Expected one ${manualPlaceholder} placeholder, found ${placeholderCount}.`
);
}
if (version.trim() === "") {
throw new Error("Expected a CLI version.");
}
return template
.replace(versionPlaceholder, version)
.replace(manualPlaceholder, manualBody);
};
export const generateMcpDocumentation = () => {
writeFileSync(
outputPath,
renderMcpDocumentation(getMcpManual(), cliVersion),
"utf8"
);
};
if (process.argv[1] === fileURLToPath(import.meta.url)) {
generateMcpDocumentation();
}