fix(docs): make Mintlify anchor audit reliable (#111265)

This commit is contained in:
Peter Steinberger
2026-07-19 00:15:40 -07:00
committed by GitHub
parent 8f2ec62917
commit 8028288f05
2 changed files with 49 additions and 31 deletions
+33 -19
View File
@@ -7,12 +7,21 @@ import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { resolveClawHubRepoPath, syncClawHubDocsTree } from "./docs-sync-publish.mjs";
import { createPnpmRunnerSpawnSpec } from "./pnpm-runner.mjs";
import { resolveNpmRunner } from "./npm-runner.mjs";
const ROOT = process.cwd();
const DOCS_DIR = path.join(ROOT, "docs");
const DOCS_JSON_PATH = path.join(DOCS_DIR, "docs.json");
const MINTLIFY_BROKEN_LINKS_ARGS = ["dlx", "mint", "broken-links", "--check-anchors"];
const MINTLIFY_CLI_VERSION = "4.2.715";
const MINTLIFY_BROKEN_LINKS_ARGS = [
"exec",
"--yes",
`--package=mint@${MINTLIFY_CLI_VERSION}`,
"--",
"mint",
"broken-links",
"--check-anchors",
];
const NODE_25_UNSUPPORTED_BY_MINTLIFY = 25;
if (!fs.existsSync(DOCS_DIR) || !fs.statSync(DOCS_DIR).isDirectory()) {
@@ -353,17 +362,26 @@ function parseNodeMajor(version) {
return Number.isFinite(major) ? major : 0;
}
function createMintlifyPnpmRunnerSpawnSpec(params, options = {}) {
return createPnpmRunnerSpawnSpec({
function createMintlifyNpmRunnerSpawnSpec(params, options = {}) {
const env = params.env ?? process.env;
const runner = resolveNpmRunner({
comSpec: params.comSpec,
cwd: params.cwd,
env: params.env ?? process.env,
nodeExecPath: options.nodeExecPath ?? params.nodeExecPath,
npmExecPath: params.npmExecPath,
env,
execPath: options.nodeExecPath ?? params.nodeExecPath,
npmArgs: MINTLIFY_BROKEN_LINKS_ARGS,
platform: params.platform,
pnpmArgs: MINTLIFY_BROKEN_LINKS_ARGS,
stdio: "inherit",
});
return {
command: runner.command,
args: runner.args,
options: {
cwd: params.cwd,
env: runner.env ?? env,
shell: runner.shell,
stdio: "inherit",
windowsVerbatimArguments: runner.windowsVerbatimArguments,
},
};
}
/**
@@ -377,7 +395,6 @@ function createMintlifyPnpmRunnerSpawnSpec(params, options = {}) {
* spawnSyncImpl: typeof spawnSync;
* env?: NodeJS.ProcessEnv;
* nodeExecPath?: string;
* npmExecPath?: string;
* platform?: NodeJS.Platform;
* comSpec?: string;
* }} params
@@ -385,11 +402,11 @@ function createMintlifyPnpmRunnerSpawnSpec(params, options = {}) {
export function resolveMintlifyAnchorAuditInvocation(params) {
const nodeVersion = params.nodeVersion ?? process.versions.node;
if (parseNodeMajor(nodeVersion) < NODE_25_UNSUPPORTED_BY_MINTLIFY) {
return createMintlifyPnpmRunnerSpawnSpec(params);
return createMintlifyNpmRunnerSpawnSpec(params);
}
const node22Probe = "process.exit(Number(process.versions.node.split('.')[0]) === 22 ? 0 : 1)";
const node22Runner = createMintlifyPnpmRunnerSpawnSpec(params, { nodeExecPath: "node" });
const node22Runner = createMintlifyNpmRunnerSpawnSpec(params, { nodeExecPath: "node" });
const candidates = [
{
command: "fnm",
@@ -413,7 +430,7 @@ export function resolveMintlifyAnchorAuditInvocation(params) {
}
}
return createMintlifyPnpmRunnerSpawnSpec(params);
return createMintlifyNpmRunnerSpawnSpec(params);
}
/**
@@ -558,7 +575,6 @@ export function auditDocsLinks(options = {}) {
* env?: NodeJS.ProcessEnv;
* nodeExecPath?: string;
* nodeVersion?: string;
* npmExecPath?: string;
* platform?: NodeJS.Platform;
* spawnSyncImpl?: typeof spawnSync;
* prepareAnchorAuditDocsDirImpl?: (sourceDir?: string) => string;
@@ -585,16 +601,14 @@ export function runDocsLinkAuditCli(options = {}) {
try {
anchorDocsDir = prepareAnchorAuditDocsDirImpl(mirroredDocsDir.dir);
// Use the npm Mintlify package explicitly. Some developer machines also
// have the Swift Package Manager tool named `mint` on PATH, and that
// binary exits with "command 'broken-links' not found".
// Mintlify's package graph expects npm's hoisted layout; pnpm dlx can fail
// to resolve declared transitive packages from its strict store layout.
const invocation = resolveMintlifyAnchorAuditInvocation({
comSpec: options.comSpec,
cwd: anchorDocsDir,
env: options.env,
nodeExecPath: options.nodeExecPath,
nodeVersion: options.nodeVersion,
npmExecPath: options.npmExecPath,
platform: options.platform,
spawnSyncImpl,
});
+16 -12
View File
@@ -215,7 +215,7 @@ describe("docs-link-audit", () => {
expect(mirroredCleaned).toBe(true);
});
it("uses Mintlify through pnpm dlx for anchor validation", () => {
it("uses a pinned Mintlify package through npm for anchor validation", () => {
let invocation:
| {
command: string;
@@ -225,16 +225,13 @@ describe("docs-link-audit", () => {
| undefined;
let cleanedDir: string | undefined;
const anchorDocsDir = path.join(os.tmpdir(), "docs-link-audit-anchor");
const fakePnpm = path.join(anchorDocsDir, "pnpm.cjs");
fs.mkdirSync(anchorDocsDir, { recursive: true });
fs.writeFileSync(fakePnpm, "#!/usr/bin/env node\n", { mode: 0o755 });
const exitCode = runDocsLinkAuditCli({
args: ["--anchors"],
env: { ...process.env, OPENCLAW_DOCS_LINK_SENTINEL: "1" },
nodeExecPath: "/opt/node/bin/node",
nodeVersion: "22.21.1",
npmExecPath: fakePnpm,
prepareAnchorAuditDocsDirImpl() {
return anchorDocsDir;
},
@@ -249,8 +246,16 @@ describe("docs-link-audit", () => {
expect(exitCode).toBe(0);
expect(invocation).toEqual({
command: "/opt/node/bin/node",
args: [fakePnpm, "dlx", "mint", "broken-links", "--check-anchors"],
command: "npm",
args: [
"exec",
"--yes",
"--package=mint@4.2.715",
"--",
"mint",
"broken-links",
"--check-anchors",
],
options: expect.objectContaining({
cwd: anchorDocsDir,
env: expect.objectContaining({ OPENCLAW_DOCS_LINK_SENTINEL: "1" }),
@@ -269,15 +274,12 @@ describe("docs-link-audit", () => {
}> = [];
let cleanedDir: string | undefined;
const anchorDocsDir = path.join(os.tmpdir(), "docs-link-audit-anchor");
const fakePnpm = path.join(anchorDocsDir, "pnpm.cjs");
fs.mkdirSync(anchorDocsDir, { recursive: true });
fs.writeFileSync(fakePnpm, "#!/usr/bin/env node\n", { mode: 0o755 });
const exitCode = runDocsLinkAuditCli({
args: ["--anchors"],
nodeExecPath: "/opt/node/bin/node",
nodeVersion: "25.3.0",
npmExecPath: fakePnpm,
prepareAnchorAuditDocsDirImpl() {
return anchorDocsDir;
},
@@ -312,9 +314,11 @@ describe("docs-link-audit", () => {
args: [
"exec",
"--using=22",
"node",
fakePnpm,
"dlx",
"npm",
"exec",
"--yes",
"--package=mint@4.2.715",
"--",
"mint",
"broken-links",
"--check-anchors",