From f09fbaec0dacf94df9d4a09acb3e439f41c7eff9 Mon Sep 17 00:00:00 2001 From: ZJ van de Weg Date: Fri, 25 Sep 2026 16:48:12 -0700 Subject: [PATCH 1/9] handbook changes: survive the move out of nuxt/ Add content/handbook/ as the newest handbook prefix and skip a rename that only moves a page between two prefixes. Without this, the commit that moves the Nuxt app to the repository root would list every handbook page as renamed in that week's Recent Changes, and the history under nuxt/content/handbook would drop out of the log's pathspec. --- nuxt/server/lib/handbookChanges.mjs | 27 ++++++++++++------ nuxt/server/lib/handbookChanges.test.mjs | 35 +++++++++++++++--------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/nuxt/server/lib/handbookChanges.mjs b/nuxt/server/lib/handbookChanges.mjs index 3945bc61d5..0917ea15e3 100644 --- a/nuxt/server/lib/handbookChanges.mjs +++ b/nuxt/server/lib/handbookChanges.mjs @@ -4,10 +4,12 @@ // week (Monday start), newest week first, so the team can review "last week's // changes" at the Monday review. // -// The handbook used to live under `src/handbook` (11ty) and now lives under -// `nuxt/content/handbook` (@nuxt/content). Both prefixes are scanned so the -// full history survives the Nuxt migration; both map onto the same -// `/handbook/...` URLs the live site serves. +// The handbook used to live under `src/handbook` (11ty), then under +// `nuxt/content/handbook` (@nuxt/content), and moves to `content/handbook` once +// the Nuxt app leaves its subdirectory. Every prefix is scanned so the full history +// survives each move; all of them map onto the same `/handbook/...` URLs the live +// site serves. A commit that only moves a page between two of them is skipped, so a +// move does not list every page as renamed. // // This module deliberately depends only on Node built-ins so it can be // imported by the Nitro server route AND executed standalone for verification. @@ -21,9 +23,10 @@ const REPO_URL = 'https://github.com/FlowFuse/website' // subjects, so subjects containing spaces or pipes parse cleanly. const SEP = '\x01' -// Path prefixes that count as handbook content. Order matters only for display -// labels; both fold onto the same handbook-relative path. -const HANDBOOK_PREFIXES = ['nuxt/content/handbook/', 'src/handbook/'] +// Path prefixes that count as handbook content, newest location first. They are +// history, not the current layout, so a move adds one rather than rewriting them. +// All fold onto the same handbook-relative path. +const HANDBOOK_PREFIXES = ['content/handbook/', 'nuxt/content/handbook/', 'src/handbook/'] // Where the CURRENT version of a page lives, used for title lookups. const CONTENT_ROOT = 'nuxt/content/handbook' @@ -42,6 +45,13 @@ export function toHandbookRel (path) { return rel } +/** True when a rename status only moves a page from one handbook prefix to another. */ +export function isRelocation (status, fromPath, toPath) { + if (!status.startsWith('R')) return false + const rel = toHandbookRel(toPath) + return rel !== null && rel === toHandbookRel(fromPath) +} + /** Map a handbook-relative file path to the URL the site serves (trailing slash, like the rest of the handbook). */ export function relToUrl (rel) { let noExt = rel.replace(/\.(md|njk)$/, '') @@ -150,7 +160,7 @@ export function getHandbookChanges (repoRoot = process.cwd()) { output = execFileSync('git', [ 'log', '--no-merges', '-M', '--name-status', '--date=short', `--pretty=format:${SEP}%H${SEP}%ad${SEP}%s`, - '--', 'nuxt/content/handbook', 'src/handbook' + '--', ...HANDBOOK_PREFIXES.map(prefix => prefix.slice(0, -1)) ], { cwd: repoRoot, maxBuffer: 64 * 1024 * 1024 }).toString() } catch (err) { // Never break the build/render if git is unavailable. @@ -171,6 +181,7 @@ export function getHandbookChanges (repoRoot = process.cwd()) { const parts = line.split('\t') const status = parts[0] const path = status.startsWith('R') || status.startsWith('C') ? parts[2] : parts[1] + if (isRelocation(status, parts[1], path)) continue if (path) cur.files.push({ status, path }) } } diff --git a/nuxt/server/lib/handbookChanges.test.mjs b/nuxt/server/lib/handbookChanges.test.mjs index 623eca8793..0d43c2750c 100644 --- a/nuxt/server/lib/handbookChanges.test.mjs +++ b/nuxt/server/lib/handbookChanges.test.mjs @@ -7,7 +7,7 @@ import { test } from 'node:test' import assert from 'node:assert/strict' import { execFileSync } from 'node:child_process' -import { getHandbookChanges, toHandbookRel, relToUrl, mondayOf, prsFromCommits } from './handbookChanges.mjs' +import { getHandbookChanges, toHandbookRel, relToUrl, mondayOf, prsFromCommits, isRelocation } from './handbookChanges.mjs' // --- pure helpers ----------------------------------------------------------- @@ -48,6 +48,7 @@ test('prsFromCommits dedupes a single commit shared across pages and sorts newes }) test('toHandbookRel keeps tracked handbook pages and strips the prefix', () => { + assert.equal(toHandbookRel('content/handbook/company/values.md'), 'company/values.md') assert.equal(toHandbookRel('nuxt/content/handbook/company/values.md'), 'company/values.md') assert.equal(toHandbookRel('src/handbook/company/values.md'), 'company/values.md') assert.equal(toHandbookRel('src/handbook/engineering/product/features.njk'), 'engineering/product/features.njk') @@ -60,6 +61,14 @@ test('toHandbookRel rejects non-handbook, non-page and excluded files', () => { assert.equal(toHandbookRel('src/handbook/data.json'), null) // other json }) +test('isRelocation recognises a page moved between handbook prefixes', () => { + assert.equal(isRelocation('R100', 'nuxt/content/handbook/company/values.md', 'content/handbook/company/values.md'), true) + assert.equal(isRelocation('R087', 'src/handbook/company/values.md', 'nuxt/content/handbook/company/values.md'), true, 'edited while moving') + assert.equal(isRelocation('R100', 'content/handbook/company/values.md', 'content/handbook/company/principles.md'), false, 'a real rename') + assert.equal(isRelocation('M', 'content/handbook/company/values.md', undefined), false) + assert.equal(isRelocation('R100', 'nuxt/content/ebooks/a.md', 'content/ebooks/a.md'), false, 'not handbook') +}) + test('relToUrl maps file paths to trailing-slash handbook URLs', () => { assert.equal(relToUrl('company/values.md'), '/handbook/company/values/') assert.equal(relToUrl('company/index.md'), '/handbook/company/') @@ -165,27 +174,27 @@ test('the actual latest handbook commit appears in the most recent week', () => const log = execFileSync('git', [ 'log', '--no-merges', '-M', '--name-status', '--date=short', `--pretty=format:${RECORD}%H%x1f%ad%x1f%s`, - '--', 'nuxt/content/handbook', 'src/handbook' + '--', 'content/handbook', 'nuxt/content/handbook', 'src/handbook' ], { cwd: process.cwd(), maxBuffer: 64 * 1024 * 1024 }).toString() + // A commit that only moves pages between handbook prefixes is skipped by the module, + // so it is left out here too, or the move itself would be "the latest change". const parsed = log.split(RECORD).filter(chunk => chunk.trim()).map(chunk => { - const [header, ...files] = chunk.split('\n').filter(Boolean) + const [header, ...fileLines] = chunk.split('\n').filter(Boolean) const [sha, date, subject] = header.split('\x1f') - return { sha, date, subject, files } - }) - assert.ok(parsed.length > 0, 'git reports at least one handbook commit') + const urls = fileLines.map(line => line.split('\t')) + .filter(parts => !isRelocation(parts[0], parts[1], parts[2])) + .map(parts => parts[0].startsWith('R') || parts[0].startsWith('C') ? parts[2] : parts[1]) + .map(toHandbookRel).filter(Boolean).map(relToUrl) + return { sha, date, subject, urls } + }).filter(commit => commit.urls.length > 0) + assert.ok(parsed.length > 0, 'git reports at least one commit touching a tracked handbook page') // Ties on the same date are fine: any commit from that date lands in the same week, // and the per-page assertions below only need one of them. const newest = parsed.reduce((a, b) => (b.date > a.date ? b : a)) - const { sha, date, subject } = newest - const fileLines = newest.files + const { sha, date, subject, urls } = newest const prMatch = subject.match(/\(#(\d+)\)\s*$/) - const files = fileLines.map(line => line.split('\t')).map(parts => - parts[0].startsWith('R') || parts[0].startsWith('C') ? parts[2] : parts[1] - ) - const urls = files.map(toHandbookRel).filter(Boolean).map(relToUrl) - assert.ok(urls.length > 0, 'the latest handbook commit touches at least one tracked page') const weeks = getHandbookChanges(process.cwd()) const recent = weeks[0] From 75258f02b0dfa33b229615e27edda54d0fb056c1 Mon Sep 17 00:00:00 2001 From: ZJ van de Weg Date: Fri, 25 Sep 2026 16:49:14 -0700 Subject: [PATCH 2/9] repo root: find it instead of counting ../ from nuxt/ The Nuxt modules took the repository root to be the parent of the Nuxt root, and seven tests reached it with a fixed '../..' from nuxt/lib/. Both stop being true once the app moves to the repository root. nuxt/lib/repo-root.mjs finds the closest directory holding package-lock.json instead, which is correct on either side of the move and, for a worktree nested under .claude/worktrees/, resolves to the worktree rather than the checkout around it. --- nuxt/lib/chrome.test.mjs | 3 +-- nuxt/lib/guides-frontmatter.test.mjs | 3 +-- nuxt/lib/mdc-bindings.test.mjs | 6 ++---- nuxt/lib/meta-title-length.test.mjs | 5 ++--- nuxt/lib/node-red-help.test.mjs | 5 ++--- nuxt/lib/redirects-node-red.test.mjs | 5 ++--- nuxt/lib/repo-root.mjs | 20 ++++++++++++++++++++ nuxt/lib/repo-root.test.mjs | 27 +++++++++++++++++++++++++++ nuxt/lib/retired-src.test.mjs | 5 +---- nuxt/modules/blueprints-source.ts | 5 +++-- nuxt/modules/docs-source.ts | 6 ++++-- 11 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 nuxt/lib/repo-root.mjs create mode 100644 nuxt/lib/repo-root.test.mjs diff --git a/nuxt/lib/chrome.test.mjs b/nuxt/lib/chrome.test.mjs index 0181fe668f..6ad1307ace 100644 --- a/nuxt/lib/chrome.test.mjs +++ b/nuxt/lib/chrome.test.mjs @@ -6,9 +6,8 @@ import assert from 'node:assert/strict' import { existsSync, readFileSync } from 'node:fs' import { dirname, join, resolve } from 'node:path' import { test } from 'node:test' -import { fileURLToPath } from 'node:url' +import { REPO_ROOT as repo } from './repo-root.mjs' -const repo = join(dirname(fileURLToPath(import.meta.url)), '..', '..') const chrome = JSON.parse(readFileSync(join(repo, 'nuxt/data/chrome.json'), 'utf8')) const navLinks = chrome.header.dropdowns.flatMap(d => d.columns.flatMap(c => c.links)) diff --git a/nuxt/lib/guides-frontmatter.test.mjs b/nuxt/lib/guides-frontmatter.test.mjs index 0ae0ca2b5a..455597c2fa 100644 --- a/nuxt/lib/guides-frontmatter.test.mjs +++ b/nuxt/lib/guides-frontmatter.test.mjs @@ -3,13 +3,12 @@ import assert from 'node:assert/strict' import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' import { findDuplicateSiblingNavTitles, findPagesWithUnreachableTitle } from './guides-frontmatter.mjs' import { GUIDES_SOURCE } from './guides-sync.mjs' import { isDirectory } from './meta-title-length.mjs' +import { REPO_ROOT as repoRoot } from './repo-root.mjs' -const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..') const guidesDir = join(repoRoot, GUIDES_SOURCE) function scratch (files) { diff --git a/nuxt/lib/mdc-bindings.test.mjs b/nuxt/lib/mdc-bindings.test.mjs index 4492d40a77..6dbea7c099 100644 --- a/nuxt/lib/mdc-bindings.test.mjs +++ b/nuxt/lib/mdc-bindings.test.mjs @@ -1,15 +1,13 @@ import { test } from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' -import { dirname, join, relative } from 'node:path' -import { fileURLToPath } from 'node:url' +import { join, relative } from 'node:path' import { findFiles } from './find-files.mjs' import { GUIDES_SOURCE } from './guides-sync.mjs' import { isDirectory } from './meta-title-length.mjs' import { bindableMustaches, unclosedMdcBlocks } from './mdc-bindings.mjs' - -const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '../..') +import { REPO_ROOT } from './repo-root.mjs' // The trees this repository owns and always has in a checkout. FlowFuse/flowfuse's own // docs go through the same MDC pipeline and the same function checks them, but they are diff --git a/nuxt/lib/meta-title-length.test.mjs b/nuxt/lib/meta-title-length.test.mjs index 589ef02dd8..52b0c98e7d 100644 --- a/nuxt/lib/meta-title-length.test.mjs +++ b/nuxt/lib/meta-title-length.test.mjs @@ -1,11 +1,10 @@ import { test } from 'node:test' import assert from 'node:assert/strict' -import { fileURLToPath } from 'node:url' -import { dirname, join } from 'node:path' +import { join } from 'node:path' import { MAX_META_TITLE_LENGTH, findOverlongMetaTitles, isDirectory } from './meta-title-length.mjs' +import { REPO_ROOT as repoRoot } from './repo-root.mjs' -const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..') const blogDir = join(repoRoot, 'nuxt/content/blog') const changelogDir = join(repoRoot, 'nuxt/content/changelog') diff --git a/nuxt/lib/node-red-help.test.mjs b/nuxt/lib/node-red-help.test.mjs index f9cd2f7533..a9b1606c98 100644 --- a/nuxt/lib/node-red-help.test.mjs +++ b/nuxt/lib/node-red-help.test.mjs @@ -1,8 +1,7 @@ import { test } from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' -import { dirname, join, relative } from 'node:path' -import { fileURLToPath } from 'node:url' +import { join, relative } from 'node:path' import { findFiles } from './find-files.mjs' import { GUIDES_SOURCE } from './guides-sync.mjs' @@ -10,8 +9,8 @@ import { isDirectory } from './meta-title-length.mjs' import { extractHelp, helpRefsIn, helpUrlFor, isSafeHelpRef, sanitiseHelp, unclaimedHelpNames, } from './node-red-help.mjs' +import { REPO_ROOT } from './repo-root.mjs' -const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '../..') const GUIDES_DIR = join(REPO_ROOT, GUIDES_SOURCE) const block = (name, body) => `` diff --git a/nuxt/lib/redirects-node-red.test.mjs b/nuxt/lib/redirects-node-red.test.mjs index 3ab42580e5..0d26af77fc 100644 --- a/nuxt/lib/redirects-node-red.test.mjs +++ b/nuxt/lib/redirects-node-red.test.mjs @@ -10,12 +10,11 @@ import { test } from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' +import { join } from 'node:path' import { GUIDES_SOURCE, listGuideFiles } from './guides-sync.mjs' +import { REPO_ROOT as repoRoot } from './repo-root.mjs' -const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..') const read = rel => readFileSync(join(repoRoot, rel), 'utf8') const withSlashes = path => '/' + path.split('/').filter(Boolean).join('/') + '/' diff --git a/nuxt/lib/repo-root.mjs b/nuxt/lib/repo-root.mjs new file mode 100644 index 0000000000..55e2967249 --- /dev/null +++ b/nuxt/lib/repo-root.mjs @@ -0,0 +1,20 @@ +import { existsSync } from 'node:fs' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +// The root of the checkout: the closest directory at or above `start` that holds +// package-lock.json. Found rather than written as a fixed run of `..`, so a caller keeps +// working when the file it lives in moves up or down a level. Closest rather than +// furthest, so a git worktree nested inside another checkout (.claude/worktrees/) +// resolves to itself and not to the checkout around it. +export function findRepoRoot (start) { + let dir = start + while (!existsSync(join(dir, 'package-lock.json'))) { + const parent = dirname(dir) + if (parent === dir) throw new Error(`No package-lock.json at or above ${start}`) + dir = parent + } + return dir +} + +export const REPO_ROOT = findRepoRoot(dirname(fileURLToPath(import.meta.url))) diff --git a/nuxt/lib/repo-root.test.mjs b/nuxt/lib/repo-root.test.mjs new file mode 100644 index 0000000000..eb98f1d665 --- /dev/null +++ b/nuxt/lib/repo-root.test.mjs @@ -0,0 +1,27 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' + +import { findRepoRoot } from './repo-root.mjs' + +test('findRepoRoot returns the closest directory holding package-lock.json', (t) => { + const root = mkdtempSync(join(tmpdir(), 'repo-root-')) + t.after(() => rmSync(root, { recursive: true, force: true })) + // An outer checkout with a worktree nested inside it, as .claude/worktrees/ does. + const worktree = join(root, '.claude', 'worktrees', 'topic') + mkdirSync(join(worktree, 'nuxt', 'lib'), { recursive: true }) + writeFileSync(join(root, 'package-lock.json'), '{}') + writeFileSync(join(worktree, 'package-lock.json'), '{}') + + assert.equal(findRepoRoot(join(worktree, 'nuxt', 'lib')), worktree) + assert.equal(findRepoRoot(worktree), worktree) + assert.equal(findRepoRoot(join(root, '.claude')), root) +}) + +test('findRepoRoot fails loudly when there is no package-lock.json above', (t) => { + const root = mkdtempSync(join(tmpdir(), 'repo-root-')) + t.after(() => rmSync(root, { recursive: true, force: true })) + assert.throws(() => findRepoRoot(root), /No package-lock.json/) +}) diff --git a/nuxt/lib/retired-src.test.mjs b/nuxt/lib/retired-src.test.mjs index 5747a568b1..173026ca43 100644 --- a/nuxt/lib/retired-src.test.mjs +++ b/nuxt/lib/retired-src.test.mjs @@ -4,11 +4,8 @@ // merges cleanly into src/blog/, and the only sign is a page that never appears. import assert from 'node:assert/strict' import { execFileSync } from 'node:child_process' -import { dirname, join } from 'node:path' import { test } from 'node:test' -import { fileURLToPath } from 'node:url' - -const repo = join(dirname(fileURLToPath(import.meta.url)), '..', '..') +import { REPO_ROOT as repo } from './repo-root.mjs' test('nothing is tracked under src/', (t) => { let tracked diff --git a/nuxt/modules/blueprints-source.ts b/nuxt/modules/blueprints-source.ts index 5b49e73ab1..94ec03e45c 100644 --- a/nuxt/modules/blueprints-source.ts +++ b/nuxt/modules/blueprints-source.ts @@ -1,10 +1,11 @@ import { defineNuxtModule, useLogger } from '@nuxt/kit' -import { dirname } from 'node:path' // Lives in nuxt/lib/, not alongside this file: Nuxt auto-registers everything in // nuxt/modules/ as a Nuxt module, so a plain helper there fails the build. // @ts-ignore untyped module, kept as plain JS so `node --test` can run it directly import { syncBlueprints } from '../lib/blueprints-sync.mjs' +// @ts-ignore same +import { findRepoRoot } from '../lib/repo-root.mjs' import { BLUEPRINTS_PAGE_SIZE } from '../composables/useBlueprintList' const logger = useLogger('blueprints-source') @@ -13,7 +14,7 @@ export default defineNuxtModule({ meta: { name: 'blueprints-source' }, async setup (_options, nuxt) { const nuxtRoot = nuxt.options.rootDir - const repoRoot = dirname(nuxtRoot) + const repoRoot = findRepoRoot(nuxtRoot) const { entries } = await syncBlueprints({ repoRoot, nuxtRoot, logger }) diff --git a/nuxt/modules/docs-source.ts b/nuxt/modules/docs-source.ts index db3a8a91b3..eaee29c5ae 100644 --- a/nuxt/modules/docs-source.ts +++ b/nuxt/modules/docs-source.ts @@ -1,6 +1,6 @@ import { defineNuxtModule, extendRouteRules, useLogger } from '@nuxt/kit' import { existsSync, readFileSync, readdirSync } from 'node:fs' -import { join, basename, dirname } from 'node:path' +import { join, basename } from 'node:path' // Lives in nuxt/lib/, not alongside this file: Nuxt auto-registers everything in // nuxt/modules/ as a Nuxt module, so a plain helper there fails the build. @@ -10,6 +10,8 @@ import { syncDocs } from '../lib/docs-sync.mjs' import { syncGuides } from '../lib/guides-sync.mjs' // @ts-ignore same import { docsRedirectRules, prerenderableRoutes } from '../lib/docs-redirects.mjs' +// @ts-ignore same +import { findRepoRoot } from '../lib/repo-root.mjs' const logger = useLogger('docs-source') @@ -34,7 +36,7 @@ export default defineNuxtModule({ const nuxtRoot = nuxt.options.rootDir const contentDocsDir = join(nuxtRoot, 'content', 'docs') - const repoRoot = dirname(nuxtRoot) + const repoRoot = findRepoRoot(nuxtRoot) // Order matters: syncDocs wipes content/docs before writing, so the guides overlaid // from this repo have to land after it, not before. From 0e947b4e50b2f2531559406bd4b704464550e3be Mon Sep 17 00:00:00 2001 From: ZJ van de Weg Date: Fri, 25 Sep 2026 16:49:57 -0700 Subject: [PATCH 3/9] search index: move the helpers into nuxt/lib and switch the scripts to ESM lib/search-index.js is the only file in the root lib/, which would collide with nuxt/lib/ once the app moves to the repository root, so it joins the other plain-JS helpers there. It and the two CommonJS scripts, index-algolia and watch_blueprints, become ES modules, since the merged package.json will declare "type": "module" for the whole repository. --- .claude/CLAUDE.md | 5 ++--- README.md | 2 +- nuxt/components/AlgoliaSearch.vue | 2 +- lib/search-index.js => nuxt/lib/search-index.mjs | 8 ++++---- package.json | 4 ++-- scripts/{index-algolia.js => index-algolia.mjs} | 13 +++++++------ .../{watch_blueprints.js => watch_blueprints.mjs} | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) rename lib/search-index.js => nuxt/lib/search-index.mjs (98%) rename scripts/{index-algolia.js => index-algolia.mjs} (97%) rename scripts/{watch_blueprints.js => watch_blueprints.mjs} (84%) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index fecd3e9ac2..16cded506c 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -22,7 +22,7 @@ path in a comment names what a page used to be, not a file that still exists. other repositories at build time (product docs, the Blueprint Library) - **Files served as-is**: `nuxt/public/`, a tracked asset tree rather than build output - **CSS**: two Tailwind v4 builds on every page: `nuxt/assets/css/style.css`, compiled by PostCSS to `nuxt/public/css/style.css`, and `nuxt/assets/css/theme.css`, bundled by Nuxt and loaded second -- **Search**: Algolia (`scripts/index-algolia.js`), indexed from the built output +- **Search**: Algolia (`scripts/index-algolia.mjs`), indexed from the built output - **Hosting**: Netlify, from `nuxt/dist` ### Production build order @@ -81,8 +81,7 @@ nuxt/ ├── composables/ ├── utils/ └── pages/ -scripts/ # sync_docs.mjs, sync_blueprints.mjs, their watchers, index-algolia.js -lib/ # search-index.js, shared with scripts/index-algolia.js +scripts/ # sync_docs.mjs, sync_blueprints.mjs, their watchers, index-algolia.mjs ``` --- diff --git a/README.md b/README.md index cde9818cfd..fff078ef73 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ Every build resolves blueprints in this order, and logs which one it used: | 3 | A clone, authenticated with a minted GitHub App installation token (`GH_BOT_APP_ID`/`GH_BOT_APP_KEY`) | Nothing above applied, and those env vars are set. This is what Netlify production deploys use — `blueprint-library` is private, so this can't clone anonymously the way docs does. | | 4 | Skipped | Nothing above applied. Matches the previous behaviour for contributors without access to the private repo. | -`npm run blueprints` runs that resolution on its own, writing `nuxt/content/blueprints` and `nuxt/public/blueprints`, both gitignored. `npm run dev` re-runs it whenever the resolved source changes (`scripts/watch_blueprints.js`), but only when it found a source to watch in the first place — no sibling checkout means no watching. +`npm run blueprints` runs that resolution on its own, writing `nuxt/content/blueprints` and `nuxt/public/blueprints`, both gitignored. `npm run dev` re-runs it whenever the resolved source changes (`scripts/watch_blueprints.mjs`), but only when it found a source to watch in the first place — no sibling checkout means no watching. ## llms.txt diff --git a/nuxt/components/AlgoliaSearch.vue b/nuxt/components/AlgoliaSearch.vue index 7cfab36266..a47daaeac0 100644 --- a/nuxt/components/AlgoliaSearch.vue +++ b/nuxt/components/AlgoliaSearch.vue @@ -1,6 +1,6 @@