Skip to content

Releases

v1.22.1 — afdocs 0.23.0

Choose a tag to compare

@dkdev24 dkdev24 released this 11 Nov 02:38

Bumps the pinned afdocs scanner CLI from 0.22.2 to 0.23.0. Re-verified end to end (verify-loop on all fixtures, lint, live scan identical to 0.22.2), so no adapter changes were needed. No behavior change otherwise. Fixture-only dependency bump (undici) is not part of the published package.

v1.22.0 — .md-sibling duplicate check + fixer

Choose a tag to compare

@dkdev24 dkdev24 released this 11 Nov 02:20

New md-duplicate-signal check in the agent-headers scanner: fails when a .md mirror and its HTML twin both return 200 and the .md has neither a canonical Link header nor X-Robots-Tag: noindex. This is the pattern behind Search Console's "duplicate without user-selected canonical" alerts on sites that publish markdown siblings for agents.

enhance fixes it per platform: Cloudflare Pages and Netlify merge a /*.md noindex rule into _headers, Vercel merges one into vercel.json, CloudFront/OpenNext gets a warning with the exact response-headers-policy instruction, and GitHub/GitLab Pages stay report-only. Existing rules are never rewritten.

Also fixes agent-headers missing .md links in Starlight-format llms.txt files (bare root-relative paths), which made the new check skip on exactly the sites it targets.

v1.21.0 — SvelteKit + Cloudflare Pages fixer

Choose a tag to compare

@dkdev24 dkdev24 released this 31 Oct 05:55

New fixer for SvelteKit (adapter-static) on Cloudflare Pages, including monorepos. enhance wires a zero-dependency postbuild script that edits only the build output: missing canonical link, homepage JSON-LD (WebSite, override with AGENT_READINESS_SCHEMA_TYPE), a hidden llms.txt pointer, .md mirrors, /404.md and llms.txt, each only when absent. Adds functions/_middleware.js for Accept: text/markdown negotiation at the Pages project root. Site source is never touched and existing files are never overwritten.

Local result on a real SvelteKit docs site: afdocs 85 → 95.

Also includes the 1.20.0 engines floor (Node >=22) that was not previously published to npm.

v1.20.0

Choose a tag to compare

@dkdev24 dkdev24 released this 26 Oct 04:50

Engines floor raised: engines.node is now >=22 (was >=18). Node 20 and older are end of life; Node 22 stays supported. CI runs on Node 24 with current GitHub Actions. No CLI behavior change.

Not published to npm yet; npm latest is still 1.19.3.

v1.17.0

Choose a tag to compare

@dkdev24 dkdev24 released this 17 Oct 08:39

Fixed: Starlight .md mirrors now stand on their own

The src/pages/[...slug].md.ts route that enhance writes for Astro + Starlight served each page's
raw MDX body. Two problems, both found on a real production Starlight docs site:

  • Relative links broke. ../guide/ in a page at /docs/page/ resolves to a different place
    next to /docs/page.md, and to nothing once an agent has the text without its URL. afdocs 0.22's
    markdown-link-portability check fails on this.
  • Component text was hidden. Starlight components stayed as raw JSX, and a LinkCard's title
    and description live in attributes, so card-based landing pages lost most of their text in the
    markdown (36–90% missing on that site). afdocs' markdown-content-parity check fails on this.

The mirror now runs the body through toAgentMarkdown() in a new src/lib/md-mirror.js:

  • Every link and image target is resolved against the page's HTML URL: absolute when
    astro.config sets site, root-relative otherwise. base is respected.
  • LinkCard becomes a list item with the description on its own line under the link,
    LinkButton a link, Badge (text), Aside a **Note:**/title label, Card/TabItem a bold
    label. CardGrid, Steps, Tabs, FileTree wrappers and import lines are dropped.
  • Fenced code is left untouched.

If you already ran enhance: it never overwrites your existing [...slug].md.ts. Re-running
siteready enhance now writes src/lib/md-mirror.js and warns when your route still serves the raw
body. Wire it in:

import { toAgentMarkdown } from '../lib/md-mirror.js';
// ...
const root = import.meta.env.BASE_URL.replace(/\/?$/, '/');
const slug = params.slug === 'index' ? '' : params.slug;
const pageUrl = new URL(`${root}${slug ? `${slug}/` : ''}`, site ?? 'http://localhost/');
const body = toAgentMarkdown(entry.body ?? '', pageUrl, Boolean(site));

