From 15876306045b820dd7bd6e41ecbf5b9ff9f6f0dd Mon Sep 17 00:00:00 2001 From: kite Date: Fri, 3 Jul 2026 20:29:29 +0800 Subject: [PATCH 01/35] feat(pages): add per-chapter routes for docs (#294) Each docs chapter previously lived at the single /docs route driven by component state, so chapters had no shareable URL and browser back/forward did not work. Add a /docs/:slug route and derive activeSlug from the URL param (falling back to quickstart), navigating via the router on switch. Also add a dev-time invariant that throws when two sidebar entries share a slug, since each slug now maps to exactly one URL. --- pages/src/App.tsx | 1 + pages/src/pages/DocsPage.tsx | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pages/src/App.tsx b/pages/src/App.tsx index ffe893e..d658fb1 100644 --- a/pages/src/App.tsx +++ b/pages/src/App.tsx @@ -23,6 +23,7 @@ const App: React.FC = () => { } /> } /> } /> + } /> ); diff --git a/pages/src/pages/DocsPage.tsx b/pages/src/pages/DocsPage.tsx index 7b37ca3..2a46056 100644 --- a/pages/src/pages/DocsPage.tsx +++ b/pages/src/pages/DocsPage.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; import { useTranslation } from '../i18n'; import Navbar from '../components/Navbar'; import Footer from '../components/Footer'; @@ -109,9 +110,24 @@ function buildFlatDocList(): { slug: DocSlug; labelKey: string }[] { } const flatDocList = buildFlatDocList(); +const validSlugs = new Set(flatDocList.map(d => d.slug)); + +/* Dev-time invariant: every sidebar slug maps to exactly one URL, so duplicates + * (two menu entries sharing a slug) would silently collide. Fail loudly in dev. */ +if (process.env.NODE_ENV !== 'production' && validSlugs.size !== flatDocList.length) { + const slugs = flatDocList.map(d => d.slug); + const dupes = [...new Set(slugs.filter((s, i) => slugs.indexOf(s) !== i))]; + throw new Error( + `[docs] Duplicate sidebar slug(s) detected: ${dupes.join(', ')} — each doc must have a unique slug for routing.` + ); +} const DocsPage: React.FC = () => { - const [activeSlug, setActiveSlug] = useState('quickstart'); + const { slug: slugParam } = useParams<{ slug?: string }>(); + const navigate = useNavigate(); + /* Active doc slug is derived from the URL param, falling back to quickstart */ + const activeSlug: DocSlug = + slugParam && validSlugs.has(slugParam as DocSlug) ? (slugParam as DocSlug) : 'quickstart'; const [expandedItems, setExpandedItems] = useState>({ 'sb-integrations': false }); const [activeHeadingId, setActiveHeadingId] = useState(''); const [hoveredHeadingId, setHoveredHeadingId] = useState(''); @@ -162,10 +178,10 @@ const DocsPage: React.FC = () => { }, []); const navigateToDoc = useCallback((slug: DocSlug) => { - setActiveSlug(slug); + navigate(`/docs/${slug}`); // Scroll page to top window.scrollTo(0, 0); - }, []); + }, [navigate]); /* Intercept clicks on internal doc links and convert to SPA navigation */ const handleContentClick = useCallback((e: React.MouseEvent) => { @@ -194,8 +210,7 @@ const DocsPage: React.FC = () => { const slugMap: Record = { 'ci': 'cicd' }; const slug = (slugMap[lastSegment] || lastSegment) as DocSlug; // Verify it's a valid doc slug - const validSlugs = flatDocList.map(d => d.slug); - if (validSlugs.includes(slug)) { + if (validSlugs.has(slug)) { e.preventDefault(); navigateToDoc(slug); // Handle anchor scroll after navigation with reliable retry From 10f587594bd6cd78a4127e363e1ea633ed8b687e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:32:24 +0800 Subject: [PATCH 02/35] chore(deps): bump github.com/anthropics/anthropic-sdk-go (#272) Bumps the go-dependencies group with 1 update: [github.com/anthropics/anthropic-sdk-go](https://github.com/anthropics/anthropic-sdk-go). Updates `github.com/anthropics/anthropic-sdk-go` from 1.52.0 to 1.55.1 - [Release notes](https://github.com/anthropics/anthropic-sdk-go/releases) - [Changelog](https://github.com/anthropics/anthropic-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/anthropics/anthropic-sdk-go/compare/v1.52.0...v1.55.1) --- updated-dependencies: - dependency-name: github.com/anthropics/anthropic-sdk-go dependency-version: 1.55.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 84dc3a3..88d5e03 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( charm.land/bubbles/v2 v2.1.0 charm.land/bubbletea/v2 v2.0.7 charm.land/lipgloss/v2 v2.0.4 - github.com/anthropics/anthropic-sdk-go v1.52.0 + github.com/anthropics/anthropic-sdk-go v1.55.1 github.com/bmatcuk/doublestar/v4 v4.10.0 github.com/modelcontextprotocol/go-sdk v1.6.1 github.com/openai/openai-go/v3 v3.41.0 diff --git a/go.sum b/go.sum index bb44b6b..cb21c84 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ charm.land/bubbletea/v2 v2.0.7 h1:7qw2tTAVar7m7klOPBYfTB0mniv/RuexsYwMRNxSeL0= charm.land/bubbletea/v2 v2.0.7/go.mod h1:DGW2q8gvzHnOpMpZTORs0aySVHCox5C+2Svk0fci1qs= charm.land/lipgloss/v2 v2.0.4 h1:lcPeVtcp23SNra7lHy8iYE4UC2aIipVQ47sbGyyxR5Q= charm.land/lipgloss/v2 v2.0.4/go.mod h1:0653x8epbZSzdDfO/XPS1a/uYPOBeSsCssOpJOqDzik= -github.com/anthropics/anthropic-sdk-go v1.52.0 h1:1TB9jt4DN87VMwS/hB1VK26tYzK0ipEOtqPaPGFtJQg= -github.com/anthropics/anthropic-sdk-go v1.52.0/go.mod h1:3EfIfmFqxH6rbiLcIP4tPFyXL/IHakx2wDG4OU+TIEI= +github.com/anthropics/anthropic-sdk-go v1.55.1 h1:GxukHUVou6AFIngxa/Aw1z79hmwg13Hmn++KE9werbM= +github.com/anthropics/anthropic-sdk-go v1.55.1/go.mod h1:3EfIfmFqxH6rbiLcIP4tPFyXL/IHakx2wDG4OU+TIEI= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o= From 9dfcffda0759161def8da7d5ed5f38ecbff714ed Mon Sep 17 00:00:00 2001 From: kite Date: Mon, 6 Jul 2026 10:31:37 +0800 Subject: [PATCH 03/35] fix(pages): address CodeQL XSS alerts in markdown rendering (#300) * fix(pages): address CodeQL XSS alerts in markdown rendering Alert #4 (headingId.ts): replace the unreliable single-pass regex used to strip HTML tags (incomplete multi-character sanitization) with DOMPurify. This also fixes a pre-existing mismatch where headings containing HTML entities produced different anchor ids on the TOC vs renderer sides. Alert #5 (MarkdownRenderer.tsx): mermaid runs with securityLevel:'strict' and already sanitizes its own SVG output, so re-running DOMPurify over the whole SVG broke rendering (namespaces, inline