Skip to content

Commit 40e6f54

Browse files
authored
docs: migrate to Starlight + merge authoring into sourcebans-pp (#1333) (#1339)
* docs: scaffold Astro + Starlight project under docs/ (#1333) Workstream 1 of the Hugo→Starlight migration. New docs/ directory holds the Astro + Starlight project that publishes to sbpp.github.io once the cutover lands. The sibling repo becomes a thin deploy shell; source of truth lives here so user-facing changes ship with their docs in the same PR. Pieces in this commit: * docs/package.json — astro 5 + @astrojs/starlight + astro-mermaid + @playwright/test (drives docs/scripts/capture.mjs in a later commit) + sharp (Astro asset pipeline). Pagefind ships inside Starlight; no separate dep. * docs/astro.config.mjs — site=https://sbpp.github.io/, base=/, full sidebar tree (Getting Started, Setup, Updating, Troubleshooting, Integrations, Customization, FAQ, Legacy), GitHub + Discord social links, edit-link back to this repo. ThemeProvider override (next bullet) is wired here so first paint matches the panel. * docs/src/components/ThemeProvider.astro — overrides Starlight's stock dark-leaning fallback with a default of 'light'. Mirrors the panel's first-paint behavior; user toggle still wins on subsequent visits via localStorage['starlight-theme']. * docs/src/assets/logo.svg + docs/public/favicon.svg — same brand mark as the panel (web/themes/default/images/favicon.svg). * docs/src/assets/auto/{install,panel}/.gitkeep — destination for the auto-capture pipeline (Workstream 7); committed empty so layout is in place before the first capture run. * docs/tsconfig.json — extends astro/tsconfigs/strict. * .gitignore — append docs/{node_modules,dist,.astro,pnpm-lock}. Auto-captured screenshots under docs/src/assets/auto/ stay TRACKED so the screenshot diff lands with the UI change. * .github/dependabot.yml — add npm ecosystem rooted at /docs/. Theme tokens land in the next commit (Workstream 2). * docs: mirror panel theme tokens into Starlight (#1333) Workstream 2. New docs/src/styles/sbpp.css carries the panel-parity overrides wired in via the customCss array in astro.config.mjs. The mapping is token-for-token from web/themes/default/css/theme.css (panel :root + html.dark blocks → Starlight's --sl-color-* / --sl-color-bg-* / --sl-color-asides-* hooks): * Brand orange (--brand-50 … --brand-950) → --sl-color-accent triplet + accent-text. Light mode uses --brand-600 as primary / --brand-700 as hover/strong (the same AA-contrast trade-off the panel made). Dark mode uses --brand-600 as primary / --brand-400 as text-accent for legibility on the zinc-950 surface. * Zinc neutrals → --sl-color-gray-1..7 + page/surface/sidebar bgs. * Semantic asides (:::note / :::tip / :::caution / :::danger) repaint to the panel's --info / --success / --warning / --danger pairs + matching soft fills. Light mode uses the explicit hex pairs from theme.css (#2563eb/#eff6ff for info, etc.); dark mode mirrors the rgb(<hex> / 0.4) recipe theme.css lines 97-101 use. * Geometry — radii (--sbpp-radius-{sm,md,lg,xl}) + shadow scales + the focus-ring outline (`2px solid var(--sl-color-accent); outline-offset: 2px`) ported across so cards / code blocks / buttons / asides have the same shape language as the panel. * color-scheme: light / color-scheme: dark mirrored from theme.css line 44 / 89 (the #1309 declaration that lets browsers paint native UA surfaces — open <select> panels, scrollbars, autofill, date pickers — in the matching scheme). * ::selection paints orange in both modes so the brand is visible even on incidental highlight. The override deliberately skips font wiring (per #1333 §2 — color identity carries the "one product" feel; matching fonts adds asset- sharing complexity for diminishing return). The panel ships vendored Inter + JetBrains Mono; Starlight stays on its defaults. The header comment + AGENTS.md row added in a later commit are how future maintainers know to mirror panel-side changes here. * docs: port content + UX folds (#1333) Workstreams 3 + 4 of the migration. The two are entangled — the tabs/asides/cross-link landings ARE the content port for the pages that use them — so they ship together. 13 source pages converted from Hugo TOML front matter to Starlight YAML, plus a landing page (index.mdx, splash template) and the legacy soft-archive landing (workstream 5). Final layout: * getting-started/quickstart.mdx ← quickstart.md (TABS) * getting-started/prerequisites.mdx ← extracted §Prerequisites + new (TABS) * setup/adding-server.md ← adding_server.md * setup/plugin-setup.md ← new (was a "see Quickstart" stub) * setup/ports.md ← ports.md * setup/mariadb.mdx ← mariadb.md (TABS) * updating/index.md ← updating.md * troubleshooting/browser-freeze.md ← browser_freeze.md * troubleshooting/could-not-find-driver.md ← could_not_find_driver.md * troubleshooting/database-errors.md ← database_errors.md * troubleshooting/debugging-connection.md ← debugging_connection.md * integrations/discord-forward-setup.md ← discord_forward_setup.md * customization/removing-default-message.md ← removing_default_message.md * customization/translating.md ← translating.md * faq/index.md ← faq/_index.md * faq/inquiries.md ← inquiries.md (placed under FAQ per the issue's "your judgment" — both are Q&A-shaped and FAQ is the more discoverable home) * legacy/index.md ← workstream 5 (caution-banner stub) * index.mdx ← new landing (splash template) Per-page port rules applied (workstream 3): * TOML +++…+++ → YAML ---…---. Dropped: bref (became `description` when not already set), weight (→ sidebar.order), toc, draft, translationKey. * HTML-in-Markdown swept: <mark>X</mark> → `X` (inline code) for placeholder values (Server Hostname, RCON Password, etc.); <samp>X</samp> → `X` (inline code) for example URLs and command names; <a target="_blank_"> stripped (Starlight handles external link affordances). * `> Note:` blockquotes promoted to Starlight asides: - 1.6.x warning in quickstart → :::caution - Cloudflare/Rocket Loader note → :::caution - Smarty 5 {php} → {load_template} → :::caution - "you can…" suggestions → :::tip - Discord forwarder web/in-game → :::note * Internal links rewritten from /docs/foo to the new IA: - /docs/quickstart → /getting-started/quickstart/ - /docs/mariadb → /setup/mariadb/ (+ #granting-permission) - /docs/adding_server → /setup/adding-server/ - /docs/updating → /updating/ - /docs/inquiries → /faq/inquiries/ - {{< ref "mariadb.md#granting-permission" >}} ditto - {{< ref "docs/quickstart.md" >}} ditto UX folds (workstream 4): * Tabs in quickstart.mdx (Linux/Windows/Shared/Docker) — chmod block ONLY in the Linux tab per the issue. * Tabs in mariadb.mdx (Ubuntu repo / official repo / MySQL) plus a paired tabs block for the GRANT syntax (MariaDB-MySQL8+ vs MySQL-5.x). * Tabs in prerequisites.mdx for the MariaDB vs MySQL DB-choice section. * Cross-link asides on every step with a known failure mode: - DB step → /troubleshooting/database-errors/ + /troubleshooting/could-not-find-driver/ - SteamID format → :::tip with a tooling pointer - Cloudflare/Rocket Loader → caution + link to /troubleshooting/browser-freeze/ - 1.6.x preflight on quickstart → caution + link to /updating/ * "What's next" footer on quickstart.mdx — LinkCard grid pointing to adding-server, plugin-setup, discord-forward-setup. * Landing page (index.mdx) ships a splash hero + 4-card grid (Quickstart / Adding Server / Troubleshooting / Updating). * Code copy buttons inherited from Starlight default — no opt-out. Other notes: * PHP version reference is the current floor (>= 8.5, per web/composer.json — AGENTS.md says PHP 8.5 floor). The legacy 1.7.0 step in updating/index.md keeps the historical ">= 8.2" wording for context but the prerequisites page cites the current floor. * Inquiries kept under /faq/ rather than under Customization; every entry is a Q&A and reads more naturally next to FAQ proper. * `kv` (KeyValues) codeblock language tags swapped to `ini` for Shiki compatibility — KeyValues is structurally close enough that the highlighter doesn't get confused. * docs/src/content.config.ts pinned to Starlight's stock docsLoader + docsSchema; no custom front-matter validators. The legacy soft-archive lands as a single index.md (workstream 5); specific upgrade-from-X content moves into legacy/ in future PRs as old paths are documented. * docs: add three CI workflows for the docs site (#1333) Workstream 6. Three new workflows under .github/workflows/, each gated on docs/** path filters so they stay out of the way of PRs that don't touch the site. * docs-build.yml — runs `npm run build` on PRs + main pushes that touch docs/. Uploads the built dist/ as an artifact (7-day retention) so reviewers can poke at chrome locally without rebuilding. Falls back to `npm install` until the lockfile ships in a follow-up. * docs-deploy-trigger.yml — runs on main pushes only, fires a repository_dispatch (event_type=docs-changed) into sbpp.github.io via a GitHub App-minted token. Uses actions/create-github-app-token@v1 with vars.DOCS_DEPLOY_APP_ID + secrets.DOCS_DEPLOY_APP_KEY (one-time setup before the workflow can succeed; documented inline + in the PR description). Concurrency group=docs-deploy-trigger so coalesced pushes don't pile up dispatches. * docs-screenshots.yml — runs on `affects-ui`-labelled PRs + workflow_dispatch. Boots the dev stack via `docker compose up -d --wait`, runs `npm run capture` (lands in workstream 7), tears down via `docker compose down -v`, then auto-commits any PNG deltas back to the PR branch via stefanzweifel/git-auto-commit-action@v5. Uses pull_request_target so it can write to forks; pinned to the PR head SHA so a malicious PR can't swap the ref under us. STEAM_API_KEY is the hardcoded all-zero dummy from #1333 §7 (the dev seed never round-trips back to Steam). All three carry top-of-file comments explaining purpose, cadence, and any required repo-side configuration. The capture script and the AGENTS.md row that mentions the `affects-ui` label land in later commits. * docs: add Playwright auto-capture skeleton (#1333) Workstream 7. New docs/scripts/capture.mjs drives Playwright + Chromium against the local dev stack to grab installer + panel screenshots. Wired via `npm run capture` in docs/package.json (landed in the scaffold commit). Output paths: docs/src/assets/auto/install/install-NN-<step>.png docs/src/assets/auto/panel/panel-NN-<page>.png Stable filenames so docs pages can reference these paths once and not re-edit when a screenshot regenerates. The script defaults: PANEL_URL → http://localhost:8080 STEAM_API_KEY → 00000000000000000000000000000000 (#1333 §7) ADMIN_USER / PASS → admin / admin VIEWPORT → 1280×800 The route list ships as a SKELETON for the first PR — install steps 1-6 + five panel routes (login, dashboard, banlist, servers, admin-dashboard). Several routes carry inline TODOs because they need actual click-through driving (the wizard handoff between steps 2-4 + the login form for admin-only routes), and the shipped login routine here is a best-effort that falls through if the form doesn't paint as expected. This is intentional: the screenshot ergonomics aren't the load- bearing part of the migration, and `docs-screenshots.yml` runs against this script wholesale, so a follow-up PR can flesh out each route without touching the CI plumbing. Documentation for the prerequisites + run sequence lands in docs/README.md in the bookkeeping commit. * docs: AGENTS.md additions for the new docs site (#1333) Workstream 8. Three additions to the existing AGENTS.md surface so agents working on the panel know to mirror their changes into docs/ in the same PR: * Five new rows in the "Keep the docs in sync" table covering the user-facing change axes the docs site is the source of truth for: install / upgrade / troubleshooting flows, config knobs (paired with UPGRADING.md when breaking), new self-hoster-visible features (with a sidebar entry in astro.config.mjs), the `affects-ui` label for screenshot-relevant PRs, and the panel-theme-token-mirror rule for web/themes/default/css/theme.css ↔ docs/src/styles/sbpp.css. * One new "Quick rule" bullet that elevates the same expectation to a top-level rule: docs ship in the same PR as the user-facing change, screenshots auto-capture, theme tokens mirror. * Two new "Where to find what" rows: one for editing / adding a docs page (covers the .md vs .mdx split, sidebar wiring, dev loop, CI gates, source-of-truth contract), one for the screenshot capture pipeline (Playwright, output paths, CI trigger, the all-zero STEAM_API_KEY). All wording verbatim from the issue body where the issue gave a template, otherwise hewing to the AGENTS.md voice (prescriptive, one-liner-by-default with the "where to look" pointer). * docs: add docs/README.md (#1333) Workstream 9 of the migration. Onboarding doc for the new docs/ project — covers: * Where things live (per-directory map of the Astro + Starlight source tree, with the panel-parity contract called out for src/styles/sbpp.css). * Local dev loop (`cd docs && npm install && npm run dev`). * Capture story (`./sbpp.sh up && cd docs && npm run capture`), including the all-zero STEAM_API_KEY note from #1333 §7 and the PANEL_URL override for parallel-stack worktrees. * CI workflow table (docs-build, docs-deploy-trigger, docs-screenshots) with the one-time setup notes for the GitHub App + the `affects-ui` label. * Authoring conventions — .md vs .mdx split, prefer Markdown- native :::note over <Aside>, cross-link asides, absolute-path internal links, Shiki language names (KV → ini), heading-level contract for the auto-ToC. * Source-of-truth statement so contributors arriving from sbpp.github.io land in the right place. This is the bookkeeping commit. The PR description (drafted in the orchestrator's PR-open step) carries the equivalent of the "requires DOCS_DEPLOY_APP_ID/KEY + affects-ui label setup" notes for reviewers. * docs: fix the build — Starlight 0.30 social shape + MDX autolink + lockfile (#1333) `npm run build` was failing in two places that only surface once the dependency tree is actually installed: 1. **`social` config shape.** Starlight 0.30 takes `social` as a `Record<KnownPlatform, url>` (see `node_modules/@astrojs/starlight/schemas/social.ts`); the `[{icon, label, href}]` array shape was added in a later minor. Swap the array literal for the record shape and pin the gotcha in a comment so a future `^0.30.0` → `^0.32.0` bump knows to re-flip it. 2. **MDX autolink.** `index.mdx` had `<https://sbpp.github.io/>` — plain Markdown's autolink syntax, but MDX parses `<...>` as a JSX tag and bails on the `/`. Swap to a labelled `[sbpp.github.io](https://sbpp.github.io/)` link. 3. **Commit the lockfile.** `npm install` generated a `package-lock.json` that the workflows (`docs-build.yml`, `docs-screenshots.yml`) explicitly check for to drop into the `npm ci` deterministic-install path. Without the lockfile the workflows fall back to `npm install` and emit a `::warning::` on every run; committing it now both makes CI quiet and pins the dep tree across environments. Verified locally: `npm run build` exits 0, builds 19 pages, Pagefind indexes 18 of them (the 404 doesn't index by design), sitemap-index.xml is generated, `astro check` reports 0 errors / 0 warnings / 0 hints. * docs(security): split screenshot workflow into untrusted-build + trusted-capture (#1333; B1, B2, m2, m3 partial, m4) The original docs-screenshots.yml ran `pull_request_target` with `contents: write`, then checked out the PR head and `npm ci`'d it. Any contributor PR could exfil the upstream repo's GITHUB_TOKEN through a postinstall hook or a tweaked capture.mjs (B1). The auto-commit step also wouldn't have worked on fork PRs — wrong checkout shape (B2). Split into two workflows: - `docs-screenshots-build.yml` runs on every `pull_request` that touches the capture script or its manifests. No secrets, no write permissions, standard `pull_request` token. `npm ci` + `node --check` on the script: catches "did this change still parse" cheaply. - `docs-screenshots-capture.yml` does the actual stack boot + capture + auto-commit. Defenses: * Trusted code (capture.mjs + lockfile + node_modules) checked out from the PR's BASE branch, NOT the PR head. `npm ci` postinstall scripts always come from main. * PR head checked out into a separate `pr-head/` directory used only for `docker compose up` (sandboxed by docker) and as the screenshot output destination. No JS/PHP code from the PR head runs on the runner. * Gated on the `safe-to-screenshot` label (maintainer ack). * `unlabel-on-synchronize` job auto-strips the label on every push so a maintainer must re-apply after each commit set — a benign opening commit can't grant blanket consent for follow-ups. * Refuses fork PRs at the workflow `if:` level (canonical "compromise the upstream maintainer" shape). Push the branch upstream first if the contribution needs screenshot regen. * `git-auto-commit-action@v5` runs from `pr-head/` with the canonical fork-PR checkout shape (`repository:` + `ref: head_ref` + `persist-credentials: true`). The fork-rejection gate above means in practice we always push to the upstream repo, but the canonical shape means a future opt-in fork support change doesn't silently break the push (B2 fix). `capture.mjs` grows a `CAPTURE_OUT_OVERRIDE` env var so the trusted script (running in `trusted/docs/`) can write into the PR head's `docs/src/assets/auto/` directory. Default behavior unchanged for local runs. Also folds in `m2` (call `./sbpp.sh db-seed` between stack boot and capture so post-install panel routes screenshot the populated state), `m3 partial` (prune install routes to the three reachable cold — licence, db-details, admin-create — defer steps 3/4/6 to a follow-up that drives the POST handoff chain), and `m4` (drop the stale "needs login" TODO from `panel-05-admin-dashboard` — `loginAsAdmin` already runs before the panel routes). Updates `docs/README.md` (CI table + new "Screenshot capture security model" section) and `AGENTS.md` (rule + quick-rules bullet) to point at the new label name and the local-run-first guidance. * docs: restructure legacy section per spec (#1333; B3, B4, B5, m5) Three things wrong with the worker's first cut: - B3: the pre-1.5.4.7 plugin upgrade content was left in `updating/index.md` (lines 86-106 of the worker's diff) instead of being moved into `legacy/`. Issue #1333 §5 explicitly says: "The pre-1.7 / pre-1.8 upgrade paths from `updating.md` lines 51-60 move here." Moved the section to a new `legacy/plugin-pre-1.5.4.7.md` page; left a one-line "see Legacy → Plugin upgrade from <= 1.5.4.7" pointer in `updating/index.md` so users still find it. - B4: the worker's `astro.config.mjs` added the Legacy group to the main sidebar. Same §5 line: "Legacy section is excluded from the main sidebar but reachable from a footer link and from the live `Updating` page." Removed the sidebar group; left a comment pointing at the override + the inline updating link as the two surviving discovery paths. - B5: there was no chrome-level discovery hook for /legacy/ — the spec says "footer link". Added `src/components/Footer.astro` that re-renders Starlight's stock per-page footer (EditLink + LastUpdated + Pagination + the optional Built-with-Starlight kudos) and appends a small "Legacy docs" affordance below it. We re-export Starlight's stock sub-components from the `virtual:` namespace rather than re-implementing them so a Starlight upgrade that adds new footer affordances picks them up automatically. Wired into `astro.config.mjs` as `components: { Footer: ... }`. - m5: the legacy banner copy was a worker rewrite ("These pages cover legacy SourceBans++ versions that are no longer actively maintained..."). Replaced with the issue's verbatim wording: "Documentation in this section refers to versions that are no longer maintained. The information may be inaccurate or out of date." (#1333 §5). Removed the "will be pruned in a future cleanup pass" sentence to match. Updated the legacy index's "Pages" section to actually list the new `/legacy/plugin-pre-1.5.4.7/` page instead of saying "empty for now". * docs(theme): default to system color-scheme + SSR-correct first paint (#1333; M1, M7, m9) Two paint mismatches between docs and panel chrome, both load-bearing for the "feels like one product" goal: - M1: ThemeProvider's `else` branch (no localStorage entry yet) was setting theme to 'light'. The panel reads `localStorage.getItem('sbpp-theme') || 'system'` and resolves 'system' via `prefers-color-scheme` (web/themes/default/js/theme.js lines 19-30). Dark-OS user landed on docs LIGHT then panel DARK — cross-product mismatch. Flipped the default to 'auto' so both surfaces honor system preference on first paint. - m9: that fix also makes the previously-unreachable `'auto'` arm of the resolved-theme expression reachable, which is the whole point. - M7: JS-disabled visitors landed on dark unconditionally because Starlight 0.30 hardcodes `<html data-theme="dark">` SSR'd into every page (node_modules/@astrojs/starlight/components/Page.astro line 39), and the worker's ThemeProvider script is JS-only. The panel paints LIGHT for no-JS visitors (no `prefers-color-scheme` media query in `theme.css`), so docs and panel diverged here too. Added a `<noscript><style>` block to ThemeProvider.astro that re-applies the LIGHT-mode color tokens to `:root[data-theme='dark']` so the cascade lands on light when JS isn't available. The block duplicates the LIGHT token list from sbpp.css; the file's leading comment carries the "keep these in sync" rule. Updated `docs/README.md`'s "Where things live" table to describe the new dual behavior + flag the noscript-block-must-mirror-sbpp.css maintenance contract. * docs: drop astro-mermaid until first diagram lands (#1333; M3) The integration was scaffolded into the initial migration commit but zero docs pages actually use a fenced \`\`\`mermaid block: rg '\`\`\`mermaid' docs/src/ # no matches That's a 36KB integration + ~600KB Mermaid runtime as a Vite chunk family + Dependabot churn for nothing the chrome currently exercises. The reviewer caught this as M3. When a docs page genuinely needs a diagram (likeliest place is the upgrader / install flow per #1333 §1's "we already use diagrams in ARCHITECTURE.md, consistency wins" framing), re-add the integration in the same PR as the first \`\`\`mermaid codeblock so the bundle weight has a paying customer. Don't add a stub mermaid block just to justify it — that's a smell. \`npm uninstall astro-mermaid\` removed 115 packages from the lockfile (astro-mermaid + its mermaid + d3 / dagre / cytoscape / @braintree and friends transitive tree). Removed the import + the integration config block from astro.config.mjs and replaced it with a comment that documents the rationale + the re-add story. * docs: flag worker-authored pages + complete plugin list (#1333; M4, M5) Two pages were authored from scratch by the migration worker without being marked as such; reviewers couldn't tell which content was a faithful port from the legacy Hugo site vs. invented text needing extra scrutiny. - M4: setup/plugin-setup.md is entirely new (the legacy sbpp.github.io site had no dedicated plugin-setup page). The worker also OMITTED sbpp_admcfg.smx from the companion plugin list, even though game/addons/sourcemod/scripting/sbpp_admcfg.sp ships in-tree. Added it (admin-config loader: "Reads Admin Files" per the .sp myinfo block, replaces SourceMod's stock admin-flatfile.smx). Added a top-of-page :::note flagging the page as new content + pointing reviewers at the source tree as the verification surface. - M5: getting-started/prerequisites.mdx is mostly an extract of Quickstart's prerequisites section, but it was authored from scratch with extra framing the legacy source didn't have (utf8mb4 paragraph, recovery-surface mention, an expanded Composer paragraph). Added a top-of-page :::note flagging it as new content + pointing at web/install/pages/page.3.php and web/composer.json as the verification surface. Spot-check pass over the prerequisites claims: * PHP >= 8.5 — verified (composer.json line 30). * memory_limit >= 64M — recommendation only; install wizard doesn't actually check this. Reworded to call that out explicitly. * Extensions list — install wizard checks `openssl, xml, gmp, pdo_mysql, mbstring` (page.3.php line 84). Worker had `gmp / pdo_mysql / openssl / xml` and was missing `mbstring`. Added it; the `php -m | grep` snippet now greps for all five. * `recovery.php` — verified (web/install/recovery.php exists post-#1332). Reworded the paragraph to mention the file by name so the description is grounded in something concrete. * docs(theme): use logical border property for RTL safety (#1333; M6) The aside repaint at sbpp.css line 193 used `border-left` (physical property) where stock Starlight uses `border-inline-start` (logical, writing-direction-aware). Issue #1333 mentions LLM-driven translation in "Future automation goals", so RTL locales (Arabic, Hebrew) will land here eventually — and they would silently get the accent stripe on the visually-trailing edge if we shipped the physical property. One-line swap + a comment explaining why so a future override doesn't silently regress it. * docs: restore per-path comments in chmod walkthrough (#1333; M8) The legacy Hugo source's chmod section had inline bullets describing why each path needs to be writable (`config.php file is writable`, `/demos folder is writable`, etc.). The worker collapsed all five chmods into a comment-less block, so a non-technical operator following the steps can't tell why they're chmod'ing each path — just that they should. Interleaved a one-line comment above each chmod line in the Linux tab block of `getting-started/quickstart.mdx` describing what the path is used for (config.php = wizard credentials, demos/ = player ban-evidence demos, themes_c/ = Smarty compiled-template cache, images/games/ = per-game admin-uploadable icons, images/maps/ = per-map thumbnails on the Servers list). Surface knowledge tax goes down without changing the actual commands the operator runs. * docs: AGENTS.md verbatim revert + minor cleanup (#1333; M2, m1, m6, m8) Cheap-wins basket from the reviewer's minor findings list: - M2: AGENTS.md row 5 paraphrased the spec — `see #1333 §2.` instead of the issue's verbatim `see #2.`. Reverted to the verbatim form per the reviewer's ask. - m1: docs-build.yml carried a "fall back to npm install if no lockfile" branch that's dead now that docs/package-lock.json is committed. Removed; `npm ci` is the deterministic path and will fail loudly if anyone bumps package.json without regenerating the lockfile (which is exactly the gate we want). - m6: .gitignore line 83 ignored docs/pnpm-lock.yaml without explanation. Dropped the line — we picked npm and an accidental pnpm lockfile slip should be a visible diff a reviewer can challenge, not silently swallowed. - m8: docs/README.md "Where things live" omitted `src/content.config.ts`. Added a row describing it as the Astro content-collection schema (re-exports Starlight's `docsLoader` + `docsSchema` so the `src/content/docs/` collection is wired with the right loader and front-matter validation). Two minor findings deliberately deferred: * m3 (partial — install routes 3/4/6 stay deferred): tracked in the inline comment above INSTALL_ROUTES in `docs/scripts/capture.mjs`. Driving the install wizard's POST handoff chain is a follow-up that lands when a real screenshot surface needs it; until then, the URL-only routes (1, 2, 5) are the three that actually paint cold. * m7 (inquiries FAQ "browse the docs" pointer): the worker's port already cross-links to specific troubleshooting / setup pages on every Q&A, so the generic "browse the docs" trailer would be a weaker version of the targeted links already present. Skipped. * docs: pin legacy slug + add env.d.ts so astro check passes (#1333; build/check fixes) Two follow-ups from running the verification gates: - The new `docs/src/content/docs/legacy/plugin-pre-1.5.4.7.md` page builds to `/legacy/plugin-pre-1547/` by default — Astro 5 strips dots from filename-derived slugs, which loses the version intent in the URL. Cross-links from updating/index.md and legacy/index.md use the dotted form. Pinned the slug explicitly via frontmatter (`slug: legacy/plugin-pre-1.5.4.7`) so the URL matches the cross-links. - `astro check` errored on the new `Footer.astro` override because it imports `virtual:starlight/components/{EditLink,LastUpdated, Pagination}` and Starlight ships those type declarations in an unscoped `virtual-internal.d.ts` that isn't a public package export entry. Added `docs/src/env.d.ts` with a triple-slash reference path into the package so consumer overrides type-check cleanly. Rerunning `npx astro check` now reports 0 errors / 0 warnings across all 7 files.
1 parent e0dfd0e commit 40e6f54

42 files changed

Lines changed: 11587 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,17 @@ updates:
1717
prefix: "Composer"
1818
include: "scope"
1919
rebase-strategy: "auto"
20+
21+
# Astro + Starlight + Pagefind + mermaid for the docs/ site (#1333).
22+
# Same monthly cadence to stay in lock-step with composer's noise floor.
23+
- package-ecosystem: "npm"
24+
directory: "/docs"
25+
schedule:
26+
interval: "monthly"
27+
labels:
28+
- "dependencies"
29+
- "docs"
30+
commit-message:
31+
prefix: "docs(deps)"
32+
include: "scope"
33+
rebase-strategy: "auto"

.github/workflows/docs-build.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# docs-build — validate the Astro + Starlight build on PRs that touch docs/.
2+
#
3+
# Cadence: per-PR + per-merge-to-main, gated on `docs/**` paths so it
4+
# stays out of the way of PRs that don't touch the docs site.
5+
#
6+
# Why it exists: catches `npm run build` failures (broken Markdown,
7+
# missing assets, busted Starlight config) BEFORE the deploy trigger
8+
# fires on main. Pair gate with docs-deploy-trigger.yml.
9+
10+
name: docs-build
11+
12+
on:
13+
push:
14+
branches:
15+
- main
16+
paths:
17+
- 'docs/**'
18+
- '.github/workflows/docs-build.yml'
19+
pull_request:
20+
paths:
21+
- 'docs/**'
22+
- '.github/workflows/docs-build.yml'
23+
24+
jobs:
25+
build:
26+
name: Build Astro + Starlight
27+
runs-on: ubuntu-24.04
28+
defaults:
29+
run:
30+
working-directory: docs
31+
32+
steps:
33+
- uses: actions/checkout@v4
34+
35+
- name: Setup Node
36+
uses: actions/setup-node@v4
37+
with:
38+
node-version: '20'
39+
cache: 'npm'
40+
cache-dependency-path: docs/package-lock.json
41+
42+
# docs/package-lock.json is committed; npm ci is the deterministic
43+
# path and will fail loudly if anyone lands a package.json bump
44+
# without regenerating the lockfile (which is exactly the gate
45+
# we want).
46+
- name: Install dependencies
47+
run: npm ci --no-audit --no-fund
48+
49+
- name: Build site
50+
run: npm run build
51+
52+
# Surface the built site as an artifact so reviewers can poke at
53+
# the chrome locally without rebuilding. Retention is short
54+
# because docs-deploy-trigger.yml is the production path.
55+
- name: Upload build artifact
56+
if: success()
57+
uses: actions/upload-artifact@v4
58+
with:
59+
name: docs-dist
60+
path: docs/dist/
61+
retention-days: 7
62+
if-no-files-found: error
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# docs-deploy-trigger — fire a repository_dispatch into sbpp.github.io
2+
# whenever main moves under docs/, kicking the Pages deploy in the
3+
# sibling repo.
4+
#
5+
# Cadence: only on push to main with a docs/** path filter. PRs use
6+
# docs-build.yml to validate; this workflow is the production trigger.
7+
#
8+
# Required repo configuration BEFORE this workflow can succeed (one-time
9+
# cutover steps documented in #1333 cutover steps 1-2):
10+
#
11+
# - Create the `sbpp-docs-deploy` GitHub App (org-owned), scope
12+
# `Actions: write` on `sbpp.github.io` only, install on
13+
# `sbpp/sbpp.github.io`.
14+
# - Repo VARIABLE `DOCS_DEPLOY_APP_ID` = the App's numeric ID.
15+
# - Repo SECRET `DOCS_DEPLOY_APP_KEY` = the App's PEM private key.
16+
#
17+
# Until those land, this workflow will fail on the first run with an
18+
# auth error. That's expected; the deploy shell in sbpp.github.io
19+
# also has a workflow_dispatch trigger as a manual fallback.
20+
21+
name: docs-deploy-trigger
22+
23+
on:
24+
push:
25+
branches:
26+
- main
27+
paths:
28+
- 'docs/**'
29+
- '.github/workflows/docs-deploy-trigger.yml'
30+
31+
# Allow at most one in-flight trigger at a time; if a second push lands
32+
# while the first is still running, queue the second and skip any
33+
# intermediate runs. The dispatched workflow in sbpp.github.io is
34+
# itself idempotent (it always builds from sourcebans-pp@main), so
35+
# coalescing here is safe.
36+
concurrency:
37+
group: docs-deploy-trigger
38+
cancel-in-progress: false
39+
40+
jobs:
41+
trigger:
42+
name: Dispatch docs-changed event
43+
runs-on: ubuntu-24.04
44+
permissions: {}
45+
46+
steps:
47+
- name: Mint installation token via GitHub App
48+
id: mint-token
49+
uses: actions/create-github-app-token@v1
50+
with:
51+
app-id: ${{ vars.DOCS_DEPLOY_APP_ID }}
52+
private-key: ${{ secrets.DOCS_DEPLOY_APP_KEY }}
53+
owner: sbpp
54+
repositories: sbpp.github.io
55+
56+
# The dispatched workflow in sbpp.github.io listens for
57+
# `event_type: docs-changed`. The client_payload carries the
58+
# commit SHA and ref so the deploy job can stamp it into the
59+
# site footer / build manifest if it wants.
60+
- name: Dispatch repository_dispatch into sbpp.github.io
61+
env:
62+
GH_TOKEN: ${{ steps.mint-token.outputs.token }}
63+
run: |
64+
gh api repos/sbpp/sbpp.github.io/dispatches \
65+
--method POST \
66+
--field event_type=docs-changed \
67+
--field 'client_payload[source_repo]=${{ github.repository }}' \
68+
--field 'client_payload[source_sha]=${{ github.sha }}' \
69+
--field 'client_payload[source_ref]=${{ github.ref }}'
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# docs-screenshots-build — sandboxed verification job for the screenshot
2+
# capture script.
3+
#
4+
# Cadence: every PR that touches the capture script, its package.json
5+
# manifest, or this workflow.
6+
#
7+
# Why split: the matching capture workflow (docs-screenshots-capture.yml)
8+
# runs `pull_request_target` with `contents: write` so it can boot the
9+
# dev stack and commit screenshots back to the PR branch. That workflow
10+
# is gated behind a maintainer-applied `safe-to-screenshot` label and
11+
# refuses fork PRs because anything else would let a contributor exfil
12+
# the GITHUB_TOKEN through a postinstall hook or a tweaked capture.mjs.
13+
# This job covers the routine "does the script still parse / install"
14+
# loop on every PR, in the standard `pull_request` sandbox (no secrets,
15+
# no write permissions, no privileged token).
16+
#
17+
# Pair with: .github/workflows/docs-screenshots-capture.yml.
18+
19+
name: docs-screenshots-build
20+
21+
on:
22+
pull_request:
23+
paths:
24+
- 'docs/scripts/capture.mjs'
25+
- 'docs/package.json'
26+
- 'docs/package-lock.json'
27+
- '.github/workflows/docs-screenshots-build.yml'
28+
- '.github/workflows/docs-screenshots-capture.yml'
29+
30+
jobs:
31+
build:
32+
name: Verify capture script
33+
runs-on: ubuntu-24.04
34+
permissions:
35+
contents: read
36+
defaults:
37+
run:
38+
working-directory: docs
39+
40+
steps:
41+
- uses: actions/checkout@v4
42+
43+
- name: Setup Node
44+
uses: actions/setup-node@v4
45+
with:
46+
node-version: '20'
47+
cache: 'npm'
48+
cache-dependency-path: docs/package-lock.json
49+
50+
- name: Install dependencies
51+
run: npm ci --no-audit --no-fund
52+
53+
# `node --check` parses the script without executing it. The
54+
# capture script imports @playwright/test at module scope, which
55+
# is installed by `npm ci` above, so the parse + import-resolution
56+
# walk is the cheap end-to-end gate.
57+
- name: Parse capture script
58+
run: node --check scripts/capture.mjs

0 commit comments

Comments
 (0)