Skip to content

Commit 976537c

Browse files
fix(scripts): scan the fumadocs-mdx docs content for stale @loopover/mcp versions
check-ui-mcp-version-copy.mjs guards UI copy against stale @loopover/mcp version strings, but its SCAN_TARGETS only reached apps/loopover-ui/src and isTextSource didn't match .mdx. Since the fumadocs-mdx migration (5003fab) the docs prose moved to apps/loopover-ui/content/docs/*.mdx — a sibling of src/ — leaving ~10 files with @loopover/mcp install snippets unscanned (the sibling check-docs-drift.mjs was updated for the move; this scanner was not). Add apps/loopover-ui/content to SCAN_TARGETS and .mdx to isTextSource so the content pipeline is scanned the same way src/ and the READMEs already are. The current docs use the correct @latest form, so the live scan still passes (now across 4 targets); a future hardcoded/stale version in any .mdx is now caught. Closes #7093
1 parent cfecb7a commit 976537c

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

scripts/check-ui-mcp-version-copy.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export const SCAN_TARGETS = [
1616
"README.md",
1717
"packages/loopover-mcp/README.md",
1818
"apps/loopover-ui/src",
19+
// The fumadocs-mdx docs content (5003fabe) lives in a sibling directory OUTSIDE src/; check-docs-drift.mjs was
20+
// updated for the move but this scanner was not, leaving 10 real .mdx files with @loopover/mcp install snippets
21+
// unscanned for stale-version drift (#7093).
22+
"apps/loopover-ui/content",
1923
];
2024

2125
async function main() {
@@ -142,7 +146,7 @@ export function collectSourceFiles(path) {
142146
}
143147

144148
export function isTextSource(path) {
145-
return /\.(md|ts|tsx|js|jsx|json)$/.test(path);
149+
return /\.(md|mdx|ts|tsx|js|jsx|json)$/.test(path);
146150
}
147151

148152
export function isMinimumSupportedContext(line) {

test/unit/check-ui-mcp-version-copy-script.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import { join } from "node:path";
55
import { afterEach, describe, expect, it } from "vitest";
66
import {
77
buildStaleVersionMatchers,
8+
collectSourceFiles,
89
collectVersionCopyFailures,
910
isMinimumSupportedContext,
11+
isTextSource,
1012
readMinimumSupportedVersion,
13+
SCAN_TARGETS,
1114
SOURCE_LATEST_PATH,
1215
writeKnownLatestVersion,
1316
} from "../../scripts/check-ui-mcp-version-copy.mjs";
@@ -102,6 +105,48 @@ describe("check-ui-mcp-version-copy script (#6292)", () => {
102105
});
103106
});
104107

108+
describe("scanning the fumadocs-mdx content directory (#7093)", () => {
109+
let tempDir: string | undefined;
110+
111+
afterEach(() => {
112+
if (tempDir) rmSync(tempDir, { recursive: true, force: true });
113+
tempDir = undefined;
114+
});
115+
116+
it("includes the docs content directory and recognizes .mdx as a text source", () => {
117+
// Before #7093, SCAN_TARGETS only reached apps/loopover-ui/src and isTextSource didn't match .mdx, so the
118+
// fumadocs content pipeline (5003fabe) was entirely invisible to this drift check.
119+
expect(SCAN_TARGETS).toContain("apps/loopover-ui/content");
120+
expect(isTextSource("apps/loopover-ui/content/docs/quickstart.mdx")).toBe(true);
121+
});
122+
123+
it("collectSourceFiles now picks up real .mdx files under apps/loopover-ui/content/docs", () => {
124+
const files = collectSourceFiles(join(root, "apps/loopover-ui/content"));
125+
expect(files.some((file) => file.endsWith(join("docs", "quickstart.mdx")))).toBe(true);
126+
});
127+
128+
it("flags a stale @loopover/mcp floor version hardcoded in an .mdx file (the regression this scan now catches)", () => {
129+
tempDir = mkdtempSync(join(tmpdir(), "mcp-mdx-"));
130+
mkdirSync(join(tempDir, "docs"), { recursive: true });
131+
const mdxPath = join(tempDir, "docs", "quickstart.mdx");
132+
writeFileSync(mdxPath, "Install with `npx -y @loopover/mcp/0.5.0 --help`\n");
133+
134+
// Discovery: the .mdx file is collected (it would have been skipped before the isTextSource change).
135+
expect(collectSourceFiles(tempDir)).toContain(mdxPath);
136+
137+
// Flagging: its stale floor version is caught by the same matcher the src/ scan already uses.
138+
const matchers = buildStaleVersionMatchers("0.5.0");
139+
const failures = collectVersionCopyFailures({
140+
label: "docs/quickstart.mdx",
141+
text: readFileSync(mdxPath, "utf8"),
142+
matchers,
143+
});
144+
expect(failures).toContain(
145+
"docs/quickstart.mdx:1: 0.5.0 is only allowed as an explicit minimum-supported compatibility floor",
146+
);
147+
});
148+
});
149+
105150
it("recognizes minimum-supported context markers", () => {
106151
expect(
107152
isMinimumSupportedContext("the minimum supported version is X"),
@@ -170,6 +215,9 @@ describe("check-ui-mcp-version-copy script (#6292)", () => {
170215
function seedTempRepo(knownLatest: string): string {
171216
const dir = mkdtempSync(join(tmpdir(), "mcp-write-cli-"));
172217
mkdirSync(join(dir, "apps/loopover-ui/src/lib"), { recursive: true });
218+
// #7093: SCAN_TARGETS now includes apps/loopover-ui/content, so the seeded repo must have it too or the
219+
// scan's statSync would ENOENT. Empty is fine — collectSourceFiles returns [] for it.
220+
mkdirSync(join(dir, "apps/loopover-ui/content"), { recursive: true });
173221
mkdirSync(join(dir, "packages/loopover-mcp"), { recursive: true });
174222
writeFileSync(join(dir, "README.md"), "# repo\n");
175223
writeFileSync(join(dir, "packages/loopover-mcp/README.md"), "# mcp\n");

0 commit comments

Comments
 (0)