Skip to content

fix(site): rewrite broken README.md and out-of-docs links#2765

Merged
waynesun09 merged 3 commits into
fullsend-ai:mainfrom
DaoDaoNoCode:vitepress-followup-fixes
Jun 29, 2026
Merged

fix(site): rewrite broken README.md and out-of-docs links#2765
waynesun09 merged 3 commits into
fullsend-ai:mainfrom
DaoDaoNoCode:vitepress-followup-fixes

Conversation

@DaoDaoNoCode

Copy link
Copy Markdown
Contributor

Summary

  • Adds a markdown-it core rule that rewrites README.md links to directory index paths — VitePress rewrites only affects routing/file output, not link resolution in markdown content
  • Converts relative links that escape the docs/ directory (e.g. ../../internal/scaffold/...) into GitHub source URLs (https://github.com/fullsend-ai/fullsend/tree/main/...)
  • Fixes 37 broken source-code links and all README.md 404s without modifying any doc content
  • Fixes eslint warnings (unnecessary regex escape, any type)

Context

After the VitePress migration (#2721), links like [Default Agents](../../agents/README.md) resolved to README.html which doesn't exist (VitePress outputs index.html). Links to source files like ../../internal/scaffold/fullsend-repo/harness/ also 404'd since they're outside the docs directory.

Test plan

  • npm run build && cd website && npm run build passes locally
  • Default Agents link resolves to /docs/agents/ (not 404)
  • Source code links resolve to github.com/fullsend-ai/fullsend/tree/main/...
  • Zero README.html references in built output
  • CI build passes

@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix VitePress markdown link resolution for README.md and out-of-docs paths

🐞 Bug fix ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Rewrites relative README.md links to directory index paths during Markdown rendering.
• Converts links escaping docs/ into GitHub source URLs to avoid 404s.
• Fixes minor TypeScript/eslint issues in the VitePress config.
Diagram

graph TD
  A["Docs markdown"] --> B["markdown-it parse"] --> C["rewrite-links rule"] --> D["VitePress HTML output"]
  B --> E["escapeVueSyntax"]
  C --> F{{"GitHub tree URL"}}
  subgraph Legend
    direction LR
    _file["Input file"] ~~~ _proc["Build step"] ~~~ _ext{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Preprocess docs links at build time (content transform script)
  • ➕ Makes the generated links explicit in the built artifacts (no runtime markdown-it dependency)
  • ➕ Can be validated with a link checker against the output directory
  • ➖ Adds a separate build step and risks drift between authored and generated content
  • ➖ Harder to keep anchors and relative semantics correct across all markdown variations
2. Use a dedicated markdown-it/link-normalization plugin
  • ➕ Less custom code to maintain if an off-the-shelf plugin matches requirements
  • ➕ Potentially better-tested URL parsing/normalization behavior
  • ➖ May not understand VitePress-specific semantics (README->index) or env.relativePath usage
  • ➖ Adds dependency surface area and upgrade/compat risks
3. Fix links in source markdown files
  • ➕ Simplest runtime behavior; no custom renderer logic
  • ➕ Links become readable and portable outside the VitePress build
  • ➖ Large doc churn and ongoing maintenance burden
  • ➖ Harder to keep cross-repo/source links consistent; more reviewer noise

Recommendation: The chosen approach (a markdown-it core rule) is the best fit given the goal of fixing link resolution without touching doc content. It addresses the key VitePress gap (rewrites don’t affect markdown link resolution) while keeping the change localized to the website config. If this grows further, consider extracting the rule into a small, tested helper module to improve maintainability and add unit coverage for edge cases (anchors, ./README.md vs README.md, and Windows-style paths if relevant).

Files changed (1) +34 / -2

Bug fix (1) +34 / -2
config.tsAdd markdown-it core rule to rewrite README/out-of-docs links +34/-2

Add markdown-it core rule to rewrite README/out-of-docs links

• Adds a markdown-it core rule that rewrites relative links ending in README.md to directory index equivalents and converts relative links that escape the docs/ tree into GitHub tree URLs. Also tightens types for the markdown parse env and fixes a minor regex escape eslint warning.

website/.vitepress/config.ts

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

Site preview

Preview: https://7386d7a1-site.fullsend-ai.workers.dev

Commit: 9aca1f9d22d2a934701d33e061886e4805f7f76d

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@qodo-code-review

qodo-code-review Bot commented Jun 29, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 51 rules

Grey Divider


Action required

1. README escaping link mangled ✓ Resolved 🐞 Bug ≡ Correctness
Description
rewrite-links rewrites any README.md href to ./ before checking whether the link escapes
docs/, so out-of-doc links like ../../README.md or ../web/admin/README.md lose the filename
and end up rewritten to the wrong GitHub target. This breaks or misdirects existing docs links
intended to point at repository READMEs outside the VitePress docs/ tree.
Code

website/.vitepress/config.ts[R350-366]

+            if (/README\.md(#.*)?$/.test(href)) {
+              child.attrSet('href', href.replace(/README\.md(#.*)?$/, (_: string, anchor: string) => anchor || './'))
+            }
+
+            if (/\.\.\/(\.\.\/)*[^.][^/]*/.test(href)) {
+              const docPath = state.env?.relativePath || ''
+              const docDir = docPath.split('/').slice(0, -1)
+              const parts = href.split('#')
+              const linkPath = parts[0]
+              const anchor = parts[1] ? '#' + parts[1] : ''
+              const segments = linkPath.split('/')
+              let depth = 0
+              for (const s of segments) { if (s === '..') depth++; else break }
+              if (depth > docDir.length) {
+                const remainder = segments.slice(depth).join('/')
+                child.attrSet('href', 'https://github.com/fullsend-ai/fullsend/tree/main/' + remainder + anchor)
+              }
Relevance

⭐⭐⭐ High

Team prioritizes fixing broken docs links; prior link-fix/lint work accepted (PRs #2181, #783).

PR-#2181
PR-#783

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The core rule first replaces README.md with ./ (which changes escaping README targets like
../../README.md and ../web/admin/README.md into ../.././ and ../web/admin/./), and only
afterwards applies the “escape docs → GitHub” rewrite. The docs contain concrete out-of-doc README
links that will be affected by this ordering.

website/.vitepress/config.ts[340-367]
docs/ADRs/0002-initial-fullsend-design.md[30-36]
docs/ADRs/0002-initial-fullsend-design.md[444-449]
docs/admin-oauth-worker.md[3-6]
docs/site-deployment.md[1-7]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `rewrite-links` rule rewrites any `README.md` link to a directory index (`./`) before determining whether the link escapes `docs/`. For links that *do* escape `docs/`, this destroys the intended target (e.g. `../../README.md` becomes `../.././`) and then the GitHub rewrite produces the wrong destination.

### Issue Context
Docs contain out-of-doc README links such as `../../README.md` and `../web/admin/README.md` that should be rewritten to GitHub URLs pointing at the README file, not the containing directory.

### Fix Focus Areas
- website/.vitepress/config.ts[340-370]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Dotdir links not rewritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
The out-of-doc rewrite guard regex rejects escaped paths whose next segment starts with a dot (e.g.
.github/...), so those links will not be converted to GitHub URLs and will remain broken in the
built site. This affects multiple docs pages that link to workflows under .github/workflows/ via
../../../.github/....
Code

website/.vitepress/config.ts[R354-367]

+            if (/\.\.\/(\.\.\/)*[^.][^/]*/.test(href)) {
+              const docPath = state.env?.relativePath || ''
+              const docDir = docPath.split('/').slice(0, -1)
+              const parts = href.split('#')
+              const linkPath = parts[0]
+              const anchor = parts[1] ? '#' + parts[1] : ''
+              const segments = linkPath.split('/')
+              let depth = 0
+              for (const s of segments) { if (s === '..') depth++; else break }
+              if (depth > docDir.length) {
+                const remainder = segments.slice(depth).join('/')
+                child.attrSet('href', 'https://github.com/fullsend-ai/fullsend/tree/main/' + remainder + anchor)
+              }
+            }
Relevance

⭐⭐⭐ High

Team has accepted regex/path edge-case fixes involving .github patterns; likely to fix dotdir
rewrite gap (PRs #337, #2398).

PR-#337
PR-#2398

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The rule’s out-of-doc rewrite is only entered if the regex matches the href; .github fails the
[^.] constraint, so ../../../.github/workflows/e2e.yml will not be rewritten. The docs contain
this exact link form.

website/.vitepress/config.ts[354-367]
docs/guides/dev/e2e-testing.md[28-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The out-of-doc conversion is gated by `/\.\.\/(\.\.\/)*[^.][^/]*/`, which fails for escaped links where the first non-`..` path segment begins with `.` (e.g. `.github`). Those links won’t be rewritten, so they will keep pointing outside `docs/` and still 404 on the generated site.

### Issue Context
Docs include links like `../../../.github/workflows/e2e.yml` which escape the docs root and should be rewritten to GitHub.

### Fix Focus Areas
- website/.vitepress/config.ts[354-367]
- docs/guides/dev/e2e-testing.md[28-33]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread website/.vitepress/config.ts Outdated
Comment thread website/.vitepress/config.ts Outdated
Add a markdown-it core rule that:
- Rewrites README.md links to directory index paths (README→index
  rewrite only affects routing, not link resolution)
- Converts relative links that escape the docs/ directory into GitHub
  source URLs, fixing 37 broken links to source code files

Also fixes eslint warnings (unnecessary regex escape, any type).

Signed-off-by: Juntao Wang <juntwang@redhat.com>
- Check out-of-docs links before README rewrite so ../../README.md
  gets GitHub-redirected with the filename intact
- Remove [^.] guard so .github/ paths are also rewritten to GitHub
- README→index rewrite only applies to links staying within docs/

Signed-off-by: Juntao Wang <juntwang@redhat.com>

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor URL construction suggestions — not blocking.

Comment thread website/.vitepress/config.ts
Files (with extensions) use /blob/main/, directories use /tree/main/,
matching GitHub's URL convention.

Signed-off-by: Juntao Wang <juntwang@redhat.com>

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Verified the CI build artifact: zero README.html 404s, blob/tree distinction working correctly for files vs directories, .github/ dotdir links rewriting properly, all internal/scaffold/ source links resolving to GitHub URLs. LGTM.

@waynesun09 waynesun09 added this pull request to the merge queue Jun 29, 2026
Merged via the queue into fullsend-ai:main with commit d2cb912 Jun 29, 2026
17 checks passed
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jun 29, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 8:43 PM UTC · Completed 8:55 PM UTC
Commit: 9aca1f9 · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #2765 — fix(site): rewrite broken README.md and out-of-docs links

Workflow type: Human-authored PR with no fullsend agent involvement.

Timeline:

  • PR created by DaoDaoNoCode at 19:47 UTC, fixing broken links after the VitePress migration (feat(site): migrate documentation site from Docusaurus to VitePress #2721)
  • qodo-code-review bot flagged two correctness issues (README escaping order, dotdir regex) — both addressed
  • Human reviewer waynesun09 suggested blob/tree URL distinction for files vs directories — implemented in follow-up commit
  • waynesun09 approved at 20:34 after verifying the build artifact
  • Merged at 20:39 (~52 minutes total)
  • Only fullsend dispatch: this retro run (triggered at merge)

Assessment: This was a clean, efficient human workflow. No fullsend review, code, or fix agents were dispatched — correctly, since the routing logic doesn't trigger those stages for human PRs on non-agent branches. The human review was effective, catching a real correctness issue (blob vs tree GitHub URLs) that the author addressed.

Skipped proposals:

  • The main finding — that a retro was dispatched for a merged human PR with zero agent involvement, wasting tokens — is already tracked by #2708 ("Skip retro dispatch for merged human PRs with no agent involvement"). No new proposal needed.

No other improvement opportunities identified. The workflow executed well within expected parameters.

waynesun09 added a commit that referenced this pull request Jun 29, 2026
The link in the org-mode deprecation notice was hardcoded to
`../getting-started/` as a workaround for VitePress not resolving
README.md links. Now that #2765 adds a markdown-it rewrite rule
to handle this automatically, revert to the canonical `README.md`
reference.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants