FN-6534: track docs screenshots

Restore the screenshot assets that published docs reference so rendered documentation no longer shows broken images.

- Keep docs/screenshots trackable by removing the blanket ignore rule.
- Add the referenced screenshot PNG assets under docs/screenshots.
- Add a regression test that verifies screenshot Markdown links resolve to tracked files.

Files changed:
 .gitignore                                         |   2 +-
 docs/screenshots/agents-view.png                   | Bin 0 -> 88902 bytes
 docs/screenshots/chat-view.png                     | Bin 0 -> 74669 bytes
 docs/screenshots/dashboard-overview.png            | Bin 0 -> 209599 bytes
 docs/screenshots/documents-view.png                | Bin 0 -> 37607 bytes
 docs/screenshots/git-manager.png                   | Bin 0 -> 135486 bytes
 docs/screenshots/list-view.png                     | Bin 0 -> 108702 bytes
 docs/screenshots/mailbox-view.png                  | Bin 0 -> 72370 bytes
 docs/screenshots/memory-view.png                   | Bin 0 -> 118122 bytes
 docs/screenshots/mission-manager.png               | Bin 0 -> 80643 bytes
 docs/screenshots/nodes-view.png                    | Bin 0 -> 59576 bytes
 docs/screenshots/roadmaps-view.png                 | Bin 0 -> 37828 bytes
 docs/screenshots/settings.png                      | Bin 0 -> 131052 bytes
 docs/screenshots/skills-view.png                   | Bin 0 -> 92259 bytes
 docs/screenshots/task-detail.png                   | Bin 0 -> 171502 bytes
 docs/screenshots/terminal.png                      | Bin 0 -> 70273 bytes
 docs/screenshots/workflow-steps.png                | Bin 0 -> 179100 bytes
 .../src/__tests__/docs-screenshot-links.test.ts    |  96 +++++++++++++++++++++
 18 files changed, 97 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6534

Fusion-Task-Lineage: a0840905-8eb5-4da0-8c52-56904ac82e04
This commit is contained in:
gsxdsm
2026-06-17 03:42:03 -07:00
parent 89171e0f16
commit 8e9b7b75a4
18 changed files with 97 additions and 1 deletions

2
.gitignore vendored
View File

@@ -65,7 +65,7 @@ homebrew-tap/
# never meant to be committed.
.DONE
improvements.md
docs/screenshots/
# FNXC:RepoHygiene 2026-06-17-00:38: Published Markdown docs embed `docs/screenshots/*.png`; keep that directory trackable so GitHub, npm-rendered docs, and fresh clones do not show broken images.
.claude/
# Local kb state and backups

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@@ -0,0 +1,96 @@
import { execFileSync } from "node:child_process";
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, relative, resolve, sep } from "node:path";
import { describe, expect, it } from "vitest";
const workspaceRoot = resolve(import.meta.dirname, "../../../..");
const docsRoot = resolve(workspaceRoot, "docs");
/*
FNXC:DocsScreenshots 2026-06-17-00:38:
Published docs render on GitHub and in fresh clones, so screenshot image references must resolve to committed files, not only developer-local files that happen to exist on disk.
Assert both filesystem presence and `git ls-files` tracking so a gitignored-but-present `docs/screenshots/` directory cannot regress silently.
*/
function collectMarkdownFiles(directory: string): string[] {
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const entryPath = resolve(directory, entry.name);
if (entry.isDirectory()) {
return collectMarkdownFiles(entryPath);
}
if (entry.isFile() && entry.name.endsWith(".md")) {
return [entryPath];
}
return [];
});
}
function toRepoRelativePath(absolutePath: string): string {
return relative(workspaceRoot, absolutePath).split(sep).join("/");
}
function gitTracks(relativePath: string): boolean {
const output = execFileSync("git", ["ls-files", "--", relativePath], {
cwd: workspaceRoot,
encoding: "utf8",
}).trim();
return output.length > 0;
}
describe("docs screenshot links", () => {
it("points every screenshot image reference at an existing tracked asset", () => {
const markdownFiles = [...collectMarkdownFiles(docsRoot), resolve(workspaceRoot, "README.md")];
const screenshotReferences: Array<{ source: string; target: string; resolvedPath: string; repoPath: string }> = [];
for (const markdownFile of markdownFiles) {
const markdown = readFileSync(markdownFile, "utf8");
const imagePattern = /!\[[^\]]*\]\(([^)]+)\)/g;
for (const match of markdown.matchAll(imagePattern)) {
const rawTarget = match[1]?.trim().replace(/^<|>$/g, "") ?? "";
const targetWithoutTitle = rawTarget.split(/\s+/)[0] ?? "";
const targetWithoutFragment = targetWithoutTitle.replace(/[?#].*$/, "");
if (!/(?:^|\/)screenshots\/[^/]+\.png$/i.test(targetWithoutFragment)) {
continue;
}
const resolvedPath = resolve(dirname(markdownFile), targetWithoutFragment);
screenshotReferences.push({
source: toRepoRelativePath(markdownFile),
target: targetWithoutTitle,
resolvedPath,
repoPath: toRepoRelativePath(resolvedPath),
});
}
}
expect(screenshotReferences.map(({ repoPath }) => repoPath).sort()).toEqual([
"docs/screenshots/agents-view.png",
"docs/screenshots/chat-view.png",
"docs/screenshots/dashboard-overview.png",
"docs/screenshots/dashboard-overview.png",
"docs/screenshots/dashboard-overview.png",
"docs/screenshots/documents-view.png",
"docs/screenshots/git-manager.png",
"docs/screenshots/list-view.png",
"docs/screenshots/mailbox-view.png",
"docs/screenshots/memory-view.png",
"docs/screenshots/mission-manager.png",
"docs/screenshots/nodes-view.png",
"docs/screenshots/skills-view.png",
"docs/screenshots/task-detail.png",
"docs/screenshots/task-detail.png",
"docs/screenshots/terminal.png",
"docs/screenshots/workflow-steps.png",
]);
const missingFiles = screenshotReferences
.filter(({ resolvedPath }) => !existsSync(resolvedPath))
.map(({ source, target, repoPath }) => `${source} -> ${target} (${repoPath})`);
const untrackedFiles = screenshotReferences
.filter(({ repoPath }) => !gitTracks(repoPath))
.map(({ source, target, repoPath }) => `${source} -> ${target} (${repoPath})`);
expect(missingFiles).toEqual([]);
expect(untrackedFiles).toEqual([]);
});
});