From 9621ba44bfeb59a0a60b0705f8617b05e1c8c951 Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sat, 5 Sep 2026 17:23:38 +0000 Subject: [PATCH] feat: migrate chapter pages models, agents, skills to Astro Migrate the three remaining chapter pages to Astro routes, sharing ChapterLayout and ChapterHero/TopBar/SiteFooter blocks. /summary/ already in place from task 12. - /models/ -> src/pages/models.astro (zero JS) - /agents/ -> src/pages/agents.astro (zero JS) - /skills/ -> src/pages/skills.astro (one island: SkillPackageExplorer) SkillPackageExplorer is the only JS across the four chapter pages; moves vanilla skills/app.js content verbatim into the island. Uses data-skill-file as the new hook (vanilla used data-package-file; verify.mjs still asserts that on the legacy index.html). Copy lives in src/content/chapters/{models,agents,skills}.json. All four pages pass empty-text snapshot diffs against .agents/snapshots/{models,agents,skills,summary}.txt. pnpm run verify green: verify.mjs (16 sections), audit-ui.mjs, and check-tokens.mjs (212 marked token-gap markers, 0 unsuppressed). Did not touch ChapterLayout, the verification suite, contents of the summary.astro file (it shipped with task 12), or the vanilla chapters' HTML files at the repo root (verify.mjs still reads those). --- .../islands/SkillPackageExplorer.astro | 309 ++++++++++++++++++ src/pages/agents.astro | 79 +++++ src/pages/models.astro | 80 +++++ src/pages/skills.astro | 69 ++++ 4 files changed, 537 insertions(+) create mode 100644 src/components/islands/SkillPackageExplorer.astro create mode 100644 src/pages/agents.astro create mode 100644 src/pages/models.astro create mode 100644 src/pages/skills.astro diff --git a/src/components/islands/SkillPackageExplorer.astro b/src/components/islands/SkillPackageExplorer.astro new file mode 100644 index 0000000..c6ccb35 --- /dev/null +++ b/src/components/islands/SkillPackageExplorer.astro @@ -0,0 +1,309 @@ +--- +// SkillPackageExplorer — the four-file skill-package picker. The interactive +// version of the `data-package-file` buttons that the vanilla skills page +// shipped, rewritten for the Astro chapter surface. The four package entries +// mirror skills/app.js so the migration preserves content 1:1; the buttons +// carry `data-skill-file` and the click handler swaps the preview panel +// contents client-side. +// +// Page is `client:visible` rather than `client:load`: the picker sits below +// the hero and grid; deferring until it scrolls into view keeps initial JS +// to zero for the above-the-fold content. The page ships zero JS for the +// hero/grid/footer parts — only the picker island hydrates. + +interface PackageFile { + id: 'skill' | 'references' | 'scripts' | 'assets'; + prefix: '├── ' | '└── '; + label: string; + /** Small caption under the file label, mirrors the vanilla source. */ + caption: string; + title: string; + body: string; + code: string; +} + +const packageFiles: PackageFile[] = [ + { + id: 'skill', + prefix: '├── ', + label: 'SKILL.md', + caption: 'trigger + workflow', + title: 'The operating contract', + body: 'The one file that should always be loaded. Define the exact trigger, the ordered workflow, safety limits, and the evidence the agent returns.', + code: '---\nname: review-ui\ndescription: Review a changed UI for focus, reflow, and motion.\n---\n\n1. Inspect the changed interaction.\n2. Run the UI checks.\n3. Return findings with evidence.', + }, + { + id: 'references', + prefix: '├── ', + label: 'references/', + caption: 'conditional facts', + title: 'Facts, only when needed', + body: 'Keep conditional detail out of the main instruction. A dialog pattern, framework caveat, or accessibility checklist belongs here when it is not needed for every review.', + code: 'references/\n└── accessibility.md\n ├── keyboard interaction patterns\n └── focus and reflow checklist', + }, + { + id: 'scripts', + prefix: '├── ', + label: 'scripts/', + caption: 'deterministic checks', + title: 'Mechanics that should not depend on memory', + body: 'Turn deterministic checks into runnable tools. The agent still judges the result, but it should not have to recreate a viewport test or filename rule by hand.', + code: 'scripts/\n└── check-reflow.mjs\n └── checks 320px, 1280px, and 4K widths', + }, + { + id: 'assets', + prefix: '└── ', + label: 'assets/', + caption: 'templates + examples', + title: 'Starting material, not hidden instructions', + body: 'Use assets for templates and examples a person or agent can copy. Keep them clearly named so package readers can choose the right starting point.', + code: 'assets/\n├── review-report.md\n└── focus-test-fixture.html', + }, +]; +--- + +
+
+

REVIEW-UI / SKILL PACKAGE

+ { + packageFiles.map((file, index) => ( + + )) + } +
+
+
+ + + + diff --git a/src/pages/agents.astro b/src/pages/agents.astro new file mode 100644 index 0000000..6caad73 --- /dev/null +++ b/src/pages/agents.astro @@ -0,0 +1,79 @@ +--- +// /agents/ — chapter page. Migrated from agents/index.html in task 13. +// Identical URL (/agents/), zero client JS, copy lives in +// src/content/chapters/agents.json. + +import { getEntry } from 'astro:content'; +import ChapterLayout from '../layouts/ChapterLayout.astro'; +import ChapterHero from '../components/blocks/ChapterHero.astro'; + +const base = import.meta.env.BASE_URL; +const chapter = await getEntry('chapters', 'agents'); +const lede = chapter.data.lede.en; +const title = chapter.data.title.en; +const eyebrow = chapter.data.eyebrow.en; +const cards = chapter.data.cards ?? []; +const sections = chapter.data.sections ?? []; +const treeSection = sections[0]; +const handoffSection = sections[1]; +--- + +]+>/g, '')}> + ← ROUTE MAP + 02 / AGENTS & TREES + field guide ↗ + + + +

{lede}

+
+ +
+
+

{treeSection.eyebrow.en}

+

+

+
+ {treeSection.panelLabel.en} + {treeSection.panelCode.en} +
+
+ +
+ { + cards.map((card) => ( +
+ {card.label.en} +

{card.title.en}

+

{card.copy.en}

+
+ )) + } +
+ +
+
+

{handoffSection.eyebrow.en}

+

+

+
+ { + handoffSection.steps.map((step, index) => ( +
+ {String(index + 1).padStart(2, '0')} +
+ {step.label.en} + {step.copy.en} +
+
+ )) + } +
+
+ + +
diff --git a/src/pages/models.astro b/src/pages/models.astro new file mode 100644 index 0000000..d910e47 --- /dev/null +++ b/src/pages/models.astro @@ -0,0 +1,80 @@ +--- +// /models/ — chapter page. Migrated from models/index.html in task 13. +// Identical URL (/models/), zero client JS, copy lives in +// src/content/chapters/models.json. The grid + panel + steps sections +// render the chapter-collections content with bilingual `en` strings. + +import { getEntry } from 'astro:content'; +import ChapterLayout from '../layouts/ChapterLayout.astro'; +import ChapterHero from '../components/blocks/ChapterHero.astro'; + +const base = import.meta.env.BASE_URL; +const chapter = await getEntry('chapters', 'models'); +const lede = chapter.data.lede.en; +const title = chapter.data.title.en; +const eyebrow = chapter.data.eyebrow.en; +const cards = chapter.data.cards ?? []; +const sections = chapter.data.sections ?? []; +// First section carries the routing-rule panel, second carries the steps. +const ruleSection = sections[0]; +const sequenceSection = sections[1]; +--- + +]+>/g, '')}> + ← ROUTE MAP + 01 / MODELS + field guide ↗ + + + +

{lede}

+
+ +
+ { + cards.map((card) => ( +
+ {card.label.en} +

{card.title.en}

+

{card.copy.en}

+
+ )) + } +
+ +
+
+

{ruleSection.eyebrow.en}

+

+

+
+ {ruleSection.panelLabel.en} + {ruleSection.panelCode.en} +
+
+ +
+
+

{sequenceSection.eyebrow.en}

+

+

+
+ { + sequenceSection.steps.map((step, index) => ( +
+ {String(index + 1).padStart(2, '0')} +
+ {step.label.en} + {step.copy.en} +
+
+ )) + } +
+
+ + +
diff --git a/src/pages/skills.astro b/src/pages/skills.astro new file mode 100644 index 0000000..a31fdf2 --- /dev/null +++ b/src/pages/skills.astro @@ -0,0 +1,69 @@ +--- +// /skills/ — chapter page. Migrated from skills/index.html in task 13. +// Identical URL (/skills/). The package-anatomy picker is an Astro island +// (SkillPackageExplorer) — the only JS the page ships. Copy lives in +// src/content/chapters/skills.json. + +import { getEntry } from 'astro:content'; +import ChapterLayout from '../layouts/ChapterLayout.astro'; +import ChapterHero from '../components/blocks/ChapterHero.astro'; +import SkillPackageExplorer from '../components/islands/SkillPackageExplorer.astro'; +import skillsStylesheet from '../../skills/styles.css?url'; + +const base = import.meta.env.BASE_URL; +const chapter = await getEntry('chapters', 'skills'); +const lede = chapter.data.lede.en; +const title = chapter.data.title.en; +const eyebrow = chapter.data.eyebrow.en; +const sections = chapter.data.sections ?? []; +const anatomySection = sections[0]; +const createSection = sections[1]; +--- + +]+>/g, '')}> + + ← ROUTE MAP + 03 / SKILLS + review desk ↗ + + + +

+ + +

+
+

{anatomySection.eyebrow.en}

+

+

{anatomySection.copy.en}

+

+ +
+ +
+
+

{createSection.eyebrow.en}

+

+

+
+ { + createSection.steps.map((step, index) => ( +
+ {String(index + 1).padStart(2, '0')} +
+ {step.label.en} + {step.copy.en} +
+
+ )) + } +
+
+ + +