From 20c51f3097866d7442af2c6add8d9bda50e46fda Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 15:44:20 -0500 Subject: [PATCH 01/17] feat(reference) Move each port's reference under its own version why: /reference/go/ put the Go API outside the Go documentation, above the version it documents, and mixed three separately versioned packages -- the core library, the Workspace Manager and the MCP server -- into one tree. A reference documents one release of one package. what: - referenceUrl(port, version, product) and referenceSegment() build every reference path, and productApiPath spells the product trees the same way: mcp/reference and workspace/reference - The reference route renders inside each port's shell, where Astro's base is already ///, so its paths carry no port segment and the core tree holds core symbols alone - The Markdown twins and tree.json follow it; the root build keeps the cross-port hub at /reference/ and the A-Z symbol index - referenceHref resolves a cross-port link through the target port's default version, which defaultVersionFor reads from the assembly's LIBTMUX_DOCS_PORT_DEFAULTS --- site/src/components/api/ApiTree.astro | 2 +- .../components/widgets/PackageInstall.astro | 3 +- site/src/lib/api-models.ts | 15 ++-- site/src/lib/page-port-links.ts | 2 +- site/src/lib/ports.ts | 30 +++++-- site/src/lib/product-api.ts | 4 +- site/src/lib/prompts.ts | 2 +- site/src/lib/sidebar.ts | 9 +- site/src/lib/versions.ts | 22 +++++ site/src/pages/index.astro | 4 +- site/src/pages/page-links.json.ts | 3 +- site/src/pages/reference/[...slug].astro | 83 +++++++++++-------- site/src/pages/reference/[...slug].md.ts | 35 ++++---- .../pages/reference/{[port] => }/tree.json.ts | 17 ++-- 14 files changed, 151 insertions(+), 80 deletions(-) rename site/src/pages/reference/{[port] => }/tree.json.ts (71%) diff --git a/site/src/components/api/ApiTree.astro b/site/src/components/api/ApiTree.astro index af631e10..5bf7cf9c 100644 --- a/site/src/components/api/ApiTree.astro +++ b/site/src/components/api/ApiTree.astro @@ -47,7 +47,7 @@ const { port, portName, tree, currentRoot, currentBucket, currentTypeId, ownerNavId, ownerId, members, withMembers, menuVersion, currentPath, } = Astro.props as Props -const base = withRoot(`/reference/${port}/`) +const base = withRoot('/reference/') const href = (slug: string) => `${base}${slug}/` let seq = 0 diff --git a/site/src/components/widgets/PackageInstall.astro b/site/src/components/widgets/PackageInstall.astro index e711a7c5..49bbdc1e 100644 --- a/site/src/components/widgets/PackageInstall.astro +++ b/site/src/components/widgets/PackageInstall.astro @@ -4,6 +4,7 @@ import { highlightInline } from '../../lib/highlight' import { PORTS, referenceUrl } from '../../lib/ports' import type { Quickstart } from '../../lib/quickstarts' import { withPortRoot } from '../../lib/site-root' +import { defaultVersionFor } from '../../lib/versions' /** * Package-manager picker for the eight libtmux ports' own install commands @@ -176,7 +177,7 @@ const installHtml = new Map( {snippets && ( )} {snippets?.[p.slug] && ( diff --git a/site/src/lib/api-models.ts b/site/src/lib/api-models.ts index 607de53f..d7b5363f 100644 --- a/site/src/lib/api-models.ts +++ b/site/src/lib/api-models.ts @@ -5,6 +5,8 @@ import jdkInv from '../data/inventories/jdk.entries.json' import pythonInv from '../data/inventories/python.entries.json' import dependencyInv from '../data/inventories/dependencies.entries.json' import { withPortRoot } from './site-root' +import { PORT_BY_SLUG, referenceUrl, type DocProduct } from './ports' +import { defaultVersionFor } from './versions' import cxxNav from '../data/api/cxx.nav.json' import dotnetNav from '../data/api/dotnet.nav.json' import goNav from '../data/api/go.nav.json' @@ -297,17 +299,20 @@ export function indexFor(model: ApiModel, hrefFor: (s: ApiSymbol) => string): Sy * Returns undefined when the port or the symbol is unknown, so a stale entry * renders as text instead of a link to nothing. */ -export function referenceHref(port: string, publicId: string): string | undefined { +export function referenceHref(port: string, publicId: string, version?: string): string | undefined { const model = API_MODELS[port] if (!model) return undefined // Existence is still checked: a stale entry should render as text rather // than link to a page that was never generated. const symbol = model.symbols.find((s) => (s.publicId ?? s.id) === publicId) if (!symbol) return undefined - // withPortRoot: this is called from ApiEntry, which renders inside shared - // prose, so it runs in every locale's build — while the reference itself is - // generated only in the default locale's tree. - return withPortRoot(`/reference/${port}/${symbol.slug ?? pageSlug(publicId)}/`) + const target = PORT_BY_SLUG[port] + if (!target) return undefined + // The version is the target port's own default unless a caller is rendering + // that port and knows better: this is called from ApiEntry, which renders + // inside shared prose and so runs in builds of every port and locale. + const product = (symbol.product ?? 'core') === 'core' || symbol.apiScope === 'internal' ? 'core' : symbol.product + return `${referenceUrl(target, version ?? defaultVersionFor(port), product as DocProduct | 'core')}${symbol.slug ?? pageSlug(publicId)}/` } /** Source-verified equivalents, shared by reference entries and page navigation. */ diff --git a/site/src/lib/page-port-links.ts b/site/src/lib/page-port-links.ts index 51ddc858..cc2d5473 100644 --- a/site/src/lib/page-port-links.ts +++ b/site/src/lib/page-port-links.ts @@ -57,7 +57,7 @@ export function pagePortLinks({ if (!path) { links = [{ href: portHomeUrl(port, targetVersion) }] } else if ((isReference && !symbolSlug) || path === 'api') { - if (API_MODELS[port.slug]) links = [{ href: referenceUrl(port) }] + if (API_MODELS[port.slug]) links = [{ href: referenceUrl(port, targetVersion) }] } else if (symbol) { for (const alternative of alternatives) { const match = alternative.ports.find((p) => p.port === port.slug) diff --git a/site/src/lib/ports.ts b/site/src/lib/ports.ts index 80fb115e..f11d6442 100644 --- a/site/src/lib/ports.ts +++ b/site/src/lib/ports.ts @@ -599,9 +599,22 @@ export function productDescription(port: Port, product: DocProduct): string { return `In development. ${DOC_PRODUCTS.mcp.description}` } +/** + * Where a reference tree sits under a port and version. + * + * Three packages, three trees. The core library answers at `reference/`, and + * the Workspace Manager and the MCP server — separately versioned packages + * that happen to be documented beside it — answer under their own section. + * One spelling for all three, because a reader who has found one should be + * able to guess the others. + */ +export function referenceSegment(product: DocProduct | 'core'): string { + return product === 'core' ? 'reference' : `${product}/reference` +} + /** Language APIs for workspace builders belong to implementation documentation. */ export function productApiPath(product: DocProduct): string { - return product === 'workspace' ? 'workspace/internals/api' : 'mcp/api' + return referenceSegment(product) } /** @@ -623,16 +636,23 @@ export const VERSIONED_PORTS = PORTS.filter((p) => p.versionedDocs) /** Ports whose language has a canonical reference of its own, too. */ export const ECOSYSTEM_PORTS = PORTS.filter((p) => p.ecosystemHost) -/** URL of the reference extracted and rendered by this site. */ -export function referenceUrl(port: Port, _version?: string): string { - return withPortRoot(`/reference/${port.slug}/`) +/** + * URL of the reference extracted and rendered by this site. + * + * Versioned like every other page under a port, because it documents one + * release of one package: `/go/latest/reference/` is the Go core library's + * API, and its Workspace Manager and MCP server answer beside it rather than + * inside it. + */ +export function referenceUrl(port: Port, version: string, product: DocProduct | 'core' = 'core'): string { + return portPageUrl(port, version, referenceSegment(product)) } /** URL of a prose page within a port and version; callers check availability. */ export function portPageUrl(port: Port, version: string, pagePath = ''): string { const rest = pagePath.replace(/^\/+|\/+$/g, '') - // Native API paths have no shared spelling; use the unified reference index. + // A port's own `api` page is the reference it now sits beside. if (rest === 'api' || rest.startsWith('api/')) return referenceUrl(port, version) const tail = rest ? `${rest}/` : '' diff --git a/site/src/lib/product-api.ts b/site/src/lib/product-api.ts index 30fa5870..9614366d 100644 --- a/site/src/lib/product-api.ts +++ b/site/src/lib/product-api.ts @@ -1,6 +1,6 @@ import { symbolsForProduct, type ApiModel, type ApiSymbol, type SymbolIndex } from '@libtmux/api-model' import { API_MODELS, createApiIndex, referenceAlternatives } from './api-models' -import { PORT_BY_SLUG, portPageUrl, productApiPath, type DocProduct } from './ports' +import { PORT_BY_SLUG, portPageUrl, productApiPath, referenceUrl, type DocProduct } from './ports' import { withPortRoot } from './site-root' /** Keep core references stable while product declarations stay in their section. */ @@ -8,7 +8,7 @@ export function productApiHref(model: ApiModel, symbol: ApiSymbol, version: stri if (symbol.product && symbol.product !== 'core' && symbol.apiScope !== 'internal') { return portPageUrl(PORT_BY_SLUG[model.port], version, `${productApiPath(symbol.product)}/${symbol.slug}`) } - return withPortRoot(`/reference/${model.port}/${symbol.slug}/`) + return `${referenceUrl(PORT_BY_SLUG[model.port], version)}${symbol.slug}/` } /** Equivalent declarations stay in their product and target port's version. */ diff --git a/site/src/lib/prompts.ts b/site/src/lib/prompts.ts index f47fde03..9fd7e2da 100644 --- a/site/src/lib/prompts.ts +++ b/site/src/lib/prompts.ts @@ -435,7 +435,7 @@ export function portParts(args: { const reading: (readonly [string, string])[] = [ [portUrl(ctx, port, 'llms.txt'), `every page for ${port.name}, as a list`], [portUrl(ctx, port, 'docs.json'), 'the same list with headings, as JSON'], - [`${ctx.docsBase}/reference/${port.slug}/`, `the ${port.name} API reference`], + [portUrl(ctx, port, 'reference/'), `the ${port.name} API reference`], ] if (port.ecosystemHost) { reading.push([port.ecosystemHost.url, `${port.name} reference on ${port.ecosystemHost.name}`]) diff --git a/site/src/lib/sidebar.ts b/site/src/lib/sidebar.ts index d2cb512e..23b1a066 100644 --- a/site/src/lib/sidebar.ts +++ b/site/src/lib/sidebar.ts @@ -18,7 +18,7 @@ */ import { getCollection } from 'astro:content' import type { CollectionEntry } from 'astro:content' -import { PORT_BY_SLUG, portPageUrl, type DocProduct } from './ports' +import { PORT_BY_SLUG, portPageUrl, referenceUrl, type DocProduct } from './ports' import { withPortRoot } from './site-root' import { DEFAULT_LOCALE, type Locale } from '../i18n/locales' import { localeOf, sourceIdOf } from '../i18n/resolve' @@ -107,10 +107,9 @@ export function referenceEntries(port: string, version: string): SidebarLinkItem if (!p) throw new Error(`sidebar.ts: unknown port slug "${port}"`) const entries: SidebarLinkItem[] = [ - // withPortRoot, not withRoot: the reference is built in the default - // locale only, so a Japanese page reaches across to it rather than - // expecting a copy under its own prefix. - { type: 'link', label: 'API reference', href: withPortRoot(`/reference/${port}/`), external: false }, + // The core library's reference, under this port and version — the + // Workspace Manager and MCP entries below carry their own. + { type: 'link', label: 'API reference', href: referenceUrl(p, version), external: false }, ] if (p.ecosystemHost) { diff --git a/site/src/lib/versions.ts b/site/src/lib/versions.ts index 65daa7be..b220fc80 100644 --- a/site/src/lib/versions.ts +++ b/site/src/lib/versions.ts @@ -206,3 +206,25 @@ export function buildTarget(env: Record) { const isDefault = env.LIBTMUX_DOCS_IS_DEFAULT === 'true' return { version, kind, isDefault } } + +/** + * The version prefix another port's page lives under. + * + * A link that crosses ports — the concept map's equivalents, the prose + * linker, a symbol index spanning all eight — names a port this build is not + * rendering, so it cannot take the version from `buildTarget`. The assembly + * passes every port's default in `LIBTMUX_DOCS_PORT_DEFAULTS`; a build + * without it (`pnpm dev`, a bare `astro build`) targets each port's trunk. + */ +let portDefaults: Record | undefined + +export function defaultVersionFor(port: string): string { + if (!portDefaults) { + try { + portDefaults = JSON.parse(process.env.LIBTMUX_DOCS_PORT_DEFAULTS || '{}') as Record + } catch { + portDefaults = {} + } + } + return portDefaults[port] ?? 'latest' +} diff --git a/site/src/pages/index.astro b/site/src/pages/index.astro index 67d4f98f..594cef40 100644 --- a/site/src/pages/index.astro +++ b/site/src/pages/index.astro @@ -6,7 +6,7 @@ import { DOC_PRODUCTS, PORTS, PORT_BY_SLUG, portPageUrl, primaryInstall, product import PortHero from '../components/PortHero.astro' import DocCard from '../components/DocCard.astro' import ApiReferences from '../components/ApiReferences.astro' -import { buildTarget } from '../lib/versions' +import { buildTarget, defaultVersionFor } from '../lib/versions' import PackageInstall from '../components/widgets/PackageInstall.astro' import AgentPrompt from '../components/widgets/AgentPrompt.astro' import { QUICKSTARTS } from '../lib/quickstarts' @@ -296,7 +296,7 @@ const noindexLanding = locale !== DEFAULT_LOCALE && !LandingContent

{p.packageName}

- API reference + API reference

)) diff --git a/site/src/pages/page-links.json.ts b/site/src/pages/page-links.json.ts index dd13a23b..6077623a 100644 --- a/site/src/pages/page-links.json.ts +++ b/site/src/pages/page-links.json.ts @@ -4,6 +4,7 @@ import { referenceAlternatives } from '../lib/api-models' import { PORTS, referenceUrl } from '../lib/ports' import { buildLocale } from '../i18n/resolve' import { DEFAULT_LOCALE } from '../i18n/locales' +import { defaultVersionFor } from '../lib/versions' /** Verified reference targets for the shell injected into native API pages. */ export const GET: APIRoute = () => { @@ -23,7 +24,7 @@ export const GET: APIRoute = () => { } return new Response(JSON.stringify({ schema: 1, - indexes: Object.fromEntries(PORTS.map((port) => [port.slug, referenceUrl(port)])), + indexes: Object.fromEntries(PORTS.map((port) => [port.slug, referenceUrl(port, defaultVersionFor(port.slug))])), symbols, }), { headers: { 'Content-Type': 'application/json' } }) } diff --git a/site/src/pages/reference/[...slug].astro b/site/src/pages/reference/[...slug].astro index 60966c22..7f6bba90 100644 --- a/site/src/pages/reference/[...slug].astro +++ b/site/src/pages/reference/[...slug].astro @@ -8,10 +8,11 @@ import { pagePortsFor } from '../../lib/page-ports-for' import BaseLayout from '../../layouts/BaseLayout.astro' import { withRoot } from '../../lib/site-root' import { API_MODELS, API_NAV, OWNER_KINDS, PORT_NAME, indexFor, ownersOf, pageSlug, referenceHref, topLevelTypesOf } from '../../lib/api-models' -import { PORT_BY_SLUG } from '../../lib/ports' +import { PORT_BY_SLUG, referenceUrl } from '../../lib/ports' import { symbolSource } from '../../lib/markdown-twins' import { DEFAULT_LOCALE } from '../../i18n/locales' import { buildLocale } from '../../i18n/resolve' +import { defaultVersionFor } from '../../lib/versions' import ApiDoc from '../../components/api/ApiDoc.astro' import ApiTree from '../../components/api/ApiTree.astro' import { navTree } from '../../lib/api-tree' @@ -34,12 +35,9 @@ import '../../styles/vendor/gp-sphinx-api.css' */ export async function getStaticPaths() { - // Only the root build. This route would otherwise render inside all - // fourteen shell builds, the way `[port]/index.astro` used to. - // The root build of the default locale only. The reference is not - // translated — a `/ja/reference/` tree would be the English body under - // another locale's prefix, which is what placeholders exist to avoid. - if (process.env.LIBTMUX_DOCS_PORT) return [] + // The default locale only. The reference is not translated — a + // `/ja/…/reference/` tree would be the English body under another locale's + // prefix, which is what placeholders exist to avoid. if (buildLocale() !== DEFAULT_LOCALE) return [] // Typed explicitly: inferring from the first element gives every field the @@ -47,27 +45,40 @@ export async function getStaticPaths() { const paths: { params: { slug: string | undefined } props: { model: ApiModel | undefined; owner: ApiSymbol | undefined; searchable?: boolean } - }[] = [{ params: { slug: undefined }, props: { model: undefined, owner: undefined } }] - - for (const [port, model] of Object.entries(API_MODELS)) { - const productIds = new Set([ - ...symbolsForProduct(model, 'mcp'), - ...symbolsForProduct(model, 'workspace'), - ].map((symbol) => symbol.id)) - paths.push({ params: { slug: port }, props: { model, owner: undefined } }) - // Every symbol, not only the types with members. A method that lives as - // an anchor on someone else's page cannot be listed in a sidebar, cannot - // carry its own examples, and cannot be linked to as a page — which was - // true of all but the owning types. - // - // `slug` comes from the model rather than from `pageSlug` because it has - // to be injective; see its comment in model.ts. - for (const owner of model.symbols) { - paths.push({ - params: { slug: `${port}/${owner.slug ?? pageSlug(owner.publicId ?? owner.id)}` }, - props: { model, owner, searchable: !productIds.has(owner.id) }, - }) - } + }[] = [] + + // The root build carries the hub alone: one page listing every port's + // reference. Each port's own tree is built inside that port's shell, where + // `base` is already `///`, so these routes need no port + // segment of their own. + const buildPort = process.env.LIBTMUX_DOCS_PORT + if (!buildPort) return [{ params: { slug: undefined }, props: { model: undefined, owner: undefined } }] + + const model = API_MODELS[buildPort] + if (!model) return [] + paths.push({ params: { slug: undefined }, props: { model, owner: undefined } }) + + // Core only. The Workspace Manager and the MCP server are separately + // versioned packages with references of their own, under their own section + // of this port — `productApiRoutes` builds those. A declaration scoped + // `internal` stays here, because no product page lists it. + // + // Every symbol, not only the types with members. A method that lives as an + // anchor on someone else's page cannot be listed in a sidebar, cannot carry + // its own examples, and cannot be linked to as a page. + // + // `slug` comes from the model rather than from `pageSlug` because it has to + // be injective; see its comment in model.ts. + const productIds = new Set([ + ...symbolsForProduct(model, 'mcp'), + ...symbolsForProduct(model, 'workspace'), + ].map((symbol) => symbol.id)) + for (const owner of model.symbols) { + if (productIds.has(owner.id)) continue + paths.push({ + params: { slug: owner.slug ?? pageSlug(owner.publicId ?? owner.id) }, + props: { model, owner }, + }) } return paths } @@ -78,6 +89,10 @@ interface Props { searchable?: boolean } const { model, owner, searchable = true } = Astro.props as Props + +/** What the hub counts per port: the core library, without its products. */ +const coreCount = (m: ApiModel) => + m.symbols.length - new Set([...symbolsForProduct(m, 'mcp'), ...symbolsForProduct(m, 'workspace')].map((s) => s.id)).size /* * The route param is the page's own path below `/reference/`, so composing * `pagePath` from it cannot disagree with the URL. Deriving it from `owner` @@ -102,7 +117,7 @@ const paged = new Set(pageOwners.map((s) => s.id)) */ const hrefFor = (s: ApiSymbol): string => model - ? withRoot(`/reference/${model.port}/${s.slug ?? pageSlug(s.publicId ?? s.id)}/`) + ? withRoot(`/reference/${s.slug ?? pageSlug(s.publicId ?? s.id)}/`) : withRoot('/reference/') /* * The stub is what the index route has instead of a model. @@ -532,10 +547,10 @@ const title = owner {Object.entries(API_MODELS).map(([port, m]) => ( {PORT_NAME[port] ?? port} - {m.symbols.length} symbols + {coreCount(m)} symbols

{m.symbols.filter((s) => s.doc?.summary).length} documented, {' '}{topLevelTypesOf(m).length} types @@ -712,10 +727,10 @@ const title = owner is a URL, and that is the whole feature. */}

- + View as Markdown -

@@ -740,7 +755,7 @@ const title = owner
Module
{moduleAnchors.has(ownerModule) ? ( - {ownerModule} + {ownerModule} ) : ( ownerModule )} diff --git a/site/src/pages/reference/[...slug].md.ts b/site/src/pages/reference/[...slug].md.ts index 9372741f..2a332791 100644 --- a/site/src/pages/reference/[...slug].md.ts +++ b/site/src/pages/reference/[...slug].md.ts @@ -1,10 +1,11 @@ import type { APIRoute } from 'astro' import { API_MODELS } from '../../lib/api-models' -import { pageSlug } from '@libtmux/api-model' +import { pageSlug, symbolsForProduct } from '@libtmux/api-model' import { symbolMarkdown } from '../../lib/symbol-markdown' -import { PORT_BY_SLUG } from '../../lib/ports' +import { PORT_BY_SLUG, referenceUrl } from '../../lib/ports' import { DEFAULT_LOCALE } from '../../i18n/locales' import { buildLocale } from '../../i18n/resolve' +import { buildTarget } from '../../lib/versions' /** * `/reference//.md` — the page, as its source. @@ -18,19 +19,25 @@ import { buildLocale } from '../../i18n/resolve' * the reference is not rendered inside the fourteen shell builds. */ export async function getStaticPaths() { - // The root build of the default locale only, matching the HTML route: the - // reference is not translated, so a twin under another locale would be the - // English body wearing that locale's prefix. - if (process.env.LIBTMUX_DOCS_PORT) return [] + // This port's shell, in the default locale only, matching the HTML route: + // the reference is not translated, so a twin under another locale would be + // the English body wearing that locale's prefix. + const port = process.env.LIBTMUX_DOCS_PORT + if (!port) return [] if (buildLocale() !== DEFAULT_LOCALE) return [] + const model = API_MODELS[port] + if (!model) return [] + const productIds = new Set([ + ...symbolsForProduct(model, 'mcp'), + ...symbolsForProduct(model, 'workspace'), + ].map((symbol) => symbol.id)) const paths: { params: { slug: string }; props: { port: string; id: string } }[] = [] - for (const [port, model] of Object.entries(API_MODELS)) { - for (const symbol of model.symbols) { - paths.push({ - params: { slug: `${port}/${symbol.slug ?? pageSlug(symbol.publicId ?? symbol.id)}` }, - props: { port, id: symbol.id }, - }) - } + for (const symbol of model.symbols) { + if (productIds.has(symbol.id)) continue + paths.push({ + params: { slug: symbol.slug ?? pageSlug(symbol.publicId ?? symbol.id) }, + props: { port, id: symbol.id }, + }) } return paths } @@ -51,7 +58,7 @@ export const GET: APIRoute = ({ props, site }) => { symbolMarkdown({ model, symbol, - canonical: `${origin}/reference/${port}/${slug}/`, + canonical: `${origin}${referenceUrl(PORT_BY_SLUG[port]!, buildTarget(process.env).version)}${slug}/`, source: repo && rev && file ? `https://github.com/${repo}/blob/${rev}/${file}${symbol.source?.line ? `#L${symbol.source.line}` : ''}` : undefined, diff --git a/site/src/pages/reference/[port]/tree.json.ts b/site/src/pages/reference/tree.json.ts similarity index 71% rename from site/src/pages/reference/[port]/tree.json.ts rename to site/src/pages/reference/tree.json.ts index d160b14a..91515761 100644 --- a/site/src/pages/reference/[port]/tree.json.ts +++ b/site/src/pages/reference/tree.json.ts @@ -5,17 +5,18 @@ * when a reader first opens another bucket or type. Buckets carry their * types, and members are keyed by type so a type opens without a second * request. Slugs rather than URLs: the page knows its own root. + * + * One file per port shell, beside that port's reference, so the tree a page + * loads is the tree of the port it belongs to. The root build has no port and + * writes nothing. */ import type { APIRoute } from 'astro' -import { API_MODELS } from '../../../lib/api-models' -import { bucketTotal, firstEntry, membersByType, navTree, type TreeBucket } from '../../../lib/api-tree' - -export function getStaticPaths() { - return Object.keys(API_MODELS).map((port) => ({ params: { port } })) -} +import { API_MODELS } from '../../lib/api-models' +import { bucketTotal, firstEntry, membersByType, navTree, type TreeBucket } from '../../lib/api-tree' -export const GET: APIRoute = ({ params }) => { - const port = String(params.port) +export const GET: APIRoute = () => { + const port = process.env.LIBTMUX_DOCS_PORT ?? '' + if (!API_MODELS[port]) return new Response('Not found', { status: 404 }) const members = membersByType(port) const bucket = (b: TreeBucket): unknown => ({ id: b.id, From ef11515084e5a341d7dacaa0af51963a08b23387 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 15:47:58 -0500 Subject: [PATCH 02/17] feat(reference) Point prose links and inventories at the new trees why: A prose mention resolved through api-model, which cannot know which version a port publishes or which package a symbol belongs to, so every cross-reference in prose still named the old path. The intersphinx inventories named it too. what: - MentionContext takes symbolHref and moduleHref; the site passes builders that know the target port version and the three trees, and tooling that only asks whether a span resolves keeps the default - Every resolved mention now routes through productApiHref - A port shell writes its own objects.inv beside its reference; the root build keeps the per-port copies and the combined one, so an external intersphinx mapping still resolves - The assembly points its /api/ redirect stubs at the new location --- packages/api-model/src/prose.ts | 19 ++++++- scripts/build-site.sh | 15 +++--- site/src/integrations/inventory.ts | 74 +++++++++++++++++----------- site/src/plugins/rehype-api-links.ts | 31 ++++++++---- 4 files changed, 93 insertions(+), 46 deletions(-) diff --git a/packages/api-model/src/prose.ts b/packages/api-model/src/prose.ts index d32f72a3..d65ce0d1 100644 --- a/packages/api-model/src/prose.ts +++ b/packages/api-model/src/prose.ts @@ -73,6 +73,10 @@ export function pageSlug(id: string): string { * a member-less type and a free function all resolve the same way, where * before each was a separate branch and two of them were wrong often enough * to produce 114 links to pages that were never generated. + * + * Unversioned, and so not what the site renders: a reference page lives under + * its port's version and its package's section, which this package cannot + * know. `MentionContext.symbolHref` is how the site supplies the real one. */ export function hrefFor(port: string, _model: ApiModel, symbol: ApiSymbol): string { return `/reference/${port}/${symbol.slug ?? pageSlug(symbol.publicId ?? symbol.id)}/` @@ -187,6 +191,16 @@ export interface MentionContext { pagePort?: string product?: ApiProduct before?: string + /** + * Where this site puts a symbol and a module index. + * + * A reference URL carries a port, a version and a product, and only the + * site knows which version a port is publishing. Tooling that asks whether + * a span resolves at all — `check-api-links` — leaves these unset and takes + * the unversioned default below. + */ + symbolHref?: (port: string, symbol: ApiSymbol) => string + moduleHref?: (port: string, module: string) => string } /** @@ -209,7 +223,8 @@ export function decideMention( return { kind: 'link', port, href: res.href, title: `${text}: ${res.project}`, external: true } } if (res.how === 'module-index') { - return { kind: 'link', port, href: `/reference/${port}/#${res.module}`, title: `${res.module}: module`, external: false } + const href = ctx.moduleHref?.(port, res.module) ?? `/reference/${port}/#${res.module}` + return { kind: 'link', port, href, title: `${res.module}: module`, external: false } } // Every outcome that carries a symbol, not just the two most common. // `module` and `chained` resolve to a real symbol too — dropping them @@ -220,7 +235,7 @@ export function decideMention( return { kind: 'link', port, - href: hrefFor(port, model, res.symbol), + href: ctx.symbolHref?.(port, res.symbol) ?? hrefFor(port, model, res.symbol), title: `${res.symbol.publicId ?? res.symbol.id}: ${PORT_NAME[port] ?? port}`, external: false, } diff --git a/scripts/build-site.sh b/scripts/build-site.sh index 58fcb5fb..a6c2c515 100755 --- a/scripts/build-site.sh +++ b/scripts/build-site.sh @@ -538,7 +538,7 @@ render_staged_reference() { # The status line is cached alongside the tree. It is what the summary prints, # and a hit that reported "built" for a generator that had been skipped would # be a lie that survives until someone reads the site. -# write_reference_redirect SLUG DEST +# write_reference_redirect SLUG VERSION DEST # # A static site has no server to answer 301 with, so the redirect is a page: # a meta refresh for the browser, a canonical link so a crawler follows the @@ -546,9 +546,9 @@ render_staged_reference() { # `noindex` keeps the placeholder out of search results while the canonical # still points at the real page. write_reference_redirect() { - local slug="$1" dest="$2" + local slug="$1" version="$2" dest="$3" # Through the site root, like every other link the assembly emits. - local path="${LIBTMUX_DOCS_ROOT%/}/reference/$slug/" + local path="${LIBTMUX_DOCS_ROOT%/}/$slug/$version/reference/" local target="${site_origin%/}$path" cat >"$dest" < @@ -984,7 +984,8 @@ while IFS='|' read -r slug name versioned renderer generator checkout ecosystem_ continue fi - # One reference per port, at /reference//. + # One reference per port and version, at ///reference/, + # rendered by that port's own shell build above. # # Five ports used to answer "the API" twice, in three different visual # systems: Breathe for C++, DocC for Swift, staged Markdown for TypeScript @@ -1001,8 +1002,8 @@ while IFS='|' read -r slug name versioned renderer generator checkout ecosystem_ # port's own pipeline uploads. if [ "$own_api" != "own-api" ]; then mkdir -p "$port_out/api" - write_reference_redirect "$slug" "$port_out/api/index.html" - summary_rows+=("$slug|$version|redirect|redirected|to $LIBTMUX_DOCS_PORT_ROOT/reference/$slug/") + write_reference_redirect "$slug" "$version" "$port_out/api/index.html" + summary_rows+=("$slug|$version|redirect|redirected|to $LIBTMUX_DOCS_PORT_ROOT/$slug/$version/reference/") continue fi @@ -1017,7 +1018,7 @@ while IFS='|' read -r slug name versioned renderer generator checkout ecosystem_ node "$script_dir/normalize-native-shell.mjs" "$port_out/api" "$LIBTMUX_DOCS_PORT_ROOT" elif [ "$ref_status" = "skipped" ]; then mkdir -p "$port_out/api" - write_reference_redirect "$slug" "$port_out/api/index.html" + write_reference_redirect "$slug" "$version" "$port_out/api/index.html" fi summary_rows+=("$slug|$version|$renderer|$ref_status|[$generator] $ref_reason") diff --git a/site/src/integrations/inventory.ts b/site/src/integrations/inventory.ts index 26560b8b..d8ac7135 100644 --- a/site/src/integrations/inventory.ts +++ b/site/src/integrations/inventory.ts @@ -26,12 +26,56 @@ import { API_MODELS, PORT_NAME, ownersOf, pageSlug } from '../lib/api-models' * reader, so a wrong one breaks their links, not ours, and nothing here * would have reported it. */ +/** + * A URI as intersphinx reads it: relative to the directory holding the + * inventory, never to the site root. + * + * `rooted` is what tells the two apart. The combined inventory sits at + * `/objects.inv` and needs the `reference//` prefix; a per-port one + * sits beside the pages it names and must not carry it, because intersphinx + * joins the URI onto the base URL it was configured with. With the prefix in + * both, a resolved C++ class came out as + * `libtmux.org/reference/cxx/reference/cxx/libtmux::pane/` — a link that + * Sphinx reported as resolved and that goes nowhere. + */ +function uriForModel(model: ApiModel, rooted = true) { + const paged = new Set(ownersOf(model).map((s) => s.id)) + return (symbol: { id: string; publicId?: string; parent?: string }) => { + const anchor = symbol.publicId ?? symbol.id + const owner = paged.has(symbol.id) + ? anchor + : symbol.parent && paged.has(symbol.parent) + ? (model.symbols.find((s) => s.id === symbol.parent)?.publicId ?? symbol.parent) + : undefined + const page = owner ? `${pageSlug(owner)}/` : '' + const prefix = rooted ? `reference/${model.port}/` : '' + return `${prefix}${page}#${anchor}` + } +} + export function inventory(): AstroIntegration { return { name: 'libtmux:inventory', hooks: { 'astro:build:done': ({ dir, logger }) => { - if (process.env.LIBTMUX_DOCS_PORT) return + // A port shell writes one inventory, beside the reference it just + // built: `///reference/objects.inv`, which is where + // that port's pages live now. + const buildPort = process.env.LIBTMUX_DOCS_PORT + if (buildPort) { + const model = API_MODELS[buildPort] + if (!model) return + const uri = uriForModel(model, false) + const path = join(dir.pathname, 'reference', 'objects.inv') + mkdirSync(dirname(path), { recursive: true }) + writeFileSync(path, writeInventory(model, { + project: `libtmux for ${PORT_NAME[buildPort] ?? buildPort}`, + version: model.revision?.slice(0, 7) ?? 'latest', + uriFor: uri, + })) + logger.info(`objects.inv written for ${buildPort} (${model.symbols.length} symbols)`) + return + } // The env var, not `buildLocale()` from i18n/resolve: this runs as an // Astro integration, in the config context, where `astro:content` — // which that module imports — does not exist. @@ -39,33 +83,7 @@ export function inventory(): AstroIntegration { const out = dir.pathname let total = 0 - /** - * A URI as intersphinx reads it: relative to the directory holding - * the inventory, never to the site root. - * - * `rooted` is what tells the two apart. The combined inventory sits - * at `/objects.inv` and needs the `reference//` prefix; a - * per-port one sits at `/reference//objects.inv` and must not - * carry it, because intersphinx joins the URI onto the base URL it - * was configured with. With the prefix in both, a resolved C++ class - * came out as - * `libtmux.org/reference/cxx/reference/cxx/libtmux::pane/` — a link - * that Sphinx reported as resolved and that goes nowhere. - */ - const uriFor = (model: ApiModel, rooted = true) => { - const paged = new Set(ownersOf(model).map((s) => s.id)) - return (symbol: { id: string; publicId?: string; parent?: string }) => { - const anchor = symbol.publicId ?? symbol.id - const owner = paged.has(symbol.id) - ? anchor - : symbol.parent && paged.has(symbol.parent) - ? (model.symbols.find((s) => s.id === symbol.parent)?.publicId ?? symbol.parent) - : undefined - const page = owner ? `${pageSlug(owner)}/` : '' - const prefix = rooted ? `reference/${model.port}/` : '' - return `${prefix}${page}#${anchor}` - } - } + const uriFor = uriForModel for (const [port, model] of Object.entries(API_MODELS)) { const bytes = writeInventory(model, { diff --git a/site/src/plugins/rehype-api-links.ts b/site/src/plugins/rehype-api-links.ts index 6d7d80a0..3535fb11 100644 --- a/site/src/plugins/rehype-api-links.ts +++ b/site/src/plugins/rehype-api-links.ts @@ -2,11 +2,12 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { visit } from 'unist-util-visit' -import { decideFilePath, decideMention, isLikelyReference, notASymbol, notApiReason, type ApiProduct, type MentionContext, type Resolver } from '@libtmux/api-model' +import { decideFilePath, decideMention, isLikelyReference, notASymbol, notApiReason, type ApiProduct, type ApiSymbol, type MentionContext, type Resolver } from '@libtmux/api-model' import { getResolver } from '../lib/prose-resolver' import { API_MODELS, PORT_NAME } from '../lib/api-models' import { withPortRoot } from '../lib/site-root' import { productApiHref } from '../lib/product-api' +import { PORT_BY_SLUG, referenceUrl } from '../lib/ports' import { buildTarget } from '../lib/versions' /** @@ -143,6 +144,10 @@ export function rehypeApiLinks() { const product = file?.data?.astro?.frontmatter?.product let defaults: Record = {} try { defaults = JSON.parse(process.env.LIBTMUX_DOCS_PORT_DEFAULTS || '{}') } catch { /* Local defaults are latest. */ } + + /** The version a port publishes: this build's, when it is that port. */ + const versionOf = (port: string) => + port === process.env.LIBTMUX_DOCS_PORT ? buildTarget(process.env).version : (defaults[port] ?? 'latest') const sections: { depth: number; port?: string }[] = [] const walk = (node: El, inLink: boolean, rowPort: string | undefined, fence: { lang?: string }, before: { text: string }) => { @@ -189,7 +194,16 @@ export function rehypeApiLinks() { } if (child.tagName === 'code' && !inLink) { const text = textOf(child).trim() - const ctx = { pagePort: rowPort ?? fence.lang ?? sections.at(-1)?.port ?? buildPort, product, before: scope.text } + const ctx = { + pagePort: rowPort ?? fence.lang ?? sections.at(-1)?.port ?? buildPort, + product, + before: scope.text, + symbolHref: (port: string, symbol: ApiSymbol) => productApiHref(API_MODELS[port], symbol, versionOf(port)), + moduleHref: (port: string, module: string) => { + const target = PORT_BY_SLUG[port] + return target ? `${referenceUrl(target, versionOf(port))}#${module}` : `#${module}` + }, + } const wrapped = linkFor(text, ctx, r) if (wrapped) { kids[i] = { type: 'element', tagName: 'a', properties: wrapped.properties, children: [child] } as El @@ -238,15 +252,14 @@ export function rehypeApiLinks() { return undefined } if (d.kind !== 'link') return undefined + // Every reference link goes through productApiHref: it knows which of + // the three trees a symbol belongs to and which version of the target + // port publishes it. `d.href` survives only for what is not a symbol + // page — a federated inventory hit, or a module index. let href = withPortRoot(d.href) - if (ctx.product && !d.external) { + if (!d.external) { const res = r.resolve(d.port, text, ctx.product) - if ('symbol' in res) { - const version = d.port === process.env.LIBTMUX_DOCS_PORT - ? buildTarget(process.env).version - : (defaults[d.port] ?? 'latest') - href = productApiHref(API_MODELS[d.port], res.symbol, version) - } + if ('symbol' in res) href = productApiHref(API_MODELS[d.port], res.symbol, versionOf(d.port)) } return { properties: { From 4653ee2b4372ddabae1c84318a67b9ed2f0a5a44 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 15:59:18 -0500 Subject: [PATCH 03/17] feat(reference) Give each product its own reference section why: The Workspace Manager's declarations answered under workspace/internals/api and the MCP server's under mcp/api, two spellings for the same thing and neither matching the core library's. A reader who has found one reference should be able to guess the others. what: - The generated pages and their landing page move together: //workspace/reference/ and .../mcp/reference/ - The workspace reference leaves Internals, because a package's API is not an implementation note; Internals keeps its guides, topics and examples, and workspaceRedirects lifts those alone - A page's own port comes from the build rather than from the second segment of its path, which no longer carries one - Checks read the trees through scripts/reference-trees.mjs, which knows a port publishes one version prefix or two and that each carries three references - Served checks, dev checks and unit expectations follow the new paths --- scripts/check-api-fidelity.mjs | 4 +- scripts/check-canonicals.mjs | 10 ++-- scripts/check-type-links.mjs | 3 +- scripts/check-xrefs.mjs | 3 +- scripts/reference-trees.mjs | 47 +++++++++++++++++++ site/scripts/check-dev.mjs | 9 ++-- site/scripts/check-fonts.mjs | 24 +++++----- site/scripts/check-native-shell.mjs | 6 +-- site/scripts/check-style-parity.mjs | 4 +- site/scripts/check-visual.mjs | 10 ++-- site/src/components/api/ApiTree.astro | 7 ++- .../ports/cxx/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/dotnet/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/go/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/java/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/py/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/rs/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/swift/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 .../ports/ts/mcp/{api.md => reference.md} | 0 .../{internals/api.md => reference.md} | 0 site/src/lib/docs-paths.ts | 2 +- site/src/lib/page-port-links.ts | 28 ++++++++--- site/src/pages/reference/[...slug].astro | 15 ++++-- site/test/api-fidelity.test.ts | 2 +- site/test/inventory-federation.test.ts | 2 +- site/test/native-switchers.test.ts | 6 +-- site/test/page-port-links.test.ts | 28 +++++------ site/test/product-reference.test.ts | 12 ++--- site/test/prompts.test.ts | 2 +- site/test/prose-port-sections.test.ts | 10 ++-- site/test/search-index.test.ts | 10 ++-- 38 files changed, 161 insertions(+), 83 deletions(-) create mode 100644 scripts/reference-trees.mjs rename site/src/content/docs/ports/cxx/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/cxx/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/dotnet/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/dotnet/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/go/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/go/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/java/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/java/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/py/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/py/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/rs/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/rs/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/swift/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/swift/workspace/{internals/api.md => reference.md} (100%) rename site/src/content/docs/ports/ts/mcp/{api.md => reference.md} (100%) rename site/src/content/docs/ports/ts/workspace/{internals/api.md => reference.md} (100%) diff --git a/scripts/check-api-fidelity.mjs b/scripts/check-api-fidelity.mjs index 365b38d4..2bc9d3b5 100755 --- a/scripts/check-api-fidelity.mjs +++ b/scripts/check-api-fidelity.mjs @@ -20,6 +20,7 @@ import { readFileSync, globSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { sourceUrl } from '../packages/api-model/src/products.ts' +import { referenceDirs } from './reference-trees.mjs' const root = process.argv[2] // `root` above is the assembled site this run measures; the port list comes @@ -88,7 +89,8 @@ for (const port of PORTS) { const symbols = new Map(model.symbols.flatMap((symbol) => [ [symbol.id, symbol], [symbol.publicId ?? symbol.id, symbol], ])) - const pages = globSync(`reference/${port}/**/index.html`, { cwd: root }) + const pages = referenceDirs(root, port, { products: true }) + .flatMap((dir) => globSync('**/index.html', { cwd: dir }).map((page) => join(dir.slice(root.length + 1), page))) if (!pages.length) { failures.push(`${port}: no reference pages built`) continue diff --git a/scripts/check-canonicals.mjs b/scripts/check-canonicals.mjs index 0f2f1d21..25124523 100644 --- a/scripts/check-canonicals.mjs +++ b/scripts/check-canonicals.mjs @@ -21,6 +21,10 @@ import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs' import { execFileSync } from 'node:child_process' import { join, dirname } from 'node:path' import { fileURLToPath } from 'node:url' +import { referenceDirs } from './reference-trees.mjs' + +const { PORTS: PORT_DEFS } = await import(`file://${join(dirname(fileURLToPath(import.meta.url)), '../site/src/lib/ports.ts')}`) +const PORTS = PORT_DEFS.map((p) => p.slug) const repoRoot = dirname(dirname(fileURLToPath(import.meta.url))) const defaultSite = join(repoRoot, '_site') @@ -49,8 +53,8 @@ if (siteDir === defaultSite && existsSync(lock)) { } } -const root = join(siteDir, 'reference') -if (!existsSync(root)) { +const roots = PORTS.flatMap((port) => referenceDirs(siteDir, port, { products: true })) +if (!roots.length) { console.error(`check-canonicals: no reference tree under ${siteDir}`) process.exit(1) } @@ -63,7 +67,7 @@ const walk = (dir) => { else if (entry === 'index.html') pages.push(full) } } -walk(root) +for (const root of roots) walk(root) const CANONICAL = / [...htmlFiles(dir)])) { const html = readFileSync(file, 'utf8') resolved += (html.match(TYPE_LINK) ?? []).length for (const block of typeBlocks(html)) { diff --git a/scripts/check-xrefs.mjs b/scripts/check-xrefs.mjs index b89d10d7..c684eb99 100755 --- a/scripts/check-xrefs.mjs +++ b/scripts/check-xrefs.mjs @@ -21,6 +21,7 @@ import { readFileSync, writeFileSync, existsSync } from 'node:fs' import { join, dirname } from 'node:path' import { fileURLToPath } from 'node:url' import { execFileSync } from 'node:child_process' +import { referenceDirs } from './reference-trees.mjs' const root = join(dirname(fileURLToPath(import.meta.url)), '..') /* `--floor` points at a different record so `check-xrefs.negative.mjs` can @@ -52,7 +53,7 @@ function countIn(dir) { } const counts = Object.fromEntries( - PORTS.map((p) => [p, countIn(join(site, 'reference', p))]), + PORTS.map((p) => [p, referenceDirs(site, p, { products: true }).reduce((n, dir) => n + countIn(dir), 0)]), ) if (args.includes('--update')) { diff --git a/scripts/reference-trees.mjs b/scripts/reference-trees.mjs new file mode 100644 index 00000000..dc4a6562 --- /dev/null +++ b/scripts/reference-trees.mjs @@ -0,0 +1,47 @@ +/* + * Where a built reference tree is, now that there are three per port. + * + * The core library answers under `//reference/`, and the + * Workspace Manager and MCP server under `/// + * reference/`. A port publishes one version prefix today and Python two, so + * every check that reads the reference has to look for all of them rather + * than the single `reference//` it used to know. + * + * One module, because five checks ask the same question and the answer moved + * once already. + */ +import { existsSync, readdirSync, statSync } from 'node:fs' +import { join } from 'node:path' + +/** Product sections carrying a reference of their own. */ +export const PRODUCT_SECTIONS = ['workspace', 'mcp'] + +/** Version prefixes built for a port, newest-agnostic and sorted for stability. */ +export function versionsOf(site, port) { + const dir = join(site, port) + if (!existsSync(dir)) return [] + return readdirSync(dir) + .filter((entry) => statSync(join(dir, entry)).isDirectory()) + .filter((entry) => existsSync(join(dir, entry, 'reference'))) + .sort() +} + +/** + * Every reference directory for a port: its core tree per version, and each + * product's tree beside it. + * + * `products` is off by default because most checks measure the core library; + * the ones that cover the whole estate ask for it. + */ +export function referenceDirs(site, port, { products = false } = {}) { + const dirs = [] + for (const version of versionsOf(site, port)) { + dirs.push(join(site, port, version, 'reference')) + if (!products) continue + for (const product of PRODUCT_SECTIONS) { + const dir = join(site, port, version, product, 'reference') + if (existsSync(dir)) dirs.push(dir) + } + } + return dirs +} diff --git a/site/scripts/check-dev.mjs b/site/scripts/check-dev.mjs index fe353cac..b1a592e6 100644 --- a/site/scripts/check-dev.mjs +++ b/site/scripts/check-dev.mjs @@ -40,7 +40,7 @@ try { const manifest = await page.request.get(`${base}/page-links.json`) assert(manifest.ok(), `Native navigation manifest: HTTP ${manifest.status()}`) assert.equal((await manifest.json()).schema, 1) - const paths = ['concepts/server-session-window-pane', 'mcp/tools', 'reference/ts/session-session-panes', + const paths = ['concepts/server-session-window-pane', 'mcp/tools', 'ts/latest/reference/session-session-panes', 'ts/latest/workspace/internals/guides', 'py/stable/workspace/guides', 'ts/latest/mcp/tools', 'dotnet/latest/mcp/tools/tmux_capture_pane'] for (const path of paths) await retryReload(async () => { @@ -51,9 +51,10 @@ try { assert.equal(await page.locator('nav[aria-label="Language"] a').first().getAttribute('href'), '/en/py/stable/') const switcher = page.locator('[data-page-port-switcher]') const hasSwitcher = path !== 'mcp/tools' + const isReference = path.includes('/reference/') const expected = path.includes('workspace/') ? `/en/${path}/` - : path === 'dotnet/latest/mcp/tools/tmux_capture_pane' ? '/en/py/stable/mcp/tools/capture_pane/' : path.startsWith('reference/') - ? '/en/reference/py/libtmux-session-panes/' : `/en/py/stable/${path.replace(/^ts\/latest\//, '')}/` + : path === 'dotnet/latest/mcp/tools/tmux_capture_pane' ? '/en/py/stable/mcp/tools/capture_pane/' : isReference + ? '/en/py/stable/reference/libtmux-session-panes/' : `/en/py/stable/${path.replace(/^ts\/latest\//, '')}/` if (hasSwitcher) assert.equal(await switcher.locator('a').first().getAttribute('href'), expected) if (path === 'py/stable/workspace/guides') { assert.equal(await switcher.locator('a').count(), 1, 'Only Python has a workspace CLI guide') @@ -66,7 +67,7 @@ try { assert.equal(await switcher.locator('a').count(), 8) assert.equal(await switcher.locator('a[aria-current="page"]').getAttribute('href'), `/en/${path}/`) } - if (path.startsWith('reference/')) { + if (isReference) { assert.match(await switcher.locator('[aria-disabled="true"]').textContent(), /Java/) const target = await page.request.get(base.replace(/\/en$/, '') + expected) assert(target.ok(), `Equivalent target: HTTP ${target.status()}`) diff --git a/site/scripts/check-fonts.mjs b/site/scripts/check-fonts.mjs index 58cdc748..59100928 100755 --- a/site/scripts/check-fonts.mjs +++ b/site/scripts/check-fonts.mjs @@ -50,8 +50,8 @@ const FAMILIES = ['IBM Plex Sans', 'IBM Plex Mono'] const ARCHETYPES = [ ['home', '/', true], ['port page', '/py/', true], - ['reference entry', '/reference/py/libtmux-server/', true], - ['reference index', '/reference/go/', true], + ['reference entry', '/py/stable/reference/libtmux-server/', true], + ['reference index', '/go/latest/reference/', true], ['symbol index', '/reference/symbols/p/', true], ['topic', '/topics/traversal/', true], ['example', '/examples/attach-and-send-keys/', true], @@ -66,20 +66,20 @@ const ARCHETYPES = [ // `libtmux.Server`, not a `_compat` shim: the reference stopped publishing // the vendored and compatibility modules, and a sample page has to be one // the port actually exports if it is to keep being built. - ['ref py', '/reference/py/libtmux-server/', true], - ['ref ts', '/reference/ts/builder-applywindowcontext/', true], - ['ref rs', '/reference/rs/blocking-runtime/', true], - ['ref go', '/reference/go/tmux-activityaction/', true], - ['ref java', '/reference/java/io-github-libtmux-batch-batch-batch/', true], - ['ref dotnet', '/reference/dotnet/libtmux-attachsessionrequest/', true], - ['ref cxx', '/reference/cxx/libtmux-argumentsensitivity/', true], - ['ref swift', '/reference/swift/calleridentity/', true], + ['ref py', '/py/stable/reference/libtmux-server/', true], + ['ref ts', '/ts/latest/reference/builder-applywindowcontext/', true], + ['ref rs', '/rs/latest/reference/blocking-runtime/', true], + ['ref go', '/go/latest/reference/tmux-activityaction/', true], + ['ref java', '/java/latest/reference/io-github-libtmux-batch-batch-batch/', true], + ['ref dotnet', '/dotnet/latest/reference/libtmux-attachsessionrequest/', true], + ['ref cxx', '/cxx/latest/reference/libtmux-argumentsensitivity/', true], + ['ref swift', '/swift/latest/reference/calleridentity/', true], // A member's own page, which is a different shape from its type's: the type // lists its members, the member carries the signature. The italic type // annotations in a signature live only here, so an archetype list without // one reports Mono 400 italic as preloaded and unused. - ['member py', '/reference/py/libtmux-server-wait_for/', true], - ['member dotnet', '/reference/dotnet/libtmux-pane-clearhistoryasync/', true], + ['member py', '/py/stable/reference/libtmux-server-wait_for/', true], + ['member dotnet', '/dotnet/latest/reference/libtmux-pane-clearhistoryasync/', true], ] /** diff --git a/site/scripts/check-native-shell.mjs b/site/scripts/check-native-shell.mjs index 77e852f4..5ea3badb 100644 --- a/site/scripts/check-native-shell.mjs +++ b/site/scripts/check-native-shell.mjs @@ -15,7 +15,7 @@ try { assert(response?.ok(), `Native Session page: HTTP ${response?.status()}`) const menu = page.locator('[data-page-port-switcher]') await menu.waitFor() - await page.waitForFunction(() => document.querySelector('[data-page-port-switcher] a[href$="/reference/ts/session-session/"]')) + await page.waitForFunction(() => document.querySelector('[data-page-port-switcher] a[href$="/ts/latest/reference/session-session/"]')) assert(loaded.has(`${base}/_shell/shell.js`), 'Native shell script did not load from this locale') assert(loaded.has(`${base}/_shell/tokens.css`), 'Native shell tokens did not load from this locale') await menu.locator('summary').click() @@ -27,9 +27,9 @@ try { }) assert(bounds.sameRow && bounds.left >= 0 && bounds.right <= bounds.viewport, 'Native dropdowns split rows or leave the viewport') await page.evaluate(() => { location.hash = 'sessions' }) - await page.waitForFunction(() => document.querySelector('[data-page-port-switcher] a[href$="/reference/ts/session-session/"]')) + await page.waitForFunction(() => document.querySelector('[data-page-port-switcher] a[href$="/ts/latest/reference/session-session/"]')) await page.evaluate(() => { location.hash = 'libtmux.Session.windows' }) - await page.waitForFunction(() => document.querySelector('[data-page-port-switcher] a[href$="/reference/ts/session-session-windows/"]')) + await page.waitForFunction(() => document.querySelector('[data-page-port-switcher] a[href$="/ts/latest/reference/session-session-windows/"]')) console.log('Native shell: script, tokens, phone dropdowns and class/member equivalents passed') } finally { await browser.close() diff --git a/site/scripts/check-style-parity.mjs b/site/scripts/check-style-parity.mjs index e16c72fd..343363db 100755 --- a/site/scripts/check-style-parity.mjs +++ b/site/scripts/check-style-parity.mjs @@ -31,7 +31,7 @@ const SPHINX = `${base}/py/stable/api/api/libtmux.server/` * shows them did, and pointing at the old one reported all seven treatments * as "not found on this site" rather than as different. */ -const OURS = `${base}/reference/py/libtmux-server-new_session/` +const OURS = `${base}/py/stable/reference/libtmux-server-new_session/` /* * A second page, because a page is now one symbol. @@ -41,7 +41,7 @@ const OURS = `${base}/reference/py/libtmux-server-new_session/` * it — and now each symbol has its own, so no single URL carries both. A case * names the page it needs; the default is the method page. */ -const OURS_ATTRIBUTE = `${base}/reference/py/libtmux-_internal-constants-hooks-after_capture_pane/` +const OURS_ATTRIBUTE = `${base}/py/stable/reference/libtmux-_internal-constants-hooks-after_capture_pane/` /** * Equivalent elements, and the properties that carry the look. diff --git a/site/scripts/check-visual.mjs b/site/scripts/check-visual.mjs index 5d331abb..0e860d70 100755 --- a/site/scripts/check-visual.mjs +++ b/site/scripts/check-visual.mjs @@ -32,13 +32,13 @@ const base = process.argv.find((a) => a.startsWith('http')) ?? 'http://localhost /** One page per rendering path, not one per port: the component is shared. */ const PAGES = [ - ['py-class', '/reference/py/libtmux-server/'], + ['py-class', '/py/stable/reference/libtmux-server/'], // Rust carries the other prose path: fenced examples and `# Errors` // rubrics, which no Python docstring in this estate uses. - ['rs-class', '/reference/rs/server-server/'], - ['cxx-class', '/reference/cxx/libtmux-pane/'], - ['swift-class', '/reference/swift/server/'], - ['port-index', '/reference/go/'], + ['rs-class', '/rs/latest/reference/server-server/'], + ['cxx-class', '/cxx/latest/reference/libtmux-pane/'], + ['swift-class', '/swift/latest/reference/server/'], + ['port-index', '/go/latest/reference/'], ['symbol-index', '/reference/symbols/p/'], ] diff --git a/site/src/components/api/ApiTree.astro b/site/src/components/api/ApiTree.astro index 5bf7cf9c..46cbba2b 100644 --- a/site/src/components/api/ApiTree.astro +++ b/site/src/components/api/ApiTree.astro @@ -19,7 +19,8 @@ import Sidebar from '../docs/Sidebar.astro' import ApiTreeItems, { type TreeNode } from './ApiTreeItems.astro' import type { NavEntry } from '../../lib/api-models' import { bucketTotal, firstEntry, type TreeBucket } from '../../lib/api-tree' -import { withRoot } from '../../lib/site-root' +import { PORT_BY_SLUG, referenceUrl } from '../../lib/ports' +import { buildTarget } from '../../lib/versions' import '../../styles/api-tree.css' interface Props { @@ -47,7 +48,9 @@ const { port, portName, tree, currentRoot, currentBucket, currentTypeId, ownerNavId, ownerId, members, withMembers, menuVersion, currentPath, } = Astro.props as Props -const base = withRoot('/reference/') +// The port's own reference root. `withRoot` would give the locale root: +// Astro's `base` prefixes routes, not strings a component builds. +const base = referenceUrl(PORT_BY_SLUG[port]!, buildTarget(process.env).version) const href = (slug: string) => `${base}${slug}/` let seq = 0 diff --git a/site/src/content/docs/ports/cxx/mcp/api.md b/site/src/content/docs/ports/cxx/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/cxx/mcp/api.md rename to site/src/content/docs/ports/cxx/mcp/reference.md diff --git a/site/src/content/docs/ports/cxx/workspace/internals/api.md b/site/src/content/docs/ports/cxx/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/cxx/workspace/internals/api.md rename to site/src/content/docs/ports/cxx/workspace/reference.md diff --git a/site/src/content/docs/ports/dotnet/mcp/api.md b/site/src/content/docs/ports/dotnet/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/dotnet/mcp/api.md rename to site/src/content/docs/ports/dotnet/mcp/reference.md diff --git a/site/src/content/docs/ports/dotnet/workspace/internals/api.md b/site/src/content/docs/ports/dotnet/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/dotnet/workspace/internals/api.md rename to site/src/content/docs/ports/dotnet/workspace/reference.md diff --git a/site/src/content/docs/ports/go/mcp/api.md b/site/src/content/docs/ports/go/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/go/mcp/api.md rename to site/src/content/docs/ports/go/mcp/reference.md diff --git a/site/src/content/docs/ports/go/workspace/internals/api.md b/site/src/content/docs/ports/go/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/go/workspace/internals/api.md rename to site/src/content/docs/ports/go/workspace/reference.md diff --git a/site/src/content/docs/ports/java/mcp/api.md b/site/src/content/docs/ports/java/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/java/mcp/api.md rename to site/src/content/docs/ports/java/mcp/reference.md diff --git a/site/src/content/docs/ports/java/workspace/internals/api.md b/site/src/content/docs/ports/java/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/java/workspace/internals/api.md rename to site/src/content/docs/ports/java/workspace/reference.md diff --git a/site/src/content/docs/ports/py/mcp/api.md b/site/src/content/docs/ports/py/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/py/mcp/api.md rename to site/src/content/docs/ports/py/mcp/reference.md diff --git a/site/src/content/docs/ports/py/workspace/internals/api.md b/site/src/content/docs/ports/py/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/py/workspace/internals/api.md rename to site/src/content/docs/ports/py/workspace/reference.md diff --git a/site/src/content/docs/ports/rs/mcp/api.md b/site/src/content/docs/ports/rs/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/rs/mcp/api.md rename to site/src/content/docs/ports/rs/mcp/reference.md diff --git a/site/src/content/docs/ports/rs/workspace/internals/api.md b/site/src/content/docs/ports/rs/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/rs/workspace/internals/api.md rename to site/src/content/docs/ports/rs/workspace/reference.md diff --git a/site/src/content/docs/ports/swift/mcp/api.md b/site/src/content/docs/ports/swift/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/swift/mcp/api.md rename to site/src/content/docs/ports/swift/mcp/reference.md diff --git a/site/src/content/docs/ports/swift/workspace/internals/api.md b/site/src/content/docs/ports/swift/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/swift/workspace/internals/api.md rename to site/src/content/docs/ports/swift/workspace/reference.md diff --git a/site/src/content/docs/ports/ts/mcp/api.md b/site/src/content/docs/ports/ts/mcp/reference.md similarity index 100% rename from site/src/content/docs/ports/ts/mcp/api.md rename to site/src/content/docs/ports/ts/mcp/reference.md diff --git a/site/src/content/docs/ports/ts/workspace/internals/api.md b/site/src/content/docs/ports/ts/workspace/reference.md similarity index 100% rename from site/src/content/docs/ports/ts/workspace/internals/api.md rename to site/src/content/docs/ports/ts/workspace/reference.md diff --git a/site/src/lib/docs-paths.ts b/site/src/lib/docs-paths.ts index 629c53f5..f00c4289 100644 --- a/site/src/lib/docs-paths.ts +++ b/site/src/lib/docs-paths.ts @@ -28,7 +28,7 @@ export function docsRoutePath( export function workspaceRedirects(paths: string[]): { path: string; target: string }[] { const published = new Set(paths) return paths.flatMap((target) => { - const path = target.replace(/(^|\/)workspace\/internals\/(topics|guides|examples|api)(\/|$)/, '$1workspace/$2$3') + const path = target.replace(/(^|\/)workspace\/internals\/(topics|guides|examples)(\/|$)/, '$1workspace/$2$3') return path !== target && !published.has(path) ? [{ path, target }] : [] }) } diff --git a/site/src/lib/page-port-links.ts b/site/src/lib/page-port-links.ts index cc2d5473..c3d6a4f1 100644 --- a/site/src/lib/page-port-links.ts +++ b/site/src/lib/page-port-links.ts @@ -5,9 +5,16 @@ import { docsPath, type DocsPage } from './docs-paths' import { productApiHref } from './product-api' import { MCP_REFERENCE, equivalentMcpTool } from './mcp-reference' +/** + * Every symbol by the route it answers on, keyed by port. + * + * A reference page's path no longer carries its port — it sits under one — + * so the port comes from the build rather than from the path's second + * segment. + */ const symbolsByRoute = new Map(Object.entries(API_MODELS).flatMap(([port, model]) => model.symbols.map((symbol) => [ - `reference/${port}/${symbol.slug ?? pageSlug(symbol.publicId ?? symbol.id)}`, + `${port}/${symbol.slug ?? pageSlug(symbol.publicId ?? symbol.id)}`, symbol, ] as const), )) @@ -41,11 +48,13 @@ export function pagePortLinks({ docs: DocsPage[] }): PagePortLink[] { const path = pagePath.replace(/^\/+|\/+$/g, '') - const [, referencePort, symbolSlug] = path.split('/') const isReference = path === 'reference' || path.startsWith('reference/') - const productReference = /^(mcp|workspace)\/(?:internals\/)?api\/(.+)$/.exec(path) - const symbol = symbolsByRoute.get(productReference ? `reference/${portSlug}/${productReference[2]}` : path) - const symbolPort = productReference ? portSlug : referencePort + const symbolSlug = isReference ? path.slice('reference/'.length) || undefined : undefined + const productReference = /^(mcp|workspace)\/reference\/(.+)$/.exec(path) + const symbol = portSlug + ? symbolsByRoute.get(`${portSlug}/${productReference ? productReference[2] : (symbolSlug ?? '')}`) + : undefined + const symbolPort = portSlug const alternatives = symbol ? referenceAlternatives(symbolPort!, symbol.publicId ?? symbol.id) : [] const entries = docs.filter((entry) => docsPath(entry) === path) const tool = path.startsWith('mcp/tools/') && portSlug @@ -61,7 +70,10 @@ export function pagePortLinks({ } else if (symbol) { for (const alternative of alternatives) { const match = alternative.ports.find((p) => p.port === port.slug) - const targetSymbol = productReference && match?.publicId + // Resolved here rather than taken from `match.href`, because the + // equivalent lives under the *target* port's version, which this + // caller knows and `referenceAlternatives` does not. + const targetSymbol = match?.publicId ? API_MODELS[port.slug]?.symbols.find((entry) => (entry.publicId ?? entry.id) === match.publicId) : undefined const href = targetSymbol ? productApiHref(API_MODELS[port.slug], targetSymbol, targetVersion) : match?.href if (href && !links.some((link) => link.href === href)) { @@ -69,7 +81,9 @@ export function pagePortLinks({ } } if (port.slug === symbolPort) { - const href = productReference ? portPageUrl(port, targetVersion, path) : referenceHref(symbolPort, symbol.publicId ?? symbol.id) + const href = productReference + ? portPageUrl(port, targetVersion, path) + : referenceHref(symbolPort, symbol.publicId ?? symbol.id, targetVersion) if (href) links = [{ href }] } } else if (tool) { diff --git a/site/src/pages/reference/[...slug].astro b/site/src/pages/reference/[...slug].astro index 7f6bba90..a8cb5858 100644 --- a/site/src/pages/reference/[...slug].astro +++ b/site/src/pages/reference/[...slug].astro @@ -12,7 +12,7 @@ import { PORT_BY_SLUG, referenceUrl } from '../../lib/ports' import { symbolSource } from '../../lib/markdown-twins' import { DEFAULT_LOCALE } from '../../i18n/locales' import { buildLocale } from '../../i18n/resolve' -import { defaultVersionFor } from '../../lib/versions' +import { buildTarget, defaultVersionFor } from '../../lib/versions' import ApiDoc from '../../components/api/ApiDoc.astro' import ApiTree from '../../components/api/ApiTree.astro' import { navTree } from '../../lib/api-tree' @@ -90,6 +90,11 @@ interface Props { } const { model, owner, searchable = true } = Astro.props as Props +/** This port and version's reference root, which every link below hangs off. */ +const refBase = model && PORT_BY_SLUG[model.port] + ? referenceUrl(PORT_BY_SLUG[model.port], buildTarget(process.env).version) + : withRoot('/reference/') + /** What the hub counts per port: the core library, without its products. */ const coreCount = (m: ApiModel) => m.symbols.length - new Set([...symbolsForProduct(m, 'mcp'), ...symbolsForProduct(m, 'workspace')].map((s) => s.id)).size @@ -117,7 +122,7 @@ const paged = new Set(pageOwners.map((s) => s.id)) */ const hrefFor = (s: ApiSymbol): string => model - ? withRoot(`/reference/${s.slug ?? pageSlug(s.publicId ?? s.id)}/`) + ? `${refBase}${s.slug ?? pageSlug(s.publicId ?? s.id)}/` : withRoot('/reference/') /* * The stub is what the index route has instead of a model. @@ -727,10 +732,10 @@ const title = owner is a URL, and that is the whole feature. */}

- + View as Markdown -

@@ -755,7 +760,7 @@ const title = owner
Module
{moduleAnchors.has(ownerModule) ? ( - {ownerModule} + {ownerModule} ) : ( ownerModule )} diff --git a/site/test/api-fidelity.test.ts b/site/test/api-fidelity.test.ts index 41cc8895..16aefa60 100644 --- a/site/test/api-fidelity.test.ts +++ b/site/test/api-fidelity.test.ts @@ -25,7 +25,7 @@ function entry(model: ApiModel, symbol: ApiSymbol, linked = true): string { } function page(path: string, port: string, entries: string[]): void { - const directory = join(path, 'reference', port, 'sample') + const directory = join(path, port, 'latest', 'reference', 'sample') mkdirSync(directory, { recursive: true }) writeFileSync(join(directory, 'index.html'), entries.join('\n')) } diff --git a/site/test/inventory-federation.test.ts b/site/test/inventory-federation.test.ts index c71b4133..1a712f57 100644 --- a/site/test/inventory-federation.test.ts +++ b/site/test/inventory-federation.test.ts @@ -76,7 +76,7 @@ describe('indexFor attaches the inventories', () => { href: 'https://docs.oracle.com/en/java/javase/21/docs/api/java/nio/file/Path.html', }) const workspace = product.linkType(signature.returns!, reader).find((span) => span.text === 'Workspace')?.link - expect(workspace?.href).toContain(`/java/${version}/workspace/internals/api/`) + expect(workspace?.href).toContain(`/java/${version}/workspace/reference/`) expect(productApiIndex(model, version)).toBe(product) } expect(core.linkType(signature.returns!, reader).find((span) => span.text === 'Workspace')?.link?.href).toMatch(/^#/) diff --git a/site/test/native-switchers.test.ts b/site/test/native-switchers.test.ts index 339d8026..a8fcc87d 100644 --- a/site/test/native-switchers.test.ts +++ b/site/test/native-switchers.test.ts @@ -12,11 +12,11 @@ const manifest = { } const pageLinks = { schema: 1, - indexes: { py: `${base}/reference/py/`, ts: `${base}/reference/ts/` }, + indexes: { py: `${base}/py/stable/reference/`, ts: `${base}/ts/latest/reference/` }, symbols: { py: { - 'libtmux.Session': [{ port: 'ts', href: `${base}/reference/ts/session-session/`, label: 'Session' }], - 'libtmux.Session.windows': [{ port: 'ts', href: `${base}/reference/ts/session-session-windows/`, label: 'Session windows' }], + 'libtmux.Session': [{ port: 'ts', href: `${base}/ts/latest/reference/session-session/`, label: 'Session' }], + 'libtmux.Session.windows': [{ port: 'ts', href: `${base}/ts/latest/reference/session-session-windows/`, label: 'Session windows' }], }, }, } diff --git a/site/test/page-port-links.test.ts b/site/test/page-port-links.test.ts index 54c2e735..2ff49d9a 100644 --- a/site/test/page-port-links.test.ts +++ b/site/test/page-port-links.test.ts @@ -71,26 +71,27 @@ describe('matching pages in another port', () => { }) it('offers reference indexes rather than transplanting the current reference path', () => { - expect(pagePortLinks({ ...options, pagePath: 'reference/ts' }).find((p) => p.port === 'py')?.links[0].href).toBe('/pr-42/en/reference/py/') + expect(pagePortLinks({ ...options, pagePath: 'reference', portSlug: 'ts' }).find((p) => p.port === 'py')?.links[0].href).toBe('/pr-42/en/py/stable/reference/') }) it('links session pane equivalents and disables Java without a direct accessor', () => { - const links = pagePortLinks({ ...options, pagePath: 'reference/ts/session-session-panes' }) - expect(links.find((p) => p.port === 'py')?.links[0].href).toBe('/pr-42/en/reference/py/libtmux-session-panes/') - expect(links.find((p) => p.port === 'ts')?.links[0].href).toBe('/pr-42/en/reference/ts/session-session-panes/') + const links = pagePortLinks({ ...options, pagePath: 'reference/session-session-panes', portSlug: 'ts' }) + expect(links.find((p) => p.port === 'py')?.links[0].href).toBe('/pr-42/en/py/stable/reference/libtmux-session-panes/') + // The page's own port keeps the version being built, not the default. + expect(links.find((p) => p.port === 'ts')?.links[0].href).toBe('/pr-42/en/ts/v1.2.3/reference/session-session-panes/') expect(links.find((p) => p.port === 'java')?.links).toEqual([]) }) it('keeps both scopes when a Swift page documents session and window overloads', () => { - const links = pagePortLinks({ ...options, pagePath: 'reference/swift/snapshot-panes(of-)' }) + const links = pagePortLinks({ ...options, pagePath: 'reference/snapshot-panes(of-)', portSlug: 'swift' }) expect(links.find((p) => p.port === 'py')?.links.map((link) => link.href).sort()).toEqual([ - '/pr-42/en/reference/py/libtmux-session-panes/', - '/pr-42/en/reference/py/libtmux-window-panes/', + '/pr-42/en/py/stable/reference/libtmux-session-panes/', + '/pr-42/en/py/stable/reference/libtmux-window-panes/', ]) }) it('leaves only the current page enabled for an unmapped symbol', () => { - const links = pagePortLinks({ ...options, pagePath: 'reference/ts/session-session-sessionbrand' }) + const links = pagePortLinks({ ...options, pagePath: 'reference/session-session-sessionbrand', portSlug: 'ts' }) expect(links.filter((p) => p.links.length).map((p) => p.port)).toEqual(['ts']) }) }) @@ -116,18 +117,17 @@ describe('workspace documentation compatibility', () => { expect(internals.filter((entry) => entry.links.length).map((entry) => entry.port)).toEqual(['ts', 'rs']) }) - it('redirects old builder paths while retaining real Python user pages', async () => { + it('lifts a port without a workspace CLI out of Internals, and leaves Python alone', async () => { const { workspaceRedirects } = await import('../src/lib/docs-paths') expect(workspaceRedirects([ 'py/stable/workspace/examples', 'py/stable/workspace/internals/examples', - 'go/latest/workspace/internals/examples', 'go/latest/workspace/internals/api/builder', + 'go/latest/workspace/internals/examples', 'go/latest/workspace/reference/builder', 'go/latest/workspace/internals', 'go/latest/guides', ])).toEqual([ { path: 'go/latest/workspace/examples', target: 'go/latest/workspace/internals/examples' }, - { path: 'go/latest/workspace/api/builder', target: 'go/latest/workspace/internals/api/builder' }, - ]) - expect(workspaceRedirects(['workspace/internals/api/builder'])).toEqual([ - { path: 'workspace/api/builder', target: 'workspace/internals/api/builder' }, ]) + // The reference is its own section now, so there is nothing under + // Internals for it to be lifted out of. + expect(workspaceRedirects(['workspace/reference/builder'])).toEqual([]) }) }) diff --git a/site/test/product-reference.test.ts b/site/test/product-reference.test.ts index 49fc022c..56a56190 100644 --- a/site/test/product-reference.test.ts +++ b/site/test/product-reference.test.ts @@ -8,20 +8,20 @@ describe('product reference equivalents', () => { const model = API_MODELS.go const symbol = model.symbols.find((entry) => entry.id === 'workspace.Build')! const group = productApiAlternatives(model, symbol, 'v1.2.3', { ts: 'stable' })[0] - expect(group.ports.find((entry) => entry.port === 'go')?.href).toBe('/go/v1.2.3/workspace/internals/api/workspace-build/') - expect(group.ports.find((entry) => entry.port === 'ts')?.href).toBe('/ts/stable/workspace/internals/api/builder-applyworkspace/') - expect(group.ports.find((entry) => entry.port === 'rs')?.href).toBe('/rs/latest/workspace/internals/api/src-workspacebuilder-build/') - expect(referenceAlternatives('go', symbol.id)[0].ports.find((entry) => entry.port === 'ts')?.href).toBe('/reference/ts/builder-applyworkspace/') + expect(group.ports.find((entry) => entry.port === 'go')?.href).toBe('/go/v1.2.3/workspace/reference/workspace-build/') + expect(group.ports.find((entry) => entry.port === 'ts')?.href).toBe('/ts/stable/workspace/reference/builder-applyworkspace/') + expect(group.ports.find((entry) => entry.port === 'rs')?.href).toBe('/rs/latest/workspace/reference/src-workspacebuilder-build/') + expect(referenceAlternatives('go', symbol.id)[0].ports.find((entry) => entry.port === 'ts')?.href).toBe('/ts/latest/workspace/reference/builder-applyworkspace/') }) - it('publishes every workspace declaration under Internals without moving MCP APIs', () => { + it('publishes every product declaration in its own reference', () => { for (const [port, model] of Object.entries(API_MODELS)) { const routes = productApiRoutes({ [port]: model }, port, {}, 'stable') for (const product of ['workspace', 'mcp']) { const declarations = routes.filter((route) => route.symbol.product === product) expect(declarations.length, `${port} ${product} declarations`).toBeGreaterThan(0) for (const route of declarations) { - const section = product === 'workspace' ? 'workspace/internals/api' : 'mcp/api' + const section = `${product}/reference` expect(route.path).toBe(`${section}/${route.symbol.slug}`) expect(route.version).toBe('stable') } diff --git a/site/test/prompts.test.ts b/site/test/prompts.test.ts index 231f807d..095ecf42 100644 --- a/site/test/prompts.test.ts +++ b/site/test/prompts.test.ts @@ -93,7 +93,7 @@ describe('prompt composition', () => { // beats "go read the docs": an agent fetches these two first. expect(text, 'llms.txt').toContain(`${DOCS_BASE}/${port.slug}/latest/llms.txt`) expect(text, 'docs.json').toContain(`${DOCS_BASE}/${port.slug}/latest/docs.json`) - expect(text, 'reference').toContain(`${DOCS_BASE}/reference/${port.slug}/`) + expect(text, 'reference').toContain(`${DOCS_BASE}/${port.slug}/latest/reference/`) expect(text, 'repository').toContain(`https://github.com/${port.repo}`) expect(text, 'registry page').toContain((port.registry?.url ?? `https://github.com/${port.repo}`)) }) diff --git a/site/test/prose-port-sections.test.ts b/site/test/prose-port-sections.test.ts index 96051303..991b5aaf 100644 --- a/site/test/prose-port-sections.test.ts +++ b/site/test/prose-port-sections.test.ts @@ -13,7 +13,7 @@ describe('API links in port sections', () => { vi.stubEnv('LIBTMUX_DOCS_PORT_DEFAULTS', '{"go":"stable"}') const paragraph = element('p', element('code', text('workspace.Parse'))) rehypeApiLinks()({ type: 'root', children: [paragraph] }, { data: { astro: { frontmatter: { port: 'go', product: 'workspace' } } } }) - expect(paragraph.children?.[0].properties?.href).toBe('/go/stable/workspace/internals/api/workspace-parse/') + expect(paragraph.children?.[0].properties?.href).toBe('/go/stable/workspace/reference/workspace-parse/') }) it('keeps the current product version while preserving core reference URLs', () => { @@ -22,8 +22,8 @@ describe('API links in port sections', () => { const product = element('p', element('code', text('workspace.Parse'))) const core = element('p', element('code', text('tmux.Server'))) rehypeApiLinks()({ type: 'root', children: [product, core] }, { data: { astro: { frontmatter: { port: 'go', product: 'workspace' } } } }) - expect(product.children?.[0].properties?.href).toBe('/go/v0.1/workspace/internals/api/workspace-parse/') - expect(core.children?.[0].properties?.href).toBe('/reference/go/tmux-server/') + expect(product.children?.[0].properties?.href).toBe('/go/v0.1/workspace/reference/workspace-parse/') + expect(core.children?.[0].properties?.href).toBe('/go/v0.1/reference/tmux-server/') }) it('links symbols and source paths under port headings, including nested sections', () => { @@ -41,9 +41,9 @@ describe('API links in port sections', () => { ], } rehypeApiLinks()(tree) - expect(first.children?.[0].properties?.href).toBe('/reference/py/libtmux-session-panes/') + expect(first.children?.[0].properties?.href).toBe('/py/latest/reference/libtmux-session-panes/') expect(nested.children?.[0].properties?.href).toMatch(/github.com\/.*\/src\/libtmux\/pane.py$/) - expect(other.children?.[0].properties?.href).toBe('/reference/go/tmux-session-panes/') + expect(other.children?.[0].properties?.href).toBe('/go/latest/reference/tmux-session-panes/') expect(shared.children?.[0].tagName).toBe('code') }) }) diff --git a/site/test/search-index.test.ts b/site/test/search-index.test.ts index 4fd11fce..61216d06 100644 --- a/site/test/search-index.test.ts +++ b/site/test/search-index.test.ts @@ -7,16 +7,16 @@ it.skipIf(!SITE_BUILT)('indexes scoped product declarations while retaining core const cases = [ ['reference/go/workspace-build', false], ['go/latest/workspace/api/workspace-build', false], - ['go/latest/workspace/internals/api/workspace-build', true], + ['go/latest/workspace/reference/workspace-build', true], ['go/latest/workspace/guides', false], ['go/latest/workspace/internals/guides', true], ['py/latest/workspace/guides', true], ['py/latest/workspace/internals', true], ['reference/ts/mcp-startup-serverstartup', false], - ['ts/latest/mcp/api/mcp-startup-serverstartup', true], - ['reference/ts/builder-applywindowcontext', true], - ['reference/go/tmux-server', true], - ['reference/go', true], + ['ts/latest/mcp/reference/mcp-startup-serverstartup', true], + ['ts/latest/reference/builder-applywindowcontext', true], + ['go/latest/reference/tmux-server', true], + ['go/latest/reference', true], ['reference', true], ] as const const window = new Window({ From 44a9e245548830d9d571571330d92a7966d4377b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:02:31 -0500 Subject: [PATCH 04/17] test(site) Point every check at the reference where it lives now why: Nine checks and eleven suites located the reference by the path it had. Left alone they would measure an empty tree and pass, which is the one failure mode a gate must not have. what: - canonicals, xrefs, type-links and api-fidelity read every port's trees through referenceDirs, which covers both version prefixes and all three products - sidebar-refs asserts the entry is ///reference/ and still first; its negative fixture drops that link - The canonicals negative case drops a version segment rather than a port segment, which is the collision the new shape can have - The switcher test asserted that no port link may carry a reference path, which is now the shape itself: it asserts each language link offers that port's root and nothing deeper - check-links no longer excuses a whole port tree as vendored output. Only the native `api/` subtree is Sphinx's or docfx's; the reference beside it is ours - Served checks, dev checks, fixtures and the publication smoke test follow the new paths --- scripts/build-site.sh | 5 ++++- scripts/check-canonicals.negative.mjs | 14 +++++++------- scripts/check-sidebar-refs.mjs | 7 ++++--- scripts/check-sidebar-refs.negative.sh | 2 +- scripts/check-type-links.negative.mjs | 2 +- scripts/check-xrefs.negative.mjs | 2 +- scripts/test-all.sh | 2 +- site/test/switcher-targets.test.ts | 18 +++++++++++------- 8 files changed, 30 insertions(+), 22 deletions(-) diff --git a/scripts/build-site.sh b/scripts/build-site.sh index a6c2c515..3cbd2523 100755 --- a/scripts/build-site.sh +++ b/scripts/build-site.sh @@ -1142,7 +1142,10 @@ while IFS='|' read -r slug _name _versioned renderer _rest; do *) continue ;; esac for version in "${versions[@]}"; do - vendored_args+=(--vendored "${LIBTMUX_DOCS_LOCALES_ROOT#/}/$locale/$slug/$version") + # The native tree alone, not the whole port: this repo's own reference + # now lives under `$slug/$version/reference/`, and excusing the port + # would excuse the one class of link worth failing on. + vendored_args+=(--vendored "${LIBTMUX_DOCS_LOCALES_ROOT#/}/$locale/$slug/$version/api") done done < <(list_ports) diff --git a/scripts/check-canonicals.negative.mjs b/scripts/check-canonicals.negative.mjs index ed857798..d6e1ca37 100644 --- a/scripts/check-canonicals.negative.mjs +++ b/scripts/check-canonicals.negative.mjs @@ -21,7 +21,7 @@ const ORIGIN = 'https://libtmux.org' /** A reference tree whose canonical for each page is `canonicalFor(path)`. */ function site(canonicalFor) { const dir = mkdtempSync(join(tmpdir(), 'check-canonicals-')) - const pages = ['reference', 'reference/py', 'reference/ts', 'reference/py/pane', 'reference/ts/pane'] + const pages = ['reference', 'py/latest/reference', 'ts/latest/reference', 'py/latest/reference/pane', 'ts/latest/reference/pane'] for (const page of pages) { mkdirSync(join(dir, page), { recursive: true }) const href = `${ORIGIN}${canonicalFor(`/${page}/`)}` @@ -55,10 +55,10 @@ const check = (name, ok, detail) => { } { - // The real defect: the port segment dropped, so /reference/py/pane/ claims - // /reference/pane/ — which does not exist, and which /reference/ts/pane/ - // claims too. - const dir = site((p) => p.replace(/^\/reference\/(py|ts)\//, '/reference/')) + // The real defect: the version segment dropped, so /py/latest/reference/pane/ + // claims /py/reference/pane/ — which does not exist, and which every other + // version of that page would claim too. + const dir = site((p) => p.replace(/^\/(py|ts)\/latest\//, '/$1/')) const { code, out } = run(dir) check( 'a dropped port segment fails', @@ -77,8 +77,8 @@ const check = (name, ok, detail) => { { const dir = mkdtempSync(join(tmpdir(), 'check-canonicals-bare-')) - mkdirSync(join(dir, 'reference'), { recursive: true }) - writeFileSync(join(dir, 'reference', 'index.html'), '') + mkdirSync(join(dir, 'py', 'latest', 'reference'), { recursive: true }) + writeFileSync(join(dir, 'py', 'latest', 'reference', 'index.html'), '') const { code, out } = run(dir) check('a page with no canonical at all fails', code !== 0 && out.includes('none'), `exited ${code}:\n${out}`) rmSync(dir, { recursive: true, force: true }) diff --git a/scripts/check-sidebar-refs.mjs b/scripts/check-sidebar-refs.mjs index a33360f1..c8e0da7e 100755 --- a/scripts/check-sidebar-refs.mjs +++ b/scripts/check-sidebar-refs.mjs @@ -123,9 +123,10 @@ for (const port of PORTS) { * prefixed build, and asserting the prefixed form would fail on an * unprefixed one. */ - const ours = sidebar.findIndex((l) => pathOf(l.href) === `/reference/${port}/`) - if (ours === -1) failures.push(`${port}: sidebar does not link /reference/${port}/`) - else if (ours !== 0) failures.push(`${port}: /reference/${port}/ is entry ${ours}, not first`) + const REFERENCE = new RegExp(`/${port}/[^/]+/reference/$`) + const ours = sidebar.findIndex((l) => REFERENCE.test(pathOf(l.href))) + if (ours === -1) failures.push(`${port}: sidebar does not link /${port}//reference/`) + else if (ours !== 0) failures.push(`${port}: /${port}//reference/ is entry ${ours}, not first`) const host = ECOSYSTEM[port] if (host) { diff --git a/scripts/check-sidebar-refs.negative.sh b/scripts/check-sidebar-refs.negative.sh index 705998e2..93a4ca0d 100755 --- a/scripts/check-sidebar-refs.negative.sh +++ b/scripts/check-sidebar-refs.negative.sh @@ -69,7 +69,7 @@ fails=0 rs=$(page_for rs) || { echo 'no rs shell page under _site — run ./scripts/build-site.sh' >&2; exit 1; } py=$(page_for py) || { echo 'no py shell page under _site — run ./scripts/build-site.sh' >&2; exit 1; } -drop 'our reference removed' "$rs" '/reference/rs/' 'rs: sidebar does not link /reference/rs/' || fails=1 +drop 'our reference removed' "$rs" '/rs/latest/reference/' 'rs: sidebar does not link /rs//reference/' || fails=1 drop 'ecosystem link removed' "$rs" 'docs.rs' 'rs: sidebar does not link docs.rs' || fails=1 drop 'upstream reference gone' "$py" '/api/' 'py: sidebar does not link the upstream gp-sphinx reference' || fails=1 diff --git a/scripts/check-type-links.negative.mjs b/scripts/check-type-links.negative.mjs index b04fccb1..6dea16be 100644 --- a/scripts/check-type-links.negative.mjs +++ b/scripts/check-type-links.negative.mjs @@ -30,7 +30,7 @@ const usr = () => function site({ n = 0, mangled = false } = {}) { const dir = mkdtempSync(join(tmpdir(), 'check-type-links-')) for (const p of PORTS) { - const d = join(dir, 'reference', p, 'thing') + const d = join(dir, p, 'latest', 'reference', 'thing') mkdirSync(d, { recursive: true }) const body = linked('Server') + diff --git a/scripts/check-xrefs.negative.mjs b/scripts/check-xrefs.negative.mjs index eb3ef05e..a67a0726 100755 --- a/scripts/check-xrefs.negative.mjs +++ b/scripts/check-xrefs.negative.mjs @@ -22,7 +22,7 @@ const PORTS = PORT_DEFS.map((p) => p.slug) function site(n) { const dir = mkdtempSync(join(tmpdir(), 'check-xrefs-')) for (const p of PORTS) { - const d = join(dir, 'reference', p, 'thing') + const d = join(dir, p, 'latest', 'reference', 'thing') mkdirSync(d, { recursive: true }) const anchors = Array.from({ length: n }, () => 'x').join('') writeFileSync(join(d, 'index.html'), `${anchors}`) diff --git a/scripts/test-all.sh b/scripts/test-all.sh index 00328f2b..96abe8ff 100755 --- a/scripts/test-all.sh +++ b/scripts/test-all.sh @@ -255,7 +255,7 @@ node scripts/check-api-fidelity.mjs "$site_out" # twin as well — which only a full assembly produces. Both run against a # running server; `pnpm test:publication` reports that they were not run rather than # implying they passed. -if curl -sf -o /dev/null "$SERVE_SITE/reference/py/libtmux-server/"; then +if curl -sf -o /dev/null "$SERVE_SITE/py/stable/reference/libtmux-server/"; then # Type is checked here rather than with the static suites because half of # it is a rendering question: which faces a page opens with is answered by # laying the page out, not by reading its HTML. diff --git a/site/test/switcher-targets.test.ts b/site/test/switcher-targets.test.ts index 43733a1e..896ae7ec 100644 --- a/site/test/switcher-targets.test.ts +++ b/site/test/switcher-targets.test.ts @@ -16,8 +16,9 @@ function samplePages(): string[] { 'index.html', 'concepts/index.html', 'mcp/tools/index.html', 'topics/architecture/index.html', 'py/index.html', 'py/latest/topics/architecture/index.html', 'ts/latest/topics/architecture/index.html', - 'rs/index.html', 'reference/index.html', 'reference/ts/index.html', - 'reference/ts/session-session-panes/index.html', 'reference/ts/session-session-sessionbrand/index.html', + 'rs/index.html', 'reference/index.html', 'ts/latest/reference/index.html', + 'ts/latest/reference/session-session-panes/index.html', 'ts/latest/reference/session-session-sessionbrand/index.html', + 'ts/latest/mcp/reference/index.html', 'go/latest/workspace/reference/index.html', ].map((page) => prefix + page) wanted.push('ja/index.html', 'ja/concepts/index.html') const present = wanted.filter((page) => existsSync(join(SITE, page))) @@ -100,17 +101,20 @@ describeIfAssembled('switcher targets', () => { expect(hrefs.filter((h) => !resolves(h)), `${page}: alternates with no page`).toEqual([]) }) - it('never offers a port link that carries a reference path', () => { - // Bug 2, stated directly. The reference lives only at the root, so a port - // link must never transplant `reference//…` under `///`. + it('offers each port its own root, never a transplanted path', () => { + // Bug 2, restated for a reference that now lives under a port. The + // language switcher answers "the same library, in another language", + // which is that port's root — not this page's path wearing another + // port's prefix, and least of all a reference path that only the port + // being read has. for (const page of pages) { const html = readFileSync(join(SITE, page), 'utf8') const nav = /]*aria-label="Language"[^>]*>([\s\S]*?)<\/nav>/.exec(html) if (!nav) continue const bad = [...nav[1].matchAll(/href="([^"]+)"/g)] .map((m) => m[1]) - .filter((h) => /\/[a-z]+\/[^/]+\/reference\//.test(h)) - expect(bad, `${page}: port link carrying a reference path`).toEqual([]) + .filter((h) => !/\/[a-z]+(?:\/[^/]+)?\/$/.test(h)) + expect(bad, `${page}: port link deeper than that port's root`).toEqual([]) } }) }) From 67e31782b62e865a5937dc791645b357e0194e37 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:05:42 -0500 Subject: [PATCH 05/17] fix(reference) Keep a core page from linking a product symbol home why: A signature on a core page can name a Workspace Manager or MCP type, and the page built that link from its own root -- 35,092 links to pages that moved. The sidebar tree listed those declarations too, since the nav sidecar covers the whole model. what: - The reference page resolves every symbol through productApiHref, so a product type links into its own package reference - navTree lists what the core reference holds, dropping declarations that belong to a product tree --- site/src/lib/api-tree.ts | 16 +++++++++++++--- site/src/pages/reference/[...slug].astro | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/site/src/lib/api-tree.ts b/site/src/lib/api-tree.ts index faea6257..1bdeab72 100644 --- a/site/src/lib/api-tree.ts +++ b/site/src/lib/api-tree.ts @@ -5,6 +5,7 @@ * Buckets and their contents are decided once per port in * `scripts/gen-api-model.mjs`; this only shapes them for a tree. */ +import { symbolsForProduct } from '@libtmux/api-model' import { API_MODELS, API_NAV, OWNER_KINDS, pageSlug, type NavEntry } from './api-models' export interface TreeBucket { @@ -48,20 +49,29 @@ const distinct = (entries: NavEntry[]): NavEntry[] => { export function navTree(port: string): TreeBucket[] { const nav = API_NAV[port] if (!nav) return [] + // The core library's tree lists the core library. A Workspace Manager or + // MCP declaration has a page in its own package's reference, so a row for + // it here would point out of this tree — and did, at a URL that no longer + // exists. + const model = API_MODELS[port] + const products = new Set(model + ? [...symbolsForProduct(model, 'mcp'), ...symbolsForProduct(model, 'workspace')].map((s) => s.publicId ?? s.id) + : []) + const core = (entries: NavEntry[]) => entries.filter((e) => !products.has(e.id)) return [ ...nav.buckets .map((b) => ({ id: b.id, label: b.label, collapsed: b.collapsed, - entries: distinct(nav.assignments[b.id] ?? []), + entries: distinct(core(nav.assignments[b.id] ?? [])), children: (b.children ?? []) - .map((c) => ({ id: c.id, label: c.label, collapsed: c.collapsed, entries: distinct(nav.assignments[c.id] ?? []), children: [] })) + .map((c) => ({ id: c.id, label: c.label, collapsed: c.collapsed, entries: distinct(core(nav.assignments[c.id] ?? [])), children: [] })) .filter((c) => c.entries.length > 0), })) .filter((b) => b.entries.length > 0 || b.children.length > 0), ...(nav.unplaced.length > 0 - ? [{ id: '__unplaced', label: 'Other', collapsed: true, entries: distinct(nav.unplaced), children: [] }] + ? [{ id: '__unplaced', label: 'Other', collapsed: true, entries: distinct(core(nav.unplaced)), children: [] }] : []), ] } diff --git a/site/src/pages/reference/[...slug].astro b/site/src/pages/reference/[...slug].astro index a8cb5858..66de631e 100644 --- a/site/src/pages/reference/[...slug].astro +++ b/site/src/pages/reference/[...slug].astro @@ -9,6 +9,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro' import { withRoot } from '../../lib/site-root' import { API_MODELS, API_NAV, OWNER_KINDS, PORT_NAME, indexFor, ownersOf, pageSlug, referenceHref, topLevelTypesOf } from '../../lib/api-models' import { PORT_BY_SLUG, referenceUrl } from '../../lib/ports' +import { productApiHref } from '../../lib/product-api' import { symbolSource } from '../../lib/markdown-twins' import { DEFAULT_LOCALE } from '../../i18n/locales' import { buildLocale } from '../../i18n/resolve' @@ -122,7 +123,10 @@ const paged = new Set(pageOwners.map((s) => s.id)) */ const hrefFor = (s: ApiSymbol): string => model - ? `${refBase}${s.slug ?? pageSlug(s.publicId ?? s.id)}/` + // productApiHref, not refBase: a signature on a core page can name a + // Workspace Manager or MCP type, and that type's page is in its own + // package's reference rather than this one. + ? productApiHref(model, s, buildTarget(process.env).version) : withRoot('/reference/') /* * The stub is what the index route has instead of a model. From 6e79c80d643f2ef5de45356991f283ca610fc116 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:08:00 -0500 Subject: [PATCH 06/17] chore(site) Regenerate the mention index for the moved references why: Every mention records the URL it links to, and all 775 moved. what: - gen-mentions --check passes again --- site/src/data/mentions.json | 654 ++++++++++++++++++------------------ 1 file changed, 327 insertions(+), 327 deletions(-) diff --git a/site/src/data/mentions.json b/site/src/data/mentions.json index cf811508..30985b77 100644 --- a/site/src/data/mentions.json +++ b/site/src/data/mentions.json @@ -1,5 +1,5 @@ { - "generated": "2026-09-13T19:38:39.127Z", + "generated": "2026-09-13T21:07:46.071Z", "mentions": [ { "port": "cxx", @@ -88,63 +88,63 @@ { "port": "cxx", "symbol": "libtmux::mcp::CallContext", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::default_tools", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::Tool", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::ToolError", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::ToolResult", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::ToolSet", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::ToolSet::call", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::ToolSet::find", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::mcp::ToolSet::tools", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, @@ -256,7 +256,7 @@ { "port": "cxx", "symbol": "libtmux::Server", - "page": "/cxx/latest/mcp/api/", + "page": "/cxx/latest/mcp/reference/", "title": "C++ MCP API", "section": "ports" }, @@ -571,22 +571,22 @@ { "port": "cxx", "symbol": "libtmux::workspace::build", - "page": "/cxx/latest/workspace/internals/api/", - "title": "C++ workspace builder API", + "page": "/cxx/latest/workspace/internals/guides/", + "title": "Develop the C++ workspace consumer", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::build", - "page": "/cxx/latest/workspace/internals/guides/", - "title": "Develop the C++ workspace consumer", + "page": "/cxx/latest/workspace/internals/topics/", + "title": "C++ workspace builder behavior", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::build", - "page": "/cxx/latest/workspace/internals/topics/", - "title": "C++ workspace builder behavior", + "page": "/cxx/latest/workspace/reference/", + "title": "C++ workspace builder API", "section": "ports" }, { @@ -599,35 +599,35 @@ { "port": "cxx", "symbol": "libtmux::workspace::BuildError", - "page": "/cxx/latest/workspace/internals/api/", - "title": "C++ workspace builder API", + "page": "/cxx/latest/workspace/internals/topics/", + "title": "C++ workspace builder behavior", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::BuildError", - "page": "/cxx/latest/workspace/internals/topics/", - "title": "C++ workspace builder behavior", + "page": "/cxx/latest/workspace/reference/", + "title": "C++ workspace builder API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::Command", - "page": "/cxx/latest/workspace/internals/api/", - "title": "C++ workspace builder API", + "page": "/cxx/latest/workspace/internals/topics/", + "title": "C++ workspace builder behavior", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::Command", - "page": "/cxx/latest/workspace/internals/topics/", - "title": "C++ workspace builder behavior", + "page": "/cxx/latest/workspace/reference/", + "title": "C++ workspace builder API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::Pane", - "page": "/cxx/latest/workspace/internals/api/", + "page": "/cxx/latest/workspace/reference/", "title": "C++ workspace builder API", "section": "ports" }, @@ -641,22 +641,22 @@ { "port": "cxx", "symbol": "libtmux::workspace::parse_tmuxp", - "page": "/cxx/latest/workspace/internals/api/", - "title": "C++ workspace builder API", + "page": "/cxx/latest/workspace/internals/guides/", + "title": "Develop the C++ workspace consumer", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::parse_tmuxp", - "page": "/cxx/latest/workspace/internals/guides/", - "title": "Develop the C++ workspace consumer", + "page": "/cxx/latest/workspace/internals/topics/", + "title": "C++ workspace builder behavior", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::parse_tmuxp", - "page": "/cxx/latest/workspace/internals/topics/", - "title": "C++ workspace builder behavior", + "page": "/cxx/latest/workspace/reference/", + "title": "C++ workspace builder API", "section": "ports" }, { @@ -676,14 +676,14 @@ { "port": "cxx", "symbol": "libtmux::workspace::ParseError::where", - "page": "/cxx/latest/workspace/internals/api/", + "page": "/cxx/latest/workspace/reference/", "title": "C++ workspace builder API", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::Window", - "page": "/cxx/latest/workspace/internals/api/", + "page": "/cxx/latest/workspace/reference/", "title": "C++ workspace builder API", "section": "ports" }, @@ -697,15 +697,15 @@ { "port": "cxx", "symbol": "libtmux::workspace::Workspace", - "page": "/cxx/latest/workspace/internals/api/", - "title": "C++ workspace builder API", + "page": "/cxx/latest/workspace/internals/topics/", + "title": "C++ workspace builder behavior", "section": "ports" }, { "port": "cxx", "symbol": "libtmux::workspace::Workspace", - "page": "/cxx/latest/workspace/internals/topics/", - "title": "C++ workspace builder behavior", + "page": "/cxx/latest/workspace/reference/", + "title": "C++ workspace builder API", "section": "ports" }, { @@ -753,49 +753,49 @@ { "port": "dotnet", "symbol": "LibTmux.Mcp.McpServerComposition.Add", - "page": "/dotnet/latest/mcp/api/", + "page": "/dotnet/latest/mcp/reference/", "title": ".NET MCP API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Mcp.McpTools.Reading", - "page": "/dotnet/latest/mcp/api/", + "page": "/dotnet/latest/mcp/reference/", "title": ".NET MCP API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Mcp.McpTools.Writing", - "page": "/dotnet/latest/mcp/api/", - "title": ".NET MCP API", + "page": "/dotnet/latest/mcp/examples/", + "title": ".NET MCP examples", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Mcp.McpTools.Writing", - "page": "/dotnet/latest/mcp/examples/", - "title": ".NET MCP examples", + "page": "/dotnet/latest/mcp/reference/", + "title": ".NET MCP API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Mcp.ReadTools", - "page": "/dotnet/latest/mcp/api/", + "page": "/dotnet/latest/mcp/reference/", "title": ".NET MCP API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Mcp.ServerPolicy", - "page": "/dotnet/latest/mcp/api/", + "page": "/dotnet/latest/mcp/reference/", "title": ".NET MCP API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Mcp.WriteTools", - "page": "/dotnet/latest/mcp/api/", + "page": "/dotnet/latest/mcp/reference/", "title": ".NET MCP API", "section": "ports" }, @@ -914,15 +914,15 @@ { "port": "dotnet", "symbol": "LibTmux.Server", - "page": "/dotnet/latest/workspace/internals/api/", - "title": ".NET workspace builder API", + "page": "/dotnet/latest/workspace/internals/examples/", + "title": ".NET workspace builder examples", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Server", - "page": "/dotnet/latest/workspace/internals/examples/", - "title": ".NET workspace builder examples", + "page": "/dotnet/latest/workspace/reference/", + "title": ".NET workspace builder API", "section": "ports" }, { @@ -1264,22 +1264,22 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness.Always", - "page": "/dotnet/latest/workspace/internals/api/", - "title": ".NET workspace builder API", + "page": "/dotnet/latest/workspace/internals/topics/", + "title": ".NET workspace builder behavior", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness.Always", - "page": "/dotnet/latest/workspace/internals/topics/", - "title": ".NET workspace builder behavior", + "page": "/dotnet/latest/workspace/reference/", + "title": ".NET workspace builder API", "section": "ports" }, { @@ -1292,15 +1292,15 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness.Auto", - "page": "/dotnet/latest/workspace/internals/api/", - "title": ".NET workspace builder API", + "page": "/dotnet/latest/workspace/internals/topics/", + "title": ".NET workspace builder behavior", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness.Auto", - "page": "/dotnet/latest/workspace/internals/topics/", - "title": ".NET workspace builder behavior", + "page": "/dotnet/latest/workspace/reference/", + "title": ".NET workspace builder API", "section": "ports" }, { @@ -1313,15 +1313,15 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness.Never", - "page": "/dotnet/latest/workspace/internals/api/", - "title": ".NET workspace builder API", + "page": "/dotnet/latest/workspace/internals/topics/", + "title": ".NET workspace builder behavior", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.PaneReadiness.Never", - "page": "/dotnet/latest/workspace/internals/topics/", - "title": ".NET workspace builder behavior", + "page": "/dotnet/latest/workspace/reference/", + "title": ".NET workspace builder API", "section": "ports" }, { @@ -1334,15 +1334,15 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceBuilder", - "page": "/dotnet/latest/workspace/internals/api/", - "title": ".NET workspace builder API", + "page": "/dotnet/latest/workspace/internals/guides/", + "title": "Use the .NET workspace builder", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceBuilder", - "page": "/dotnet/latest/workspace/internals/guides/", - "title": "Use the .NET workspace builder", + "page": "/dotnet/latest/workspace/reference/", + "title": ".NET workspace builder API", "section": "ports" }, { @@ -1355,7 +1355,7 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceBuilder.BuildAsync", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, @@ -1366,13 +1366,6 @@ "title": "Build a workspace from a file", "section": "examples" }, - { - "port": "dotnet", - "symbol": "LibTmux.Workspace.WorkspaceBuildException", - "page": "/dotnet/latest/workspace/internals/api/", - "title": ".NET workspace builder API", - "section": "ports" - }, { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceBuildException", @@ -1382,8 +1375,8 @@ }, { "port": "dotnet", - "symbol": "LibTmux.Workspace.WorkspaceBuildException.PartialResult", - "page": "/dotnet/latest/workspace/internals/api/", + "symbol": "LibTmux.Workspace.WorkspaceBuildException", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, @@ -1401,6 +1394,13 @@ "title": ".NET workspace builder behavior", "section": "ports" }, + { + "port": "dotnet", + "symbol": "LibTmux.Workspace.WorkspaceBuildException.PartialResult", + "page": "/dotnet/latest/workspace/reference/", + "title": ".NET workspace builder API", + "section": "ports" + }, { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceBuildException.PartialResult", @@ -1411,7 +1411,7 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceFile", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, @@ -1439,21 +1439,21 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceFormatException", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspacePane", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceResult", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, @@ -1474,42 +1474,42 @@ { "port": "dotnet", "symbol": "LibTmux.Workspace.WorkspaceWindow", - "page": "/dotnet/latest/workspace/internals/api/", + "page": "/dotnet/latest/workspace/reference/", "title": ".NET workspace builder API", "section": "ports" }, { "port": "go", "symbol": "mcp.AssumeResponseCommit", - "page": "/go/latest/mcp/api/", + "page": "/go/latest/mcp/reference/", "title": "Go MCP API", "section": "ports" }, { "port": "go", "symbol": "mcp.Instance", - "page": "/go/latest/mcp/api/", + "page": "/go/latest/mcp/reference/", "title": "Go MCP API", "section": "ports" }, { "port": "go", "symbol": "mcp.Instance.Connect", - "page": "/go/latest/mcp/api/", + "page": "/go/latest/mcp/reference/", "title": "Go MCP API", "section": "ports" }, { "port": "go", "symbol": "mcp.NewServer", - "page": "/go/latest/mcp/api/", + "page": "/go/latest/mcp/reference/", "title": "Go MCP API", "section": "ports" }, { "port": "go", "symbol": "mcp.Run", - "page": "/go/latest/mcp/api/", + "page": "/go/latest/mcp/reference/", "title": "Go MCP API", "section": "ports" }, @@ -1670,14 +1670,14 @@ { "port": "go", "symbol": "tmux.Server", - "page": "/go/latest/mcp/api/", + "page": "/go/latest/mcp/reference/", "title": "Go MCP API", "section": "ports" }, { "port": "go", "symbol": "tmux.Server", - "page": "/go/latest/workspace/internals/api/", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, @@ -1887,7 +1887,7 @@ { "port": "go", "symbol": "workspace.Bool", - "page": "/go/latest/workspace/internals/api/", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, @@ -1905,13 +1905,6 @@ "title": "Go workspace internals", "section": "ports" }, - { - "port": "go", - "symbol": "workspace.Build", - "page": "/go/latest/workspace/internals/api/", - "title": "Go workspace builder API", - "section": "ports" - }, { "port": "go", "symbol": "workspace.Build", @@ -1935,16 +1928,16 @@ }, { "port": "go", - "symbol": "workspace.BuildInto", - "page": "/go/latest/workspace/internals/", - "title": "Go workspace internals", + "symbol": "workspace.Build", + "page": "/go/latest/workspace/reference/", + "title": "Go workspace builder API", "section": "ports" }, { "port": "go", "symbol": "workspace.BuildInto", - "page": "/go/latest/workspace/internals/api/", - "title": "Go workspace builder API", + "page": "/go/latest/workspace/internals/", + "title": "Go workspace internals", "section": "ports" }, { @@ -1970,15 +1963,15 @@ }, { "port": "go", - "symbol": "workspace.Command", - "page": "/go/latest/workspace/internals/api/", + "symbol": "workspace.BuildInto", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, { "port": "go", - "symbol": "workspace.ErrInvalidWorkspace", - "page": "/go/latest/workspace/internals/api/", + "symbol": "workspace.Command", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, @@ -1989,10 +1982,17 @@ "title": "Go workspace builder behavior", "section": "ports" }, + { + "port": "go", + "symbol": "workspace.ErrInvalidWorkspace", + "page": "/go/latest/workspace/reference/", + "title": "Go workspace builder API", + "section": "ports" + }, { "port": "go", "symbol": "workspace.Pane", - "page": "/go/latest/workspace/internals/api/", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, @@ -2010,13 +2010,6 @@ "title": "Go workspace internals", "section": "ports" }, - { - "port": "go", - "symbol": "workspace.Parse", - "page": "/go/latest/workspace/internals/api/", - "title": "Go workspace builder API", - "section": "ports" - }, { "port": "go", "symbol": "workspace.Parse", @@ -2033,22 +2026,22 @@ }, { "port": "go", - "symbol": "workspace.Window", - "page": "/go/latest/workspace/internals/api/", + "symbol": "workspace.Parse", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, { "port": "go", - "symbol": "workspace.Workspace", - "page": "/go/latest/workspace/internals/api/", + "symbol": "workspace.Window", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, { "port": "go", - "symbol": "workspace.Workspace.InitialSessionRequest", - "page": "/go/latest/workspace/internals/api/", + "symbol": "workspace.Workspace", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, @@ -2068,8 +2061,8 @@ }, { "port": "go", - "symbol": "workspace.Workspace.MissingDirectories", - "page": "/go/latest/workspace/internals/api/", + "symbol": "workspace.Workspace.InitialSessionRequest", + "page": "/go/latest/workspace/reference/", "title": "Go workspace builder API", "section": "ports" }, @@ -2080,6 +2073,13 @@ "title": "Go workspace builder behavior", "section": "ports" }, + { + "port": "go", + "symbol": "workspace.Workspace.MissingDirectories", + "page": "/go/latest/workspace/reference/", + "title": "Go workspace builder API", + "section": "ports" + }, { "port": "java", "symbol": "io.github.libtmux.batch.Batch.Batch", @@ -2160,21 +2160,21 @@ { "port": "java", "symbol": "io.github.libtmux.mcp.TmuxMcpServer.TmuxMcpServer", - "page": "/java/latest/mcp/api/", + "page": "/java/latest/mcp/reference/", "title": "Java MCP API", "section": "ports" }, { "port": "java", "symbol": "io.github.libtmux.mcp.TmuxMcpServer.TmuxMcpServer.overStdio", - "page": "/java/latest/mcp/api/", + "page": "/java/latest/mcp/reference/", "title": "Java MCP API", "section": "ports" }, { "port": "java", "symbol": "io.github.libtmux.mcp.TmuxMcpServer.TmuxMcpServer.serving", - "page": "/java/latest/mcp/api/", + "page": "/java/latest/mcp/reference/", "title": "Java MCP API", "section": "ports" }, @@ -2321,15 +2321,15 @@ { "port": "java", "symbol": "io.github.libtmux.Server.Server", - "page": "/java/latest/workspace/internals/api/", - "title": "Java workspace builder API", + "page": "/java/latest/workspace/internals/examples/", + "title": "Java workspace builder examples", "section": "ports" }, { "port": "java", "symbol": "io.github.libtmux.Server.Server", - "page": "/java/latest/workspace/internals/examples/", - "title": "Java workspace builder examples", + "page": "/java/latest/workspace/reference/", + "title": "Java workspace builder API", "section": "ports" }, { @@ -2524,14 +2524,14 @@ { "port": "java", "symbol": "io.github.libtmux.workspace.PaneSpec.PaneSpec", - "page": "/java/latest/workspace/internals/api/", + "page": "/java/latest/workspace/reference/", "title": "Java workspace builder API", "section": "ports" }, { "port": "java", "symbol": "io.github.libtmux.workspace.WindowSpec.WindowSpec", - "page": "/java/latest/workspace/internals/api/", + "page": "/java/latest/workspace/reference/", "title": "Java workspace builder API", "section": "ports" }, @@ -2542,13 +2542,6 @@ "title": "Build a workspace from a file", "section": "examples" }, - { - "port": "java", - "symbol": "io.github.libtmux.workspace.Workspace.Workspace", - "page": "/java/latest/workspace/internals/api/", - "title": "Java workspace builder API", - "section": "ports" - }, { "port": "java", "symbol": "io.github.libtmux.workspace.Workspace.Workspace", @@ -2565,16 +2558,16 @@ }, { "port": "java", - "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder", - "page": "/java/latest/workspace/internals/", - "title": "Java workspace internals", + "symbol": "io.github.libtmux.workspace.Workspace.Workspace", + "page": "/java/latest/workspace/reference/", + "title": "Java workspace builder API", "section": "ports" }, { "port": "java", "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder", - "page": "/java/latest/workspace/internals/api/", - "title": "Java workspace builder API", + "page": "/java/latest/workspace/internals/", + "title": "Java workspace internals", "section": "ports" }, { @@ -2586,8 +2579,8 @@ }, { "port": "java", - "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder.build", - "page": "/java/latest/workspace/internals/api/", + "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder", + "page": "/java/latest/workspace/reference/", "title": "Java workspace builder API", "section": "ports" }, @@ -2607,8 +2600,8 @@ }, { "port": "java", - "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder.parse", - "page": "/java/latest/workspace/internals/api/", + "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder.build", + "page": "/java/latest/workspace/reference/", "title": "Java workspace builder API", "section": "ports" }, @@ -2621,8 +2614,8 @@ }, { "port": "java", - "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder.read", - "page": "/java/latest/workspace/internals/api/", + "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder.parse", + "page": "/java/latest/workspace/reference/", "title": "Java workspace builder API", "section": "ports" }, @@ -2640,6 +2633,13 @@ "title": "Java workspace builder behavior", "section": "ports" }, + { + "port": "java", + "symbol": "io.github.libtmux.workspace.WorkspaceBuilder.WorkspaceBuilder.read", + "page": "/java/latest/workspace/reference/", + "title": "Java workspace builder API", + "section": "ports" + }, { "port": "py", "symbol": "libtmux_mcp.models.RunCommandResult.exit_status", @@ -2678,14 +2678,14 @@ { "port": "py", "symbol": "libtmux_mcp.server.build_mcp_server", - "page": "/py/latest/mcp/api/", + "page": "/py/latest/mcp/reference/", "title": "Python MCP API", "section": "ports" }, { "port": "py", "symbol": "libtmux_mcp.server.run_server", - "page": "/py/latest/mcp/api/", + "page": "/py/latest/mcp/reference/", "title": "Python MCP API", "section": "ports" }, @@ -2895,7 +2895,7 @@ { "port": "py", "symbol": "libtmux.pane.Pane", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, @@ -3021,7 +3021,7 @@ { "port": "py", "symbol": "libtmux.server.Server", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, @@ -3168,7 +3168,7 @@ { "port": "py", "symbol": "libtmux.session.Session", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, @@ -3245,7 +3245,7 @@ { "port": "py", "symbol": "libtmux.window.Window", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, @@ -3322,105 +3322,98 @@ { "port": "py", "symbol": "tmuxp.workspace.builder.classic.ClassicWorkspaceBuilder", - "page": "/py/latest/workspace/internals/api/", - "title": "Python workspace internal API", + "page": "/py/latest/workspace/internals/topics/", + "title": "Python workspace builder behavior", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.builder.classic.ClassicWorkspaceBuilder", - "page": "/py/latest/workspace/internals/topics/", - "title": "Python workspace builder behavior", + "page": "/py/latest/workspace/reference/", + "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.builder.classic.ClassicWorkspaceBuilder.session", - "page": "/py/latest/workspace/internals/api/", - "title": "Python workspace internal API", + "page": "/py/latest/workspace/internals/examples/", + "title": "Python workspace builder example", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.builder.classic.ClassicWorkspaceBuilder.session", - "page": "/py/latest/workspace/internals/examples/", - "title": "Python workspace builder example", + "page": "/py/latest/workspace/reference/", + "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.builder.protocol.WorkspaceBuilderProtocol", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.builder.WorkspaceBuilder", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.freezer.freeze", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.freezer.inline", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.loader.expand", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.loader.trickle", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "py", "symbol": "tmuxp.workspace.validation.validate_schema", - "page": "/py/latest/workspace/internals/api/", + "page": "/py/latest/workspace/reference/", "title": "Python workspace internal API", "section": "ports" }, { "port": "rs", "symbol": "config.ConfigError", - "page": "/rs/latest/workspace/internals/api/", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, { "port": "rs", "symbol": "config.PaneConfig", - "page": "/rs/latest/workspace/internals/api/", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, { "port": "rs", "symbol": "config.WindowConfig", - "page": "/rs/latest/workspace/internals/api/", - "title": "Rust workspace builder API", - "section": "ports" - }, - { - "port": "rs", - "symbol": "config.Workspace", - "page": "/rs/latest/workspace/internals/api/", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, @@ -3440,16 +3433,16 @@ }, { "port": "rs", - "symbol": "config.Workspace.from_yaml", - "page": "/rs/latest/workspace/internals/", - "title": "Rust workspace internals", + "symbol": "config.Workspace", + "page": "/rs/latest/workspace/reference/", + "title": "Rust workspace builder API", "section": "ports" }, { "port": "rs", "symbol": "config.Workspace.from_yaml", - "page": "/rs/latest/workspace/internals/api/", - "title": "Rust workspace builder API", + "page": "/rs/latest/workspace/internals/", + "title": "Rust workspace internals", "section": "ports" }, { @@ -3466,6 +3459,13 @@ "title": "Rust workspace builder behavior", "section": "ports" }, + { + "port": "rs", + "symbol": "config.Workspace.from_yaml", + "page": "/rs/latest/workspace/reference/", + "title": "Rust workspace builder API", + "section": "ports" + }, { "port": "rs", "symbol": "config.Workspace.session_name", @@ -3476,22 +3476,22 @@ { "port": "rs", "symbol": "config.Workspace.to_yaml", - "page": "/rs/latest/workspace/internals/api/", - "title": "Rust workspace builder API", + "page": "/rs/latest/workspace/internals/guides/", + "title": "Use the Rust workspace builder", "section": "ports" }, { "port": "rs", "symbol": "config.Workspace.to_yaml", - "page": "/rs/latest/workspace/internals/guides/", - "title": "Use the Rust workspace builder", + "page": "/rs/latest/workspace/internals/topics/", + "title": "Rust workspace builder behavior", "section": "ports" }, { "port": "rs", "symbol": "config.Workspace.to_yaml", - "page": "/rs/latest/workspace/internals/topics/", - "title": "Rust workspace builder behavior", + "page": "/rs/latest/workspace/reference/", + "title": "Rust workspace builder API", "section": "ports" }, { @@ -3539,22 +3539,22 @@ { "port": "rs", "symbol": "freeze.freeze", - "page": "/rs/latest/workspace/internals/api/", - "title": "Rust workspace builder API", + "page": "/rs/latest/workspace/internals/guides/", + "title": "Use the Rust workspace builder", "section": "ports" }, { "port": "rs", "symbol": "freeze.freeze", - "page": "/rs/latest/workspace/internals/guides/", - "title": "Use the Rust workspace builder", + "page": "/rs/latest/workspace/internals/topics/", + "title": "Rust workspace builder behavior", "section": "ports" }, { "port": "rs", "symbol": "freeze.freeze", - "page": "/rs/latest/workspace/internals/topics/", - "title": "Rust workspace builder behavior", + "page": "/rs/latest/workspace/reference/", + "title": "Rust workspace builder API", "section": "ports" }, { @@ -3567,7 +3567,7 @@ { "port": "rs", "symbol": "mcp.src.TmuxTools.builder", - "page": "/rs/latest/mcp/api/", + "page": "/rs/latest/mcp/reference/", "title": "Rust MCP API", "section": "ports" }, @@ -3588,7 +3588,7 @@ { "port": "rs", "symbol": "mcp.src.TmuxTools.offered", - "page": "/rs/latest/mcp/api/", + "page": "/rs/latest/mcp/reference/", "title": "Rust MCP API", "section": "ports" }, @@ -3798,7 +3798,7 @@ { "port": "rs", "symbol": "plan.Safety", - "page": "/rs/latest/mcp/api/", + "page": "/rs/latest/mcp/reference/", "title": "Rust MCP API", "section": "ports" }, @@ -3819,15 +3819,15 @@ { "port": "rs", "symbol": "server.Server", - "page": "/rs/latest/mcp/api/", - "title": "Rust MCP API", + "page": "/rs/latest/mcp/examples/", + "title": "Rust MCP examples", "section": "ports" }, { "port": "rs", "symbol": "server.Server", - "page": "/rs/latest/mcp/examples/", - "title": "Rust MCP examples", + "page": "/rs/latest/mcp/reference/", + "title": "Rust MCP API", "section": "ports" }, { @@ -3840,7 +3840,7 @@ { "port": "rs", "symbol": "server.Server", - "page": "/rs/latest/workspace/internals/api/", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, @@ -3938,7 +3938,7 @@ { "port": "rs", "symbol": "session.Session", - "page": "/rs/latest/workspace/internals/api/", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, @@ -4015,7 +4015,7 @@ { "port": "rs", "symbol": "src.BuildError", - "page": "/rs/latest/workspace/internals/api/", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, @@ -4033,13 +4033,6 @@ "title": "Rust workspace internals", "section": "ports" }, - { - "port": "rs", - "symbol": "src.WorkspaceBuilder", - "page": "/rs/latest/workspace/internals/api/", - "title": "Rust workspace builder API", - "section": "ports" - }, { "port": "rs", "symbol": "src.WorkspaceBuilder", @@ -4049,8 +4042,8 @@ }, { "port": "rs", - "symbol": "src.WorkspaceBuilder.build", - "page": "/rs/latest/workspace/internals/api/", + "symbol": "src.WorkspaceBuilder", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, @@ -4070,8 +4063,8 @@ }, { "port": "rs", - "symbol": "src.WorkspaceBuilder.new", - "page": "/rs/latest/workspace/internals/api/", + "symbol": "src.WorkspaceBuilder.build", + "page": "/rs/latest/workspace/reference/", "title": "Rust workspace builder API", "section": "ports" }, @@ -4082,6 +4075,13 @@ "title": "Use the Rust workspace builder", "section": "ports" }, + { + "port": "rs", + "symbol": "src.WorkspaceBuilder.new", + "page": "/rs/latest/workspace/reference/", + "title": "Rust workspace builder API", + "section": "ports" + }, { "port": "rs", "symbol": "src.WorkspaceBuilder.plan", @@ -4092,22 +4092,22 @@ { "port": "rs", "symbol": "src.WorkspaceBuilder.plan", - "page": "/rs/latest/workspace/internals/api/", - "title": "Rust workspace builder API", + "page": "/rs/latest/workspace/internals/guides/", + "title": "Use the Rust workspace builder", "section": "ports" }, { "port": "rs", "symbol": "src.WorkspaceBuilder.plan", - "page": "/rs/latest/workspace/internals/guides/", - "title": "Use the Rust workspace builder", + "page": "/rs/latest/workspace/internals/topics/", + "title": "Rust workspace builder behavior", "section": "ports" }, { "port": "rs", "symbol": "src.WorkspaceBuilder.plan", - "page": "/rs/latest/workspace/internals/topics/", - "title": "Rust workspace builder behavior", + "page": "/rs/latest/workspace/reference/", + "title": "Rust workspace builder API", "section": "ports" }, { @@ -4253,14 +4253,14 @@ { "port": "swift", "symbol": "MCPRequestHandler", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "MCPService", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, @@ -4316,15 +4316,15 @@ { "port": "swift", "symbol": "PanePlan", - "page": "/swift/latest/workspace/internals/api/", - "title": "Swift workspace builder API", + "page": "/swift/latest/workspace/internals/topics/", + "title": "Swift workspace builder behavior", "section": "ports" }, { "port": "swift", "symbol": "PanePlan", - "page": "/swift/latest/workspace/internals/topics/", - "title": "Swift workspace builder behavior", + "page": "/swift/latest/workspace/reference/", + "title": "Swift workspace builder API", "section": "ports" }, { @@ -4554,22 +4554,22 @@ { "port": "swift", "symbol": "ServerConfiguration", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "Session", - "page": "/swift/latest/workspace/internals/api/", - "title": "Swift workspace builder API", + "page": "/swift/latest/workspace/internals/topics/", + "title": "Swift workspace builder behavior", "section": "ports" }, { "port": "swift", "symbol": "Session", - "page": "/swift/latest/workspace/internals/topics/", - "title": "Swift workspace builder behavior", + "page": "/swift/latest/workspace/reference/", + "title": "Swift workspace builder API", "section": "ports" }, { @@ -4631,28 +4631,28 @@ { "port": "swift", "symbol": "TmuxTools", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "TmuxTools.call(_:reporting:)", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "TmuxTools.visibleDefinitions", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "ToolAuthority", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, @@ -4666,7 +4666,7 @@ { "port": "swift", "symbol": "ToolError", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, @@ -4680,35 +4680,35 @@ { "port": "swift", "symbol": "Toolset", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "Toolset.execute", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "Toolset.inspect", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "Toolset.manage", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, { "port": "swift", "symbol": "Toolset.teardown", - "page": "/swift/latest/mcp/api/", + "page": "/swift/latest/mcp/reference/", "title": "Swift MCP API", "section": "ports" }, @@ -4736,15 +4736,15 @@ { "port": "swift", "symbol": "WindowPlan", - "page": "/swift/latest/workspace/internals/api/", - "title": "Swift workspace builder API", + "page": "/swift/latest/workspace/internals/topics/", + "title": "Swift workspace builder behavior", "section": "ports" }, { "port": "swift", "symbol": "WindowPlan", - "page": "/swift/latest/workspace/internals/topics/", - "title": "Swift workspace builder behavior", + "page": "/swift/latest/workspace/reference/", + "title": "Swift workspace builder API", "section": "ports" }, { @@ -4764,15 +4764,15 @@ { "port": "swift", "symbol": "Workspace", - "page": "/swift/latest/workspace/internals/api/", - "title": "Swift workspace builder API", + "page": "/swift/latest/workspace/internals/topics/", + "title": "Swift workspace builder behavior", "section": "ports" }, { "port": "swift", "symbol": "Workspace", - "page": "/swift/latest/workspace/internals/topics/", - "title": "Swift workspace builder behavior", + "page": "/swift/latest/workspace/reference/", + "title": "Swift workspace builder API", "section": "ports" }, { @@ -4785,21 +4785,21 @@ { "port": "swift", "symbol": "Workspace.decode(json:)", - "page": "/swift/latest/workspace/internals/api/", - "title": "Swift workspace builder API", + "page": "/swift/latest/workspace/internals/guides/", + "title": "Use the Swift workspace builder", "section": "ports" }, { "port": "swift", "symbol": "Workspace.decode(json:)", - "page": "/swift/latest/workspace/internals/guides/", - "title": "Use the Swift workspace builder", + "page": "/swift/latest/workspace/reference/", + "title": "Swift workspace builder API", "section": "ports" }, { "port": "swift", "symbol": "WorkspaceBuilder", - "page": "/swift/latest/workspace/internals/api/", + "page": "/swift/latest/workspace/reference/", "title": "Swift workspace builder API", "section": "ports" }, @@ -4820,36 +4820,36 @@ { "port": "swift", "symbol": "WorkspaceBuilder.build(_:on:)", - "page": "/swift/latest/workspace/internals/api/", + "page": "/swift/latest/workspace/reference/", "title": "Swift workspace builder API", "section": "ports" }, { "port": "swift", "symbol": "WorkspaceBuilderError", - "page": "/swift/latest/workspace/internals/api/", + "page": "/swift/latest/workspace/reference/", "title": "Swift workspace builder API", "section": "ports" }, { "port": "swift", "symbol": "WorkspaceBuilderError.rollbackFailed(original:cleanup:)", - "page": "/swift/latest/workspace/internals/api/", - "title": "Swift workspace builder API", + "page": "/swift/latest/workspace/internals/guides/", + "title": "Use the Swift workspace builder", "section": "ports" }, { "port": "swift", "symbol": "WorkspaceBuilderError.rollbackFailed(original:cleanup:)", - "page": "/swift/latest/workspace/internals/guides/", - "title": "Use the Swift workspace builder", + "page": "/swift/latest/workspace/internals/topics/", + "title": "Swift workspace builder behavior", "section": "ports" }, { "port": "swift", "symbol": "WorkspaceBuilderError.rollbackFailed(original:cleanup:)", - "page": "/swift/latest/workspace/internals/topics/", - "title": "Swift workspace builder behavior", + "page": "/swift/latest/workspace/reference/", + "title": "Swift workspace builder API", "section": "ports" }, { @@ -4876,7 +4876,7 @@ { "port": "ts", "symbol": "builder.applyWorkspace", - "page": "/ts/latest/workspace/internals/api/", + "page": "/ts/latest/workspace/reference/", "title": "TypeScript workspace builder API", "section": "ports" }, @@ -4887,13 +4887,6 @@ "title": "TypeScript workspace internals", "section": "ports" }, - { - "port": "ts", - "symbol": "builder.planWorkspace", - "page": "/ts/latest/workspace/internals/api/", - "title": "TypeScript workspace builder API", - "section": "ports" - }, { "port": "ts", "symbol": "builder.planWorkspace", @@ -4910,8 +4903,8 @@ }, { "port": "ts", - "symbol": "builder.WorkspaceApplyError", - "page": "/ts/latest/workspace/internals/api/", + "symbol": "builder.planWorkspace", + "page": "/ts/latest/workspace/reference/", "title": "TypeScript workspace builder API", "section": "ports" }, @@ -4922,6 +4915,13 @@ "title": "TypeScript workspace builder behavior", "section": "ports" }, + { + "port": "ts", + "symbol": "builder.WorkspaceApplyError", + "page": "/ts/latest/workspace/reference/", + "title": "TypeScript workspace builder API", + "section": "ports" + }, { "port": "ts", "symbol": "builder.WorkspaceApplyError.requiresReplan", @@ -4946,29 +4946,29 @@ { "port": "ts", "symbol": "config.parseWorkspace", - "page": "/ts/latest/workspace/internals/api/", - "title": "TypeScript workspace builder API", + "page": "/ts/latest/workspace/internals/guides/", + "title": "Use the TypeScript workspace builder", "section": "ports" }, { "port": "ts", "symbol": "config.parseWorkspace", - "page": "/ts/latest/workspace/internals/guides/", - "title": "Use the TypeScript workspace builder", + "page": "/ts/latest/workspace/reference/", + "title": "TypeScript workspace builder API", "section": "ports" }, { "port": "ts", "symbol": "config.parseWorkspaceYaml", - "page": "/ts/latest/workspace/internals/api/", - "title": "TypeScript workspace builder API", + "page": "/ts/latest/workspace/internals/guides/", + "title": "Use the TypeScript workspace builder", "section": "ports" }, { "port": "ts", "symbol": "config.parseWorkspaceYaml", - "page": "/ts/latest/workspace/internals/guides/", - "title": "Use the TypeScript workspace builder", + "page": "/ts/latest/workspace/reference/", + "title": "TypeScript workspace builder API", "section": "ports" }, { @@ -5023,14 +5023,14 @@ { "port": "ts", "symbol": "mcp.server.createTmuxMcpServer", - "page": "/ts/latest/mcp/api/", + "page": "/ts/latest/mcp/reference/", "title": "TypeScript MCP API", "section": "ports" }, { "port": "ts", "symbol": "mcp.server.serverFromEnvironment", - "page": "/ts/latest/mcp/api/", + "page": "/ts/latest/mcp/reference/", "title": "TypeScript MCP API", "section": "ports" }, @@ -5114,7 +5114,7 @@ { "port": "ts", "symbol": "planning.WorkspacePlan", - "page": "/ts/latest/workspace/internals/api/", + "page": "/ts/latest/workspace/reference/", "title": "TypeScript workspace builder API", "section": "ports" }, @@ -5184,15 +5184,15 @@ { "port": "ts", "symbol": "server.Server", - "page": "/ts/latest/mcp/api/", - "title": "TypeScript MCP API", + "page": "/ts/latest/mcp/examples/", + "title": "TypeScript MCP examples", "section": "ports" }, { "port": "ts", "symbol": "server.Server", - "page": "/ts/latest/mcp/examples/", - "title": "TypeScript MCP examples", + "page": "/ts/latest/mcp/reference/", + "title": "TypeScript MCP API", "section": "ports" }, { @@ -5205,15 +5205,15 @@ { "port": "ts", "symbol": "server.Server", - "page": "/ts/latest/workspace/internals/api/", - "title": "TypeScript workspace builder API", + "page": "/ts/latest/workspace/internals/examples/", + "title": "TypeScript workspace builder examples", "section": "ports" }, { "port": "ts", "symbol": "server.Server", - "page": "/ts/latest/workspace/internals/examples/", - "title": "TypeScript workspace builder examples", + "page": "/ts/latest/workspace/reference/", + "title": "TypeScript workspace builder API", "section": "ports" }, { @@ -5303,15 +5303,15 @@ { "port": "ts", "symbol": "session.Session", - "page": "/ts/latest/workspace/internals/api/", - "title": "TypeScript workspace builder API", + "page": "/ts/latest/workspace/internals/topics/", + "title": "TypeScript workspace builder behavior", "section": "ports" }, { "port": "ts", "symbol": "session.Session", - "page": "/ts/latest/workspace/internals/topics/", - "title": "TypeScript workspace builder behavior", + "page": "/ts/latest/workspace/reference/", + "title": "TypeScript workspace builder API", "section": "ports" }, { @@ -5556,79 +5556,79 @@ }, { "port": "swift", - "text": "TmuxWorkspace", - "page": "/swift/latest/workspace/internals/api/", - "line": 13, + "text": "YAMLWorkspaces", + "page": "/swift/latest/workspace/internals/examples/", + "line": 19, "why": "not defined in the stated port" }, { "port": "swift", - "text": "Sendable", - "page": "/swift/latest/workspace/internals/api/", - "line": 21, + "text": "TmuxWorkspace", + "page": "/swift/latest/workspace/internals/guides/", + "line": 13, "why": "not defined in the stated port" }, { "port": "swift", - "text": "Hashable", - "page": "/swift/latest/workspace/internals/api/", - "line": 21, + "text": "TmuxFixture", + "page": "/swift/latest/workspace/internals/guides/", + "line": 14, "why": "not defined in the stated port" }, { "port": "swift", - "text": "Codable", - "page": "/swift/latest/workspace/internals/api/", - "line": 21, + "text": "TmuxWorkspace", + "page": "/swift/latest/workspace/internals/", + "line": 33, "why": "not defined in the stated port" }, { "port": "swift", "text": "YAMLWorkspaces", - "page": "/swift/latest/workspace/internals/api/", - "line": 24, + "page": "/swift/latest/workspace/internals/", + "line": 38, "why": "not defined in the stated port" }, { "port": "swift", "text": "YAMLWorkspaces", - "page": "/swift/latest/workspace/internals/examples/", + "page": "/swift/latest/workspace/internals/topics/", "line": 19, "why": "not defined in the stated port" }, { "port": "swift", "text": "TmuxWorkspace", - "page": "/swift/latest/workspace/internals/guides/", + "page": "/swift/latest/workspace/reference/", "line": 13, "why": "not defined in the stated port" }, { "port": "swift", - "text": "TmuxFixture", - "page": "/swift/latest/workspace/internals/guides/", - "line": 14, + "text": "Sendable", + "page": "/swift/latest/workspace/reference/", + "line": 21, "why": "not defined in the stated port" }, { "port": "swift", - "text": "TmuxWorkspace", - "page": "/swift/latest/workspace/internals/", - "line": 33, + "text": "Hashable", + "page": "/swift/latest/workspace/reference/", + "line": 21, "why": "not defined in the stated port" }, { "port": "swift", - "text": "YAMLWorkspaces", - "page": "/swift/latest/workspace/internals/", - "line": 38, + "text": "Codable", + "page": "/swift/latest/workspace/reference/", + "line": 21, "why": "not defined in the stated port" }, { "port": "swift", "text": "YAMLWorkspaces", - "page": "/swift/latest/workspace/internals/topics/", - "line": 19, + "page": "/swift/latest/workspace/reference/", + "line": 24, "why": "not defined in the stated port" }, { From 0e8b78e6fe54f56c3fc4a27ab5852863a7f03f40 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:09:17 -0500 Subject: [PATCH 07/17] docs(site) Name the reference where it lives now why: Thirty-three prose links and three notes named the old path. what: - Each link is rewritten to the tree that holds that symbol: a Workspace Manager type to workspace/reference, an MCP one to mcp/reference, the rest to the core reference under the port version - The parity note and the edge-function example follow --- infra/README.md | 2 +- notes/gp-sphinx-parity.md | 20 +++++++++++-------- .../docs/ports/cxx/workspace/reference.md | 2 +- .../docs/ports/dotnet/workspace/reference.md | 10 +++++----- .../docs/ports/go/workspace/reference.md | 14 ++++++------- .../java/workspace/internals/examples.md | 2 +- .../docs/ports/java/workspace/reference.md | 8 ++++---- .../ports/py/workspace/internals/index.md | 2 +- .../docs/ports/rs/workspace/reference.md | 4 ++-- .../ports/swift/workspace/internals/guides.md | 2 +- .../ports/swift/workspace/internals/index.md | 2 +- .../docs/ports/swift/workspace/reference.md | 8 ++++---- .../docs/ports/ts/workspace/reference.md | 12 +++++------ site/src/data/mentions.json | 2 +- 14 files changed, 47 insertions(+), 43 deletions(-) diff --git a/infra/README.md b/infra/README.md index 5793de4b..cae7efb6 100644 --- a/infra/README.md +++ b/infra/README.md @@ -179,7 +179,7 @@ them and trusts the KeyValueStore lookup to miss for anything that is not one. | `/en/py/latest` | 3 | 301 to `/en/py/latest/`, never the KVS default — `parts[3]` is truthy | | `/en/py/v0.46.2` | 3 (`2` is not an asset extension) | 301 to `/en/py/v0.46.2/` | | `/en/dotnet/stable/api/libtmux.client` | 3 (`client` is not an asset extension) | 301 with a trailing slash | -| `/en/reference/py/objects.inv` | none (`inv` is an asset extension) | passes through — this is how an external Sphinx project resolves intersphinx into this site | +| `/en/py/stable/reference/objects.inv` | none (`inv` is an asset extension) | passes through — this is how an external Sphinx project resolves intersphinx into this site | | `/en/py/stable/api/.buildinfo` | none (`buildinfo` is an asset extension) | passes through; a leading dot is a separator like any other | | `/en/pagefind/pagefind.js` | none (`js` is an asset extension) | passes through | | `/en/versions.json` | none (dot excludes rule 1, `json` is an asset extension) | passes through | diff --git a/notes/gp-sphinx-parity.md b/notes/gp-sphinx-parity.md index 52956f71..0e35942a 100644 --- a/notes/gp-sphinx-parity.md +++ b/notes/gp-sphinx-parity.md @@ -1,6 +1,7 @@ # Where the reference differs from gp-sphinx, and why -The eight-port reference at `/reference/` is meant to be visually +The reference each port publishes at `///reference/` is meant +to be visually indistinguishable from gp-sphinx's rendering. It is not identical *code*, and this is the list of every place it deliberately diverges. An unrecorded difference is a defect; this file is what makes that statement checkable. @@ -25,17 +26,20 @@ That choice is why entries are `dl.py` / `dt.sig` / `dd`. The brief left the structure open, and this is the structure those rules match — also the one docutils chose, because a reference entry *is* a definition list. -## One reference per port +## One reference per package, under the version it documents -Every port's `///api/` redirects to `/reference//`, and -Python is the only exception. +Every port's `///api/` redirects to +`///reference/`, and Python is the only exception. The +Workspace Manager and the MCP server are separately versioned packages and +answer beside it, at `///workspace/reference/` and +`///mcp/reference/`. Five ports used to answer "the API" twice, in three different visual systems: Sphinx+Breathe for C++, DocC for Swift, staged Markdown for TypeScript and -.NET, and this site's own components at `/reference/`. A reader arriving at -`/cxx/stable/api/` met a page with no cards, no badges, no source links and no -prose at all, while `/reference/cxx/` had all four. Whatever else parity means, -it cannot mean two answers. +.NET, and this site's own components. A reader arriving at `/cxx/stable/api/` +met a page with no cards, no badges, no source links and no prose at all, +while this site's reference had all four. Whatever else parity means, it +cannot mean two answers. Python keeps its generated tree because `/py/stable/api/` is not a duplicate: it is gp-sphinx rendering upstream's own documentation, which is a different diff --git a/site/src/content/docs/ports/cxx/workspace/reference.md b/site/src/content/docs/ports/cxx/workspace/reference.md index 6e19dff9..77b3fcc2 100644 --- a/site/src/content/docs/ports/cxx/workspace/reference.md +++ b/site/src/content/docs/ports/cxx/workspace/reference.md @@ -43,7 +43,7 @@ to parse YAML. ## Core operations The returned session is a core libtmux value. Use the -[C++ core reference](/reference/cxx/) for subsequent inspection and mutation. +[C++ core reference](/cxx/latest/reference/) for subsequent inspection and mutation. Consumer source contracts remain the authority for the workspace types. [Workspace header](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/workspace.hpp); [YAML header](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/tmuxp.hpp). diff --git a/site/src/content/docs/ports/dotnet/workspace/reference.md b/site/src/content/docs/ports/dotnet/workspace/reference.md index 1932d4d5..0d103981 100644 --- a/site/src/content/docs/ports/dotnet/workspace/reference.md +++ b/site/src/content/docs/ports/dotnet/workspace/reference.md @@ -15,16 +15,16 @@ that uses a caller-supplied LibTmux `Server`. ## Configuration -[`WorkspaceFile`](/reference/dotnet/libtmux-workspace-workspacefile/) parses +[`WorkspaceFile`](/dotnet/latest/workspace/reference/libtmux-workspace-workspacefile/) parses YAML and holds the session description. `WorkspaceWindow` and `WorkspacePane` hold nested configuration. `WorkspaceFormatException` identifies unsupported or invalid configuration. ## Builder options -[`WorkspaceBuilder`](/reference/dotnet/libtmux-workspace-workspacebuilder/) +[`WorkspaceBuilder`](/dotnet/latest/workspace/reference/libtmux-workspace-workspacebuilder/) accepts a server, an optional positive readiness timeout, and a -[`PaneReadiness`](/reference/dotnet/libtmux-workspace-panereadiness/) policy. +[`PaneReadiness`](/dotnet/latest/workspace/reference/libtmux-workspace-panereadiness/) policy. Its `BuildAsync` accepts the configuration and an optional cancellation token. The default timeout is ten seconds. `Auto`, `Always`, and `Never` select which @@ -33,11 +33,11 @@ heuristic and its limitations. ## Results and failures -[`WorkspaceResult`](/reference/dotnet/libtmux-workspace-workspaceresult/) +[`WorkspaceResult`](/dotnet/latest/workspace/reference/libtmux-workspace-workspaceresult/) contains the created session, windows, and rejected layouts. A rejected layout does not discard its window. -[`WorkspaceBuildException`](/reference/dotnet/libtmux-workspace-workspacebuildexception/) +[`WorkspaceBuildException`](/dotnet/latest/workspace/reference/libtmux-workspace-workspacebuildexception/) keeps a `PartialResult` when state could be materialized before failure. It can be null when no such result could be read. Inspect live tmux state before retrying; a missing result does not prove that no command reached tmux. diff --git a/site/src/content/docs/ports/go/workspace/reference.md b/site/src/content/docs/ports/go/workspace/reference.md index b6366c2c..6ee20e6b 100644 --- a/site/src/content/docs/ports/go/workspace/reference.md +++ b/site/src/content/docs/ports/go/workspace/reference.md @@ -16,23 +16,23 @@ and cancellation. ## Parse configuration -[`Parse`](/reference/go/workspace-parse/) reads YAML into a -[`Workspace`](/reference/go/workspace-workspace/). Its errors match +[`Parse`](/go/latest/workspace/reference/workspace-parse/) reads YAML into a +[`Workspace`](/go/latest/workspace/reference/workspace-workspace/). Its errors match `ErrInvalidWorkspace`. Inspect the individual diagnostics to locate unknown keys or invalid values. -[`Window`](/reference/go/workspace-window/), -[`Pane`](/reference/go/workspace-pane/), and -[`Command`](/reference/go/workspace-command/) let applications construct the +[`Window`](/go/latest/workspace/reference/workspace-window/), +[`Pane`](/go/latest/workspace/reference/workspace-pane/), and +[`Command`](/go/latest/workspace/reference/workspace-command/) let applications construct the same data in Go. `Bool` preserves tmuxp's supported boolean spellings. ## Build a session -[`Build`](/reference/go/workspace-build/) creates the initial session and owns +[`Build`](/go/latest/workspace/reference/workspace-build/) creates the initial session and owns a temporary control connection for the duration of construction. It returns a session and an error; a non-nil error can accompany a partial session. -[`BuildInto`](/reference/go/workspace-buildinto/) populates a supplied session +[`BuildInto`](/go/latest/workspace/reference/workspace-buildinto/) populates a supplied session and preserves the caller's connection ownership. `Workspace.InitialSessionRequest` produces the initial request for that workflow. diff --git a/site/src/content/docs/ports/java/workspace/internals/examples.md b/site/src/content/docs/ports/java/workspace/internals/examples.md index 0f93a172..a64b577c 100644 --- a/site/src/content/docs/ports/java/workspace/internals/examples.md +++ b/site/src/content/docs/ports/java/workspace/internals/examples.md @@ -18,7 +18,7 @@ fences and runs them against real tmux. Within an application that already has a `Server`, import `Workspace` and `WorkspaceBuilder` from [`io.github.libtmux.workspace`](https://github.com/libtmux/libtmux-java/tree/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/src/main/java/io/github/libtmux/workspace), and `Session` from -[`io.github.libtmux`](/reference/java/). This excerpt uses the same configuration as the module's +[`io.github.libtmux`](/java/latest/reference/). This excerpt uses the same configuration as the module's result example: ```java diff --git a/site/src/content/docs/ports/java/workspace/reference.md b/site/src/content/docs/ports/java/workspace/reference.md index 069fc4d6..fe83c880 100644 --- a/site/src/content/docs/ports/java/workspace/reference.md +++ b/site/src/content/docs/ports/java/workspace/reference.md @@ -16,7 +16,7 @@ before building through a core `Server`. ## Builder facade -[`WorkspaceBuilder`](/reference/java/io-github-libtmux-workspace-workspacebuilder-workspacebuilder/) +[`WorkspaceBuilder`](/java/latest/workspace/reference/io-github-libtmux-workspace-workspacebuilder-workspacebuilder/) provides three static entry points: - `read(Path)` reads a YAML file and wraps I/O errors in `UncheckedIOException`. @@ -28,11 +28,11 @@ server's support for the requested layout. ## Configuration records -[`Workspace`](/reference/java/io-github-libtmux-workspace-workspace-workspace/) +[`Workspace`](/java/latest/workspace/reference/io-github-libtmux-workspace-workspace-workspace/) holds the session name and ordered windows. -[`WindowSpec`](/reference/java/io-github-libtmux-workspace-windowspec-windowspec/) +[`WindowSpec`](/java/latest/workspace/reference/io-github-libtmux-workspace-windowspec-windowspec/) holds the name, optional layout, and panes. -[`PaneSpec`](/reference/java/io-github-libtmux-workspace-panespec-panespec/) +[`PaneSpec`](/java/latest/workspace/reference/io-github-libtmux-workspace-panespec-panespec/) holds the ordered shell commands. These records copy their lists so later changes to an input list do not alter diff --git a/site/src/content/docs/ports/py/workspace/internals/index.md b/site/src/content/docs/ports/py/workspace/internals/index.md index fe171429..cc6266af 100644 --- a/site/src/content/docs/ports/py/workspace/internals/index.md +++ b/site/src/content/docs/ports/py/workspace/internals/index.md @@ -28,4 +28,4 @@ attachment or client switching. The upstream [Internals documentation](https://tmuxp.git-pull.com/internals/) contains the full architecture and module reference. Use the -[libtmux Python API](/reference/py/) for general tmux programming. +[libtmux Python API](/py/stable/reference/) for general tmux programming. diff --git a/site/src/content/docs/ports/rs/workspace/reference.md b/site/src/content/docs/ports/rs/workspace/reference.md index c652f48f..a759b739 100644 --- a/site/src/content/docs/ports/rs/workspace/reference.md +++ b/site/src/content/docs/ports/rs/workspace/reference.md @@ -16,14 +16,14 @@ for actual tmux operations. ## Configuration -[`Workspace`](/reference/rs/config-workspace/) holds the session description. +[`Workspace`](/rs/latest/workspace/reference/config-workspace/) holds the session description. `Workspace::from_yaml` parses it, and `to_yaml` emits its YAML representation. `WindowConfig` and `PaneConfig` describe the nested objects; `ConfigError` identifies invalid configuration. ## Builder -[`WorkspaceBuilder`](/reference/rs/src-workspacebuilder/) borrows a `Server`. +[`WorkspaceBuilder`](/rs/latest/workspace/reference/src-workspacebuilder/) borrows a `Server`. `new` selects that server, `plan` returns the inert construction plan, and `build` asynchronously creates the requested session. Keep the server alive for the builder's lifetime. diff --git a/site/src/content/docs/ports/swift/workspace/internals/guides.md b/site/src/content/docs/ports/swift/workspace/internals/guides.md index c4aa6e44..7dd6be2b 100644 --- a/site/src/content/docs/ports/swift/workspace/internals/guides.md +++ b/site/src/content/docs/ports/swift/workspace/internals/guides.md @@ -10,7 +10,7 @@ sidebar: tableOfContents: true --- -Add `TmuxWorkspace` and [`LibTmux`](/reference/swift/) to a SwiftPM target. This isolated example +Add `TmuxWorkspace` and [`LibTmux`](/swift/latest/reference/) to a SwiftPM target. This isolated example also uses the public `TmuxFixture` product for server startup and cleanup. The following dependency selects the source revision used by these examples: diff --git a/site/src/content/docs/ports/swift/workspace/internals/index.md b/site/src/content/docs/ports/swift/workspace/internals/index.md index b59117ee..a7e2f2d1 100644 --- a/site/src/content/docs/ports/swift/workspace/internals/index.md +++ b/site/src/content/docs/ports/swift/workspace/internals/index.md @@ -32,7 +32,7 @@ handling, and attachment. `TmuxWorkspace` builds a tmux session from Swift values or a [tmuxp](https://tmuxp.git-pull.com)-style configuration. It is a SwiftPM -library product beside the core [`LibTmux`](/reference/swift/) product. +library product beside the core [`LibTmux`](/swift/latest/reference/) product. Swift and JSON descriptions work without a YAML dependency. Enable the `YAMLWorkspaces` package trait to add YAML decoding. Building uses the same diff --git a/site/src/content/docs/ports/swift/workspace/reference.md b/site/src/content/docs/ports/swift/workspace/reference.md index f9d28559..8cb7f98d 100644 --- a/site/src/content/docs/ports/swift/workspace/reference.md +++ b/site/src/content/docs/ports/swift/workspace/reference.md @@ -10,12 +10,12 @@ sidebar: tableOfContents: true --- -Import `TmuxWorkspace` for the configuration and builder, and [`LibTmux`](/reference/swift/) for +Import `TmuxWorkspace` for the configuration and builder, and [`LibTmux`](/swift/latest/reference/) for the server and returned session value. ## Configuration values -[`Workspace`](/reference/swift/workspace/) contains the session name, optional +[`Workspace`](/swift/latest/workspace/reference/workspace/) contains the session name, optional working directory, and ordered windows. `WindowPlan` contains its name, directory, layout, and panes. `PanePlan` contains its directory and commands. The values conform to `Sendable`, `Hashable`, and `Codable`. @@ -26,14 +26,14 @@ existing description; it does not query tmux for a live export. ## Builder -[`WorkspaceBuilder`](/reference/swift/workspacebuilder/) exposes the async +[`WorkspaceBuilder`](/swift/latest/workspace/reference/workspacebuilder/) exposes the async `build(_:on:)` operation. It creates a new session on the supplied server and returns a `Session`. Keep using the server for live observation; session properties do not refresh themselves. ## Typed errors -[`WorkspaceBuilderError`](/reference/swift/workspacebuildererror/) distinguishes +[`WorkspaceBuilderError`](/swift/latest/workspace/reference/workspacebuildererror/) distinguishes an empty window list, an existing session name, a vanished session, underlying tmux errors, and failure of rollback. diff --git a/site/src/content/docs/ports/ts/workspace/reference.md b/site/src/content/docs/ports/ts/workspace/reference.md index 523a0beb..5f3d13bf 100644 --- a/site/src/content/docs/ports/ts/workspace/reference.md +++ b/site/src/content/docs/ports/ts/workspace/reference.md @@ -17,26 +17,26 @@ not choose a workspace or apply one automatically. ## Parse and validate -[`parseWorkspace`](/reference/ts/config-parseworkspace/) validates data already +[`parseWorkspace`](/ts/latest/workspace/reference/config-parseworkspace/) validates data already read by your application. -[`parseWorkspaceYaml`](/reference/ts/config-parseworkspaceyaml/) +[`parseWorkspaceYaml`](/ts/latest/workspace/reference/config-parseworkspaceyaml/) adds Bun's YAML parsing. Both produce the workspace configuration consumed by the builder. ## Plan and apply -[`planWorkspace`](/reference/ts/builder-planworkspace/) returns a description -of membership changes. [`WorkspacePlan`](/reference/ts/planning-workspaceplan/) +[`planWorkspace`](/ts/latest/workspace/reference/builder-planworkspace/) returns a description +of membership changes. [`WorkspacePlan`](/ts/latest/workspace/reference/planning-workspaceplan/) records creations, removals, renames, and retained surplus. -[`applyWorkspace`](/reference/ts/builder-applyworkspace/) performs the work and +[`applyWorkspace`](/ts/latest/workspace/reference/builder-applyworkspace/) performs the work and resolves to the resulting `Session`. Its options control pruning and whether commands run in existing panes. Planning accepts pruning policy; command policy belongs to application. ## Handle failure -[`WorkspaceApplyError`](/reference/ts/builder-workspaceapplyerror/) preserves +[`WorkspaceApplyError`](/ts/latest/workspace/reference/builder-workspaceapplyerror/) preserves the cause and completed milestones. Reinspect tmux before retrying; the error is not a transaction log of every effect or a receipt for shell commands. diff --git a/site/src/data/mentions.json b/site/src/data/mentions.json index 30985b77..419484db 100644 --- a/site/src/data/mentions.json +++ b/site/src/data/mentions.json @@ -1,5 +1,5 @@ { - "generated": "2026-09-13T21:07:46.071Z", + "generated": "2026-09-13T21:09:17.426Z", "mentions": [ { "port": "cxx", From e664e5fd3b37820ab99a0961e3b229e22c7e3e24 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:14:30 -0500 Subject: [PATCH 08/17] fix(reference) Root a prose reference link once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit why: The plugin added the site root to an href the injected builders had already rooted, so every module link read /en/en/… -- 320 broken links from prose. Twenty-four pages also pointed at ./api/, the product page that became a reference of its own. what: - Only the package default, which carries no root, gets one added - The relative prose links follow the product reference out of Internals --- site/src/content/docs/ports/cxx/mcp/index.md | 2 +- site/src/content/docs/ports/cxx/mcp/reference.md | 2 +- site/src/content/docs/ports/cxx/workspace/index.md | 2 +- .../src/content/docs/ports/cxx/workspace/internals/index.md | 2 +- site/src/content/docs/ports/dotnet/mcp/index.md | 2 +- site/src/content/docs/ports/dotnet/mcp/reference.md | 2 +- site/src/content/docs/ports/dotnet/workspace/index.md | 2 +- .../content/docs/ports/dotnet/workspace/internals/index.md | 2 +- site/src/content/docs/ports/go/mcp/index.md | 2 +- site/src/content/docs/ports/go/mcp/reference.md | 2 +- site/src/content/docs/ports/go/workspace/index.md | 2 +- site/src/content/docs/ports/go/workspace/internals/index.md | 2 +- site/src/content/docs/ports/java/mcp/index.md | 2 +- site/src/content/docs/ports/java/mcp/reference.md | 2 +- site/src/content/docs/ports/java/workspace/index.md | 2 +- .../content/docs/ports/java/workspace/internals/index.md | 2 +- site/src/content/docs/ports/py/mcp/index.md | 2 +- site/src/content/docs/ports/py/mcp/reference.md | 2 +- site/src/content/docs/ports/py/workspace/internals/index.md | 2 +- .../src/content/docs/ports/py/workspace/internals/topics.md | 2 +- site/src/content/docs/ports/rs/mcp/index.md | 2 +- site/src/content/docs/ports/rs/mcp/reference.md | 2 +- site/src/content/docs/ports/rs/workspace/index.md | 2 +- site/src/content/docs/ports/rs/workspace/internals/index.md | 2 +- site/src/content/docs/ports/swift/mcp/index.md | 2 +- site/src/content/docs/ports/swift/mcp/reference.md | 2 +- site/src/content/docs/ports/swift/workspace/index.md | 2 +- .../content/docs/ports/swift/workspace/internals/index.md | 2 +- site/src/content/docs/ports/ts/mcp/index.md | 2 +- site/src/content/docs/ports/ts/mcp/reference.md | 2 +- site/src/content/docs/ports/ts/workspace/index.md | 2 +- site/src/content/docs/ports/ts/workspace/internals/index.md | 2 +- site/src/data/mentions.json | 2 +- site/src/plugins/rehype-api-links.ts | 6 ++++-- 34 files changed, 37 insertions(+), 35 deletions(-) diff --git a/site/src/content/docs/ports/cxx/mcp/index.md b/site/src/content/docs/ports/cxx/mcp/index.md index 25c12a5d..b0662d98 100644 --- a/site/src/content/docs/ports/cxx/mcp/index.md +++ b/site/src/content/docs/ports/cxx/mcp/index.md @@ -23,7 +23,7 @@ hierarchy discovery only. - [Guides](./guides/) build the executable and select an endpoint. - [Topics](./topics/) explain platform coverage, identifiers, and failures. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The server offers tools only. It does not offer resources, prompts, subscriptions, or configurable toolsets. diff --git a/site/src/content/docs/ports/cxx/mcp/reference.md b/site/src/content/docs/ports/cxx/mcp/reference.md index 07bb446e..82c42ce9 100644 --- a/site/src/content/docs/ports/cxx/mcp/reference.md +++ b/site/src/content/docs/ports/cxx/mcp/reference.md @@ -41,5 +41,5 @@ JSON text. Strict argument validation precedes tmux execution. [Protocol tests](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/apps/mcp/tests/protocol_test.cpp) cover supported lifecycle revisions and result shapes. -[Workspace builder API](../../workspace/internals/api/) documents a separate source +[Workspace builder API](../../workspace/reference/) documents a separate source consumer; it is not a workspace operation in this MCP catalog. diff --git a/site/src/content/docs/ports/cxx/workspace/index.md b/site/src/content/docs/ports/cxx/workspace/index.md index 79342d41..0ca18c44 100644 --- a/site/src/content/docs/ports/cxx/workspace/index.md +++ b/site/src/content/docs/ports/cxx/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/cxx/workspace/internals/index.md b/site/src/content/docs/ports/cxx/workspace/internals/index.md index 487bed0e..d1821c94 100644 --- a/site/src/content/docs/ports/cxx/workspace/internals/index.md +++ b/site/src/content/docs/ports/cxx/workspace/internals/index.md @@ -26,7 +26,7 @@ builder tests; they do not load workspace files as a user application. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/content/docs/ports/dotnet/mcp/index.md b/site/src/content/docs/ports/dotnet/mcp/index.md index 882425ee..b695a17f 100644 --- a/site/src/content/docs/ports/dotnet/mcp/index.md +++ b/site/src/content/docs/ports/dotnet/mcp/index.md @@ -23,7 +23,7 @@ Its registered operations use the `tmux_` prefix, including - [Guides](./guides/) install the tool and choose a socket. - [Topics](./topics/) explain tiers, result limits, jobs, and subscriptions. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The default surface tier is `mutating`. Dedicated removal requires `destructive`; `readonly` omits writing tools. diff --git a/site/src/content/docs/ports/dotnet/mcp/reference.md b/site/src/content/docs/ports/dotnet/mcp/reference.md index 2c82df99..ca8e995b 100644 --- a/site/src/content/docs/ports/dotnet/mcp/reference.md +++ b/site/src/content/docs/ports/dotnet/mcp/reference.md @@ -43,4 +43,4 @@ and pane content. Prompts include `tmux_run_and_report`, [Protocol behavior](https://github.com/libtmux/libtmux-dotnet/blob/6656a563ec9e07ab52e0c3ac96f7704fc94cc0c0/docs/mcp/README.md). For a published configuration library, use -[Workspace builder API](../../workspace/internals/api/). +[Workspace builder API](../../workspace/reference/). diff --git a/site/src/content/docs/ports/dotnet/workspace/index.md b/site/src/content/docs/ports/dotnet/workspace/index.md index 0276bfdc..707c1e24 100644 --- a/site/src/content/docs/ports/dotnet/workspace/index.md +++ b/site/src/content/docs/ports/dotnet/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/dotnet/workspace/internals/index.md b/site/src/content/docs/ports/dotnet/workspace/internals/index.md index 8a2ddc45..f6e763c3 100644 --- a/site/src/content/docs/ports/dotnet/workspace/internals/index.md +++ b/site/src/content/docs/ports/dotnet/workspace/internals/index.md @@ -26,7 +26,7 @@ command-line handling, attachment, and server lifetime. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/content/docs/ports/go/mcp/index.md b/site/src/content/docs/ports/go/mcp/index.md index 7cd85f8f..9f04eaf6 100644 --- a/site/src/content/docs/ports/go/mcp/index.md +++ b/site/src/content/docs/ports/go/mcp/index.md @@ -25,7 +25,7 @@ capabilities. - [Guides](./guides/) install the command and diagnose its connection. - [Topics](./topics/) explain capabilities, operation ceilings, and jobs. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The server includes resources, subscriptions, prompts, and a `build_workspace` tool backed by the diff --git a/site/src/content/docs/ports/go/mcp/reference.md b/site/src/content/docs/ports/go/mcp/reference.md index f5478a86..fca2c265 100644 --- a/site/src/content/docs/ports/go/mcp/reference.md +++ b/site/src/content/docs/ports/go/mcp/reference.md @@ -38,7 +38,7 @@ and the operation ceiling filter both listing and invocation. Resources expose metadata and content with their corresponding capability gates. Prompts provide workflow recipes. `build_workspace` uses the -separate [workspace module](../../workspace/internals/api/). +separate [workspace module](../../workspace/reference/). [Server registration](https://github.com/libtmux/libtmux-go/blob/5f808882015a975a65acc7f9da5b3ff0d5cbdc91/mcp/server.go) and [agent example](../examples/) connect the language and protocol APIs. diff --git a/site/src/content/docs/ports/go/workspace/index.md b/site/src/content/docs/ports/go/workspace/index.md index 28d8bd6e..bb5d1d77 100644 --- a/site/src/content/docs/ports/go/workspace/index.md +++ b/site/src/content/docs/ports/go/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/go/workspace/internals/index.md b/site/src/content/docs/ports/go/workspace/internals/index.md index 85962ce8..19cd95c2 100644 --- a/site/src/content/docs/ports/go/workspace/internals/index.md +++ b/site/src/content/docs/ports/go/workspace/internals/index.md @@ -26,7 +26,7 @@ reading, deadlines, command-line handling, and attachment. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/content/docs/ports/java/mcp/index.md b/site/src/content/docs/ports/java/mcp/index.md index 29db25b8..6cf5d442 100644 --- a/site/src/content/docs/ports/java/mcp/index.md +++ b/site/src/content/docs/ports/java/mcp/index.md @@ -24,7 +24,7 @@ toolsets at startup. It serves MCP over stdin and stdout. - [Guides](./guides/) build the launcher and connect a client. - [Topics](./topics/) explain toolsets, input preflight, and wait semantics. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The only MCP resource is the static `tmux://capabilities` report. The server does not register workflow prompts or dynamic resource diff --git a/site/src/content/docs/ports/java/mcp/reference.md b/site/src/content/docs/ports/java/mcp/reference.md index e5a10263..37dc816d 100644 --- a/site/src/content/docs/ports/java/mcp/reference.md +++ b/site/src/content/docs/ports/java/mcp/reference.md @@ -41,6 +41,6 @@ It reports tool selection, connection provenance, and capability declarations. The server does not register prompts or dynamic hierarchy subscriptions. -Use the [Workspace builder API](../../workspace/internals/api/) for declarative +Use the [Workspace builder API](../../workspace/reference/) for declarative configuration. It is a separate Java library and has no corresponding workspace-file MCP route. diff --git a/site/src/content/docs/ports/java/workspace/index.md b/site/src/content/docs/ports/java/workspace/index.md index 9eb7e273..1e3c2e71 100644 --- a/site/src/content/docs/ports/java/workspace/index.md +++ b/site/src/content/docs/ports/java/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/java/workspace/internals/index.md b/site/src/content/docs/ports/java/workspace/internals/index.md index 387b4c18..0272278a 100644 --- a/site/src/content/docs/ports/java/workspace/internals/index.md +++ b/site/src/content/docs/ports/java/workspace/internals/index.md @@ -26,7 +26,7 @@ command-line handling, attachment, and the server connection. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/content/docs/ports/py/mcp/index.md b/site/src/content/docs/ports/py/mcp/index.md index 141beb59..1e0dbea3 100644 --- a/site/src/content/docs/ports/py/mcp/index.md +++ b/site/src/content/docs/ports/py/mcp/index.md @@ -23,7 +23,7 @@ and `execute`; deletion tools require an explicit selection. - [Guides](./guides/) connect a client and select a tmux socket. - [Topics](./topics/) explain toolsets, trust, waiting, and caller context. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. For declarative session configuration, use the [Workspace Manager](../workspace/), provided by the separate `tmuxp` diff --git a/site/src/content/docs/ports/py/mcp/reference.md b/site/src/content/docs/ports/py/mcp/reference.md index 2c23ecbd..b931f6bb 100644 --- a/site/src/content/docs/ports/py/mcp/reference.md +++ b/site/src/content/docs/ports/py/mcp/reference.md @@ -42,5 +42,5 @@ their existence does not make them separate MCP tools. - [Registration source](https://github.com/tmux-python/libtmux-mcp/blob/v0.1.0a22/src/libtmux_mcp/server.py) Use [Examples](../examples/) to inspect the protocol with an in-process -client. Use the [Workspace builder API](../../workspace/internals/api/) for tmuxp +client. Use the [Workspace builder API](../../workspace/reference/) for tmuxp configuration and builders. diff --git a/site/src/content/docs/ports/py/workspace/internals/index.md b/site/src/content/docs/ports/py/workspace/internals/index.md index cc6266af..ddcaaf93 100644 --- a/site/src/content/docs/ports/py/workspace/internals/index.md +++ b/site/src/content/docs/ports/py/workspace/internals/index.md @@ -24,7 +24,7 @@ attachment or client switching. - [Topics](./topics/) explain the loader pipeline and builder extension points. - [Examples](./examples/) show expansion and building on an isolated server. -- [API](./api/) links the internal loading, building, and freezing interfaces. +- [API](../reference/) links the internal loading, building, and freezing interfaces. The upstream [Internals documentation](https://tmuxp.git-pull.com/internals/) contains the full architecture and module reference. Use the diff --git a/site/src/content/docs/ports/py/workspace/internals/topics.md b/site/src/content/docs/ports/py/workspace/internals/topics.md index 5a849391..3d997408 100644 --- a/site/src/content/docs/ports/py/workspace/internals/topics.md +++ b/site/src/content/docs/ports/py/workspace/internals/topics.md @@ -34,6 +34,6 @@ build does not have universal transactional rollback. The CLI owns its existing-session prompts and the attachment or client-switching workflow. See the upstream [custom builder guide](https://tmuxp.git-pull.com/topics/custom-workspace-builders/) -for extension configuration and the [API](../api/) for interface contracts. +for extension configuration and the [API](../reference/) for interface contracts. [Configuration loader](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [Classic builder](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py). diff --git a/site/src/content/docs/ports/rs/mcp/index.md b/site/src/content/docs/ports/rs/mcp/index.md index d76e4a8a..bfca5808 100644 --- a/site/src/content/docs/ports/rs/mcp/index.md +++ b/site/src/content/docs/ports/rs/mcp/index.md @@ -23,7 +23,7 @@ includes shell commands and terminal input. - [Guides](./guides/) install the executable and choose a socket. - [Topics](./topics/) explain tiers, live-stream effects, and job lifetimes. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The Rust [Workspace Manager](../workspace/) is a separate crate. MCP's `run_plan` executes typed operations; it is not the workspace crate's diff --git a/site/src/content/docs/ports/rs/mcp/reference.md b/site/src/content/docs/ports/rs/mcp/reference.md index 671a147a..d3917d5f 100644 --- a/site/src/content/docs/ports/rs/mcp/reference.md +++ b/site/src/content/docs/ports/rs/mcp/reference.md @@ -38,7 +38,7 @@ for individual objects and pane content. Prompts depend on the selected tier. MCP `run_plan` uses the core operation-plan model. -[Workspace builder API](../../workspace/internals/api/) describes the separate +[Workspace builder API](../../workspace/reference/) describes the separate workspace parser, builder, and live-session export. [Crate source and examples](https://github.com/libtmux/libtmux-rs/tree/9331cdf556ea7a1f2589e9c3e6cece6ccdc7765c/crates/tmux-mcp). diff --git a/site/src/content/docs/ports/rs/workspace/index.md b/site/src/content/docs/ports/rs/workspace/index.md index 4136cd2a..db15b036 100644 --- a/site/src/content/docs/ports/rs/workspace/index.md +++ b/site/src/content/docs/ports/rs/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/rs/workspace/internals/index.md b/site/src/content/docs/ports/rs/workspace/internals/index.md index 0f243e92..9c98018d 100644 --- a/site/src/content/docs/ports/rs/workspace/internals/index.md +++ b/site/src/content/docs/ports/rs/workspace/internals/index.md @@ -26,7 +26,7 @@ reading, the async runtime, command-line handling, and attachment. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/content/docs/ports/swift/mcp/index.md b/site/src/content/docs/ports/swift/mcp/index.md index 4a037eaf..a79c5f39 100644 --- a/site/src/content/docs/ports/swift/mcp/index.md +++ b/site/src/content/docs/ports/swift/mcp/index.md @@ -25,7 +25,7 @@ tmux is required at runtime. - [Guides](./guides/) build the executable and configure its environment. - [Topics](./topics/) explain tiers, exact tool selection, and opaque targets. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The default tier is readonly. Writing tools need explicit opt-in. Resources expose snapshots, sessions, filter vocabulary, and pane content; diff --git a/site/src/content/docs/ports/swift/mcp/reference.md b/site/src/content/docs/ports/swift/mcp/reference.md index 3673facf..c39b1467 100644 --- a/site/src/content/docs/ports/swift/mcp/reference.md +++ b/site/src/content/docs/ports/swift/mcp/reference.md @@ -45,5 +45,5 @@ Prompts include `run_and_wait`, `watch_until_ready`, [Resource source](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/Sources/LibTmuxMCP/Resources.swift) and [prompt source](https://github.com/libtmux/libtmux-swift/blob/f02a4668570e1cc5198c941413750e021f42c214/Sources/LibTmuxMCP/Prompts.swift). -The [Workspace builder API](../../workspace/internals/api/) owns workspace decoding +The [Workspace builder API](../../workspace/reference/) owns workspace decoding and construction. `apply_workspace` exposes that behavior over MCP. diff --git a/site/src/content/docs/ports/swift/workspace/index.md b/site/src/content/docs/ports/swift/workspace/index.md index fc64a551..10906a92 100644 --- a/site/src/content/docs/ports/swift/workspace/index.md +++ b/site/src/content/docs/ports/swift/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/swift/workspace/internals/index.md b/site/src/content/docs/ports/swift/workspace/internals/index.md index a7e2f2d1..af224c70 100644 --- a/site/src/content/docs/ports/swift/workspace/internals/index.md +++ b/site/src/content/docs/ports/swift/workspace/internals/index.md @@ -26,7 +26,7 @@ handling, and attachment. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/content/docs/ports/ts/mcp/index.md b/site/src/content/docs/ports/ts/mcp/index.md index f761426a..d187a7ea 100644 --- a/site/src/content/docs/ports/ts/mcp/index.md +++ b/site/src/content/docs/ports/ts/mcp/index.md @@ -23,7 +23,7 @@ macOS artifact checks do not establish runtime support. - [Guides](./guides/) install and connect a client. - [Topics](./topics/) explain toolsets, socket provenance, and waiting. - [Examples](./examples/) call a tool, then explore server internals. -- [Language API](./api/) documents embedding and implementation types. +- [Language API](./reference/) documents embedding and implementation types. The server exposes a static `tmux://capabilities` resource. It does not register workflow prompts or dynamic hierarchy resources. diff --git a/site/src/content/docs/ports/ts/mcp/reference.md b/site/src/content/docs/ports/ts/mcp/reference.md index 2551d14a..000cef9b 100644 --- a/site/src/content/docs/ports/ts/mcp/reference.md +++ b/site/src/content/docs/ports/ts/mcp/reference.md @@ -45,4 +45,4 @@ hierarchy-resource subscriptions. [Resource registration](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/mcp/src/resources.ts). Workspace parsing and application belong to -[`@libtmux/workspace`](../../workspace/internals/api/), not to a workspace MCP tool. +[`@libtmux/workspace`](../../workspace/reference/), not to a workspace MCP tool. diff --git a/site/src/content/docs/ports/ts/workspace/index.md b/site/src/content/docs/ports/ts/workspace/index.md index 806067d2..e3e5650c 100644 --- a/site/src/content/docs/ports/ts/workspace/index.md +++ b/site/src/content/docs/ports/ts/workspace/index.md @@ -27,4 +27,4 @@ The [Internals](./internals/) section documents the current builder: - [Guides](./internals/guides/) show application setup and builder calls. - [Topics](./internals/topics/) explain supported configuration and behavior. - [Examples](./internals/examples/) exercise the library or source consumer. -- [API](./internals/api/) covers the builder and configuration interfaces. +- [API](./reference/) covers the builder and configuration interfaces. diff --git a/site/src/content/docs/ports/ts/workspace/internals/index.md b/site/src/content/docs/ports/ts/workspace/internals/index.md index 4d4e0ac8..d91e6e12 100644 --- a/site/src/content/docs/ports/ts/workspace/internals/index.md +++ b/site/src/content/docs/ports/ts/workspace/internals/index.md @@ -26,7 +26,7 @@ command-line handling, attachment, and application lifetime. - [Guides](./guides/) show builder setup and application code. - [Topics](./topics/) explain configuration, behavior, and failures. - [Examples](./examples/) exercise the builder through the language API. -- [API](./api/) links the configuration and construction interfaces. +- [API](../reference/) links the configuration and construction interfaces. ## Implementation scope diff --git a/site/src/data/mentions.json b/site/src/data/mentions.json index 419484db..c156fbcd 100644 --- a/site/src/data/mentions.json +++ b/site/src/data/mentions.json @@ -1,5 +1,5 @@ { - "generated": "2026-09-13T21:09:17.426Z", + "generated": "2026-09-13T21:14:30.938Z", "mentions": [ { "port": "cxx", diff --git a/site/src/plugins/rehype-api-links.ts b/site/src/plugins/rehype-api-links.ts index 3535fb11..6ad75ccf 100644 --- a/site/src/plugins/rehype-api-links.ts +++ b/site/src/plugins/rehype-api-links.ts @@ -255,8 +255,10 @@ export function rehypeApiLinks() { // Every reference link goes through productApiHref: it knows which of // the three trees a symbol belongs to and which version of the target // port publishes it. `d.href` survives only for what is not a symbol - // page — a federated inventory hit, or a module index. - let href = withPortRoot(d.href) + // page — a federated inventory hit, or a module index — and the + // builders this plugin supplies already carry the site root, so only a + // bare path from the package's own default needs one. + let href = d.href.startsWith('/reference/') ? withPortRoot(d.href) : d.href if (!d.external) { const res = r.resolve(d.port, text, ctx.product) if ('symbol' in res) href = productApiHref(API_MODELS[d.port], res.symbol, versionOf(d.port)) From d161856b68741922a29cdf2fc9f9d8ab395adcd8 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:20:41 -0500 Subject: [PATCH 09/17] fix(reference) Give every prose linker the same reference builder why: ProseText resolved a mention through api-model and rooted the unversioned default, so a port landing page linked six symbols at the old path. Ten prose links and one component still named ../api/. what: - ProseText injects the same symbolHref and moduleHref the rehype plugin does, so both spell a reference URL one way - The MCP tool page and the last relative links point at the reference beside them --- site/src/components/ProseText.astro | 16 ++++++++++++++-- site/src/components/mcp/ToolReference.astro | 2 +- .../docs/ports/py/workspace/internals/topics.md | 2 +- .../content/docs/ports/ts/workspace/reference.md | 2 +- site/src/data/mentions.json | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/site/src/components/ProseText.astro b/site/src/components/ProseText.astro index 0735bc79..9d445674 100644 --- a/site/src/components/ProseText.astro +++ b/site/src/components/ProseText.astro @@ -1,5 +1,8 @@ --- import { decideMention, notASymbol } from '@libtmux/api-model' +import { productApiHref } from '../lib/product-api' +import { PORT_BY_SLUG, referenceUrl } from '../lib/ports' +import { defaultVersionFor } from '../lib/versions' import { getResolver } from '../lib/prose-resolver' import { API_MODELS } from '../lib/api-models' import { withPortRoot } from '../lib/site-root' @@ -41,13 +44,22 @@ const segments = text.split(/`([^`]+)`/).map((value, i) => ({ const resolved = segments.map((seg) => { if (!seg.code || notASymbol(seg.value)) return { ...seg, href: undefined, title: undefined } - const d = decideMention(seg.value, { pagePort: port }, resolver, API_MODELS) + const d = decideMention(seg.value, { + pagePort: port, + // The same builders the rehype plugin injects: a reference URL carries a + // port, a version and a package, none of which api-model can know. + symbolHref: (target, symbol) => productApiHref(API_MODELS[target], symbol, defaultVersionFor(target)), + moduleHref: (target, module) => { + const meta = PORT_BY_SLUG[target] + return meta ? `${referenceUrl(meta, defaultVersionFor(target))}#${module}` : `#${module}` + }, + }, resolver, API_MODELS) if (d.kind !== 'link') return { ...seg, href: undefined, title: undefined } return { ...seg, // withPortRoot, as in rehype-api-links: an internal mention resolves // into the reference, which is not built per locale. - href: d.external ? d.href : withPortRoot(d.href), + href: d.external || !d.href.startsWith('/reference/') ? d.href : withPortRoot(d.href), title: d.title, external: d.external, } diff --git a/site/src/components/mcp/ToolReference.astro b/site/src/components/mcp/ToolReference.astro index 20fb69c9..0159fede 100644 --- a/site/src/components/mcp/ToolReference.astro +++ b/site/src/components/mcp/ToolReference.astro @@ -60,7 +60,7 @@ const headings = tool ? [ advertises {reference.registrations.length} tools with the reference configuration below. Your client’s list follows the policy configured for its server.

Read the setup guide before choosing tool access. - The language API reference covers embedding and implementation types.

+ The language API reference covers embedding and implementation types.

{port === 'cxx' &&

This is the POSIX catalog. The Windows preview exposes a smaller read-only surface; see platform limits.

}

Download the protocol catalog as JSON.

diff --git a/site/src/content/docs/ports/py/workspace/internals/topics.md b/site/src/content/docs/ports/py/workspace/internals/topics.md index 3d997408..eddc6e5b 100644 --- a/site/src/content/docs/ports/py/workspace/internals/topics.md +++ b/site/src/content/docs/ports/py/workspace/internals/topics.md @@ -34,6 +34,6 @@ build does not have universal transactional rollback. The CLI owns its existing-session prompts and the attachment or client-switching workflow. See the upstream [custom builder guide](https://tmuxp.git-pull.com/topics/custom-workspace-builders/) -for extension configuration and the [API](../reference/) for interface contracts. +for extension configuration and the [API](../../reference/) for interface contracts. [Configuration loader](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/loader.py); [Classic builder](https://github.com/tmux-python/tmuxp/blob/618b398acc05506d3c682906c36cdeb29dcfa1ff/src/tmuxp/workspace/builder/classic.py). diff --git a/site/src/content/docs/ports/ts/workspace/reference.md b/site/src/content/docs/ports/ts/workspace/reference.md index 5f3d13bf..22706cc2 100644 --- a/site/src/content/docs/ports/ts/workspace/reference.md +++ b/site/src/content/docs/ports/ts/workspace/reference.md @@ -42,6 +42,6 @@ is not a transaction log of every effect or a receipt for shell commands. The language API builds workspaces directly. Availability through an MCP server is a separate protocol capability; consult this port's -[MCP section](../../../mcp/) for its advertised tools. +[MCP section](../../mcp/) for its advertised tools. [Public exports](https://github.com/libtmux/libtmux-ts/blob/f85b8de551353f746d50eaf36bf0112f4fe5a528/packages/workspace/package.json) diff --git a/site/src/data/mentions.json b/site/src/data/mentions.json index c156fbcd..f9bf7b0c 100644 --- a/site/src/data/mentions.json +++ b/site/src/data/mentions.json @@ -1,5 +1,5 @@ { - "generated": "2026-09-13T21:14:30.938Z", + "generated": "2026-09-13T21:20:41.972Z", "mentions": [ { "port": "cxx", From f30b97e0c4b3a67d0e74029f1912fe379a4a2d44 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:28:38 -0500 Subject: [PATCH 10/17] fix(reference) Canonicalise a reference page to its own version why: The route passed no port to the layout, so every page declared /en/reference// -- the URL it used to have, which no longer exists. 12,600 pages pointed there. what: - The route passes its port and version, so the canonical is built the way every other port page builds one - check-canonicals asserts the port rule it now follows: a page is canonical to itself under the default version, and another version of it points there --- scripts/check-canonicals.mjs | 34 +++++++++++++++++------- site/src/pages/reference/[...slug].astro | 2 ++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/scripts/check-canonicals.mjs b/scripts/check-canonicals.mjs index 25124523..259a21dd 100644 --- a/scripts/check-canonicals.mjs +++ b/scripts/check-canonicals.mjs @@ -1,14 +1,15 @@ #!/usr/bin/env node /* - * Every reference page's canonical URL is its own URL. + * Every reference page canonicalises to itself under the port's default + * version. * - * The reference tree carries no version and no locale, so unlike the port - * prose there is no legitimate reason for one of its pages to canonicalise - * anywhere but itself. That makes the invariant exact, and exactness is what - * this tree needed: `pagePath` was composed from the symbol rather than from - * the route, so every page in all eight ports declared a canonical without - * the port segment — a URL that does not exist, and the same one for any two - * ports sharing a symbol slug. + * A reference lives under the version it documents, so its canonical follows + * the rule the rest of a port's pages follow: the default version is the one + * URL, and another version of the same page points at it. What is never + * legitimate is pointing outside the port, or at a version that was not + * built — `pagePath` was once composed from the symbol rather than from the + * route, so every page in all eight ports declared a canonical without the + * port segment, the same URL for any two ports sharing a symbol slug. * * Nothing caught it. The pages are noindex today, so no ranking moved; the * links in them all resolve, so check-links passed; and no test asserts a @@ -26,6 +27,16 @@ import { referenceDirs } from './reference-trees.mjs' const { PORTS: PORT_DEFS } = await import(`file://${join(dirname(fileURLToPath(import.meta.url)), '../site/src/lib/ports.ts')}`) const PORTS = PORT_DEFS.map((p) => p.slug) +/** + * Each port's default version, read from the tree that was built: a port + * publishing one prefix is its own default, and Python's two make `stable` + * the canonical one. + */ +const DEFAULTS = Object.fromEntries(PORTS.map((port) => { + const built = referenceDirs(siteDir, port).map((dir) => dir.split('/').at(-2)) + return [port, built.includes('stable') ? 'stable' : built[0]] +}).filter(([, version]) => version)) + const repoRoot = dirname(dirname(fileURLToPath(import.meta.url))) const defaultSite = join(repoRoot, '_site') const siteDir = process.argv.slice(2).find((a) => !a.startsWith('--')) ?? defaultSite @@ -87,8 +98,13 @@ for (const file of pages) { const declared = new URL(found[1]).pathname.replace(new RegExp(`^/${LOCALE}/`), '/') // The page's own path, as served: the directory holding its index.html. const own = `${file.slice(siteDir.length, -'index.html'.length)}` + // Its canonical twin: the same page under this port's default version. + const [, port, version] = own.split('/') + const want = DEFAULTS[port] && DEFAULTS[port] !== version + ? own.replace(`/${port}/${version}/`, `/${port}/${DEFAULTS[port]}/`) + : own checked += 1 - if (declared !== own) wrong.push({ file, want: own, got: declared }) + if (declared !== want) wrong.push({ file, want, got: declared }) } if (wrong.length) { diff --git a/site/src/pages/reference/[...slug].astro b/site/src/pages/reference/[...slug].astro index 66de631e..c8905e1c 100644 --- a/site/src/pages/reference/[...slug].astro +++ b/site/src/pages/reference/[...slug].astro @@ -469,6 +469,8 @@ const title = owner : 'Types, methods, and functions in the libtmux language libraries.' } pagePath={slug ? `reference/${slug}` : 'reference'} + portSlug={model?.port} + version={buildTarget(process.env).version} noindex={true} searchable={searchable} pageSource={owner && model ? symbolSource(model, owner) : undefined} From efe6db06efdaeb6d7668a96d4ee1bf32307ea0ab Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:29:02 -0500 Subject: [PATCH 11/17] fix(scripts) Read the built versions after the site dir is known why: The defaults lookup ran above the argument it reads, so check-canonicals threw before it checked anything -- and its negative test is what caught it. what: - The lookup moves below the site directory it depends on --- scripts/check-canonicals.mjs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/check-canonicals.mjs b/scripts/check-canonicals.mjs index 259a21dd..b65d0cab 100644 --- a/scripts/check-canonicals.mjs +++ b/scripts/check-canonicals.mjs @@ -27,15 +27,6 @@ import { referenceDirs } from './reference-trees.mjs' const { PORTS: PORT_DEFS } = await import(`file://${join(dirname(fileURLToPath(import.meta.url)), '../site/src/lib/ports.ts')}`) const PORTS = PORT_DEFS.map((p) => p.slug) -/** - * Each port's default version, read from the tree that was built: a port - * publishing one prefix is its own default, and Python's two make `stable` - * the canonical one. - */ -const DEFAULTS = Object.fromEntries(PORTS.map((port) => { - const built = referenceDirs(siteDir, port).map((dir) => dir.split('/').at(-2)) - return [port, built.includes('stable') ? 'stable' : built[0]] -}).filter(([, version]) => version)) const repoRoot = dirname(dirname(fileURLToPath(import.meta.url))) const defaultSite = join(repoRoot, '_site') @@ -64,6 +55,16 @@ if (siteDir === defaultSite && existsSync(lock)) { } } +/** + * Each port's default version, read from the tree that was built: a port + * publishing one prefix is its own default, and Python's two make `stable` + * the canonical one. + */ +const DEFAULTS = Object.fromEntries(PORTS.map((port) => { + const built = referenceDirs(siteDir, port).map((dir) => dir.split('/').at(-2)) + return [port, built.includes('stable') ? 'stable' : built[0]] +}).filter(([, version]) => version)) + const roots = PORTS.flatMap((port) => referenceDirs(siteDir, port, { products: true })) if (!roots.length) { console.error(`check-canonicals: no reference tree under ${siteDir}`) From 9b55cd934618c7feaf20ac628d79e5457cdf600b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:37:18 -0500 Subject: [PATCH 12/17] fix(docs) Link a reference from prose without naming a version why: The preview build publishes one version per port, so a prose link that spelled /py/stable/reference/ broke there while passing on an assembly that builds both. CI caught it: one broken link in 1,987,189. what: - Every same-port reference link in prose is relative to the page, so it resolves under whichever version prefix the build produced - The type-name ceilings move to the wider basis: the check reads all three trees per port now, where before it read only the core tree and never saw a product page --- scripts/type-links-ceiling.json | 12 ++++++------ .../content/docs/ports/cxx/workspace/reference.md | 2 +- .../docs/ports/dotnet/workspace/reference.md | 10 +++++----- .../content/docs/ports/go/workspace/reference.md | 14 +++++++------- .../ports/java/workspace/internals/examples.md | 2 +- .../content/docs/ports/java/workspace/reference.md | 8 ++++---- .../docs/ports/py/workspace/internals/index.md | 2 +- .../content/docs/ports/rs/workspace/reference.md | 4 ++-- .../docs/ports/swift/workspace/internals/guides.md | 2 +- .../docs/ports/swift/workspace/internals/index.md | 2 +- .../docs/ports/swift/workspace/reference.md | 8 ++++---- .../content/docs/ports/ts/workspace/reference.md | 12 ++++++------ site/src/data/mentions.json | 2 +- 13 files changed, 40 insertions(+), 40 deletions(-) diff --git a/scripts/type-links-ceiling.json b/scripts/type-links-ceiling.json index e1851404..1fc32dad 100644 --- a/scripts/type-links-ceiling.json +++ b/scripts/type-links-ceiling.json @@ -1,10 +1,10 @@ { - "py": 138, - "ts": 94, - "rs": 510, - "go": 107, + "py": 262, + "ts": 90, + "rs": 546, + "go": 112, "java": 137, "dotnet": 22, - "cxx": 259, - "swift": 1269 + "cxx": 258, + "swift": 1603 } diff --git a/site/src/content/docs/ports/cxx/workspace/reference.md b/site/src/content/docs/ports/cxx/workspace/reference.md index 77b3fcc2..06685bb5 100644 --- a/site/src/content/docs/ports/cxx/workspace/reference.md +++ b/site/src/content/docs/ports/cxx/workspace/reference.md @@ -43,7 +43,7 @@ to parse YAML. ## Core operations The returned session is a core libtmux value. Use the -[C++ core reference](/cxx/latest/reference/) for subsequent inspection and mutation. +[C++ core reference](../../reference/) for subsequent inspection and mutation. Consumer source contracts remain the authority for the workspace types. [Workspace header](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/workspace.hpp); [YAML header](https://github.com/libtmux/libtmux-cxx/blob/c7f1146d2ebd7a8323d9f9814517dc3cdf86b4ee/examples/workspace/include/libtmux_consumers/tmuxp.hpp). diff --git a/site/src/content/docs/ports/dotnet/workspace/reference.md b/site/src/content/docs/ports/dotnet/workspace/reference.md index 0d103981..cf2c28e0 100644 --- a/site/src/content/docs/ports/dotnet/workspace/reference.md +++ b/site/src/content/docs/ports/dotnet/workspace/reference.md @@ -15,16 +15,16 @@ that uses a caller-supplied LibTmux `Server`. ## Configuration -[`WorkspaceFile`](/dotnet/latest/workspace/reference/libtmux-workspace-workspacefile/) parses +[`WorkspaceFile`](./libtmux-workspace-workspacefile/) parses YAML and holds the session description. `WorkspaceWindow` and `WorkspacePane` hold nested configuration. `WorkspaceFormatException` identifies unsupported or invalid configuration. ## Builder options -[`WorkspaceBuilder`](/dotnet/latest/workspace/reference/libtmux-workspace-workspacebuilder/) +[`WorkspaceBuilder`](./libtmux-workspace-workspacebuilder/) accepts a server, an optional positive readiness timeout, and a -[`PaneReadiness`](/dotnet/latest/workspace/reference/libtmux-workspace-panereadiness/) policy. +[`PaneReadiness`](./libtmux-workspace-panereadiness/) policy. Its `BuildAsync` accepts the configuration and an optional cancellation token. The default timeout is ten seconds. `Auto`, `Always`, and `Never` select which @@ -33,11 +33,11 @@ heuristic and its limitations. ## Results and failures -[`WorkspaceResult`](/dotnet/latest/workspace/reference/libtmux-workspace-workspaceresult/) +[`WorkspaceResult`](./libtmux-workspace-workspaceresult/) contains the created session, windows, and rejected layouts. A rejected layout does not discard its window. -[`WorkspaceBuildException`](/dotnet/latest/workspace/reference/libtmux-workspace-workspacebuildexception/) +[`WorkspaceBuildException`](./libtmux-workspace-workspacebuildexception/) keeps a `PartialResult` when state could be materialized before failure. It can be null when no such result could be read. Inspect live tmux state before retrying; a missing result does not prove that no command reached tmux. diff --git a/site/src/content/docs/ports/go/workspace/reference.md b/site/src/content/docs/ports/go/workspace/reference.md index 6ee20e6b..0fc0c83a 100644 --- a/site/src/content/docs/ports/go/workspace/reference.md +++ b/site/src/content/docs/ports/go/workspace/reference.md @@ -16,23 +16,23 @@ and cancellation. ## Parse configuration -[`Parse`](/go/latest/workspace/reference/workspace-parse/) reads YAML into a -[`Workspace`](/go/latest/workspace/reference/workspace-workspace/). Its errors match +[`Parse`](./workspace-parse/) reads YAML into a +[`Workspace`](./workspace-workspace/). Its errors match `ErrInvalidWorkspace`. Inspect the individual diagnostics to locate unknown keys or invalid values. -[`Window`](/go/latest/workspace/reference/workspace-window/), -[`Pane`](/go/latest/workspace/reference/workspace-pane/), and -[`Command`](/go/latest/workspace/reference/workspace-command/) let applications construct the +[`Window`](./workspace-window/), +[`Pane`](./workspace-pane/), and +[`Command`](./workspace-command/) let applications construct the same data in Go. `Bool` preserves tmuxp's supported boolean spellings. ## Build a session -[`Build`](/go/latest/workspace/reference/workspace-build/) creates the initial session and owns +[`Build`](./workspace-build/) creates the initial session and owns a temporary control connection for the duration of construction. It returns a session and an error; a non-nil error can accompany a partial session. -[`BuildInto`](/go/latest/workspace/reference/workspace-buildinto/) populates a supplied session +[`BuildInto`](./workspace-buildinto/) populates a supplied session and preserves the caller's connection ownership. `Workspace.InitialSessionRequest` produces the initial request for that workflow. diff --git a/site/src/content/docs/ports/java/workspace/internals/examples.md b/site/src/content/docs/ports/java/workspace/internals/examples.md index a64b577c..904742bb 100644 --- a/site/src/content/docs/ports/java/workspace/internals/examples.md +++ b/site/src/content/docs/ports/java/workspace/internals/examples.md @@ -18,7 +18,7 @@ fences and runs them against real tmux. Within an application that already has a `Server`, import `Workspace` and `WorkspaceBuilder` from [`io.github.libtmux.workspace`](https://github.com/libtmux/libtmux-java/tree/4f057d367a25dee818d70876fa283fc503a3a7eb/libtmux-workspace/src/main/java/io/github/libtmux/workspace), and `Session` from -[`io.github.libtmux`](/java/latest/reference/). This excerpt uses the same configuration as the module's +[`io.github.libtmux`](../../../reference/). This excerpt uses the same configuration as the module's result example: ```java diff --git a/site/src/content/docs/ports/java/workspace/reference.md b/site/src/content/docs/ports/java/workspace/reference.md index fe83c880..2ab7a5bf 100644 --- a/site/src/content/docs/ports/java/workspace/reference.md +++ b/site/src/content/docs/ports/java/workspace/reference.md @@ -16,7 +16,7 @@ before building through a core `Server`. ## Builder facade -[`WorkspaceBuilder`](/java/latest/workspace/reference/io-github-libtmux-workspace-workspacebuilder-workspacebuilder/) +[`WorkspaceBuilder`](./io-github-libtmux-workspace-workspacebuilder-workspacebuilder/) provides three static entry points: - `read(Path)` reads a YAML file and wraps I/O errors in `UncheckedIOException`. @@ -28,11 +28,11 @@ server's support for the requested layout. ## Configuration records -[`Workspace`](/java/latest/workspace/reference/io-github-libtmux-workspace-workspace-workspace/) +[`Workspace`](./io-github-libtmux-workspace-workspace-workspace/) holds the session name and ordered windows. -[`WindowSpec`](/java/latest/workspace/reference/io-github-libtmux-workspace-windowspec-windowspec/) +[`WindowSpec`](./io-github-libtmux-workspace-windowspec-windowspec/) holds the name, optional layout, and panes. -[`PaneSpec`](/java/latest/workspace/reference/io-github-libtmux-workspace-panespec-panespec/) +[`PaneSpec`](./io-github-libtmux-workspace-panespec-panespec/) holds the ordered shell commands. These records copy their lists so later changes to an input list do not alter diff --git a/site/src/content/docs/ports/py/workspace/internals/index.md b/site/src/content/docs/ports/py/workspace/internals/index.md index ddcaaf93..903af9a1 100644 --- a/site/src/content/docs/ports/py/workspace/internals/index.md +++ b/site/src/content/docs/ports/py/workspace/internals/index.md @@ -28,4 +28,4 @@ attachment or client switching. The upstream [Internals documentation](https://tmuxp.git-pull.com/internals/) contains the full architecture and module reference. Use the -[libtmux Python API](/py/stable/reference/) for general tmux programming. +[libtmux Python API](../../reference/) for general tmux programming. diff --git a/site/src/content/docs/ports/rs/workspace/reference.md b/site/src/content/docs/ports/rs/workspace/reference.md index a759b739..f65e2186 100644 --- a/site/src/content/docs/ports/rs/workspace/reference.md +++ b/site/src/content/docs/ports/rs/workspace/reference.md @@ -16,14 +16,14 @@ for actual tmux operations. ## Configuration -[`Workspace`](/rs/latest/workspace/reference/config-workspace/) holds the session description. +[`Workspace`](./config-workspace/) holds the session description. `Workspace::from_yaml` parses it, and `to_yaml` emits its YAML representation. `WindowConfig` and `PaneConfig` describe the nested objects; `ConfigError` identifies invalid configuration. ## Builder -[`WorkspaceBuilder`](/rs/latest/workspace/reference/src-workspacebuilder/) borrows a `Server`. +[`WorkspaceBuilder`](./src-workspacebuilder/) borrows a `Server`. `new` selects that server, `plan` returns the inert construction plan, and `build` asynchronously creates the requested session. Keep the server alive for the builder's lifetime. diff --git a/site/src/content/docs/ports/swift/workspace/internals/guides.md b/site/src/content/docs/ports/swift/workspace/internals/guides.md index 7dd6be2b..77369fe8 100644 --- a/site/src/content/docs/ports/swift/workspace/internals/guides.md +++ b/site/src/content/docs/ports/swift/workspace/internals/guides.md @@ -10,7 +10,7 @@ sidebar: tableOfContents: true --- -Add `TmuxWorkspace` and [`LibTmux`](/swift/latest/reference/) to a SwiftPM target. This isolated example +Add `TmuxWorkspace` and [`LibTmux`](../../../reference/) to a SwiftPM target. This isolated example also uses the public `TmuxFixture` product for server startup and cleanup. The following dependency selects the source revision used by these examples: diff --git a/site/src/content/docs/ports/swift/workspace/internals/index.md b/site/src/content/docs/ports/swift/workspace/internals/index.md index af224c70..dc5a3580 100644 --- a/site/src/content/docs/ports/swift/workspace/internals/index.md +++ b/site/src/content/docs/ports/swift/workspace/internals/index.md @@ -32,7 +32,7 @@ handling, and attachment. `TmuxWorkspace` builds a tmux session from Swift values or a [tmuxp](https://tmuxp.git-pull.com)-style configuration. It is a SwiftPM -library product beside the core [`LibTmux`](/swift/latest/reference/) product. +library product beside the core [`LibTmux`](../../reference/) product. Swift and JSON descriptions work without a YAML dependency. Enable the `YAMLWorkspaces` package trait to add YAML decoding. Building uses the same diff --git a/site/src/content/docs/ports/swift/workspace/reference.md b/site/src/content/docs/ports/swift/workspace/reference.md index 8cb7f98d..7183d29c 100644 --- a/site/src/content/docs/ports/swift/workspace/reference.md +++ b/site/src/content/docs/ports/swift/workspace/reference.md @@ -10,12 +10,12 @@ sidebar: tableOfContents: true --- -Import `TmuxWorkspace` for the configuration and builder, and [`LibTmux`](/swift/latest/reference/) for +Import `TmuxWorkspace` for the configuration and builder, and [`LibTmux`](../../reference/) for the server and returned session value. ## Configuration values -[`Workspace`](/swift/latest/workspace/reference/workspace/) contains the session name, optional +[`Workspace`](./workspace/) contains the session name, optional working directory, and ordered windows. `WindowPlan` contains its name, directory, layout, and panes. `PanePlan` contains its directory and commands. The values conform to `Sendable`, `Hashable`, and `Codable`. @@ -26,14 +26,14 @@ existing description; it does not query tmux for a live export. ## Builder -[`WorkspaceBuilder`](/swift/latest/workspace/reference/workspacebuilder/) exposes the async +[`WorkspaceBuilder`](./workspacebuilder/) exposes the async `build(_:on:)` operation. It creates a new session on the supplied server and returns a `Session`. Keep using the server for live observation; session properties do not refresh themselves. ## Typed errors -[`WorkspaceBuilderError`](/swift/latest/workspace/reference/workspacebuildererror/) distinguishes +[`WorkspaceBuilderError`](./workspacebuildererror/) distinguishes an empty window list, an existing session name, a vanished session, underlying tmux errors, and failure of rollback. diff --git a/site/src/content/docs/ports/ts/workspace/reference.md b/site/src/content/docs/ports/ts/workspace/reference.md index 22706cc2..4ad9b910 100644 --- a/site/src/content/docs/ports/ts/workspace/reference.md +++ b/site/src/content/docs/ports/ts/workspace/reference.md @@ -17,26 +17,26 @@ not choose a workspace or apply one automatically. ## Parse and validate -[`parseWorkspace`](/ts/latest/workspace/reference/config-parseworkspace/) validates data already +[`parseWorkspace`](./config-parseworkspace/) validates data already read by your application. -[`parseWorkspaceYaml`](/ts/latest/workspace/reference/config-parseworkspaceyaml/) +[`parseWorkspaceYaml`](./config-parseworkspaceyaml/) adds Bun's YAML parsing. Both produce the workspace configuration consumed by the builder. ## Plan and apply -[`planWorkspace`](/ts/latest/workspace/reference/builder-planworkspace/) returns a description -of membership changes. [`WorkspacePlan`](/ts/latest/workspace/reference/planning-workspaceplan/) +[`planWorkspace`](./builder-planworkspace/) returns a description +of membership changes. [`WorkspacePlan`](./planning-workspaceplan/) records creations, removals, renames, and retained surplus. -[`applyWorkspace`](/ts/latest/workspace/reference/builder-applyworkspace/) performs the work and +[`applyWorkspace`](./builder-applyworkspace/) performs the work and resolves to the resulting `Session`. Its options control pruning and whether commands run in existing panes. Planning accepts pruning policy; command policy belongs to application. ## Handle failure -[`WorkspaceApplyError`](/ts/latest/workspace/reference/builder-workspaceapplyerror/) preserves +[`WorkspaceApplyError`](./builder-workspaceapplyerror/) preserves the cause and completed milestones. Reinspect tmux before retrying; the error is not a transaction log of every effect or a receipt for shell commands. diff --git a/site/src/data/mentions.json b/site/src/data/mentions.json index f9bf7b0c..7f63cbae 100644 --- a/site/src/data/mentions.json +++ b/site/src/data/mentions.json @@ -1,5 +1,5 @@ { - "generated": "2026-09-13T21:20:41.972Z", + "generated": "2026-09-13T21:36:55.929Z", "mentions": [ { "port": "cxx", From 40448bdaf4541a6220571b9572464258a4c48cb6 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:44:19 -0500 Subject: [PATCH 13/17] test(site) Follow the product sections and their structured data why: A product reference is a section of its product now, so the assembled suite looked for pages under the path it had, and the structured-data rule named api and tools but not reference. what: - The product section list carries reference beside Internals rather than inside it, and the workspace breadcrumb reads Reference - Seo marks any reference page APIReference, the core tree included, where before only a product api or tools page qualified - The exported metadata assertion follows the same spelling --- site/src/components/Seo.astro | 2 +- site/test/product-docs.test.ts | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/site/src/components/Seo.astro b/site/src/components/Seo.astro index cdb46611..ee46a57f 100644 --- a/site/src/components/Seo.astro +++ b/site/src/components/Seo.astro @@ -148,7 +148,7 @@ const graph: Graph = { ...(pagePath ? [ { - '@type': /^(mcp|workspace)\/(internals\/)?(api|tools)(\/|$)/.test(pagePath) ? 'APIReference' as const : 'TechArticle' as const, + '@type': /^(?:(?:mcp|workspace)\/)?(?:internals\/)?(?:reference|api|tools)(\/|$)/.test(pagePath) ? 'APIReference' as const : 'TechArticle' as const, '@id': `${canonical}#article`, url: canonical, headline: title, diff --git a/site/test/product-docs.test.ts b/site/test/product-docs.test.ts index fb596601..d4aa62c5 100644 --- a/site/test/product-docs.test.ts +++ b/site/test/product-docs.test.ts @@ -40,10 +40,13 @@ const urlFor = (path: string) => new URL(`/${SITE_PREFIX}${path}`, 'https://libt const productUrl = /\/(?:py|ts|rs|go|java|dotnet|cxx|swift)\/[^/]+\/(?:mcp|workspace)(?:\/|$)/ function sectionsFor(port: string, product: ProductPage['product']): string[] { - if (product === 'mcp') return ['', 'topics', 'guides', 'examples', 'api'] + // `reference` is a section of the product now, not a page inside Internals: + // the Workspace Manager and the MCP server are packages with APIs of their + // own, and Internals keeps the notes about building one. + if (product === 'mcp') return ['', 'topics', 'guides', 'examples', 'reference'] return port === 'py' - ? ['', 'topics', 'guides', 'examples', 'internals', 'internals/topics', 'internals/examples', 'internals/api'] - : ['', 'internals', 'internals/topics', 'internals/guides', 'internals/examples', 'internals/api'] + ? ['', 'topics', 'guides', 'examples', 'reference', 'internals', 'internals/topics', 'internals/examples'] + : ['', 'reference', 'internals', 'internals/topics', 'internals/guides', 'internals/examples'] } function pages(): ProductPage[] { @@ -204,7 +207,7 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { }) it('links generated declarations and schema-bearing tools inside their product', () => { - for (const page of pages().filter((entry) => entry.section === 'api' || entry.section === 'internals/api')) { + for (const page of pages().filter((entry) => entry.section === 'reference')) { const prefix = `${page.port}/${page.version}/${page.product}/${page.section}/` const declarations = inspect(page.path, (document) => [...document.querySelectorAll('[aria-labelledby="generated-api"] a[href]')] @@ -222,11 +225,10 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { if (page.product === 'workspace') { const labels = [...document.querySelectorAll('nav[aria-label="Breadcrumb"] a, nav[aria-label="Breadcrumb"] [aria-current="page"]')] .map((item) => item.textContent.trim()) - expect(labels.slice(0, 3)).toEqual([page.name, 'Workspace Manager', 'Internals']) + expect(labels.slice(0, 3)).toEqual([page.name, 'Workspace Manager', 'Reference']) expect(graph(document).find((entry) => entry['@type'] === 'BreadcrumbList')?.itemListElement?.map((item) => item.name)).toEqual(labels) } else developmentStatus(document, samplePath) }) - if (page.product === 'workspace') redirectsTo(samplePath.replace('/internals/api/', '/api/'), samplePath) if (page.product !== 'mcp') continue const toolsPath = `${page.port}/${page.version}/mcp/tools/` const tools = inspect(toolsPath, (document) => { @@ -344,7 +346,7 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { for (const product of products) { const metadata = advertised.products.find((entry) => entry.slug === product)! expect(metadata.inDevelopment, `${root}${port.slug} ${product} development status`).toBe(product === 'mcp' || port.slug !== 'py') - const section = product === 'workspace' ? 'internals/api' : 'api' + const section = 'reference' expect(new URL(metadata.reference, urlFor(root)).pathname).toBe(urlFor(`${port.slug}/${defaults[port.slug]}/${product}/${section}/`).pathname) if (product === 'workspace') expect(metadata.cli, `${root}${port.slug} user CLI`).toBe(port.slug === 'py' ? 'tmuxp load' : null) else expect(resolves(metadata.protocol!, urlFor(root).href), `${root}${port.slug} MCP protocol`).toBe(true) From 48495388549d628b2fef61ee89a44f82646d0f55 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 16:46:45 -0500 Subject: [PATCH 14/17] test(site) Clear the last old paths from checks and fixtures why: Four files still named workspace/internals/api, and the intersphinx writer looked for an inventory at the root copy alone. what: - check-dev, the font audit and the product suite name the product reference section - add-intersphinx prefers the versioned inventory beside its reference, falling back to nothing rather than to a path that no longer holds one --- scripts/add-intersphinx.mjs | 13 ++++++++++--- site/scripts/check-dev.mjs | 4 ++-- site/test/font-audit.test.ts | 2 +- site/test/product-docs.test.ts | 4 ++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/scripts/add-intersphinx.mjs b/scripts/add-intersphinx.mjs index cfa9f304..90bfe55f 100755 --- a/scripts/add-intersphinx.mjs +++ b/scripts/add-intersphinx.mjs @@ -18,6 +18,7 @@ import { appendFileSync, existsSync, readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' +import { referenceDirs } from './reference-trees.mjs' const [confDir, siteDir, baseUrl, skipPort] = process.argv.slice(2) if (!confDir || !siteDir || !baseUrl) { @@ -43,9 +44,15 @@ const PORTS = PORT_DEFS.map((p) => p.slug) const entries = [] for (const port of PORTS) { if (port === skipPort) continue - const inv = join(siteDir, 'reference', port, 'objects.inv') - if (!existsSync(inv)) continue - entries.push([`libtmux-${port}`, `${baseUrl.replace(/\/*$/, '')}/reference/${port}/`, inv]) + // A port's inventory sits beside the reference it describes, under the + // version that published it. The root build's copy at `reference//` + // stays for consumers configured before the move. + for (const dir of referenceDirs(siteDir, port)) { + const inv = join(dir, 'objects.inv') + if (!existsSync(inv)) continue + entries.push([`libtmux-${port}`, `${baseUrl.replace(/\/*$/, '')}/${dir.slice(siteDir.length).replace(/^\/+/, '')}/`, inv]) + break + } } if (!entries.length) { diff --git a/site/scripts/check-dev.mjs b/site/scripts/check-dev.mjs index b1a592e6..b643c89b 100644 --- a/site/scripts/check-dev.mjs +++ b/site/scripts/check-dev.mjs @@ -94,8 +94,8 @@ try { } }) for (const path of [ - 'py/stable/workspace/internals/api/tmuxp-workspace-builder-classicworkspacebuilder', - 'java/latest/workspace/internals/api/io-github-libtmux-workspace-workspacebuilder-workspacebuilder', + 'py/stable/workspace/reference/tmuxp-workspace-builder-classicworkspacebuilder', + 'java/latest/workspace/reference/io-github-libtmux-workspace-workspacebuilder-workspacebuilder', ]) await retryReload(async () => { const response = await page.goto(`${base}/${path}/`, { waitUntil: 'load' }) assert(response?.ok(), `${path}: HTTP ${response?.status()}`) diff --git a/site/test/font-audit.test.ts b/site/test/font-audit.test.ts index 1af66979..34e46a97 100644 --- a/site/test/font-audit.test.ts +++ b/site/test/font-audit.test.ts @@ -22,7 +22,7 @@ function audit(html: string) { describe('font audit redirect exemptions', () => { it('recognizes an Astro redirect with long paths in its title and code labels', () => { - const target = '/en/dotnet/latest/workspace/internals/api/libtmux-workspace-workspacebuilder-buildsessionasync/' + const target = '/en/dotnet/latest/workspace/reference/libtmux-workspace-workspacebuilder-buildsessionasync/' const source = target.replace('/internals/', '/') const result = audit(` Redirecting to: ${target} diff --git a/site/test/product-docs.test.ts b/site/test/product-docs.test.ts index d4aa62c5..b80836f2 100644 --- a/site/test/product-docs.test.ts +++ b/site/test/product-docs.test.ts @@ -283,7 +283,7 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { it('redirects previous workspace implementation URLs without replacing Python CLI docs', () => { for (const page of pages().filter((entry) => entry.product === 'workspace' - && (entry.section === 'internals/api' || (entry.port !== 'py' && entry.section.startsWith('internals/'))))) { + && (entry.section === 'reference' || (entry.port !== 'py' && entry.section.startsWith('internals/'))))) { redirectsTo(page.path.replace('/internals/', '/'), page.path) } for (const page of pages().filter((entry) => entry.port === 'py' && entry.product === 'workspace' @@ -330,7 +330,7 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { expect(index.pages.some((entry) => entry.url === url), `${url} in docs.json`).toBe(true) expect(llms, `${url} in llms.txt`).toContain(`](${url})`) expect(sitemap, `${url} in sitemap`).toContain(`${url}`) - if (page.product === 'workspace' && (page.section === 'internals/api' + if (page.product === 'workspace' && (page.section === 'reference' || (page.port !== 'py' && page.section.startsWith('internals/')))) { const legacy = url.replace('/workspace/internals/', '/workspace/') expect(sitemap, `${legacy} redirect is not canonical`).not.toContain(`${legacy}`) From 570d4799c57c68973fd284065bf0cdab846236d0 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 17:00:04 -0500 Subject: [PATCH 15/17] fix(site) Advertise the reference where an agent can fetch it why: docs.json named /reference// for every port, so sixteen manifest entries pointed at pages that no longer exist -- the one file an agent reads first. The native navigation manifest test and the workspace redirect expectations named the old shape too. what: - Each port entry, its Markdown twin and its inventory carry the port's default version, the same one the pages are built under - A product reference is a section of its product, so no legacy twin redirects to it and the sitemap lists it like any other page --- site/src/pages/docs.json.ts | 12 ++++++------ site/test/exports.test.ts | 2 +- site/test/product-docs.test.ts | 8 +++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/site/src/pages/docs.json.ts b/site/src/pages/docs.json.ts index 8b8fe662..7614aec8 100644 --- a/site/src/pages/docs.json.ts +++ b/site/src/pages/docs.json.ts @@ -79,10 +79,10 @@ export const GET: APIRoute = async ({ site }) => { description: `${model.symbols.length} symbols extracted from source, ${types.length} with their own page.`, section: 'API reference', // refBase, not base: the reference is generated in the default locale - // only, so a Japanese manifest advertising /ja/reference/… names pages - // nothing builds. Nothing parses this file, so nothing reported it. - url: `${origin}${refBase}reference/${port}/`, - markdownUrl: `${origin}${refBase}reference/${port}/index.md`, + // only, so a Japanese manifest advertising a locale-prefixed reference + // names pages nothing builds. + url: `${origin}${refBase}${port}/${defaults[port] ?? 'latest'}/reference/`, + markdownUrl: `${origin}${refBase}${port}/${defaults[port] ?? 'latest'}/reference/index.md`, headings: types.slice(0, 200).map((t) => ({ id: t.publicId ?? t.id, level: 2, @@ -111,7 +111,7 @@ export const GET: APIRoute = async ({ site }) => { name: p.name, language: p.language, package: p.packageName, - reference: hasReference(p) ? referenceUrl(p, 'stable') : null, + reference: hasReference(p) ? referenceUrl(p, defaults[p.slug] ?? 'latest') : null, products: Object.entries(DOC_PRODUCTS).map(([slug, product]) => ({ slug, name: product.label, inDevelopment: productInDevelopment(p, slug as DocProduct), @@ -125,7 +125,7 @@ export const GET: APIRoute = async ({ site }) => { ? { symbols: API_MODELS[p.slug].symbols.length, extractor: API_MODELS[p.slug].extractor, - inventory: `${refBase}reference/${p.slug}/objects.inv`, + inventory: `${refBase}${p.slug}/${defaults[p.slug] ?? 'latest'}/reference/objects.inv`, } : null, })), diff --git a/site/test/exports.test.ts b/site/test/exports.test.ts index b34591f7..77a28bf6 100644 --- a/site/test/exports.test.ts +++ b/site/test/exports.test.ts @@ -143,7 +143,7 @@ describeIfAssembled('published exports', () => { expect(manifest.schema).toBe(1) expect(Object.keys(manifest.indexes).sort()).toEqual(PORTS.map((port) => port.slug).sort()) expect(manifest.symbols.py['libtmux.Session.windows']).toEqual(expect.arrayContaining([ - expect.objectContaining({ port: 'ts', href: expect.stringMatching(/\/reference\/ts\/session-session-windows\/$/) }), + expect.objectContaining({ port: 'ts', href: expect.stringMatching(/\/ts\/[^/]+\/reference\/session-session-windows\/$/) }), ])) const targets = new Set([ ...Object.values(manifest.indexes as Record), diff --git a/site/test/product-docs.test.ts b/site/test/product-docs.test.ts index b80836f2..911e09ec 100644 --- a/site/test/product-docs.test.ts +++ b/site/test/product-docs.test.ts @@ -282,8 +282,11 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { }) it('redirects previous workspace implementation URLs without replacing Python CLI docs', () => { + // The reference is a section of the product now, not a page inside + // Internals, so it has no lifted twin to redirect. What remains under + // Internals still does, for a port with no workspace CLI of its own. for (const page of pages().filter((entry) => entry.product === 'workspace' - && (entry.section === 'reference' || (entry.port !== 'py' && entry.section.startsWith('internals/'))))) { + && entry.port !== 'py' && entry.section.startsWith('internals/'))) { redirectsTo(page.path.replace('/internals/', '/'), page.path) } for (const page of pages().filter((entry) => entry.port === 'py' && entry.product === 'workspace' @@ -330,8 +333,7 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { expect(index.pages.some((entry) => entry.url === url), `${url} in docs.json`).toBe(true) expect(llms, `${url} in llms.txt`).toContain(`](${url})`) expect(sitemap, `${url} in sitemap`).toContain(`${url}`) - if (page.product === 'workspace' && (page.section === 'reference' - || (page.port !== 'py' && page.section.startsWith('internals/')))) { + if (page.product === 'workspace' && page.port !== 'py' && page.section.startsWith('internals/')) { const legacy = url.replace('/workspace/internals/', '/workspace/') expect(sitemap, `${legacy} redirect is not canonical`).not.toContain(`${legacy}`) } From 749689f5c168991490fd029bcffabd0668641173 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 17:08:49 -0500 Subject: [PATCH 16/17] test(site) Expect the breadcrumb and index of a product reference why: A product reference hangs directly off its product now, so a symbol page has no Internals level in its breadcrumb, and the search cases named two pages that no longer exist. what: - The breadcrumb assertion pins the product and the page, not the level between them that moved - The search cases name the trees that exist: a product declaration, the core reference, its index and the hub --- site/test/product-docs.test.ts | 5 ++++- site/test/search-index.test.ts | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/test/product-docs.test.ts b/site/test/product-docs.test.ts index 911e09ec..3b8af8b8 100644 --- a/site/test/product-docs.test.ts +++ b/site/test/product-docs.test.ts @@ -225,7 +225,10 @@ describe.skipIf(!SITE_BUILT)('assembled MCP and Workspace Manager docs', () => { if (page.product === 'workspace') { const labels = [...document.querySelectorAll('nav[aria-label="Breadcrumb"] a, nav[aria-label="Breadcrumb"] [aria-current="page"]')] .map((item) => item.textContent.trim()) - expect(labels.slice(0, 3)).toEqual([page.name, 'Workspace Manager', 'Reference']) + // The reference is a section of the product, so its pages hang + // directly off it: no Internals level in between any more. + expect(labels.slice(0, 2)).toEqual([page.name, 'Workspace Manager']) + expect(labels.at(-1)).toBe(sample.title) expect(graph(document).find((entry) => entry['@type'] === 'BreadcrumbList')?.itemListElement?.map((item) => item.name)).toEqual(labels) } else developmentStatus(document, samplePath) }) diff --git a/site/test/search-index.test.ts b/site/test/search-index.test.ts index 61216d06..d28f554b 100644 --- a/site/test/search-index.test.ts +++ b/site/test/search-index.test.ts @@ -5,14 +5,11 @@ import { SITE_BUILT, sitePath } from './site-root' it.skipIf(!SITE_BUILT)('indexes scoped product declarations while retaining core, internal, and index pages', () => { const cases = [ - ['reference/go/workspace-build', false], - ['go/latest/workspace/api/workspace-build', false], ['go/latest/workspace/reference/workspace-build', true], ['go/latest/workspace/guides', false], ['go/latest/workspace/internals/guides', true], ['py/latest/workspace/guides', true], ['py/latest/workspace/internals', true], - ['reference/ts/mcp-startup-serverstartup', false], ['ts/latest/mcp/reference/mcp-startup-serverstartup', true], ['ts/latest/reference/builder-applywindowcontext', true], ['go/latest/reference/tmux-server', true], From da8b0aa3036fcdef4fbcc4a9ac600d3e96c7347d Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 13 Sep 2026 17:16:53 -0500 Subject: [PATCH 17/17] test(site) Measure cross-references across all three trees why: The check counted one tree per port and that tree held everything, duplicates included. It reads the core reference and both product references now, which is every page a port publishes -- so seven ports rise, Python falls, and neither movement is a change in resolution. Python falls because its 627 workspace and MCP declarations left the core tree for product pages. Both render the same ApiEntry, but a core reference page wraps it in examples, related entries and module links, and those carry cross-references the product page has no room for. The duplicates that used to be counted are gone with them. what: - py 13,027 -> 11,925, and the seven that rose take their new counts: dotnet 3,975 -> 4,771, swift 3,298 -> 3,739, rs 3,750 -> 4,330 --- scripts/xref-floor.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/xref-floor.json b/scripts/xref-floor.json index ad92298e..77a173c7 100644 --- a/scripts/xref-floor.json +++ b/scripts/xref-floor.json @@ -1,10 +1,10 @@ { - "py": 13027, - "ts": 2072, - "rs": 3750, - "go": 13194, - "java": 1647, - "dotnet": 3975, - "cxx": 1901, - "swift": 3298 + "py": 11925, + "ts": 2094, + "rs": 4330, + "go": 13216, + "java": 1672, + "dotnet": 4771, + "cxx": 1982, + "swift": 3739 }