Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ Helpful docs:
- [Integration outreach pack](./docs/distribution/INTEGRATION-OUTREACH.md)
- [Claude Code walkthrough](./docs/oss/CLAUDE-CODE-WALKTHROUGH.md)
- [Ralph-style loop safety guide](./docs/oss/RALPH-LOOP-SAFETY.md)
- [Release surface report](./docs/oss/RELEASE-SURFACE-REPORT.md)
- [OSS surface overview](./docs/oss/README.md)

---

Expand Down
223 changes: 0 additions & 223 deletions docs/posts/cmpejena2004q2gmdhsnid1p9.md

This file was deleted.

109 changes: 108 additions & 1 deletion scripts/tests/readme-public-surface.test.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { access, readFile, readdir } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

import rootPackageJson from "../../package.json" with { type: "json" };
import mcpPackageJson from "../../packages/mcp/package.json" with { type: "json" };

const ROOT_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const PUBLIC_LINK_SURFACES = [
"README.md",
"docs/oss",
"docs/distribution",
"packages/mcp/README.md",
];

const FORBIDDEN_README_PATTERNS = [
/\b0\.1\.4\b/i,
Expand All @@ -33,6 +39,62 @@ async function readReadme() {
return readFile(path.join(ROOT_DIR, "README.md"), "utf8");
}

async function readRepoFile(relativePath) {
return readFile(path.join(ROOT_DIR, relativePath), "utf8");
}

async function collectMarkdownFiles(relativePath) {
const fullPath = path.join(ROOT_DIR, relativePath);
const entries = await readdir(fullPath, { withFileTypes: true });
const files = [];

for (const entry of entries) {
const entryRelativePath = path.posix.join(relativePath.replaceAll("\\", "/"), entry.name);
if (entry.isDirectory()) {
files.push(...(await collectMarkdownFiles(entryRelativePath)));
continue;
}

if (entry.isFile() && entry.name.endsWith(".md")) {
files.push(entryRelativePath);
}
}

return files;
}

async function listPublicMarkdownSurfaces() {
const files = [];

for (const surface of PUBLIC_LINK_SURFACES) {
if (surface.endsWith(".md")) {
files.push(surface);
continue;
}

files.push(...(await collectMarkdownFiles(surface)));
}

return files.sort();
}

function stripCodeFences(contents) {
return contents.replace(/```[\s\S]*?```/g, "");
}

function extractLocalMarkdownLinks(contents) {
const stripped = stripCodeFences(contents);
const matches = stripped.matchAll(/!?\[[^\]]*]\((?!https?:|mailto:|#)([^)]+)\)/g);

return [...new Set(
[...matches]
.map((match) => match[1].trim())
.map((target) => target.replace(/^<|>$/g, ""))
.map((target) => target.split("#")[0]?.split("?")[0] ?? "")
.filter(Boolean),
)].sort();
Comment on lines +89 to +95
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current link extraction logic does not account for Markdown links that include titles (e.g., [text](url "title")) or those wrapped in angle brackets (e.g., [text](<url>)). The match[1] will capture the entire string inside the parentheses, which will cause access() to fail when verifying the path. Additionally, it's safer to extract the URL part before splitting by fragments or queries.

  return [...new Set(
    [...matches]
      .map((match) => {
        const raw = match[1].trim();
        // Handle links with titles or wrapped in angle brackets
        return raw.startsWith("<") ? raw.split(">")[0].slice(1) : raw.split(/\s+/)[0];
      })
      .map((target) => target.split("#")[0]?.split("?")[0] ?? "")
      .filter(Boolean),
  )].sort();

}

test("root README matches the current public package versions and launch surfaces", async () => {
const readme = await readReadme();

Expand All @@ -57,3 +119,48 @@ test("root README stays clean client-facing public copy", async () => {
assert.doesNotMatch(readme, pattern);
}
});

test("public markdown links resolve inside the repo", async () => {
const markdownFiles = await listPublicMarkdownSurfaces();

for (const relativePath of markdownFiles) {
const contents = await readRepoFile(relativePath);
const targets = extractLocalMarkdownLinks(contents);

for (const target of targets) {
const resolvedPath = path.resolve(path.dirname(path.join(ROOT_DIR, relativePath)), target);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Links starting with / (repo-root-relative) are not handled correctly by path.resolve when combined with a directory path. In Node.js, path.resolve(dir, '/path') resolves to the system root, not the repository root. These should be resolved relative to ROOT_DIR.

      const resolvedPath = target.startsWith("/")
        ? path.join(ROOT_DIR, target)
        : path.resolve(path.dirname(path.join(ROOT_DIR, relativePath)), target);

await access(resolvedPath);
}
}
});

test("docs/posts does not contain unlinked markdown artifacts", async () => {
const postDir = path.join(ROOT_DIR, "docs", "posts");
let postFiles = [];

try {
postFiles = (await readdir(postDir, { withFileTypes: true }))
.filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
.map((entry) => entry.name)
.sort();
} catch (error) {
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
return;
}

throw error;
}

const surfaceFiles = await listPublicMarkdownSurfaces();
const surfaceContents = await Promise.all(surfaceFiles.map((relativePath) => readRepoFile(relativePath)));
const referenceText = surfaceContents.join("\n");

for (const postFile of postFiles) {
const linked =
referenceText.includes(`docs/posts/${postFile}`) ||
referenceText.includes(`./docs/posts/${postFile}`) ||
referenceText.includes(postFile);

assert.equal(linked, true, `docs/posts/${postFile} must be linked from a public markdown surface`);
}
Comment on lines +154 to +165
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current check for unlinked posts uses a simple String.prototype.includes() on a concatenated string of all surface contents. This is prone to false positives (e.g., matching a filename in a sentence or a code block) and is inefficient as it re-reads and joins all files. It is more robust to reuse the link extraction and resolution logic to verify that each post file is actually the target of a resolved link.

  const surfaceFiles = await listPublicMarkdownSurfaces();
  const allResolvedTargets = new Set();
  for (const file of surfaceFiles) {
    const contents = await readRepoFile(file);
    const targets = extractLocalMarkdownLinks(contents);
    for (const target of targets) {
      const resolvedPath = target.startsWith("/")
        ? path.join(ROOT_DIR, target)
        : path.resolve(path.dirname(path.join(ROOT_DIR, file)), target);
      allResolvedTargets.add(resolvedPath);
    }
  }

  for (const postFile of postFiles) {
    const fullPostPath = path.join(postDir, postFile);
    assert.ok(allResolvedTargets.has(fullPostPath), `docs/posts/${postFile} must be linked from a public markdown surface`);
  }

});
Loading