Skip to content

Releases: brandon-behring/book-scaffold-astro

v4.9.0 — universal slug + XRef crash & build-labels slug-404 fixes

30 May 17:35
a64fc7e

Choose a tag to compare

Minor release. Makes the optional slug URL-override field universal across all profiles, and fixes two latent bugs surfaced by the mathematical-guides / claude-books consumers:

  • fix(XRef.astro): the frontmatter doc comment's {/* */} example, inside a /** */ JSDoc block, closed the block early — esbuild threw Unexpected "}" on any MDX import of <XRef>. Now // line comments; the MDX-correct example is restored.
  • fix(build-labels): cross-reference hrefs now prefer frontmatter slug: over the filename, matching Astro's entry.id (no more 404s under a custom slug).
  • feat(schemas): slug added to academic / tools / minimal / course-notes (research-portfolio already had it).

288 tests (was 275). Full notes in CHANGELOG.md.

🤖 Generated with Claude Code

v4.4.0 — book-genre visual baselines + exercises auto-collection + /exercises route

25 May 17:37
801ef8d

Choose a tag to compare

[4.4.0] — 2026-05-25

Minor release. Polish closure of v4.3.0 deferred items. No new consumer issues since v4.3.0 ship — this release closes internal backlog before the next consumer-feedback cycle begins. All additive; consumers upgrade by bumping version with zero config changes.