(params and site come from the GET handler's context.)

v1.16.1

Choose a tag to compare

@dkdev24 dkdev24 released this 17 Oct 07:50

Changed: afdocs 0.20.0 → 0.22.2

The afdocs scanner now runs at 0.22.2. Its JSON output is compatible with siteready's scorecard,
so reports keep the same shape. afdocs 0.22 adds five checks:

  • bot-protection-interference
  • embedded-data-serialization
  • markdown-link-portability
  • page-size-transfer
  • single-fetch-completeness

Scores can move because of the new checks and weights, not because your site changed. A
diff-report between a baseline scanned with 1.16.0 or earlier and a rescan with 1.16.1 lists
these five as new checks. For a clean before/after comparison, re-run the baseline with 1.16.1.

To try a different afdocs version for one run without upgrading siteready:
AFDOCS_VERSION=<version> siteready <url>.

v1.16.0

Choose a tag to compare

@dkdev24 dkdev24 released this 17 Oct 07:30

Fixed: markdown-negotiation middleware returned 404 to agents (Cloudflare Pages, Netlify)

The middleware enhance writes for Cloudflare Pages (functions/_middleware.js) and Netlify
(netlify/edge-functions/) treated every markdown-preferring request as a page request. For any
URL that already has a file extension it looked up <path>.md, found nothing and served the
/404.md mirror with a 404:

  • .md URLs requested with Accept: text/markdown (Claude Code's WebFetch sends
    text/markdown, text/html, */*), so the .md links your llms.txt advertises were broken for
    those clients.
  • robots.txt, sitemap.xml and nested llms*.txt indexes requested by an AI crawler UA
    (GPTBot, ClaudeBot, ...).

The templates now skip negotiation for any path with a file extension. Claude-User (Claude's
user-initiated fetcher) is added to the bot list. Vercel's Proxy was not affected.

If you already ran enhance: it never overwrites an existing middleware, so your site still
has the old one. Either delete the generated file and re-run siteready enhance, or add this
guard before the markdown branch:

const url = new URL(request.url);
const hasExtension = /\.[a-z0-9]+$/i.test(url.pathname);
if (wantsMarkdown && !hasExtension) {

New: agent-headers scanner (on by default)

The external scanners test one header pattern per URL type and follow redirects, so they all
passed the broken middleware above. agent-headers requests every kind of URL your llms.txt
links to (index files, .md links, pages, plus robots.txt/sitemap.xml, following nested
llms*.txt one level) with real agent headers (Claude Code's Accept, a GPTBot UA) and without
following redirects. A check fails when a URL that works for a plain request returns an error, or
redirects to a different path, for an agent.

It's plain fetch() with no hosted API behind it, so it runs by default for scan/rescan and
for scan-local/rescan-local/loop. Run it alone with --scanners agent-headers.

v1.15.0

Choose a tag to compare

@dkdev24 dkdev24 released this 12 Sep 15:22

Restored: the loop command

scan-local -> enhance -> rescan-local, chained into one command with no manual step in between —
an opt-in single-shot convenience for a quick pass (e.g. a POC). The three-separate-commands path
stays the default recommendation, since it lets you review the enhance diff before re-scanning.

loop was removed in v1.14.0 over a theory that two Quick Tunnels opened back-to-back were
unreliable. That theory turned out to be wrong: the real cause was tunnel.js probing a
freshly-minted tunnel hostname before it was actually safe to. Fixed directly (gate the first probe
on cloudflared's own "precheck complete" signal) — two tunnels in one process are now no less
reliable than one, so loop came back.

Side effect of chasing that fix down: is-agentic's long-standing "could not fetch homepage" error
against subfolder-hosted sites (e.g. a GitHub Pages project site) is now confirmed to be a
scanner-side bug that breaks on any non-root path — not something siteready can fix, but no longer
a mystery either.

New: local-scan vs. deployed-URL score gap, documented and surfaced

scan-local/rescan-local/loop only run a platform's real edge runtime locally for Cloudflare
Pages and Vercel. Every other platform (Netlify, GitLab Pages, generic static-host fallback) gets a
plain static-file server, which can't execute that platform's edge functions — confirmed
concretely for Netlify, whose markdown-negotiation Edge Function fix can only be verified against a
real deploy. A local scan now prints a clear note when this applies, and the same note is written
into report.md/report.json (localScanNote) — instead of the local score just reading lower
with no explanation.

Fixed

  • A latent bug in loop (present before its v1.14.0 removal too, not introduced here): it was
    missing the same Jekyll guard scan-local already had.
  • Stale documentation describing the reverted Quick Tunnel min-gap guard as still-current behavior
    (docs/architecture.md, SKILL.md, CLI help text).

Full history: WORKLOG.md.

v1.14.0

Choose a tag to compare

@dkdev24 dkdev24 released this 12 Sep 12:15

Quick Tunnel reliability + loop command removed

Tunnel reliability fix: traced Cloudflare Quick Tunnel's DNS-propagation flap to spacing
between tunnel creations, not per-attempt delay. src/lib/tunnel.js now refuses to open a new
tunnel under a 2-minute gap since the last one (persisted across CLI invocations), with a clear
error naming how long to wait -- an evidence-based known-bad-zone filter, not a claim that 2
minutes is proven sufficient. Reachability-flap failures no longer retry back-to-back with no gap.
Added a rolling tunnel-count warning as usage nears the observed (undocumented) ~20/hour creation
rate limit.

Removed the loop command. Its whole design -- chaining baseline-scan -> enhance -> re-scan ->
diff-report into one automatic shot -- was exactly the back-to-back-tunnel pattern just proven
unreliable for hosted scanners (is-agentic/ora). No deprecation, since there are no real users
yet. New rescan-local command (scan-local's rescan counterpart) means the reliable replacement
workflow now exists: scan-local -> enhance -> rescan-local, run as three separate commands so
a real gap (e.g. reviewing the report) naturally falls between the two tunnel-needing steps.

Changed

  • src/lib/tunnel.js: persisted min-gap guard, reachability-flap-aware retry loop, rate-limit
    proximity warning.
  • src/cli.js: new rescan-local command; loop command removed.
  • src/loop.js: runLoop removed (kept runScanLocal and its supporting helpers).
  • scripts/verify-loop.js: rewritten to compose runScanLocal + enhance + buildDiffReport
    directly instead of calling the removed runLoop.
  • README.md, docs/, SKILL.md, AGENTS.md, CONTRIBUTING.md: every loop reference replaced with the
    scan-local / enhance / rescan-local sequence.

Verified: npm run verify-loop green across all three reference fixtures, scripts/check-syntax.js clean.

v1.13.0 — GitLab Pages platform module

Choose a tag to compare

@dkdev24 dkdev24 released this 12 Sep 03:58

Third step toward "support as many framework/platform combos as possible, zero new accounts or auth" (NEXT_ACTIONS.md #20-#24).

#22 — GitLab Pages platform module
New src/platforms/gitlab-pages.js — static-only warning fixer, same shape as github-pages.js (no server-side Accept-header branching possible on either static host).

detect-stack.js gained hasGitlabPagesJob(), detecting .gitlab-ci.yml + a top-level pages: job as its own platform signal (no YAML parse dependency, matching the existing config-file-existence style used for every other platform signal). Applied to both the npm-ecosystem branch (astro/astro-starlight + gitlab-pages is now a supported enhance pairing) and the Jekyll branch (previously hardcoded to github-pages, now gitlab-pages or github-pages depending on the CI config present).

loop.js's runScanLocal guard was generalized from a per-platform allowlist to excluding Jekyll by framework (its build is Ruby/bundler, not npm run build, regardless of which Pages host it targets) — so gitlab-pages, and any future platform detect-stack.js learns, rides scan-local automatically with no allowlist to keep extending.

Docs (README.md, docs/install.md, docs/why.md, docs/architecture.md) updated for this and the previous release's Netlify + generic static-server changes.

Verified: detectStack() across 5 synthetic repos (including 2 regression checks confirming plain Jekyll and plain Astro behavior is unchanged), idempotent enhance(), runScanLocal correctly rejects Jekyll regardless of platform, npm run verify-loop green.

Full detail: WORKLOG.md v1.13.0.