7650327: Add ai.ask.retrieval — maxResults, excerptChars, and contextBudget — so a site can size how much documentation each Ask AI question injects into the model’s prompt. Injected characters are the dominant term in time-to-first-token, and on a self-hosted backend the fixed 10,000-character grounding could push a single question past 40 seconds. The three knobs stay separate because they aren’t interchangeable: contextBudget caps the total, excerptChars decides how deep into one long page an excerpt reaches, and maxResults caps how many pages retrieval adds (the page the reader is viewing is injected on top of them). Defaults are unchanged (6 / 2000 / 10000), so existing sites behave exactly as before.
0c2c985: Try It message composer on native AsyncAPI operation pages. Each send/receive operation ships an interactive Try it panel: a payload editor prefilled from the message’s examples (or a value sampled from the payload schema when the message declares none) and validated against the payload schema as you type, an input per channel parameter, and a server picker fed by the channel’s servers with a free-text URL override. The protocol-aware code samples (wscat, browser WebSocket, kcat, mosquitto_pub/mosquitto_sub) stay in lockstep with the form, filling the channel address template with the parameter values you type. On ws/wss bindings the panel also connects live to the resolved channel URL, shows connection state, sends composed messages, and logs received frames with timestamps — there’s no reconnect logic; other protocols get the composer and copyable CLI samples, since Blume doesn’t fake broker connectivity from a browser tab. The panel is server-rendered collapsed and loads its JavaScript only when a reader first opens it; asyncapi.playground mirrors openapi.playground, so it’s on by default with the native renderer and false turns it off. playground.proxy stays OpenAPI-only, and no broker credentials are collected or persisted for event operations.
e2dbf74: Adopt Astro’s client router (<ClientRouter />) for page navigation. Same-origin link clicks now swap the new page into the live document instead of tearing it down for a full load, so navigation is flicker-free in every browser — including Firefox, which has no cross-document paint holding and briefly flashed a blank frame between pages. Navigations animate with native view transitions where supported and Astro’s fade fallback elsewhere, both honoring prefers-reduced-motion; the sidebar keeps its scroll position across pages; search results navigate through the router too; and PostHog analytics captures a pageview per client-side navigation. The Scalar API reference intentionally keeps full-page loads (it is a SPA that mounts once per document), and the cross-document @view-transition rule from the previous release is gone — the router supersedes it.
97a9b30: Support a dark-mode favicon. A dark mark is invisible against dark browser chrome, so Blume now auto-detects a -dark sibling of your icon file — the same name and directory with -dark before the extension, like icon.svg → icon-dark.svg — and emits both icons behind media="(prefers-color-scheme: …)", preceded by a plain light link so crawlers and browsers that ignore media queries on icons still get a sensible mark. Only the sibling of the icon Blume resolved is picked up, so an unrelated -dark file can’t pair with your mark by accident. Ship one icon and nothing changes: a single <link rel="icon">, as before. The bundled Blume fallback now ships a light variant too, so a site with no icon of its own keeps a visible favicon in dark mode in browsers that honor media queries on icon links.
2597b38: Ignore repo-locating GIT_* environment variables (GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE and friends) when resolving git last-modified dates and shallow-clone status. A parent git process exports an absolute GIT_DIR to its hooks, so a build run from inside one — a husky hook, a post-merge script, a CI wrapper — silently read the wrong repository and dropped every page’s date.
0c2c985: Try It playground on native OpenAPI operation pages. Each operation ships an interactive Try it panel: a form generated from the operation’s parameters and request-body schema, prefilled from the spec’s examples, with a server picker fed by the spec’s servers and auth inputs matching the operation’s security schemes (bearer, API key, basic, and a token paste field for OAuth2). Values typed into the form update the generated code samples live, and Send fires the request directly from the browser — with an optional proxy for APIs that don’t allow cross-origin requests from the docs site (openapi.playground.proxy: a URL of your own, or true for the built-in /_api-proxy server route). The panel is server-rendered collapsed and loads its JavaScript only when a reader first opens it; it’s on by default with the native renderer, and playground: false turns it off.
e31ff0a: Add ai.openInChat to configure the “Open in chat” page action: false hides it, and an array of provider keys ("v0", "chatgpt", "claude", "t3", "scira", "cursor") shows just that subset, in order.
5f41cbb: Keep the Ask AI panel alive across page navigations. The island now rides the client router with transition:persist, so the conversation, a draft question, and the open panel all survive moving between pages instead of resetting on every click. The island re-anchors its portaled panel and the desktop content-push attribute after each swap, and the mobile overlay’s focus containment re-applies to the new page’s content.
6eceaea: Segment search text for every non-Latin default locale, not just Japanese, Chinese, Korean, and Thai. Orama’s default tokenizer keeps only basic Latin letters and digits, so when i18n.defaultLocale was a Cyrillic, Greek, Hebrew, or Devanagari language the index collapsed to zero tokens and every query silently returned no hits. The script now comes from Intl.Locale.maximize() — sr-Latn keeps Orama’s tokenizer while az-Cyrl is segmented — with legacy tags (ja_JP.UTF-8, zh-cmn-Hans) resolved by their language subtag, and Latin terms on a segmented index fold diacritics so café still matches cafe. The tokenizer follows the default locale for the whole index, so non-Latin translations on a Latin-default site are unchanged.
0c2c985: Harden the Try It playground: empty auth inputs no longer send their redaction placeholder as a real credential (the live request goes out anonymous instead), pre-network URL/header errors are reported as themselves rather than as a CORS failure, spec-derived names are escaped before selector interpolation, external proxy URLs that already carry a query string join with &, blank required parameters stay visible in samples and sends, and mid-edit invalid JSON renders as a string literal in the JS/Python samples instead of broken syntax. The AsyncAPI composer now connects with an empty payload editor, prefills channel parameters from declared defaults/examples/enums instead of the sampler literal string, and degrades a no-example, no-schema payload to {} rather than null. The built-in CORS proxy allowlist skips templated server URLs, and a proxy with no allowable origin warns at build time.
c289eff: Stop blume validate reporting colocated images as broken assets. A relative image embed () — the form the docs recommend for local images, since those are optimized at build time — was resolved into a site route and then looked for under public/, where it never lands: the image pipeline emits it to _astro/ from beside the content. Every such reference came back as BLUME_BROKEN_ASSET, so --strict failed on a site whose pages render the image correctly. Validation now accepts an image embed whose file exists next to its page source, passing the raw target through the same resolver that decides which colocated images the /blume-assets/content endpoint serves, so the two can’t disagree about what one is. Everything that resolver would skip is still reported: a plain link to a relative path (only image nodes go through the pipeline), a ?query/#fragment suffix, a case-mismatched or directory-shaped name (which breaks on the case-sensitive production build), and a reference that resolves nowhere — the last with a diagnostic that points at the page’s folder rather than public/, and even when no public/ directory exists.
1517f9c: Fix the sidebar rendering empty on archived version pages when header tabs are configured. A version tree’s navigation root is versionized while tab paths stay in current-docs space, so the root tab was misread as a section tab that owns no group in the snapshot; it is now recognized as the root tab — via a single shared containment check used by sidebar scoping, tab-section pruning, and hoisting alike — and the archived sidebar renders its full tree. Header tabs also no longer claim aria-current on archived pages: they link back to the current docs, so none of them is the current page there.