Added

  • fixture-book-genre visual regression fixture — 5 routes × 4 viewport widths = 20 new baseline PNGs at AE=0. Exercises all 6 v4.3.0 book-genre components (<Tip>, <TipsCard>, <Exercise>, <Practice>, <Solution>, <ExerciseSolutions>) plus both /tips and /exercises auto-routes. Closes the visual-coverage gap deferred from v4.3.0 to keep velocity.
  • <ExerciseSolutions auto /> mode — new optional boolean prop on the v4.3.0 component. When auto is true, the component reads src/data/exercises.json (emitted by book-scaffold build-exercises), scopes by the current chapter via Astro.url.pathname (matching the /chapters/<slug>/ route pattern auto-injected since v4.3.0 #69), and auto-renders a list of exercise problem statements with placeholder solution lines (_Add your solution here._). Default auto: false preserves v4.3.0 manual-<Solution> behavior — no regression for existing consumers. Graceful skip + clear hint message when exercises.json is missing or the chapter URL pattern doesn't match.
  • book-scaffold build-exercises script — sister to v4.3.0's build-tips. Scans chapter MDX (honoring loader.base overrides via readChaptersBase from v4.1.2) for <Exercise id="X">body</Exercise> instances via 2-branch regex (single + double quote portability, no backreference — same v4.1.2 cross-runtime lesson). Emits src/data/exercises.json keyed by chapter slug. Run on prebuild. Wired into the bin/book-scaffold dispatcher.
  • /exercises auto-route — opt-in via routes.exercises: true in defineBookConfig (default false per profile, mirroring routes.tips). New pages/exercises.astro reads src/data/exercises.json and renders an index grouped by chapter with /chapters/<slug>/#exercise-<id> deep links + per-exercise problem-text previews (first 120 chars). Auto-injected via bookScaffoldIntegration (ROUTE_REGISTRY.exercises entry).
  • RouteToggles.exercises: boolean added to profile-kit.ts (default false for all 5 built-in profiles — academic / tools / minimal / course-notes / research-portfolio).
  • 9 new build-exercises extractor tests (tests/build-exercises.test.mjs) — mirror the v4.3.0 build-tips test suite: double-quoted / single-quoted / multiple / whitespace normalization / full body preserved / no-id skip / empty-id skip / empty source / no-Exercise source.

Changed

  • ExerciseSolutions.astro now branches on auto prop. Manual mode (no prop) renders the slot content exactly as v4.3.0 (regression-safe). Auto mode renders the auto-generated section.
  • bin/book-scaffold.mjs registers the new build-exercises sub-command + updates help text.

Migration

None. Pure additive minor release.

Out of scope / next sessions

  • MDX AST-based solution-slot extraction (<Fragment slot="solution">...</Fragment> inside <Exercise>) — v4.4.0 auto-collection captures problem text only, not solutions. Full solution-slot extraction would require MDX AST traversal at build time. Defer until a consumer asks; file a request if you'd like it in v4.5.0.
  • #15 Multibook routing, #16 AnkiCard + extract-cards CLI — still no consumer signal; deferred.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@4.4.0 ships alongside.
  • Pre-publish smoke gate (v3.6.5) ran end-to-end against academic before publish.
  • 215 unit tests pass (206 existing + 9 new build-exercises).
  • 96 visual baselines at AE=0 (76 existing + 20 new fixture-book-genre).
  • Feedback loop: file friction at https://github.com/brandon-behring/book-scaffold-astro/issues with the consumer:<workspace> label. If you'd like <Fragment slot="solution"> extraction for auto-rendered actual solutions, file a v4.5.0 request.

v4.3.0 — chapters bug + pedagogy infrastructure batch

25 May 04:03
85173fb

Choose a tag to compare

[4.3.0] — 2026-05-24

Minor release. Bundles 4 issues filed since v4.2.0 shipped (within ~36 hours): one real bug (#69), one docs gap (#68), and two pedagogy-component requests from the claude-books supplement-format decision round (#70 + #71). All additive; consumers upgrade by bumping version with zero config changes.

Fixed

  • /chapters/ index links + auto-injected per-chapter route (#69). The shipped /chapters/ index page previously linked to /<slug>/ (root-level) instead of /chapters/<slug>/ (under the chapters prefix). Every link on the academic chapters index 404'd. Two-part fix:

    • package/pages/chapters.astro:115 — href corrected to /chapters/${id}/
    • NEW package/pages/chapters/[...slug].astro — per-chapter dynamic route auto-injected by bookScaffoldIntegration whenever routes.chapters: true. Mirrors the v3.4.0 frontmatter pattern (toolkit ships BOTH index + dynamic route together). Layout switches by preset: Chapter.astro for academic + research-portfolio (KaTeX + theorem chrome); Base.astro for tools + minimal + course-notes (lighter).

    Pre-v4.3.0 every academic consumer wrote the same dynamic-route boilerplate in their own src/pages/chapters/[...slug].astro. v4.3.0 removes that boilerplate. Migration note for existing consumers: if you have your own src/pages/chapters/[...slug].astro AND upgrade to v4.3.0, Astro will error on duplicate routes — either delete your local file (recommended) or keep yours and don't enable routes.chapters: true (your file takes precedence as a consumer route).

Added

  • <Tip n="..." title="..."> numbered-tips component (#70) — Pragmatic Programmer-style pull-quotable rules. Author provides the number; registry doesn't auto-number. Gold border + Tip {n} badge + #tip-{n} anchor for cross-references.
  • defineTips({ volumeOffset, volumeLabel }) API — cross-volume coordination helper. Branded type (matches defineStyle pattern); lets a multi-volume series offset displayed numbers without renumbering source tags. See package/src/lib/define-tips.ts.
  • <TipsCard> component — print-friendly pull-out card listing all tips. Reads src/data/tips.json. Graceful skip when tips.json missing.
  • /tips auto-injected route — opt-in via routes.tips: true. Renders all tips with #tip-{n} permalinks, chapter backlinks, and 80-char body previews. Reads src/data/tips.json from the new build script.
  • book-scaffold build-tips script — scans chapter MDX for <Tip> instances via 4-branch regex (handles single + double + mixed quote styles, no backreference for cross-runtime portability — same lesson as v4.1.2 regex fix). Emits src/data/tips.json sorted by n; warns (doesn't fail) on duplicate numbers. Wired into bin/book-scaffold.mjs dispatcher.
  • <Exercise id="..."> inline-at-concept-introduction component (#71) — CS:APP precedent. Light treatment; #exercise-{id} anchor for cross-linking from <Solution>.
  • <Practice id="..." difficulty="1-4"> end-of-chapter component — diamond markers (◆◆◇◇ for difficulty=2). Closed TS literal union on difficulty (inlined single-line per v4.1.0 PocLayout lesson). #practice-{id} anchor.
  • <Solution for="..."> companion paired by id — backlinks to #exercise-{id}. Manual pairing (no build-time auto-collection in v4.3.0).
  • <ExerciseSolutions> chapter-end wrapper — provides ## Exercise solutions heading + container for nested <Solution> elements. Author places <Solution> items inside manually.
  • New "book-genre" component family (cross-profile, 6 components) — documented in package/CLAUDE.md alongside the v4.1.0 pedagogy family. Names trace genre lineage (Pragmatic Programmer for Tip; CS:APP for Exercise/Practice).
  • RouteToggles.tips: boolean field added (all profiles default tips: false).
  • package/recipes/17-draft-chapter-workflow.md (#68) — documents the canonical getCollection('chapters', (e) => !e.data.draft) filter pattern, when to use draft vs delete vs reorder, and a BOOK_INCLUDE_DRAFTS preview-env pattern consumers can wire into their own override route. Closes the docs-discoverability loose end from #63's resolution.
  • 27 new tests — 9 build-tips extractor tests, 6 defineTips identity/branding tests, 12 book-genre component contract tests.

Changed

  • bin/book-scaffold.mjs dispatcher gains build-tips sub-command + updated help text.
  • build-figures row in CLI table notes that TikZ stage (v4.2.0) ships in build-figures.

Migration

None required for the additive changes (#68, #70, #71). For #69 specifically: if you've been hand-maintaining src/pages/chapters/[...slug].astro AND you opt into routes.chapters: true (the academic preset doesn't by default), DELETE your local file before upgrading or Astro will error on duplicate routes. v3 consumers who never used routes.chapters: true are unaffected.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@4.3.0 ships alongside.
  • Pre-publish smoke gate (v3.6.5) ran end-to-end against academic + research-portfolio before publish.
  • 206 unit tests pass (171 existing + 27 new from this release + 8 carry-over from earlier patches).
  • 76 visual baselines at AE=0 (existing fixtures unaffected by the #69 href fix — rendered output is byte-equivalent).
  • Feedback loop: file friction at https://github.com/brandon-behring/book-scaffold-astro/issues with the consumer:<workspace> label.

v4.2.0 — TikZ standalone → SVG via build-figures (#17)

23 May 22:14
a023429

Choose a tag to compare

[4.2.0] — 2026-05-23

Minor release. Closes #17book-scaffold build-figures now auto-compiles TikZ standalone .tex sources to .pdf via pdflatex before the existing PDF→SVG conversion runs. Additive only; consumers with .pdf-only figures are unaffected; consumers without TeX Live continue to work (clear ERROR + skip for .tex files; pre-built .pdf files still convert normally).

Added

  • TikZ standalone → PDF → SVG pipeline (#17). package/scripts/build-figures.mjs now scans figures/ for both .pdf AND .tex files. For each .tex source: if no sibling .pdf exists OR the .tex is newer than the .pdf, runs pdflatex -halt-on-error -interaction=nonstopmode -output-directory=. <name>.tex in the source directory. The generated .pdf then flows into the existing pdf2svg conversion stage unchanged. Missing-pdflatex case: emits clear ERROR with TeX Live install link (https://www.tug.org/texlive/) and skips .tex files; continues processing any .pdf-only topics. Doesn't crash the build.
  • package/recipes/16-tikz-figures.md — end-to-end recipe covering the \documentclass[tikz,border=2mm]{standalone} convention, discovery rule (when pdflatex runs vs skips), working-directory semantics (compiles in figures/<topic>/ so \input{} relative paths work), .gitignore snippet for intermediate .aux/.log/.fls/.fdb_latexmk/.synctex.gz files, TeX Live install instructions per OS, CI workflow snippet for runners that need to regenerate from source, and common debugging tips.
  • tests/build-figures-tikz.test.mjs — 2 tests. (1) End-to-end: copy a minimal tikz-basic.tex fixture to a temp project, run build-figures, assert that pdf exists alongside .tex AND that .svg exists under public/figures/sample/ AND that the SVG contains valid <svg> markup. (2) Missing-pdflatex error message format. Both tests skip cleanly when pdflatex / pdftocairo aren't on PATH (uses { skip: undefined } semantics — Node 22's test runner treats null as a skip-with-reason, so undefined is required for "run the test").
  • tests/fixtures/figures/tikz-basic.tex — minimal TikZ standalone source for the pipeline test.
  • PACKAGE_DESIGN.md §7 — new "Optional system dependencies" subsection documenting pdflatex + pdftocairo install paths.
  • PACKAGE_DESIGN.md §8build-figures row updated to note the v4.2.0 TikZ stage.

Changed

  • build-figures output line — now includes tikz→pdf count when stage 1 ran on at least one source (e.g., build-figures: 3 total, 3 converted (0 png fallback), 0 cached, 1 tikz→pdf).

Migration

None. Pure additive minor release. Upgrade by bumping @brandon_m_behring/book-scaffold-astro and @brandon_m_behring/create-book to ^4.2.0 (lock-step). Consumers without .tex figures see zero behavior change. Consumers WITH .tex figures now get automatic compilation IF they have TeX Live installed; otherwise see a clear ERROR + continued processing of .pdf figures.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@4.2.0 ships alongside.
  • Pre-publish smoke gate (v3.6.5) ran end-to-end against academic + research-portfolio before publish.
  • 171 unit tests pass (169 existing + 2 new TikZ tests; latter skip cleanly when TeX Live unavailable).
  • Feedback loop: file friction at https://github.com/brandon-behring/book-scaffold-astro/issues with the consumer:<workspace> label.

v4.1.2 — readChaptersBase regex CI compatibility

23 May 22:05
653542f

Choose a tag to compare

[4.1.2] — 2026-05-23

Hotfix release. Republishes v4.1.1's scope (#63 chapter discovery fix + fixture-pedagogy baselines) with a more permissive regex in readChaptersBase. The v4.1.1 tag exists on GitHub but was never published to npm because the readChaptersBase: double-quoted loader.base override works unit test failed in CI's Node 22 environment — the regex's (['"])([^'"]+)\1 backreference form behaved differently on the runner than locally. v4.1.2 uses two separate alternation branches (one per quote style) instead of a backreference; the test passes locally AND in CI. No consumer impact since v4.1.1 never reached npm.

Fixed

  • readChaptersBase regex rewritten without backreference — replaced chapters\s*[:=][\s\S]{0,400}?loader\s*:[\s\S]{0,200}?base\s*:\s*(['"])([^'"]+)\1 with \bchapters\b[\s\S]{0,500}?\bbase\s*:\s*'([^']+)'|\bchapters\b[\s\S]{0,500}?\bbase\s*:\s*"([^"]+)". Two consequences: (1) no more backreference (more portable across regex engines), (2) more permissive matching pattern — relaxes the requirement that chapters be immediately followed by : or =. All 8 existing chapters-base-resolution.test.mjs tests pass; behavior is conceptually unchanged.

Carries forward from the unreleased v4.1.1

  • book-scaffold validate + book-scaffold build-labels honor loader.base overrides (#63)
  • fixture-pedagogy visual regression fixture — 20 new baseline PNGs at AE=0
  • PocLayout.astro type union flattened to single line

See the v4.1.1 entry below for the full details of those changes.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@4.1.2 ships alongside.
  • Pre-publish smoke gate (v3.6.5) ran end-to-end against academic + research-portfolio before publish.
  • Test gate caught the regex regression in CI before publish — exactly the gate's intended purpose.

v4.1.1 — #63 chapter discovery fix + fixture-pedagogy baselines

23 May 21:48
fabfde5

Choose a tag to compare

This version was tagged but never published to npm. A CI-only test-harness race condition was caught by the pre-publish test gate. The v4.1.1 scope (closes #63 + ships fixture-pedagogy) was republished as v4.1.2 with the harness fix. Install v4.1.2 instead.

v4.1.0 — claude-books pedagogy consumer batch

23 May 15:34
3b9783b

Choose a tag to compare

[4.1.0] — 2026-05-23

Consumer-batch minor release. Bundles 6 issues filed by the claude-books consumer during its 2026-05-23 pedagogy PoC round. All additive; no breaking changes; v4.0.0 consumers upgrade by bumping the version with no config edits required.

Why

The 2026-05-23 PoC round at claude-books/handbook rendered 5 supplement formats of Chapter 1 side-by-side (tutorial / how-to / TL;DR / part-summary / cheat-sheet) backed by research at claude-books/docs/research/11-pedagogy/ (Sweller cognitive-load, Bloom's-taxonomy, React.dev callout vocabulary). The round surfaced 4 missing components + 1 layout primitive + 1 build-noise bug + 1 docs gap, all at once. This release ships all 6.

Added

  • <Pitfall> component (#58) — React.dev "Pitfall" vocabulary for retrospective "common mistake" callouts. Distinct from <WarnBox> (which is preemptive). Crimson border + tinted background (new --warm-crimson token).
  • <WorkedExample> component (#57) — collapsible demonstration block backed by Sweller/Cooper's worked-example-effect theory. Native <details> (no JS); id prop becomes #worked-example-{id} anchor (prefixed to avoid heading-anchor collisions); optional expanded prop. Plum border + chip in the summary.
  • <YouWillLearn> component (#59) — chapter-opener "what this chapter delivers" callout (Bloom's-taxonomy framing). Slotted body (MDX bullets); optional prerequisites prop renders a "Before you start" sub-block. Gold border.
  • <PocLayout> component (#56) — per-PoC-kind layout selector. Closed discriminated kind union: 'tutorial' | 'how-to' | 'tldr' | 'part-summary' | 'cheat-sheet'. Each kind swaps 3 CSS variables (--bs-content-line-length, --bs-content-vertical-rhythm, --bs-heading-emphasis) on a .poc-layout-{kind} wrapper. New package/styles/poc-layouts.css ships the variant table; consumers override via :where(.poc-layout-X) selectors.
  • Pedagogy familyPitfall / WorkedExample / YouWillLearn form a new "pedagogy" component family (any preset can use them). Documented in package/CLAUDE.md.
  • PACKAGE_DESIGN.md §5a (#61) — new section "Custom collections + YAML date types" covers the z.date() vs z.string() gotcha + 2 safe patterns + anti-pattern. No zodDateString helper export in this release (one consumer hit the issue; docs solve it).
  • 17 new contract tests (tests/pedagogy-callouts.test.mjs + tests/poc-layout-css.test.mjs) — assert each component's Props interface, default values, CSS class names; assert each PocLayout kind's CSS variable set.
  • 9 new isYamlEmpty tests (tests/sources-empty-detection.test.mjs) — empty / whitespace / comment-only / [] / single-entry / multi-entry / missing-file / malformed-yaml.

Changed

  • Empty sources/manifest.yaml no longer emits noisy WARN (#60). Astro's file() content loader previously logged [file-loader] No items found in sources/manifest.yaml for every build — including when the file existed with [] content (valid pre-bibliography state in early Phase 1 chapter development). package/src/schemas-entry.ts now detects empty manifests (after stripping #-comment lines + whitespace; treats [] and empty as empty) and skips registering the collection entirely. Distinguished states:
    • File missing → collection not registered; build is silent (preserves existing behavior).
    • File exists, parses empty → collection not registered; build is silent (new).
    • File exists with entries → collection registered; loader runs normally (unchanged).
    • File exists, malformed YAML → Astro's loader surfaces the real ERROR (unchanged).

Migration

None. Pure additive minor release. Upgrade by bumping @brandon_m_behring/book-scaffold-astro and @brandon_m_behring/create-book to ^4.1.0 (lock-step).

Out of scope / next sessions

  • Visual regression baselines for new components deferred to v4.1.1 (component contract tests cover the API; visual-pixel verification follows when fixture-pedagogy gets captured).
  • zodDateString helper export — wait for a second consumer to ask (avoids ad-hoc API surface).
  • <PocLayout kind: string> escape hatch — closed union enforces vocabulary discipline; revisit if a sixth kind is needed.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@4.1.0 ships alongside the toolkit.
  • Pre-publish smoke gate (v3.6.5) ran end-to-end against academic + research-portfolio before publish.
  • 161 unit tests pass (124 existing + 17 new pedagogy + 9 new empty-manifest + 11 existing katex/define-style).
  • Visual regression baselines (56 existing) unaffected — no v4.0.0 components changed.
  • Feedback loop: file friction at https://github.com/brandon-behring/book-scaffold-astro/issues with the consumer:<workspace> label. v4.x is the iteration window for this API.

v4.0.0 — defineStyle architecture (BREAKING)

23 May 15:22
b1ab66d

Choose a tag to compare

[4.0.0] — 2026-05-23

BREAKING: the v3.x preset: / profile: shorthand on defineBookConfig is removed. Replaced by typed defineStyle() composition via the new styles: [...] field. Migration is ~2 lines per book. Full migration recipe in package/MIGRATION-v3-to-v4.md; composition patterns in package/recipes/15-defining-styles.md.

Why

The v3.x API accumulated through 7 consumer-pilot releases. Each release added one or two top-level BookConfigOptions fields to address a specific consumer ask (routes, katexMacros, extraStyles, extraIntegrations, mdxComponentsModule, ...). v4 unifies that surface around a typed, branded, composable Style object: define a style once, import it across many books, override per-book explicitly. The user can now build style clusters (guidesFamilyStyle, coursebookStyle) once and reuse them across workspace siblings without per-book repetition.

Foundational design choices (locked during v4.0.0 design session, see /.claude/plans/examine-what-has-happened-peppy-scroll.md):

  • Explicit over silent — no profile-level magic defaults; every config decision visible in the call site or the imported Style.
  • No legacy debt — hard break at v4; sunset of v3 API is immediate.
  • TypeScript strict-mode best practices — branded types via unique symbol, closed shape (no public index signature; scoped extra? field instead — preserves typo protection on toolkit fields), satisfies for narrow registry inference, readonly on all DTO fields, .js extensions in imports.

Added

  • defineStyle(opts: StyleInput): Style — identity helper that creates a typed, branded, composable Style. Zero runtime overhead beyond an object spread + version marker. Branded type prevents confusion with Partial<BookConfigOptions>. See PACKAGE_DESIGN.md §4a.
  • 5 built-in Style exportsacademicStyle, toolsStyle, minimalStyle, courseNotesStyle, researchPortfolioStyle. One per preset. Plus BUILTIN_STYLES: Record<BookPreset, Style> (as const satisfies — narrow inferred lookup).
  • composeStyles(styles) — public helper for advanced consumer composition. Per-key merge strategy documented in PACKAGE_DESIGN.md §4a table.
  • styles?: readonly Style[] on BookConfigOptions — array of Styles composed left-to-right; top-level fields win over composed style chain.
  • deploy?: 'pages' | 'workers' on BookConfigOptions and Style (#50) — drives create-book's wrangler.toml shape. Inherited from chosen style; academic/tools/minimal default to 'workers', course-notes/research-portfolio default to 'pages'.
  • routes.frontmatter widened to boolean | { enabled: boolean; prefix?: string } (#49) — object form lets consumers control the URL prefix (prefix: '' mounts pages at root). Boolean form keeps working with default prefix 'frontmatter'.
  • extra?: Readonly<Record<string, unknown>> on Style — scoped consumer-side metadata namespace. Ignored by toolkit; survives composition as per-key spread. Preserves typo protection on known toolkit fields (closed shape — no public index signature).
  • __styleVersion: 1 marker on every Style (auto-set by defineStyle) — forward-compatibility hook for future API-shape evolution.
  • package/recipes/15-defining-styles.md — new recipe covering workspace-local vs npm-package patterns, per-key merge semantics, escape hatches, feedback loop.
  • package/MIGRATION-v3-to-v4.md — step-by-step migration recipe for the 4 known consumers + external users.
  • PACKAGE_DESIGN.md §4 rewritten + new §4a — full defineBookConfig v4 API contract + defineStyle API reference.
  • 40 unit tests in package/tests/define-style.test.mjs — identity, branding, merge semantics for each field, BUILTIN_STYLES integrity, composition edge cases.
  • 5 new create-book scaffold tests — per-preset wrangler.toml + new v4 astro.config.mjs shape.

Removed (BREAKING)

  • preset?: BookPreset field on BookConfigOptions — replaced by styles: [<presetName>Style]. Runtime check detects v3 usage and throws BookConfigError with auto-suggested replacement code + missing import line + link to MIGRATION-v3-to-v4.md.
  • profile?: BookPreset field (v3.4.0 backward-compat alias) — same treatment as preset. Both throw the same migration error.
  • No backward-compatibility shim. Consumers in early pilot phase (~4 known + workspace siblings, all maintained by same author); migration is ~2 lines per book. The v3.7.1 line stays installable indefinitely via npm for consumers who need more time.

Changed

  • book-scaffold build-bib strips %-prefixed comment lines before parsing (#54). Permanent fix for the citation-js parse-error class that drove the v3.6.1 → v3.6.4 hotfix chain. The library treats line-leading @TYPE tokens (e.g., % @article{...}) as entry starts even inside comments; the pre-pass stripBibtexLineComments removes any line whose first non-whitespace character is % before passing to @citation-js/plugin-bibtex. No consumer action needed; all existing .bib files continue to work.
  • create-book generated astro.config.mjs uses v4 API — emits import { defineBookConfig, <preset>Style } from '@brandon_m_behring/book-scaffold-astro'; export default await defineBookConfig({ styles: [<preset>Style], site: '...' }); instead of v3 preset: '<preset>' form.
  • create-book emits per-preset wrangler.toml — Workers shape (academic/tools/minimal) vs Pages shape (course-notes/research-portfolio).
  • PROFILES[preset]?.katex === true gate preserved from v3.7.1 — KaTeX wiring activates for both academic and research-portfolio based on the profile registry, not the preset literal. The fix is unchanged by the v4 API redesign.

Migration

For each book using @brandon_m_behring/book-scaffold-astro@^3.x, edit astro.config.mjs:

- import { defineBookConfig } from '@brandon_m_behring/book-scaffold-astro';
+ import { defineBookConfig, academicStyle } from '@brandon_m_behring/book-scaffold-astro';

  export default await defineBookConfig({
-   preset: 'academic',
+   styles: [academicStyle],
    site: 'https://my-book.example.com/',
  });
v3 preset v4 import v4 styles field
'academic' academicStyle [academicStyle]
'tools' toolsStyle [toolsStyle]
'minimal' minimalStyle [minimalStyle]
'course-notes' courseNotesStyle [courseNotesStyle]
'research-portfolio' researchPortfolioStyle [researchPortfolioStyle]

If migration friction surfaces, file an issue at https://github.com/brandon-behring/book-scaffold-astro/issues with the consumer:<your-workspace> label. The v4.x release line is explicitly the iteration window for this API.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@4.0.0 ships alongside the toolkit.
  • Pre-publish smoke gate (v3.6.5) ran end-to-end against academic + research-portfolio before publish.
  • 124 unit tests + 56 visual baselines (AE=0) verify DOM output is unchanged by the API redesign.

v3.7.1 — consumer:guides bug-fix patch (#52 + #51 + #48)

23 May 12:47
41d26f9

Choose a tag to compare

Patch release closing 3 issues from the brandon-behring/guides + brandon-behring/guides-experimentation Phase 0b batch (2026-05-22→23). Unblocks that workspace's CI (was crashing on validate under Node 20) and fixes brace-math rendering in research-portfolio.

Fixed

  • book-scaffold validate no longer requires Node 22 (#52). scripts/validate.mjs previously imported glob from node:fs/promises, an API added in Node 22. The scaffold's generated consumer CI templates ship node-version: '20', so npm run validate crashed on every consumer's prebuild hook with SyntaxError: The requested module 'node:fs/promises' does not provide an export named 'glob'. Replaced with a recursive readdir walker (extracted to scripts/walk-mdx.mjs for unit-testability). Works on Node 18+; output format matches the previous glob shape.
  • MDX math with curly braces now renders in research-portfolio preset (#51). Expressions like $\mathbb{E}\{X\}$, $\mathbb{P}\{X|Y\}$, $\mathrm{Cov}\{X, Y\}$ previously failed because src/config.ts gated the KaTeX wiring on the literal profile === 'academic', ignoring the katex: true flag that research-portfolio sets in its profile definition. Without remark-math intercepting first, MDX parsed {X} as a JSX expression containing undefined variable X. Fix: gate on PROFILES[profile]?.katex === true (single source of truth: the profile registry). New visual fixture fixture-research-portfolio/.../math.mdx covers brace-math at 4 viewport widths.
  • create-book now adds KaTeX peer deps for research-portfolio scaffolds (paired with the above). Previously only academic scaffolds got katex/rehype-katex/remark-math in their generated package.json.
  • create-book now accepts course-notes and research-portfolio presets (latent bug fix). VALID_PROFILES had been rejecting both since they shipped (v3.3.0 and v3.5.0 respectively) — they could only be selected by editing a scaffolded book manually.

Added

  • Component prop tables for v3.5.0 components (#48) in PACKAGE_DESIGN.md §10. Covers PreReleaseBanner, PolicyRef, AICollaborationDisclosure, BlockedByCallout with prop signatures + default values + slot semantics.

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@3.7.1 ships alongside the toolkit.
  • Pre-publish smoke gate (v3.6.5) ran for both academic and research-portfolio scaffolds before publish.

v3.7.0 — chapters profile-strategy refactor (#35) + academic visual baseline (#36)

23 May 03:32
d54164f

Choose a tag to compare

Minor release. Refactors the /chapters route from a field-presence discriminator into a per-profile renderer strategy plugged into the existing PROFILES registry. Adds a visual-regression baseline for the academic /chapters route. Closes #35 and #36.

No breaking API changes. Consumer DOM output is byte-equivalent for tools profile (verified at AE=0 against all 3 pre-existing visual fixtures).

Architecture

Layer Owns
Route (pages/chapters.astro) Data fetch, byPart grouping, ToolFilter wiring, CSS, inline filter script
Renderer (per profile, src/profiles/renderers/*-chapters.ts) Numbering format, badge selection, sort key, data-tools value
Registry (PROFILES[profile].chaptersRenderer) Dispatch point read at route render time

Pure-function strategy — no Astro imports in renderer modules, preserving the chapter-sort.ts pattern that keeps tsup's DTS bundler stable.

Added

  • ChaptersRenderer interface and three implementations:
    • toolsChaptersRenderer — numeric Part/Chapter, volatility badge, freshness affordance, tools-compared tags.
    • academicChaptersRenderer — string-enum Part, Week N numbering, status badge.
    • fallbackChaptersRenderer — field-presence dispatch (v3.5.2 logic, preserved for minimal / course-notes / research-portfolio safety net).
  • ProfileDefinition.chaptersRenderer?: ChaptersRenderer — optional field; each of the 5 shipped profiles wired to its renderer.
  • package/tests/visual/fixture-academic-chapters/ — new visual-regression fixture exercising defineBookConfig({ profile: 'academic', routes: { chapters: true } }) end-to-end. 5 chapters across foundations / ssm-core / beyond-ssm / synthesis parts; 4 routes screenshotted at 4 viewport widths = 16 baselines.
  • package/tests/chapters-renderer.test.mjs — 31 cases across all 3 renderers + cross-renderer agreement + chapterSortKey backward-compat.

Changed

  • pages/chapters.astro precomputes per-card render data in the frontmatter --- block (sidesteps an Astro-compiler limitation where TypeScript generic casts inside {...} JSX expressions get parsed as tag-start tokens).
  • package.json files allowlist adds src/profiles/, src/profile-kit.ts, src/schemas.ts. Required for the refactored route's transitive imports to resolve at consumer build time — uncovered by the v3.6.5 pre-publish smoke gate before any npm ship.

Pre-publish smoke (v3.6.5 gate) caught two real bugs

  • Pre-publish smoke surfaced both missing-file-in-tarball bugs before any npm publish. Process win — exactly the failure class v3.6.5 was designed to catch. Without it, v3.7.0 would have shipped a broken first build for every new consumer.

Backward compatibility

  • Public API: chapterSortKey(data) export retained; behavior unchanged.
  • New types added (additive): ChaptersRenderer, PartKey, VolatilityBadge, StatusBadge, FreshnessAffordance. Three renderer instances exported.
  • Frontmatter schemas unchanged.
  • DOM output byte-equivalent for tools profile (verified by visual regression).

Release policy

  • D12 lock-step preserved: @brandon_m_behring/create-book@3.7.0 ships alongside the toolkit.