# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- **Every file is named in lowercase kebab-case, and the template imports its own layers through `@/`.** `SiteHeader.astro` is now
  `site-header.astro`, `buildDocuments.ts` is `build-documents.ts`, `src/presentation/sideCard/` is `src/presentation/side-card/`, in the
  template, the tests, the e2e specs and the scripts. Only the names of exports are CamelCase. Inside `template/src/`, an import that leaves
  its folder is `@/infrastructure` and not `../../infrastructure`. A generated site changes in the same way, so this is a release that
  touches every file of a site. `sitekit upgrade` moves the files for you: a file you did not edit gets the new name and the new version,
  and a file you edited moves with your changes and the new version next to it to merge. A file of your own that imports a renamed file by
  its old name needs the new name. The `FileSystem` port of the CLI has a new `remove`, and the result of an upgrade has a new `renamed`
  list.

## [0.2.4] - 2026-11-05

### Added

- **A site can name the picture a shared link shows.** The pages already said what they are with `og:title` and `og:description`, but gave no image, so a chat or a feed showed a bare link. Two new keys of `site` change it: `image` names a picture, a file in `public/` such as `/social.png` or a full `https` address, and `imageAlt` is its alt text. With `image` set, every page has `og:image`, `twitter:image` and their alt text, and `twitter:card` is `summary_large_image`. Without it nothing changes: no picture, and `summary`. The kit draws no card and adds no dependency, so a generated site weighs what it did; [social-card-action](https://github.com/miguelcolmenares/social-card-action) draws one in the style of the kit when you want it. The options page explains both keys, and the configuration reference lists them. Existing sites get the tags with `sitekit upgrade`, which replaces the layout.

## [0.2.3] - 2026-11-04

### Changed

- **The footer line names the site without the copyright sign and the year, and "Built with" links to the microsite.** The legal line of the footer reads `docs-sitekit · MIT licensed · v0.2.2`, the name, then the license and the version, with no `©` and no year. The credit "Built with docs-sitekit" links to [miguelcolmenares.com/docs-sitekit](https://miguelcolmenares.com/docs-sitekit/) instead of the repository. The kit's own site is named `docs-sitekit` in its `sitekit.config.json`. A generated site takes its name from `package.json`, the repository or the folder, as before. A site generated earlier gets this after `SiteFooter.tsx` and `BaseLayout.astro` are copied from this version, or with `sitekit upgrade`.
- **CodeQL also runs on every push to `main`.** A scan of a pull request does not close an alert on `main`, so the eight alerts fixed by the previous change stayed open until the next Monday scan. The workflow now analyses `main` after each merge.

### Fixed

- **Seven more CodeQL alerts, four of them polynomial regular expressions.** `absoluteUrl` (in `llms.ts`, which every generated site carries), `parseGitHubUrl`, `packageName` and the link reader of `check` for `llms.txt` no longer use a pattern that tries again from every position, so a long run of one character stays linear. They have tests with long inputs. The test helper of the code block HTML tests now reads tags and entities in one pass, and the e2e test of reusable content escapes the version for a `RegExp` with every metacharacter. A site generated earlier gets the `absoluteUrl` fix after `llms.ts` is copied from this version, or with `sitekit upgrade`. The eighth alert, on the table cells of `scripts/configReference.ts`, is fixed in the next entry.

- **A pipe after a backslash no longer breaks a row of the generated configuration reference.** A cell escaped a pipe with `\|` and left backslashes alone, so a description that already had `\|` became `\\|`, where GFM reads the first backslash as escaping the second and the pipe splits the cell into three (the last CodeQL alert, `js/incomplete-sanitization`). The backslashes right before a pipe are now doubled, and any other backslash, such as those of a pattern in a code span, stays single, so the page on disk does not change. It has a test that fails without the fix. This is repository tooling, not part of the template.

- **The search button and the doc layout pass axe at desktop width (#69).** The search button had `aria-label="Search"`, but from `sm` up its visible text is `Search ⌘K`, which fails Label in Name (WCAG 2.5.3). It has no `aria-label` now, and its name is the text `Search`: the word is visible from `sm` up, and it is hidden but still read on a phone, where the icon is the only thing shown. The two `aside` landmarks of the doc layout, the docs menu and the "On this page" list, had the same role and no name, which fails `landmark-unique`. They are `div`s now, because the `nav` in each one already has the name. The desktop axe check of the kit's specs runs the WCAG 2.1 A and AA rules and the best practices, with no exemption, and any finding fails it. Two template tests read the markup of the button and the asides. A site generated earlier gets the fix after `SiteHeader.astro` and `DocPage.astro` are copied from this version, or with `sitekit upgrade`.

## [0.2.2] - 2026-10-31

### Changed

- **The Publish workflow creates the GitHub Release.** After the package is on npm, a second job, the only one that can write to the repository, creates the Release for the tag with the matching section of the CHANGELOG as its notes, and does nothing if the Release already exists. A tag whose version has no section in the CHANGELOG fails that job. The Release no longer has to be made by hand.

- **A CodeQL workflow for this repository.** `.github/workflows/codeql.yml` analyses the JavaScript and TypeScript of `src/` and `template/` on pull requests to `main` and every Monday, with the configuration of css-js-minifier. The actions are pinned by SHA.

### Fixed

- **Three CodeQL warnings in code that every generated site carries**, found when CodeQL analysed a site made by 0.2.0. `parseCustomSvg` removed comments in a single pass, which could leave a `<!--` that the removal itself had closed up, so it now repeats until the text stops changing. The link text of `llms.txt` escaped brackets but not the backslash that could escape them, so a title ending in `\` could break the link, and it now escapes both. The inline text reader of the search index took comments with `.`, which does not match a line break, and now takes them with `[\s\S]`. The first two have regression tests. A site generated earlier gets the fixes after `customSvg.ts`, `buildLlmsText.ts` and `searchText.ts` are copied from this version, or with `sitekit upgrade`.

## [0.2.0] - 2026-10-30

### Added

- **The site base is added to the links of `nav` and `footer.links`.** A `href` that starts with `/` is a path of the site, and the build adds the `base` to it, in the header, in the menu of a phone and in the footer, as the buttons of the hero already did: with the base `/acme/`, `/docs/getting-started/` becomes `/acme/docs/getting-started/`. Web addresses, `//host` addresses, `mailto:` links, `#` anchors, paths relative to the page and paths that already start with the base are left as written, so a site that wrote the base into its hrefs keeps working and a site served from `/` does not change. A path that starts with the base by accident is taken as complete: with the base `/docs/`, `/docs/api/` stays `/docs/api/`, and `/docs/docs/api/` reaches the page below it. The rule is the pure function `withSiteBase` in the domain layer of the template, with a unit test, a test with a real `sitekit.config.json`, and a browser spec on a generated site with the base `/widget/` and a `nav` and `footer.links` (`verify-package` builds it a second time, and it is served on the port after the one of the project site). The warning on `docs/options-navigation.md` that asked for the base in each `href` is replaced by the rule. A site generated earlier gets this after `BaseLayout.astro`, `domain/siteHref.ts` and the line in `domain/index.ts` are copied from this version. See `docs/options-navigation.md`.
- **Guides for extending a site, each one run as a test.** A new group, Extending your site, in the Docs of the project site: an index and six guides. An interactive page that is not markdown (a configurator with a form, a live preview and the generated `hero` key), a new collection with its own place in the menu and its own groups, a component you changed and what `add` and `sitekit upgrade` do to it, a new accent in `design/tokens.json` with a script that checks its contrast, a brand logo of your own and the layout of a collection, and what `sitekit check` looks for with a rule of your own under `anonymize.denyPatterns`. Each guide is a folder in `e2e/recipes/` that has the layout of the repository. `scripts/recipes.mjs` applies it to a site made by `init` (a file is copied, `site/sitekit.config.json` is merged into the config, a `.diff` is applied with `git apply`), `scripts/verify-package.mjs` runs the commands the guide names with the real CLI and builds and checks the site, and `e2e/specs/recipes.spec.ts` drives it in Chromium. The configurator is tested at 320, 375 and 1280 px (no sideways scroll, targets of 44 px, a long line that scrolls inside its block), in both themes with measured contrast, without JavaScript, with no request to another host, and its output is compared with an expected text. The files a guide shows are copied from the folder by `npm run build:docs` (`scripts/build-recipe-docs.mjs`), and a test fails while a page is out of date. The guides add no package to the site: a check compares `package.json` and `package-lock.json` before and after. See `docs/extending.md`.
- **`npm run build:tokens` in a generated site.** The script that turns `design/tokens.json` into `src/styles/tokens.css` is now `scripts/build-tokens.mjs` in the site, with `--check` to fail when the CSS is out of date, and the kit's own script uses the same function. Until now only the repository of the kit had it, so a site owner who changed the tokens had no command to regenerate the CSS. A site generated earlier gets it after `scripts/build-tokens.mjs` is copied from this version and `"build:tokens": "node scripts/build-tokens.mjs"` is added to its `package.json`.
- **A page for each component, with a live preview, the code, the add command and its props.** The new Components section of the project site (`/components/<name>/`) has 19 pages, from `Button` to `PageInfo`. Each has a preview of the real component drawn with the tokens of the site and a switch to see it in the other theme without leaving the page (the colors of each theme come from `design/tokens.json` under a `data-preview-theme` attribute, written by `npm run build:tokens` into a stylesheet that only the project site loads); the code that produced the preview, in a code block with its title and copy button, behind a Preview and Code tab control (tabs pattern, `aria-selected`, arrow keys, Home and End), and both shown one after the other without JavaScript; the command in a `CommandBox`, the files it writes and what it requires, each linked; a table of props with `ReferenceTable`; each variant and state as a preview of its own; and notes on keyboard use, target size and what is announced. Preview and code come from one file, `template/src/examples/<name>/example.astro`, which the page imports as a component and as text (`?raw`), so they cannot drift apart, and the copy button copies exactly that text. The tables are generated by `scripts/build-component-docs.mjs` (run by `npm run build:docs`) from the TypeScript types and TSDoc of the component, into `template/src/examples/props.json`: a prop with no description fails the script and is named, and a test fails while the file is out of date. Only the props the template declares are listed, not what a component takes from the DOM. The ten entries of the registry without a page, such as `cn`, the stock shadcn/ui primitives that no component uses, `site-header` and `mobile-menu`, are listed in `docs/components.md` each with its reason, and a test fails when an entry has neither a page nor a place in that list. `docs/components.md` is now the index of the section, a link to each page, and the text it had about `StatRow`, `ReferenceTable` and `CatalogFilter` moved to their pages. The registry has an optional `example` pointer that `add` ignores. The examples, the layout of the pages and the generated files are not in the package and not in a generated site (`verify-package` checks the tarball, a generated site and `add`), and the generated site has no new dependency and the pages make no request to another host. A collection can now have a layout of its own: a file named after its id in `src/presentation/layouts/collections/` renders `DocPage` with more in its slot, and a site without that folder is not affected. The browser tests of the pages run against a build of the project site that `verify-package` makes, served on the port after the one of the generated site, at 320, 360, 390 and 1280 px: no sideways scroll, WCAG AA contrast in both themes (in the preview, in the other theme and in the code), 44 px controls, keyboard use of the tabs, and the copy button. See `docs/components.md`.
- **Mobile LCP under 2.5 s, and a font swap that moves nothing.** The mobile menu is a native modal `<dialog>` and a short script, not a React sheet, so a page no longer downloads React and the Radix packages for a toggle (`MobileMenu.tsx` is now `MobileMenu.astro`, the layout renders it, and the registry entry follows). The layout preloads the Latin files of Geist and Geist Mono, and `Geist Fallback` and `Geist Mono Fallback` are local fonts scaled to Geist's measures with `size-adjust` and the ascent, descent and line gap overrides, listed after the web font in `design/tokens.json`. On a site generated by `init`, in Lighthouse 12.6.1 mobile, three runs: LCP 2.86 to 3.00 s became 1.95 s, performance 93 to 94 became 99, and the page went from 337 KB to 152 KB. An inline stylesheet was measured and left out because it moved nothing. A browser test loads pages with the fonts 500 ms late and fails above a layout shift of 0.01 (`e2e/specs/vitals.spec.ts`, which reports the LCP element and its phases), and a CI job runs the public `lighthouse` package on the generated site against a budget for LCP, CLS, total blocking time and score, and uploads the reports. `e2e/serve.mjs` takes `--compress` and `E2E_PORT` picks the port of the browser tests. A site generated earlier gets this after it copies `MobileMenu.astro`, `SiteHeader.astro`, `BaseLayout.astro`, `global.css` and `design/tokens.json` and deletes `MobileMenu.tsx`. See `docs/performance.md`.
- **A configuration reference generated from the schema.** `npm run build:docs` reads the config schema and writes `docs/configuration.md`: one table per group of `sitekit.config.json`, with the key, its type, its default, the values it allows and its description. Every key of the schema now has a `.describe()`, and the script fails and names the keys that have none, so a key cannot be added undocumented. A test compares the page with the schema and fails while it is out of date, and a second run of the script leaves no diff. The `check` group lists every kind of finding as its own row with its default severity, read from `FINDING_KINDS`, `DEFAULT_SEVERITY` and the new `FINDING_DESCRIPTIONS`, so a new kind cannot be left out. The hand-written tables of keys in `docs/llms.md`, `docs/design-tokens.md` and `docs/edit-link.md`, and the Default column of the kinds in `docs/content.md`, are replaced by links to the page, and the README links to it. Also a `ReferenceTable` component for a reference written in Astro: names in code, a type, a default, the values allowed and a text, inside a bordered region that scrolls sideways on a phone and takes keyboard focus (`tabindex="0"` in the HTML, with a name), with a caption and row headers. `sitekit add reference-table` restores it. A site generated earlier keeps its own copy of the template, so it gets the component after `ReferenceTable.tsx` is copied from this version. See `docs/configuration.md` and `docs/components.md`.
- **Brand logos: `icon: "brand:<slug>"` in the config.** The kit ships 11 logos (Astro, Docker, GitHub, GitLab, Next.js, Node.js, npm, React, Tailwind CSS, TypeScript and Vercel) as path data, generated by `npm run build:brands` from `simple-icons` pinned to 16.36.0, a development dependency of the kit only. A logo is an inline SVG filled with `currentColor`, hidden from assistive technology unless `Icon` gets a `label`, and it asks nothing from any host, so a generated site has no new dependency. An unknown slug fails the build with the slug and the closest brands. The licence gate fails the script for an icon that is not CC0 unless it is on `scripts/brands/allowlist.json` with its licence, author and attribution, which then go to `THIRD_PARTY_NOTICES.md`; PHP (CC BY-SA 4.0) and AWS are not shipped. A logo the kit does not have is added as `brands/<name>.svg` next to the config and used as `brand:custom/<name>`; only plain `<path>` shapes are accepted. The header shows a repository button with the logo of the host (GitHub or GitLab, else a plain icon) and its name, 44 px tall, in the open menu on a phone, and the footer link has the logo too. A site generated earlier keeps its own copy of the template, so it gets this after `Icon.tsx`, the `domain/brands` folder, `customBrands.ts`, `config.ts` and the changes in `loadSite.ts`, `SiteHeader.astro`, `MobileMenu.tsx`, `SiteFooter.tsx` and `BaseLayout.astro` are copied from this version. See `docs/brand-logos.md`.
- **An "Edit this page" link and the date of the last change.** The `editLink` key (`enabled`, `branch`, `host`) puts a link at the foot of every page to its source file on the repository host: `{repository}/edit/{branch}/{path}` on GitHub, with the GitLab and Bitbucket forms too. The host is found from `site.repository`, `host` is for a repository on a domain of its own, and an unknown host turns the link off with a message in the build and in `sitekit check`, never a broken address. The path includes the folder of the sources inside the git repository, so a site in a subfolder gets the right address. The `lastUpdated` key shows the date of the last commit that changed the file itself, read with `git log` at build time, as a `<time datetime>` element. In a shallow clone, or outside git, no dates are shown and the build says why, and `sitekit check` warns when the clone is shallow. The link is a 44 px target and the line reaches WCAG AA in both themes. `sitekit init` turns both on for a new site and writes `fetch-depth: 0` in the workflow it generates. A site without the keys does not change, and `sitekit upgrade` adds both with `enabled: false`. The component is `PageInfo`, and `sitekit add page-info` restores it. A site generated earlier gets the line after `PageInfo.tsx`, `DocPage.astro`, `loadSite.ts`, `gitHistory.ts`, `buildPageMeta.ts`, `editLink.ts`, `lastUpdated.ts` and the change in `config.ts` are copied from this version. See `docs/edit-link.md`.
- **Variables and shared snippets in Markdown.** `{{ version }}` in prose, headings, link text and the frontmatter is replaced when the site is built, with the version of the repository's `package.json` or a value from the new `vars` key of `sitekit.config.json` (string values, and `vars` wins). In code spans and fenced code it is left as written. A snippet is a file under `snippets/` included with `<!-- include: name.md -->` alone on a line: the indentation of the comment goes in front of each line, so it works inside a list item, it goes one level deep, and the folder is not published as pages. The replacement happens first, when the content is read, so the title, the description, the search index, `llms.txt` and the Markdown copies show the replaced text. An unknown variable is a `variables` finding, a warning, and a missing snippet a `snippets` finding, an error, both with the file and line, in the build and in `sitekit check`, and both follow `check` in the config. A page that uses neither feature is not touched. GitHub shows `{{ version }}` as literal text and hides the include comment. See `docs/content.md`.
- **A detail layout with a side card of metadata.** A page with `meta` (a list of `label` and `value`), `links` (a list of `label` and `href`) and `tags` in its frontmatter shows a card beside its text, with no new data format. On a desktop (`lg` and up) the card is on the right and stays in view while the text scrolls, and it takes the place of the table of contents. On a phone it is under the title and above the text, collapsed to its first three rows, with an "All details" button that has `aria-expanded` and a 44 px target. Without JavaScript the whole card is shown and the button is not. The metadata is a `<dl>`, the links are real links resolved like the links in the text (a page becomes its route, a file of the repository becomes its address, a link to a missing or excluded file is left out), and a long value wraps. A page with only `tags`, such as an index with a filter bar, and a page with none of the three, do not change. The `SideCard` component takes its data through props and imports no content, and `sitekit add side-card` restores it. What the card's frontmatter got wrong is a new kind of finding, `card`, an error by default and configurable under `check` like the others: a key the card does not read (`lable` for `label`), an item without text, a `meta` or `links` that is not a list, and a link with a scheme other than `http:`, `https:` or `mailto:`. `sitekit check` and the build print it with the file and the line of the key in the frontmatter, and `check` exits with 1. A link of the card to a file that is missing or excluded is a `links` or `excludedLinks` finding, like the same link in the text. `meta` and `links` are now keys that the `frontmatter` check knows. A site generated earlier keeps its own copy of the template, so it gets the card after `DocPage.astro`, `document.ts`, `findings.ts`, `buildDocuments.ts`, `validateContent.ts`, `loadSite.ts` and the files of `side-card` are copied from this version. See `docs/detail-page.md`.
- **A filter bar for the index pages.** A page can have `tags` in its frontmatter, a list or a comma separated string. When any page of an index has a tag, the index shows a text field and one toggle button per tag above its cards. The cards that do not match get the `hidden` attribute, a polite status line says "N of M shown.", and a state with no match says so and offers "Clear filter". The state is in the address, `?tag=ui&q=card`, so a filtered view can be shared and the back button works. Without JavaScript every card is shown and the bar is hidden, and an index without tags does not change. The controls are 44 px high, with `aria-pressed` on the tags. The matching is a pure function in the domain layer, and `sitekit add catalog-filter` restores the files. A site generated earlier keeps its own copy of the template, so it gets the bar after `Document.tags`, `buildDocuments.ts`, `CollectionIndex.astro`, `ItemCard.tsx` and the files of `catalog-filter` are copied from this version. See `docs/components.md`.
- **Code blocks with a title, highlighted lines, diff lines and a copy button.** The options go after the language in the fence, which GitHub ignores: `ts title="src/config.ts" {2,4-6}`. A title is a caption bar over the block. The lines in the braces have a tone and a bar on their left edge. A line that ends with a `[!code ++]` or `[!code --]` comment, or a line of a `diff` block that starts with `+` or `-`, is shown as added or removed, with a sign as well as a tone, so color is not the only cue. The markers are taken out of the code. Every block has a copy button, a real button named "Copy code" with a 44 px target and a focus ring, that copies the text of the code (not the markers, and not the signs drawn in the margin) and says "Copied" in a polite status region. The button is written hidden and shown by a script of about 540 bytes that ships in the page and makes no request, so without JavaScript the block still reads. A long line scrolls inside the block, and a block with no options looks as it did. It is built on the Shiki transformers of the markdown package, so there is no new dependency. The tones are three new color tokens in both sets, `code-highlight`, `code-add` and `code-remove`, and the contrast tests check them against every token color of both code themes. A site generated earlier keeps its own copy of the template, so it draws these blocks only after the files that `docs/code-blocks.md` lists are copied from this version. See `docs/code-blocks.md`.
- **A `StatRow` component for a few numbers with their labels.** Two to five items, each a value, a label and an optional note, as a description list so the label and the value are read together. The value is the large text in the mono face and wraps when it is long. The grid has explicit tracks, one column on a phone, and it chooses no status color. The home page shows it when `sitekit.config.json` has a `stats` key (two to five items, or none), and a site without the key does not change. `sitekit add stat-row` restores it. See `docs/components.md`.
- **Search.** A header button, Ctrl K or Cmd K, and the slash key open a dialog that searches the title, headings and text of every page, and opens the section that matched. The search code and the index load on first use, and `search.enabled` in the config turns it off. `sitekit check` verifies that the index lists every page. Typo tolerance is not in this version.
- **A light theme, with a switch in the header.** The site stays dark by default. `theme.default` in `sitekit.config.json` takes `dark`, `light` or `system`, and an invalid value fails the build with the key named. A visitor's choice is saved in the browser and wins over the default, and the theme is applied before the first paint. The light set is a second set of colors in `design/tokens.json`, with the same keys as the dark one, and a test fails when the keys differ. Code blocks have a light highlighter theme. A site generated with an earlier version keeps its own `design/tokens.json`, which has no light set, so it stays dark until it adds one.
- **An `llms` key for `llms.txt`.** With `enabled`, the site writes `llms.txt` at its base: an H1 with the name, the description, one H2 per collection with absolute links and descriptions, and `## Optional` for the collections listed in `optional`. With `markdownPages`, each page also has a Markdown copy at its address with `index.html.md` after it, and the page links to it. `sitekit init` turns it on for a new site, and a site without the key does not change. It is a community proposal, not a search feature. See `docs/llms.md`.
- `sitekit check` verifies `llms.txt` when it is on: the H1, every link, every page listed, the Markdown copies, and the credential and internal host scan.
- **Callouts written in markdown.** A blockquote that starts with `> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`, `> [!WARNING]` or `> [!CAUTION]` on its own line becomes a callout, the alert syntax that GitHub renders too. It is plain HTML with `role="note"`, a hidden icon and a visible label, so it needs no JavaScript, and the tones come from the existing color tokens. A callout can hold paragraphs, lists and code, and can sit in a list item. A blockquote without a marker, an unknown marker such as `[!NOTES]`, and a marker in code are left as they are. The `Callout` component has the same five kinds, `role="note"` and a colored left edge, and the docs have a new page, Callouts. A site generated earlier keeps its own copy of the template, so it renders callouts only after `callouts.ts`, `calloutIcons.ts`, `remarkCallouts.ts`, the change in `renderMarkdown.ts` and the callout styles of `prose.css` are copied from this version. See `docs/callouts.md`.
- **`sitekit upgrade`, to bring a generated site up to the installed kit.** For each file in `site/.sitekit.json` it compares your file, the version it was written from (by hash) and the kit's file. A file you did not edit and the kit changed is replaced. A file you edited and the kit did not change is kept. A file you edited and the kit changed is left as it is, with the new version written next to it as `<file>.sitekit-new`, so your file is never lost. A file that is new in the kit is added. `--dry-run` prints the report and writes nothing, and the upgrade is a dry run by default when the working tree has uncommitted changes, unless you pass `--apply`. It never writes `docs/`, your other content, the deploy workflow or files that are not in the lock, and it adds only the options that do not exist yet to `sitekit.config.json` (`theme`, `search`, `llms`), with the value that keeps the site as it was. The lock is rewritten for the files that were replaced or added. The package name and description of a site are kept. See `docs/upgrading.md`.
- **Content findings in `sitekit check` and in the build.** The markdown is read as data and each problem is reported as `docs/guide.md:42: warning: ...`, with a severity, the file and the line of the link, image, heading or key: a relative link to a file that does not exist or that you excluded, a link to a heading that is not in the target page, an image that does not exist, a frontmatter key the kit does not read, an `order` that is not a number, two headings that make the same anchor, and an unknown callout marker such as `[!NOTES]`. `check` counts them and exits with 1 on any `error`, the build prints them and does not fail. A missing image and a bad `order` are errors, the rest warnings, and the new `check` key in `sitekit.config.json` sets each kind to `error`, `warning` or `off`; a name that is not a kind fails with the name in the message. Links, images, headings and markers inside code are never reported. The warnings that `loadSite` collected while rendering, and that nothing printed, are replaced by these findings. A site generated earlier gets the findings in `check` at once, because the CLI reads them, and in the build once it copies the changed files of `template/src/` and `astro.config.ts` from this version. See `docs/content.md`.
- **Options by topic, with examples.** Eight new pages in the documentation: an index and one page each for identity and the home page, navigation and collections, theme and design, search and `llms.txt`, content checks and publishing, the edit link and dates, and brand logos. Each group of keys has a `sitekit.config.json` example and says what it changes on the built site, found by building a site with that key. The keys stay documented once, in the generated configuration reference, and the topic pages link to it. A test reads the schema and fails for every key that no example shows, one test checks each example against the real schema, and one fails when a page repeats a row or a description of the generated reference. Two more tests fail when a message quoted on a page, or a finding shown in the table of the checks page, is not the one the code prints. A new end to end spec reads the facts of the default site on the generated site. The table of the kinds of finding in `docs/content.md` is replaced by links, because the reference already lists them. The documentation site keeps two example texts on its `anonymize.allow` list, since the checks page shows them. See `docs/options.md`.

### Changed

- **The project site announces `https://miguelcolmenares.com/docs-sitekit/` as its address**, in its canonical links, its sitemap and its `llms.txt`. The personal domain serves the site through a proxy, and GitHub Pages keeps answering at the old address. A site generated with `init` is not affected.
- **The default accent is the VS Code blue**: `accent` `#4fc1ff`, `accent-strong` `#007acc` and `accent-contrast` `#ffffff`, in place of the purple. A site generated with `init` takes the blue from the kit it is generated with. A site generated earlier keeps its own `design/tokens.json`, so it stays purple until its owner changes that file.
- **The Action's Marketplace icon is blue**, `branding.color` in `action.yml`, to match the new default accent. Blue is the closest color the Marketplace offers to the VS Code blue.

### Fixed

- **Four things the component pages measured in the components themselves.** The destructive `Button` was white on the danger color, 3.52:1 in the dark theme and 2.77:1 in the light one, and now takes the page color on it. The outline `Button` had a shadow, against the rule of 1 px borders. The command of a `CommandBox` scrolls sideways without a scroll bar and could not be reached with the keyboard, so it takes focus (`tabindex="0"`), as every scrollable region does. The contrast meter of the browser tests left out the text of a disabled control, as WCAG 1.4.3 does, and its own test covers that. A site generated earlier gets the first three after `button.tsx` and `CommandBox.tsx` are copied from this version.
- **The name of the tool is `docs-sitekit` everywhere a reader sees it.** The footer of every generated site, the Action address, its name, the issue forms, the contributing steps and the help text used the old short name. The `sitekit` command and the file names do not change. A test reads these texts and fails on the old name. The Action address in the 0.1.0 notes is corrected too.

## [0.1.1] - 2026-10-28

### Fixed

- **Two CodeQL findings in `describe.ts`**, the file that turns markdown into titles and descriptions and that every generated site carries. Removing HTML tags in a single pass left a `<script` behind when tags were nested, so tags are now removed until the text stops changing. The check for a row of badges used a nested repetition that could backtrack exponentially on a long run of badge-like text, and now removes each badge with a single pattern. Both have regression tests. A site generated with 0.1.0 can copy `describe.ts` from this version.
- The project site is served under `/docs-sitekit/`, where it was still asking for its assets under the old repository name. A test now ties the site's base path, address and repository to `package.json`.

## [0.1.0] - 2026-10-28

First release. The package is `docs-sitekit` and the action is `miguelcolmenares/docs-sitekit`. The `sitekit` command is the one you run: `npx docs-sitekit init`.

### Added

- `sitekit init`, `check`, `list` and `add`. `init` reads `package.json` and the git remote, finds `docs/`, `docs/tutorials/`, `docs/examples/` and `examples/`, writes the site and a GitHub Pages workflow, and refuses a folder that already has files.
- **Collections and groups.** A site has any number of collections (Docs, Tutorials, Examples). A page belongs to the collection with the deepest folder, so `docs/tutorials/` can sit inside `docs/`. Pages can be put in groups with a tone, and a page that is in no group, or a group that names a page that does not exist, fails the build instead of being skipped.
- **A reusable GitHub Action** (`miguelcolmenares/docs-sitekit`) that installs, builds and checks a site and uploads it as the Pages artifact. The workflow `init` writes uses it and rebuilds the site when a release is published. Deploying stays in a separate job.
- A dark design system on Astro, Tailwind, shadcn/ui and lucide-react: tokens, header, hero, section headers, cards, feature grid, flow diagram, command table, callouts, footer, doc layout with table of contents, and copy buttons. Tokens come from one file, and contrast is tested on them.
- A content pipeline that turns markdown into pages, derives titles and descriptions without being fooled by badges, tables or code fences, rewrites relative links, and fails on two files that would get the same route.
- The version in the footer is read from the repository's `package.json` on every build, so a site rebuilt for a release shows the release.
- A publish check, `sitekit check`: credentials and internal hosts in the content and in the built files, the repository's visibility (a private repository's Pages site is public), and the shape of the output, including a `404.html` that is not a copy of `index.html`.
- Pack-and-install verification, and Playwright tests on a phone (320, 360 and 390 px) and a desktop: WCAG AA contrast measured in the browser, touch targets, scrollable code blocks and tables that can be focused, no horizontal scroll, keyboard use, and accessibility checks.
- Security policy, contributing guide, issue and pull request templates, and third-party notices.
