mirror of https://github.com/openclaw/openclaw.git
Docs: unify link audit entrypoint (#55912)
Merged via squash.
Prepared head SHA: 6b1ccb9f1f
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
This commit is contained in:
parent
d35f37a58c
commit
47ae562cc9
|
|
@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Plugins/startup: auto-load bundled provider and CLI-backend plugins from explicit config refs, so bundled Claude CLI, Codex CLI, and Gemini CLI message-provider setups no longer need manual `plugins.allow` entries.
|
||||
- Config/TTS: auto-migrate legacy speech config on normal reads and secret resolution, keep legacy diagnostics for Doctor, and remove regular-mode runtime fallback for old bundled `tts.<provider>` API-key shapes.
|
||||
- OpenAI/apply_patch: enable `apply_patch` by default for OpenAI and OpenAI Codex models, and align its sandbox policy access with `write` permissions.
|
||||
- Docs: add `pnpm docs:check-links:anchors` for Mintlify anchor validation while keeping `scripts/docs-link-audit.mjs` as the stable link-audit entrypoint. (#55912) Thanks @velvet-shark.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -506,7 +506,8 @@ Useful env vars:
|
|||
|
||||
## Docs sanity
|
||||
|
||||
Run docs checks after doc edits: `pnpm docs:list`.
|
||||
Run docs checks after doc edits: `pnpm check:docs`.
|
||||
Run full Mintlify anchor validation when you need in-page heading checks too: `pnpm docs:check-links:anchors`.
|
||||
|
||||
## Offline regression (CI-safe)
|
||||
|
||||
|
|
|
|||
|
|
@ -717,6 +717,7 @@
|
|||
"docs:bin": "node scripts/build-docs-list.mjs",
|
||||
"docs:check-i18n-glossary": "node scripts/check-docs-i18n-glossary.mjs",
|
||||
"docs:check-links": "node scripts/docs-link-audit.mjs",
|
||||
"docs:check-links:anchors": "node scripts/docs-link-audit.mjs --anchors",
|
||||
"docs:dev": "cd docs && mint dev",
|
||||
"docs:list": "node scripts/docs-list.js",
|
||||
"docs:spellcheck": "bash scripts/docs-spellcheck.sh",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
|
@ -288,12 +289,32 @@ export function auditDocsLinks() {
|
|||
return { checked, broken };
|
||||
}
|
||||
|
||||
function isCliEntry() {
|
||||
const cliArg = process.argv[1];
|
||||
return cliArg ? import.meta.url === pathToFileURL(cliArg).href : false;
|
||||
}
|
||||
/**
|
||||
* @param {{
|
||||
* args?: string[];
|
||||
* spawnSyncImpl?: typeof spawnSync;
|
||||
* }} [options]
|
||||
*/
|
||||
export function runDocsLinkAuditCli(options = {}) {
|
||||
const args = options.args ?? process.argv.slice(2);
|
||||
if (args.includes("--anchors")) {
|
||||
const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync;
|
||||
const result = spawnSyncImpl("mint", ["broken-links", "--check-anchors"], {
|
||||
cwd: DOCS_DIR,
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
if (result.error?.code === "ENOENT") {
|
||||
const fallback = spawnSyncImpl("pnpm", ["dlx", "mint", "broken-links", "--check-anchors"], {
|
||||
cwd: DOCS_DIR,
|
||||
stdio: "inherit",
|
||||
});
|
||||
return fallback.status ?? 1;
|
||||
}
|
||||
|
||||
return result.status ?? 1;
|
||||
}
|
||||
|
||||
if (isCliEntry()) {
|
||||
const { checked, broken } = auditDocsLinks();
|
||||
console.log(`checked_internal_links=${checked}`);
|
||||
console.log(`broken_links=${broken.length}`);
|
||||
|
|
@ -302,7 +323,14 @@ if (isCliEntry()) {
|
|||
console.log(`${item.file}:${item.line} :: ${item.link} :: ${item.reason}`);
|
||||
}
|
||||
|
||||
if (broken.length > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
return broken.length > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
function isCliEntry() {
|
||||
const cliArg = process.argv[1];
|
||||
return cliArg ? import.meta.url === pathToFileURL(cliArg).href : false;
|
||||
}
|
||||
|
||||
if (isCliEntry()) {
|
||||
process.exit(runDocsLinkAuditCli());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,21 @@
|
|||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const { normalizeRoute, resolveRoute } =
|
||||
const { normalizeRoute, resolveRoute, runDocsLinkAuditCli } =
|
||||
(await import("../../scripts/docs-link-audit.mjs")) as unknown as {
|
||||
normalizeRoute: (route: string) => string;
|
||||
resolveRoute: (
|
||||
route: string,
|
||||
options?: { redirects?: Map<string, string>; routes?: Set<string> },
|
||||
) => { ok: boolean; terminal: string; loop?: boolean };
|
||||
runDocsLinkAuditCli: (options?: {
|
||||
args?: string[];
|
||||
spawnSyncImpl?: (
|
||||
command: string,
|
||||
args: string[],
|
||||
options: { cwd: string; stdio: string },
|
||||
) => { status: number | null; error?: { code?: string } };
|
||||
}) => number;
|
||||
};
|
||||
|
||||
describe("docs-link-audit", () => {
|
||||
|
|
@ -28,4 +37,63 @@ describe("docs-link-audit", () => {
|
|||
terminal: "/plugins/building-plugins",
|
||||
});
|
||||
});
|
||||
|
||||
it("prefers a local mint binary for anchor validation", () => {
|
||||
let invocation:
|
||||
| {
|
||||
command: string;
|
||||
args: string[];
|
||||
options: { cwd: string; stdio: string };
|
||||
}
|
||||
| undefined;
|
||||
|
||||
const exitCode = runDocsLinkAuditCli({
|
||||
args: ["--anchors"],
|
||||
spawnSyncImpl(command, args, options) {
|
||||
invocation = { command, args, options };
|
||||
return { status: 0 };
|
||||
},
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(invocation).toBeDefined();
|
||||
expect(invocation?.command).toBe("mint");
|
||||
expect(invocation?.args).toEqual(["broken-links", "--check-anchors"]);
|
||||
expect(invocation?.options.stdio).toBe("inherit");
|
||||
expect(path.basename(invocation?.options.cwd ?? "")).toBe("docs");
|
||||
});
|
||||
|
||||
it("falls back to pnpm dlx when mint is not on PATH", () => {
|
||||
const invocations: Array<{
|
||||
command: string;
|
||||
args: string[];
|
||||
options: { cwd: string; stdio: string };
|
||||
}> = [];
|
||||
|
||||
const exitCode = runDocsLinkAuditCli({
|
||||
args: ["--anchors"],
|
||||
spawnSyncImpl(command, args, options) {
|
||||
invocations.push({ command, args, options });
|
||||
if (command === "mint") {
|
||||
return { status: null, error: { code: "ENOENT" } };
|
||||
}
|
||||
return { status: 0 };
|
||||
},
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(invocations).toHaveLength(2);
|
||||
expect(invocations[0]).toMatchObject({
|
||||
command: "mint",
|
||||
args: ["broken-links", "--check-anchors"],
|
||||
options: { stdio: "inherit" },
|
||||
});
|
||||
expect(invocations[1]).toMatchObject({
|
||||
command: "pnpm",
|
||||
args: ["dlx", "mint", "broken-links", "--check-anchors"],
|
||||
options: { stdio: "inherit" },
|
||||
});
|
||||
expect(path.basename(invocations[0]?.options.cwd ?? "")).toBe("docs");
|
||||
expect(path.basename(invocations[1]?.options.cwd ?? "")).toBe("docs");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue