Skip to content

Release 0.10.0: it finds your site - #32

Merged
likeBloodMoon merged 8 commits into
masterfrom
claude/release-roadmap-0-8-0-v79592
Sep 26, 2026
Merged

likeBloodMoon merged 8 commits into
masterfrom
claude/release-roadmap-0-8-0-v79592

Conversation

@likeBloodMoon

Copy link
Copy Markdown
Owner

The 0.10.0 step of the 1.0 plan in ROADMAP.md. The commits are in order, and each one passes lint, typecheck and the tests on its own.

What changed

  • Next.js, in depth.
    • A server build is built and started with next start on a free port.
    • The crawl starts from the pages the build's own manifests list (prerender, routes, app paths, pages), so a page nothing links to is still audited. Report discovery is "manifest".
    • basePath, i18n and trailingSlash are respected.
    • A dynamic route with no prerendered pages is named as not audited.
    • A standalone build is served by its own server.js. next dev is never used.
    • The fixtures are manifests from real Next.js 16 builds, with the preview keys redacted.
  • Twenty more stacks, 41 in the registry.
    • Apps: Qwik, SolidStart, TanStack Start, Analog, Vue CLI, Parcel, Rsbuild, Rspack, Ember.
    • Docs and static generators: Hexo, MkDocs, Sphinx, mdBook, Zola, Quarto, Pelican. Each has its output directory read from its config, which is never executed.
    • Never started: Drupal, Statamic, and Ghost and Shopify themes.
    • Every recognised framework comes with the evidence for it.
  • Package managers. Corepack's packageManager field is read first, then the lockfile: bun.lock, deno.lock and package-lock.json are now recognised. The lockfile is looked for up to the repository root. Deno scripts run as tasks.
  • Monorepos. pnpm, yarn and npm workspaces, Turborepo, Nx and Lerna are recognised. One site is audited as if the command ran inside it; several are listed with the command for each. init asks which site to set up.
  • Single-page-app shells. A page with nothing a visitor can perceive before a script runs is set aside and listed as not audited, instead of passing. A build that holds only a shell stops, and suggests --browser.
  • storybook-static/ is never audited.
  • eaa-kit detect [--json] says what an audit would do and why. It builds and starts nothing.
  • eaa-kit doctor checks Node, the package manager, the site, the config, the CI pipeline, the baseline and Playwright/Chromium on one screen. Each problem comes with the command that fixes it.
  • The gate. tests/fixtures/stacks/ has 14 stack fixtures, each with an expected.json that detect must match.
  • soak.yml runs nightly. It scaffolds Next.js (on all 3 operating systems), Astro, SvelteKit, Nuxt, Docusaurus and Vite from their official starters, then audits each with no directory.

Verification

  • pnpm lint, pnpm typecheck, pnpm smoke and pnpm release:check pass.

  • pnpm test: 1,525 tests pass.

    • The one failing file is the Playwright test, which fails in this container on master too because its Chromium doesn't match. CI installs its own.
    • test:packaged fails its 3 real-Chromium checks for the same reason.
  • End to end with the built CLI. Each starter was scaffolded and installed for real, then run through eaa-kit audit with no directory:

    • Astro: its build folder, 1 page.
    • SvelteKit and Nuxt: built, served and crawled.
    • Docusaurus: 28 pages.
    • Next 16: served and seeded from its manifests.
    • A Next 16 app with basePath: '/docs': all 5 pages, including one nothing links to, with /docs/user/[id] reported as not audited.
    • No server was left running afterwards.
  • Scaffolds. Every scaffold command in soak.yml was run with stdin closed and needs no terminal.

  • pnpm bench is at or below the 0.9.0 baseline:

    Measurement 0.9.0 0.10.0
    1 page 1,444 ms 1,156 ms
    20 pages 3,854 ms 2,890 ms
    Cache hit 343 ms 296 ms

Report format

completeness.discovery gains the value "manifest". schemaVersion stays 2 because nothing was removed or renamed. This is noted in the CHANGELOG and in docs/reports.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM


Generated by Claude Code

… each

- The registry recognises Qwik, SolidStart, TanStack Start, Analog, Vue CLI,
  Parcel, Rsbuild, Rspack, Ember, Hexo, MkDocs, Sphinx, mdBook, Zola, Quarto
  and Pelican, and Drupal, Statamic, Ghost and Shopify themes, which are never
  started. Hugo is also found through config/_default/. Zola is told from Hugo
  by what config.toml says.
- detectFramework says why it recognised a framework and where the output
  directory came from, for `eaa-kit detect`.
- The package manager comes from corepack's packageManager field first, then a
  lockfile, including Bun's text bun.lock, deno.lock and package-lock.json,
  searched up to the repository root so an app in a monorepo finds the
  workspace's lockfile. Deno runs scripts as tasks.
- storybook-static/ is never audited as part of the site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
A plain `next build` writes no HTML this tool can audit as files, so the
project was built, started and crawled from its home page, which finds what
the navigation links to rather than the site.

- The build's manifests (prerender, routes, app paths, pages) are read for
  every page it has, and the crawl is seeded from them, so a page nothing
  links to is audited. Report discovery is "manifest".
- basePath, the default locale's unprefixed paths, and trailingSlash are
  respected; API routes, error pages and metadata files are left out.
- A dynamic route with no prerendered pages is named as not audited rather
  than silently missed.
- A standalone build is served by its server.js when its static files are in
  place; otherwise `next start`, never `next dev`.
- Servers are offered a free port through PORT, the announced URL is read
  through colour codes and 0.0.0.0, and more framework ports are probed.

The fixtures are the manifests of real Next.js 16 builds, with the preview
keys redacted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
…passed

- Run from the root of a pnpm, yarn or npm workspace, or a Turborepo, Nx or
  Lerna repository, the audit finds the packages that are sites. One site is
  audited as though the command ran inside it; several are listed with the
  command for each. `init` asks which site and writes the config there, and
  refuses to guess when there is nobody to ask.
- A page with nothing a visitor could perceive before a script runs, such as
  a Vite build's empty div#root, is set aside and named as not audited, since
  the browserless engine would report it clean. A build holding only a shell
  stops with the command to audit it in a browser. --browser runs the
  script and audits it as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
`eaa-kit detect [dir]` says what an audit here would do and the evidence
for each part of it: the framework and what identified it, the package
manager and why, the build output or what would be built or started, a
Next.js build's page count and its unlisted dynamic routes, a monorepo's
sites. It builds, starts and writes nothing. `--json` prints the same as
data.

tests/fixtures/stacks holds one project layout per kind of stack, each with
the answer detect must give in expected.json, and the suite checks every
one. Generators that are not npm packages carry their own build command,
so a Hugo or MkDocs project with no build yet is told what to run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
One screen with everything this tool needs to work in a project, each
problem followed by the command that fixes it:
- the Node.js version, against the engines range;
- the project's package manager, and whether it is installed;
- what detection makes of the site;
- the config, and whether it parses;
- a GitHub, GitLab or Bitbucket pipeline that runs eaa-kit;
- the baseline, and entries in it that have expired;
- Playwright and Chromium, for the optional --browser.

Exit 2 only for what stops an audit from running; a missing config, CI
file or baseline is advice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
… starter

Next.js (on Linux, macOS and Windows), Astro, SvelteKit, Nuxt, Docusaurus
and a Vite app (in a browser, since it is an app shell) are scaffolded from
their official starters at pinned majors, installed, and audited with no
directory, so detection decides. Exit 2 or no pages fails the job. Every
scaffold command was checked to run without a terminal, and the audits
were run against the same starters before this was committed.

Progress messages name the real command a server is started with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
Docs for detection, detect and doctor, the builder table, the changelog,
the version, the Action pins, the examples and the roadmap status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
Windows has no process groups, and killing the cmd.exe that ran the
project's start script left the Node server it spawned running. On CI
that left the temporary project directory locked (EBUSY) and orphaned
servers behind; on a user's machine the server outlived the audit.
taskkill /T /F takes the tree down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM

Copy link
Copy Markdown
Owner Author

check (windows-latest, 24) failed because of a real bug, fixed in e9230e2. On Windows, stopping the server an audit had started killed only the cmd.exe that launched it. The Node server underneath kept running, holding the temporary directory (EBUSY) and showing up as orphaned processes. stop() now uses taskkill /T /F to kill the whole process tree.

github-advanced-security failed for a reason outside this PR. It is the same GitHub-side configuration failure as on #27–#30, and none of this PR's changes touch it, so there is nothing for this PR to fix. It clears once the repository's code scanning setting is corrected.


Generated by Claude Code

@likeBloodMoon
likeBloodMoon marked this pull request as ready for review September 26, 2026 20:26
@likeBloodMoon
likeBloodMoon merged commit e121773 into master Sep 26, 2026
5 of 6 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9230e25d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli/setup.ts
Comment on lines 90 to 94
pnpm: 'pnpm install --frozen-lockfile',
yarn: 'yarn install --frozen-lockfile',
bun: 'bun install --frozen-lockfile',
deno: 'deno install --frozen',
}[manager]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not emit deno install --frozen

When Deno is selected as the package manager, init supplies this as the action’s install-command, and the composite action executes it before the build (action.yml:164-174). deno install installs a named script/executable rather than project dependencies; without its required command, deno install --frozen exits nonzero, so every generated Deno workflow stops before deno task build or the audit. Omit this install step or generate a valid Deno cache command instead.

Useful? React with 👍 / 👎.

Comment thread src/cli/setup.ts
Comment on lines 82 to +83
if (manager === 'bun') setup.push(' - uses: oven-sh/setup-bun@v2')
if (manager === 'deno') setup.push(' - uses: denoland/setup-deno@v2')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Configure native Deno projects without package.json

Native Deno sites commonly have deno.json and deno.lock but no package.json. workflowFor sets manager to undefined whenever readPackageJson returns undefined (line 65), so this new Deno setup branch and the deno task build branch are both skipped; init consequently writes a workflow that neither installs Deno nor builds the site before auditing it. Detect the manager independently of package.json and read Deno tasks for this project shape.

Useful? React with 👍 / 👎.

Comment thread src/audit/crawl.ts
Comment on lines +478 to +480
if (seeded.length > 0) {
discovery = 'manifest'
for (const url of seeded) enqueue(url, 0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Queue manifest seeds before sitemap URLs

When both sources exist—for example, an automatically served Next app with a sitemap larger than --max-pages—the sitemap URLs have already been enqueued at line 466 before these manifest seeds are added. The page limit then drains sitemap entries first and can leave manifest-only routes unrequested, defeating the stated Next manifest coverage while the report still labels discovery as manifest. Enqueue or otherwise prioritize seeds ahead of sitemap URLs.

Useful? React with 👍 / 👎.

Comment thread src/audit/workspaces.ts
Comment on lines +98 to +100
return [...block.matchAll(/^[ \t]*-[ \t]*['"]?([^'"\n#]+?)['"]?[ \t]*(?:#.*)?$/gm)]
.map((match) => match[1] ?? '')
.filter((entry) => entry !== '' && !entry.startsWith('!'))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor pnpm workspace exclusion patterns

For a workspace such as packages: ['apps/*', '!apps/legacy'], this drops the negated pattern and findWorkspaceSites subsequently glob-matches apps/legacy/package.json anyway. If that excluded package has a recognized framework, it is presented as an auditable site and can turn a one-site automatic audit into a misleading choose-site prompt. Preserve negated entries as glob ignores when scanning manifests.

Useful? React with 👍 / 👎.

likeBloodMoon pushed a commit that referenced this pull request Sep 26, 2026
…ace exclusions

Four findings from the review of #32:

- init no longer gives a Deno project `deno install --frozen` as its
  install command, which is not a dependency install on every Deno
  version and stopped the workflow at its first step. Deno gets no
  install step; `deno task` fetches what the build needs.
- A Deno project with no package.json gets a workflow that sets up Deno
  and runs `deno task build`, read from deno.json or deno.jsonc. A Deno
  config marks the project as Deno even before it has a lockfile.
- A Next.js build's own page list is queued ahead of the sitemap, so a
  --max-pages limit cannot run out on sitemap entries first.
- Exclusions in pnpm-workspace.yaml and package.json workspaces
  (`!apps/legacy`) are applied, so an excluded package is not offered
  as a site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants