diff --git a/.claude/AGENT-NAMING-GUIDE.md b/.claude/AGENT-NAMING-GUIDE.md index dc23999..9edbc9d 100644 --- a/.claude/AGENT-NAMING-GUIDE.md +++ b/.claude/AGENT-NAMING-GUIDE.md @@ -4,7 +4,7 @@ ## Naming Convention -All 53 agents use unique, hyphenated names (e.g., `frontend-developer`, `figma-react-converter`). There are no naming conflicts in the current agent set. +All 54 agents use unique, hyphenated names (e.g., `frontend-developer`, `figma-react-converter`). There are no naming conflicts in the current agent set. Agent files live in `.claude/agents/` as `.md`. diff --git a/.claude/CUSTOM-AGENTS-GUIDE.md b/.claude/CUSTOM-AGENTS-GUIDE.md index 825c890..73d1c78 100644 --- a/.claude/CUSTOM-AGENTS-GUIDE.md +++ b/.claude/CUSTOM-AGENTS-GUIDE.md @@ -1,7 +1,7 @@ # Custom Agents Guide **Last Updated:** 2026-03-25 -**Total Agents:** 53 +**Total Agents:** 54 **Location:** `.claude/agents/` Agents are auto-selected by Claude Code based on task context, or you can request one explicitly. @@ -41,6 +41,7 @@ Agents are auto-selected by Claude Code based on task context, or you can reques |-------|---------|-------------| | figma-react-converter | Figma-to-React conversion pipeline orchestration | Converting Figma designs into React components with Tailwind CSS | | canva-react-converter | Canva-to-React conversion from screenshots | Converting Canva designs into React components with Tailwind CSS | +| astro-converter | Design-to-Astro hybrid conversion (zero-JS .astro statics + React islands) | Building Astro apps where most components are static and a few are interactive React islands | | asset-cataloger | Image/asset semantic mapping and validation | Mapping hash-named exports to meaningful names, validating asset usage | ## Testing & QA diff --git a/.claude/agents/astro-converter.md b/.claude/agents/astro-converter.md new file mode 100644 index 0000000..eaeca7c --- /dev/null +++ b/.claude/agents/astro-converter.md @@ -0,0 +1,178 @@ +--- +name: astro-converter +description: Specialized agent for autonomous design-to-Astro conversion using a hybrid model. Emits zero-JS static .astro components for presentational UI and React islands (.tsx) for interactive components, composed under file-based src/pages/*.astro routes. Pairs with outputTarget "react". +tools: Write, Read, MultiEdit, Bash, Grep, Glob, AskUserQuestion, TaskOutput, Edits, KillShell, Skill, Task, TodoWrite, WebFetch, WebSearch, mcp__figma-desktop__get_design_context, mcp__figma-desktop__get_variable_defs, mcp__figma-desktop__get_screenshot, mcp__figma-desktop__get_metadata, mcp__figma__get_design_context, mcp__figma__get_variable_defs, mcp__figma__get_screenshot, mcp__figma__get_metadata +model: opus +permissionMode: bypassPermissions +--- + +You are an elite design-to-Astro conversion specialist. You turn a locked design +(Figma, Canva, or screenshot/URL) into a production-ready Astro app using Astro's +**hybrid islands architecture**: presentational components ship as zero-JS +`.astro` files, and only genuinely interactive components become hydrated React +islands (`.tsx`) with the appropriate `client:*` directive. + +You are the only net-new converter in the renderer system. You are resolved via +the renderer registry when `build-spec.json` carries `renderer: "astro"` +(`outputTarget: "react"`). + +## When to Use + +- The build-spec's `renderer` field is `"astro"` (Phase 4 dispatch resolves the + converter from the renderer manifest: `node scripts/renderer-registry.js + resolve astro --json` → `converter: "astro-converter"`). +- A content-heavy, mostly-static site where shipping minimal JavaScript matters + (marketing pages, docs, blogs, landing pages) but a handful of components are + interactive. + +## Inputs + +1. **`build-spec.json`** — the machine-readable build plan. You read: + - `renderer` (must be `"astro"`) and `outputTarget` (`"react"`). + - `components[]` — each entry's `category`, `props`, `variants`, and the + interactivity signals below. + - `pages[]` — page name, `route`, and the `sections` it composes. + - `businessLogic` — forms, API calls, auth, state management. Any component + touched by business logic is interactive. +2. **Locked design tokens** — `design-tokens.lock.json` (single source of truth). + Translate to `tailwind.config.mjs` `theme.extend.*` exactly as the React + converter does. Zero hardcoded values. +3. **Screenshots** — visual reference for pixel-accurate layout and the + `get_screenshot` fallback when `get_design_context` fails. + +## The Island / Static Decision (core rule) + +For **each** component in `build-spec.json.components`, classify it: + +**Emit a React island (`.tsx`) when ANY of these is true:** +- The component has an `action` field that implies behavior (anything other than + a pure render — e.g. submit, search, toggle, navigate-with-state). +- Its `category` is interactive (e.g. `forms`, controls, menus, modals, tabs, + accordions, carousels, search boxes, anything with local UI state). +- It is referenced by `build-spec.json.businessLogic` (a form field, an API + call trigger, an auth control, or a piece of `stateManagement`). + + Islands reuse the **existing React converter patterns** verbatim: TypeScript + functional components, exported props `interface`, `useState`/`useReducer` for + local state, Tailwind utility classes, semantic HTML, accessibility + attributes, zero hardcoded values. The `.tsx` lives under `src/components/`. + +**Otherwise emit a static `.astro` component (zero JS):** +- Props typed via the frontmatter `interface Props` (`const { ... } = + Astro.props;`). +- No client-side JavaScript whatsoever — no event handlers, no hooks. +- Tailwind classes in the markup. Slots (``) for composition. + +When in doubt, prefer static: a component is only an island if it must run in +the browser. Presentational cards, heroes, navs (without interactive menus), +footers, sections, and feature lists are static `.astro`. + +## Hydration Directives (`client:*`) + +Reference each island from the page with the cheapest correct directive: + +| Directive | Use when | +|-----------|----------| +| `client:load` | Above-the-fold interactivity needed immediately (primary CTA, header search). | +| `client:visible` | Below-the-fold islands — hydrate when scrolled into view (default for most islands). | +| `client:idle` | Non-urgent interactivity that can wait for the main thread to be idle. | +| `client:media` | Interactivity only relevant at certain breakpoints (e.g. a mobile-only menu). | + +Default to `client:visible`; use `client:load` only for above-the-fold islands. +Never hydrate a static `.astro` component (it has no client directive). + +## Pages + +- Pages are **file-based** routes: `src/pages/*.astro` (index → `/`, `about` → + `/about`, matching each `build-spec.pages[].route`). +- A page imports both static `.astro` components and React islands and composes + them. Static components render inline; islands carry a `client:*` directive. +- Shared chrome (head, html/body, global layout) lives in a layout component the + pages import. + +## Tests (read from `manifest.test`: `runner: vitest`, `containerApi: true`) + +Generate a colocated test for every component you emit: + +- **React islands (`.tsx`)** → Vitest + `@testing-library/react` (`render`, + `screen`, `userEvent`), exactly like the Vite/Next React path. Assert + rendering, interaction, and accessibility. +- **Static `.astro` components** → Vitest + the **Astro Container API**. Render + with `experimental_AstroContainer` and assert against the returned HTML + string: + ```ts + import { experimental_AstroContainer as AstroContainer } from "astro/container"; + import { expect, test } from "vitest"; + import Hero from "./Hero.astro"; + + test("renders the title", async () => { + const container = await AstroContainer.create(); + const html = await container.renderToString(Hero, { + props: { title: "Welcome" }, + }); + expect(html).toContain("Welcome"); + }); + ``` +- **Page-level interactivity** (multi-step flows that cross component + boundaries) → Playwright E2E in Phase 6 (`e2e-test-generator`), not unit tests. + +## Autonomous Workflow + +**Phase 1: Discovery (interactive)** +1. Confirm `renderer: "astro"` in the build-spec; resolve the manifest. +2. Extract / load design tokens and write `tailwind.config.mjs`. +3. Classify every component as island vs. static (the rule above). Produce a + table: component → kind (`.astro` | `.tsx`) → `client:*` (islands only). +4. Survey pages and their sections with screenshots. +5. Present the classification + page plan to the user: "Proceed?" + +**Phase 2: Execution (autonomous)** +1. Write `tailwind.config.mjs` from locked tokens. +2. Build static `.astro` components (presentational) with `interface Props`. +3. Build React islands (`.tsx`) reusing React converter component/prop patterns. +4. Build the layout component and compose `src/pages/*.astro`, wiring each + island's `client:*` directive (`client:load` above the fold, `client:visible` + below). +5. Generate tests: RTL for islands, Container API for `.astro`. +6. Work through all components without "should I continue?" prompts; log errors + and continue. + +**Phase 3: Completion** +1. Summarize: components created (split by island/static), tokens mapped, pages + composed, and any issues. +2. Recommend hydration tuning (e.g. promoting a `client:load` to `client:visible` + if it is below the fold) and follow-up E2E flows. + +## Quality Standards + +- **Static-first.** Ship zero JS unless interactivity is required. The whole + point of Astro is minimizing client JavaScript. +- **Correct hydration.** Every island has exactly one `client:*` directive; + no static component has one. +- **Zero hardcoded values.** Colors, spacing, typography, radii, shadows all map + to Tailwind tokens from the lockfile. +- **TypeScript native.** Island props via exported `interface`; static props via + frontmatter `interface Props`. No `any`. +- **Accessible & responsive.** WCAG 2.1 AA, semantic HTML, mobile-first Tailwind + breakpoints, keyboard navigation, focus-visible styles. +- **Tested.** Every component has a colocated test (RTL or Container API). + +## Key Principles + +1. **Hybrid by default** — static `.astro` for presentation, React islands for + interaction. +2. **Signals drive the split** — `action` / interactive `category` / + `businessLogic` → island; otherwise static. +3. **Cheapest correct hydration** — prefer `client:visible`; `client:load` only + above the fold. +4. **Reuse React patterns for islands** — islands are ordinary React converter + output. +5. **Fully autonomous** — work through all components after Phase 1 approval. +6. **Production ready** — accessible, responsive, token-driven, tested. + +--- + +**Agent Version:** 1.0.0 +**Created:** 2026-05-28 +**Model:** Opus (for hybrid island/static interpretation) +**Execution Mode:** Autonomous with Phase 1 classification review diff --git a/.claude/commands/build-from-canva.md b/.claude/commands/build-from-canva.md index d71573e..2bbed6d 100644 --- a/.claude/commands/build-from-canva.md +++ b/.claude/commands/build-from-canva.md @@ -39,7 +39,7 @@ Use `TodoWrite` to create a master checklist. Update each item as phases complet [ ] Phase 1: Intake — canva-intake skill → build-spec.json [ ] Phase 2: Token Inference — canva-token-inference skill → lockfile + tailwind config (requires user confirmation) [ ] Phase 3: TDD Scaffold — tdd-from-figma skill → failing tests (RED) -[ ] Phase 4: Component Build — canva-react-converter agent → tests pass (GREEN) +[ ] Phase 4: Component Build — converter agent (per resolved renderer manifest) → tests pass (GREEN) [ ] Phase 4.5: Storybook — generate-stories.sh → auto-generated stories [ ] Phase 5: Visual Verification — pixel-diff loop (max N iterations, against Canva screenshots) [ ] Phase 5.5: Dark Mode — check-dark-mode.sh → dark mode visual verification @@ -104,18 +104,28 @@ Identical to `/build-from-figma` Phase 3. After Phase 3 completes (TDD scaffold with failing tests confirmed), hand off remaining phases to the parallel orchestration skill. +**Read `renderer` from `build-spec.json` and resolve its manifest before dispatching:** + +```bash +node scripts/renderer-registry.js resolve --json +``` + +The manifest drives both converter dispatch (`manifest.converter`) and phase exclusion (`manifest.phases.exclude`). + **Invoke the `parallel-orchestration` skill with:** - Phases to run: `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]` + - Drop any phase listed in `manifest.phases.exclude` - Context: - Build spec: `.claude/plans/build-spec.json` - Lockfile: `src/styles/design-tokens.lock.json` - Test files: `src/components/**/*.test.tsx` - Pipeline source: `"canva"` + - Renderer manifest: from `renderer-registry.js resolve --json` - Reference screenshots: `.claude/visual-qa/screenshots/canva/` - Config: `.claude/pipeline.config.json` → `orchestration` section The parallel orchestration skill will: -1. Start `component-build` first (dispatches `canva-react-converter` agent) +1. Start `component-build` first (dispatches the converter named in the resolved manifest, see Phase 4) 2. After build completes, fan out independent phases in parallel (max 3 concurrent) 3. Run `e2e-tests` after `visual-diff` completes 4. Run `report` after both `quality-gate` and `e2e-tests` complete @@ -126,19 +136,30 @@ The parallel orchestration skill will: The individual phase descriptions below serve as reference for what each phase does. The parallel orchestration skill dispatches the same agents, skills, and scripts — it only changes the execution order. -## Phase 4: Component Build +## Phase 4: Component Build (Renderer-Driven) + +Read `renderer` from `build-spec.json`, resolve its manifest, and dispatch the converter it names: + +```bash +node scripts/renderer-registry.js resolve --json +``` + +**Converter selection:** +- If `manifest.language === "react"`, prefer the source-appropriate React converter. For the Canva pipeline that is `canva-react-converter` (it builds React components from Canva screenshots). The shipped React manifests (nextjs, vite) set `converter` to the generic `figma-react-converter`; for the Canva source, use `canva-react-converter` instead. +- Otherwise dispatch `manifest.converter` directly (e.g. `react-native-converter` for expo, and the future `vue-converter` / `svelte-converter`). -Dispatch the `canva-react-converter` agent. +The component extension, directory, page-routing convention, and test command come from `manifest.component` and `manifest.commands.test`. -**Input:** build-spec.json, lockfile, existing test files, Canva screenshots -**Output:** `src/components/**/*.tsx`, page files +**Input:** build-spec.json, resolved renderer manifest, lockfile, existing test files, Canva screenshots +**Output:** Component and page files for the renderer's framework (React: `src/components/**/*.tsx`) This phase: -1. Reads build-spec.json — verifies `source` is `"canva"` -2. References lockfile for all token values (no approximating) -3. Uses Canva screenshots for layout/structure decisions -4. Generates components that satisfy the test files from Phase 3 -5. Runs `pnpm vitest run` after each component batch to confirm GREEN +1. Reads build-spec.json — verifies `source` is `"canva"` and reads `renderer` +2. Resolves the manifest and dispatches the converter (see selection rule above) +3. References lockfile for all token values (no approximating) +4. Uses Canva screenshots for layout/structure decisions +5. Generates components (at `manifest.component.dir` with `manifest.component.ext`) that satisfy the test files from Phase 3 +6. Runs `manifest.commands.test` after each component batch to confirm GREEN **Critical rule:** If tests fail, fix the component — never modify the test files. diff --git a/.claude/commands/build-from-figma.md b/.claude/commands/build-from-figma.md index 45d2bbb..5a28282 100644 --- a/.claude/commands/build-from-figma.md +++ b/.claude/commands/build-from-figma.md @@ -115,18 +115,28 @@ Process components in dependency order: UI primitives → Layout → Sections After Phase 3 completes (TDD scaffold with failing tests confirmed), hand off remaining phases to the parallel orchestration skill. +**Read `renderer` from `build-spec.json` and resolve its manifest before dispatching:** + +```bash +node scripts/renderer-registry.js resolve --json +``` + +The manifest drives both converter dispatch (`manifest.converter`) and phase exclusion (`manifest.phases.exclude`). + **Invoke the `parallel-orchestration` skill with:** - Phases to run: `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]` + - Drop any phase listed in `manifest.phases.exclude` - Context: - Build spec: `.claude/plans/build-spec.json` - Lockfile: `src/styles/design-tokens.lock.json` - Test files: `src/components/**/*.test.tsx` - Pipeline source: `"figma"` + - Renderer manifest: from `renderer-registry.js resolve --json` - Figma screenshots: `.claude/visual-qa/screenshots/figma/` - Config: `.claude/pipeline.config.json` → `orchestration` section The parallel orchestration skill will: -1. Start `component-build` first (all other phases depend on it) +1. Start `component-build` first (dispatches the converter named in the resolved manifest, see Phase 4 — all other phases depend on it) 2. After build completes, fan out independent phases in parallel (max 3 concurrent) 3. Run `e2e-tests` after `visual-diff` completes 4. Run `report` after both `quality-gate` and `e2e-tests` complete @@ -137,18 +147,28 @@ The parallel orchestration skill will: The individual phase descriptions below serve as reference for what each phase does. The parallel orchestration skill dispatches the same agents, skills, and scripts — it only changes the execution order. -## Phase 4: Component Build +## Phase 4: Component Build (Renderer-Driven) + +Read `renderer` from `build-spec.json`, resolve its manifest, and dispatch the converter it names: + +```bash +node scripts/renderer-registry.js resolve --json +``` + +**Converter selection:** +- If `manifest.language === "react"`, prefer the source-appropriate React builder. For the Figma pipeline that is `figma-react-converter`, driven by the `figma-to-react-workflow` skill (which detects build-spec.json and lockfile automatically). The shipped React manifests (nextjs, vite) already name `figma-react-converter` as their `converter`. +- Otherwise dispatch `manifest.converter` directly (e.g. `react-native-converter` for expo, and the future `vue-converter` / `svelte-converter`). -Invoke the `figma-to-react-workflow` skill (which detects build-spec.json and lockfile automatically). +The component extension, directory, page-routing convention, and test command come from `manifest.component` and `manifest.commands.test`. -**Input:** build-spec.json, lockfile, existing test files -**Output:** `src/components/**/*.tsx`, page files +**Input:** build-spec.json, resolved renderer manifest, lockfile, existing test files +**Output:** Component and page files for the renderer's framework (React: `src/components/**/*.tsx`) This phase: -1. Skips discovery (build-spec.json exists) +1. Skips discovery (build-spec.json exists); reads `renderer` and resolves its manifest 2. References lockfile for all token values (no approximating) -3. Generates components that satisfy the test files from Phase 3 -4. Runs `pnpm vitest run` after each component batch to confirm GREEN +3. Generates components (at `manifest.component.dir` with `manifest.component.ext`) that satisfy the test files from Phase 3 +4. Runs `manifest.commands.test` after each component batch to confirm GREEN **Critical rule:** If tests fail, fix the component — never modify the test files. diff --git a/.claude/commands/build-from-screenshot.md b/.claude/commands/build-from-screenshot.md index 5d17f1a..b1eafc0 100644 --- a/.claude/commands/build-from-screenshot.md +++ b/.claude/commands/build-from-screenshot.md @@ -12,7 +12,7 @@ You are the master orchestrator for converting screenshots or a live URL into a - **E2E tests are generated** — Phase 6 generates and runs Playwright E2E tests appropriate to the app type. - **App-type aware** — Chrome extensions, PWAs, and web apps each get tailored test strategies. - **Token inference requires confirmation** — Phase 2 extracts tokens via AI vision and MUST get user confirmation before locking. -- **Output-target aware** — Phase 4 dispatches the correct converter agent based on `build-spec.json.outputTarget`. +- **Renderer-driven** — Phase 4 dispatches the converter agent named by the resolved renderer manifest (`renderer-registry.js resolve `), not a hardcoded `outputTarget` table. ## Input @@ -51,7 +51,7 @@ Use `TodoWrite` to create a master checklist. Update each item as phases complet [ ] Phase 1: Intake — screenshot-intake skill → build-spec.json (with outputTarget) [ ] Phase 2: Token Inference — canva-token-inference skill → lockfile + config (requires user confirmation) [ ] Phase 3: TDD Scaffold — tdd-from-figma skill → failing tests (RED) -[ ] Phase 4: Component Build — converter agent (per outputTarget) → tests pass (GREEN) +[ ] Phase 4: Component Build — converter agent (per resolved renderer manifest) → tests pass (GREEN) [ ] Phase 4.5: Storybook — generate-stories.sh → auto-generated stories [ ] Phase 5: Visual Verification — pixel-diff loop (max N iterations, against source screenshots) [ ] Phase 5.5: Dark Mode — check-dark-mode.sh → dark mode visual verification @@ -116,23 +116,29 @@ Identical to `/build-from-figma` Phase 3. After Phase 3 completes (TDD scaffold with failing tests confirmed), hand off remaining phases to the parallel orchestration skill. -**Read `build-spec.json` to determine `outputTarget` before dispatching.** +**Read `renderer` from `build-spec.json` and resolve its manifest before dispatching:** + +```bash +node scripts/renderer-registry.js resolve --json +``` + +The manifest drives both converter dispatch (`manifest.converter`) and phase exclusion (`manifest.phases.exclude`). **Invoke the `parallel-orchestration` skill with:** - Phases to run: `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]` - - For `react-native` outputTarget: exclude `visual-diff`, `dark-mode`, `cross-browser`, `responsive` - - For `chrome-extension` appType: exclude `cross-browser` + - Drop any phase listed in `manifest.phases.exclude` (e.g. expo excludes `visual-diff`, `dark-mode`, `cross-browser`, `responsive`) + - For `chrome-extension` appType: also exclude `cross-browser` - Context: - Build spec: `.claude/plans/build-spec.json` - Lockfile: `src/styles/design-tokens.lock.json` - Test files: `src/components/**/*.test.*` - Pipeline source: `"screenshot"` - - Output target: from `build-spec.json.outputTarget` + - Renderer manifest: from `renderer-registry.js resolve --json` - Reference screenshots: `.claude/visual-qa/screenshots/source/` - Config: `.claude/pipeline.config.json` → `orchestration` section The parallel orchestration skill will: -1. Start `component-build` first (dispatches the correct converter agent per outputTarget) +1. Start `component-build` first (dispatches the converter named in the resolved manifest, see Phase 4) 2. After build completes, fan out independent phases in parallel (max 3 concurrent) 3. Run `e2e-tests` after `visual-diff` completes (or after `component-build` if visual-diff excluded) 4. Run `report` after both `quality-gate` and `e2e-tests` complete @@ -143,35 +149,36 @@ The parallel orchestration skill will: The individual phase descriptions below serve as reference for what each phase does. The parallel orchestration skill dispatches the same agents, skills, and scripts — it only changes the execution order. -## Phase 4: Component Build (Output-Target-Aware) +## Phase 4: Component Build (Renderer-Driven) + +Read `renderer` from `build-spec.json`, resolve its manifest, and dispatch the converter it names: + +```bash +node scripts/renderer-registry.js resolve --json +``` -Read `build-spec.json` and dispatch the correct converter agent based on `outputTarget`: +**Converter selection:** +- If `manifest.language === "react"`, prefer the source-appropriate React converter. For the screenshot pipeline that is `figma-react-converter` (the generic React builder) — it builds React components from reference screenshots regardless of source. The shipped React manifests (nextjs, vite) already set `converter` to `figma-react-converter`. +- Otherwise dispatch `manifest.converter` directly (e.g. `react-native-converter` for the expo renderer, and the future `vue-converter` / `svelte-converter`). -| outputTarget | Agent | Output | -|---|---|---| -| `react` | `canva-react-converter` | `src/components/**/*.tsx`, page files | -| `vue` | `vue-converter` | `src/components/**/*.vue`, page files | -| `svelte` | `svelte-converter` | `src/lib/components/**/*.svelte`, page files | -| `react-native` | `react-native-converter` | `src/components/**/*.tsx` (RN), screen files | +The component file extension, directory, and page-routing convention come from `manifest.component` (`ext`, `dir`, `pageRouting`); the test command comes from `manifest.commands.test`. -**Input:** build-spec.json, lockfile, existing test files, source screenshots -**Output:** Component and page files for the target framework +**Input:** build-spec.json, resolved renderer manifest, lockfile, existing test files, source screenshots +**Output:** Component and page files for the renderer's framework This phase: -1. Reads build-spec.json — verifies `source` is `"screenshot"` and reads `outputTarget` -2. Dispatches the correct converter agent (see table above) +1. Reads build-spec.json — verifies `source` is `"screenshot"` and reads `renderer` +2. Resolves the manifest and dispatches the converter (see selection rule above) 3. References lockfile for all token values (no approximating) 4. Uses source screenshots for layout/structure decisions -5. Generates components that satisfy the test files from Phase 3 -6. Runs the appropriate test command after each component batch to confirm GREEN: - - `react` / `vue` / `svelte`: `pnpm vitest run` - - `react-native`: `pnpm jest` or `pnpm vitest run` (per project config) +5. Generates components (at `manifest.component.dir` with `manifest.component.ext`) that satisfy the test files from Phase 3 +6. Runs `manifest.commands.test` after each component batch to confirm GREEN **Critical rule:** If tests fail, fix the component — never modify the test files. ## Phase 4.5: Storybook Generation (Non-Blocking) -Identical to `/build-from-figma` Phase 4.5. Skipped for `react-native` outputTarget. +Identical to `/build-from-figma` Phase 4.5. Skipped when the renderer has no browser story (e.g. expo). ```bash ./scripts/generate-stories.sh @@ -185,7 +192,7 @@ Same process as `/build-from-figma` Phase 5, but reference screenshots come from For each page: ``` -1. Start: pnpm dev (background) — skip if appType is chrome-extension or outputTarget is react-native +1. Start: pnpm dev (background) — skip if appType is chrome-extension or the renderer excludes `visual-diff` (e.g. expo) 2. Wait for server ready 3. Reference screenshots already exist in .claude/visual-qa/screenshots/source/ @@ -211,17 +218,17 @@ For each page: 5. Stop dev server ``` -**Note:** For `react-native` outputTarget, visual verification is skipped (no browser rendering). Mark as N/A in the checklist. +**Note:** When the resolved renderer excludes `visual-diff` (e.g. expo, which has no browser rendering), this phase is skipped. Mark as N/A in the checklist. ## Phases 5.5 through 9 Identical to `/build-from-figma`. All shared phases work the same regardless of design source: -- **Phase 5.5:** Dark Mode verification (`check-dark-mode.sh`) — skipped for `react-native` +- **Phase 5.5:** Dark Mode verification (`check-dark-mode.sh`) — skipped when the renderer excludes `dark-mode` - **Phase 6:** E2E test generation (`e2e-test-generator` skill) -- **Phase 7:** Cross-browser screenshots (Firefox, WebKit) — skipped for `react-native` +- **Phase 7:** Cross-browser screenshots (Firefox, WebKit) — skipped when the renderer excludes `cross-browser` - **Phase 8:** Quality gate (coverage, types, build, tokens, Lighthouse) -- **Phase 8.5:** Responsive screenshots (`check-responsive.sh`) — skipped for `react-native` +- **Phase 8.5:** Responsive screenshots (`check-responsive.sh`) — skipped when the renderer excludes `responsive` - **Phase 9:** Build report (`.claude/visual-qa/build-report.md`) The build report should note: @@ -236,7 +243,7 @@ The build report should note: - **Screenshot capture fails:** Ask user to manually capture screenshots and provide file paths. - **Image files not found:** List missing files. Ask user to verify paths. - **Token inference low confidence:** Present all tokens with detailed confidence breakdown. Offer to accept user-provided brand guidelines as override. -- **Converter agent missing:** If the requested outputTarget agent does not exist yet, inform the user and offer to fall back to `canva-react-converter` for React output. +- **Converter agent missing:** If the converter named by the resolved manifest does not exist yet, inform the user. For `react` renderers, fall back to `figma-react-converter` (the generic React builder). - **Dev server will not start:** Check for port conflicts, missing dependencies. Run `pnpm install` if needed. - **Tests will not pass after 3 attempts:** Mark component as needing manual intervention, continue with remaining. - **Build fails:** Check TypeScript errors first, then dependency issues. Report blockers. diff --git a/.claude/skills/canva-intake/SKILL.md b/.claude/skills/canva-intake/SKILL.md index 42dd252..da31b92 100644 --- a/.claude/skills/canva-intake/SKILL.md +++ b/.claude/skills/canva-intake/SKILL.md @@ -65,16 +65,14 @@ Feed each exported screenshot to Claude for structural analysis: **Simultaneously scan the local project** (identical to figma-intake): ``` -1. Detect framework: - - next.config.* → Next.js (outputTarget: "react") - - vite.config.* + vue in package.json → Vue + Vite (outputTarget: "vue") - - nuxt.config.* → Nuxt (outputTarget: "vue") - - svelte.config.* → SvelteKit (outputTarget: "svelte") - - vite.config.* + svelte in package.json → Svelte + Vite (outputTarget: "svelte") - - app.json with "expo" → Expo (outputTarget: "react-native") - - vite.config.* → Vite + React (outputTarget: "react") - - remix.config.* → Remix (outputTarget: "react") - - None → New project needed (ask output target question) +1. Detect framework via the renderer registry: + - Run: node scripts/renderer-registry.js detect . --json + - On { "renderer": "", "language": "" }: + set build-spec renderer = + set build-spec outputTarget = (react | vue | svelte | react-native) + - On { "renderer": null }: + no framework detected → New project needed (ask output target question) + Do not hand-sniff config files or package.json deps; the registry owns detection. 2. Detect app type: - manifest.json with "manifest_version" → Chrome Extension @@ -162,12 +160,12 @@ Only ask questions whose answers cannot be derived from the design or local proj > (Only ask if existing project detected) **Question 6 — Output Target (only if no framework detected):** -> What framework should I build this in? -> a) React (Next.js / Vite / Remix) -> b) Vue 3 (Nuxt / Vite) -> c) Svelte (SvelteKit / Vite) -> d) React Native (Expo) -> (Skip if existing project with framework detected — auto-detect from package.json) +> Run `node scripts/renderer-registry.js list --json` and present the returned +> renderer names as the choices (each entry has `name` and `language`): +> "Which renderer should I build this in? [numbered list of registry renderers]" +> - Greenfield React default: `vite`. +> - Set build-spec `renderer` = the chosen name and `outputTarget` = its `language`. +> (Skip if the registry already detected a framework for the existing project.) ### Step 4: Generate build-spec.json @@ -178,7 +176,8 @@ Write the spec file that all downstream phases consume: { "version": "1.0.0", "source": "canva", - "outputTarget": "react", // "react" | "vue" | "svelte" | "react-native" + "renderer": "vite", // registry renderer name (from `renderer-registry list`): "nextjs" | "vite" | "sveltekit" | "expo" | "astro" | ... + "outputTarget": "react", // resolved language; equals the renderer's language. "react" | "vue" | "svelte" | "react-native" "createdAt": "2026-03-18T12:00:00Z", "canva": { "designId": "DAGxyz...", @@ -191,7 +190,7 @@ Write the spec file that all downstream phases consume: }, "appType": "web-app", "framework": { - "type": "vite", // "nextjs-app" | "nextjs-pages" | "vite" | "remix" | "nuxt" | "sveltekit" | "expo" + "type": "vite", // DEPRECATED — superseded by top-level `renderer`. Retained for back-compat only. "version": "6.0.0", "outputDir": "src" }, @@ -257,6 +256,12 @@ Write the spec file that all downstream phases consume: } ``` +**Renderer fields:** +- `renderer` (string) is the authoritative framework field. Valid values are the renderer names from `node scripts/renderer-registry.js list --json` (currently `nextjs`, `vite`, `sveltekit`, `expo`, `astro`). +- `outputTarget` is retained and **equals the resolved renderer's `language`** (react / vue / svelte / react-native). Set both together from the registry `detect`/`resolve` output. +- `framework.type` is **deprecated** — folded into `renderer`. Keep it only for back-compat with older specs; `renderer` wins on any conflict. +- **Back-compat rule:** a build-spec carrying only `outputTarget` (no `renderer`) resolves to that language's DEFAULT renderer: `react → vite`, `svelte → sveltekit`, `react-native → expo`. (`vue` has no renderer yet — its default is unsupported/future.) + **Key differences from Figma build-spec:** - `source` is `"canva"` instead of `"figma"` - `canva` block replaces `figma` block (different metadata) diff --git a/.claude/skills/canva-token-inference/SKILL.md b/.claude/skills/canva-token-inference/SKILL.md index 94dae22..c18f64e 100644 --- a/.claude/skills/canva-token-inference/SKILL.md +++ b/.claude/skills/canva-token-inference/SKILL.md @@ -263,13 +263,20 @@ After user confirmation, write `src/styles/design-tokens.lock.json` in the same } ``` -### Step 6: Generate Tailwind Config and CSS Properties +### Step 6: Generate Framework Config and CSS Properties -Identical to `design-token-lock` Steps 4-5: +The token-extraction above is framework-agnostic; only the config target changes. Resolve the build-spec's `renderer` manifest to pick the target: -1. Generate or update `tailwind.config.ts` from the lockfile -2. Generate `src/styles/tokens.css` with CSS custom properties -3. All values reference `var(--color-*)` — no raw hex in config +```bash +node scripts/renderer-registry.js resolve --json +``` + +Use `manifest.language` to choose the styling approach and `manifest.template` to locate where the framework's config lives and what shape it takes: + +- **`react` / `vue` / `svelte`** — Tailwind CSS-variable approach. Generate or update the Tailwind config (e.g. `tailwind.config.ts`, alongside `manifest.template`) plus `src/styles/tokens.css`. All values reference `var(--color-*)` — no raw hex in config. (Astro reuses this React/Tailwind path: its language is `react`.) +- **`react-native`** — NativeWind. Generate the NativeWind/Tailwind config and a StyleSheet token module for the Expo template (`manifest.template`) instead of a web `tokens.css`. + +Steps otherwise mirror `design-token-lock` Steps 4-5. ### Step 7: Validate Lockfile @@ -287,8 +294,8 @@ Report any gaps to the user before proceeding. | File | Purpose | |------|---------| | `src/styles/design-tokens.lock.json` | Versioned lockfile — identical format to Figma path | -| `tailwind.config.ts` | Tailwind theme extended from lockfile | -| `src/styles/tokens.css` | CSS custom properties from lockfile | +| Framework config (`tailwind.config.ts` for react/vue/svelte/astro; NativeWind config for react-native) | Theme extended from lockfile, target chosen from `manifest.language` | +| `src/styles/tokens.css` (web) / StyleSheet token module (react-native) | CSS custom properties from lockfile, or RN token module | ## Accuracy Expectations diff --git a/.claude/skills/design-token-lock/SKILL.md b/.claude/skills/design-token-lock/SKILL.md index 5aadee2..cfbf3e1 100644 --- a/.claude/skills/design-token-lock/SKILL.md +++ b/.claude/skills/design-token-lock/SKILL.md @@ -177,9 +177,22 @@ Write `src/styles/design-tokens.lock.json`: } ``` -### Step 4: Generate Tailwind Config +### Step 4: Generate Framework Config -Generate or update `tailwind.config.ts` from the lockfile: +The lockfile and token extraction above are framework-agnostic; only the config target changes. Resolve the build-spec's `renderer` manifest to select it: + +```bash +node scripts/renderer-registry.js resolve --json +``` + +Use `manifest.language` to choose the styling approach and `manifest.template` to locate where the framework's config lives: + +- **`react` / `vue` / `svelte`** — Tailwind CSS-variable approach (the path documented here). Generate or update the Tailwind config (e.g. `tailwind.config.ts`, alongside `manifest.template`). Astro reuses this same React/Tailwind path (its language is `react`). +- **`react-native`** — NativeWind: generate the NativeWind/Tailwind config plus a StyleSheet token module for the Expo template instead of a web `tokens.css`. + +The Figma pipeline targets React renderers (nextjs, vite), so in practice this resolves to the Tailwind path below. + +Generate or update the Tailwind config from the lockfile: ```typescript // Read design-tokens.lock.json and map to Tailwind theme diff --git a/.claude/skills/figma-intake/SKILL.md b/.claude/skills/figma-intake/SKILL.md index 44b4663..f1a6c8b 100644 --- a/.claude/skills/figma-intake/SKILL.md +++ b/.claude/skills/figma-intake/SKILL.md @@ -35,16 +35,14 @@ Run these Figma MCP calls to gather context automatically: Simultaneously scan the local project: ``` -1. Detect framework: - - next.config.* → Next.js (outputTarget: "react") - - vite.config.* + vue in package.json → Vue + Vite (outputTarget: "vue") - - nuxt.config.* → Nuxt (outputTarget: "vue") - - svelte.config.* → SvelteKit (outputTarget: "svelte") - - vite.config.* + svelte in package.json → Svelte + Vite (outputTarget: "svelte") - - app.json with "expo" → Expo (outputTarget: "react-native") - - vite.config.* → Vite + React (outputTarget: "react") - - remix.config.* → Remix (outputTarget: "react") - - None → New project needed (ask output target question) +1. Detect framework via the renderer registry: + - Run: node scripts/renderer-registry.js detect . --json + - On { "renderer": "", "language": "" }: + set build-spec renderer = + set build-spec outputTarget = (react | vue | svelte | react-native) + - On { "renderer": null }: + no framework detected → New project needed (ask output target question) + Do not hand-sniff config files or package.json deps; the registry owns detection. 2. Detect app type: - manifest.json with "manifest_version" → Chrome Extension @@ -127,12 +125,12 @@ Only ask questions whose answers cannot be derived from the Figma file or local > (Only ask if existing project detected) **Question 6 — Output Target (only if no framework detected):** -> What framework should I build this in? -> a) React (Next.js / Vite / Remix) -> b) Vue 3 (Nuxt / Vite) -> c) Svelte (SvelteKit / Vite) -> d) React Native (Expo) -> (Skip if existing project with framework detected — auto-detect from package.json) +> Run `node scripts/renderer-registry.js list --json` and present the returned +> renderer names as the choices (each entry has `name` and `language`): +> "Which renderer should I build this in? [numbered list of registry renderers]" +> - Greenfield React default: `vite`. +> - Set build-spec `renderer` = the chosen name and `outputTarget` = its `language`. +> (Skip if the registry already detected a framework for the existing project.) **Question 7 — App Type (only if ambiguous):** > I detected this as a [chrome-extension / web-app / pwa]. Is that correct? @@ -147,7 +145,8 @@ Write the spec file that all downstream phases consume: { "version": "1.0.0", "source": "figma", // "figma" | "canva" - "outputTarget": "react", // "react" | "vue" | "svelte" | "react-native" + "renderer": "vite", // registry renderer name (from `renderer-registry list`): "nextjs" | "vite" | "sveltekit" | "expo" | "astro" | ... + "outputTarget": "react", // resolved language; equals the renderer's language. "react" | "vue" | "svelte" | "react-native" "createdAt": "2026-03-16T12:00:00Z", "figma": { "fileKey": "abc123", @@ -156,7 +155,7 @@ Write the spec file that all downstream phases consume: }, "appType": "web-app", // "web-app" | "chrome-extension" | "pwa" "framework": { - "type": "vite", // "nextjs-app" | "nextjs-pages" | "vite" | "remix" | "nuxt" | "sveltekit" | "expo" + "type": "vite", // DEPRECATED — superseded by top-level `renderer`. Retained for back-compat only. "version": "6.0.0", "outputDir": "src" }, @@ -233,6 +232,12 @@ Write the spec file that all downstream phases consume: } ``` +**Renderer fields:** +- `renderer` (string) is the authoritative framework field. Valid values are the renderer names from `node scripts/renderer-registry.js list --json` (currently `nextjs`, `vite`, `sveltekit`, `expo`, `astro`). +- `outputTarget` is retained and **equals the resolved renderer's `language`** (react / vue / svelte / react-native). Set both together from the registry `detect`/`resolve` output. +- `framework.type` is **deprecated** — folded into `renderer`. Keep it only for back-compat with older specs; `renderer` wins on any conflict. +- **Back-compat rule:** a build-spec carrying only `outputTarget` (no `renderer`) resolves to that language's DEFAULT renderer: `react → vite`, `svelte → sveltekit`, `react-native → expo`. (`vue` has no renderer yet — its default is unsupported/future.) + ### Step 5: Confirm and Proceed Present a summary of the build plan: diff --git a/.claude/skills/parallel-orchestration/SKILL.md b/.claude/skills/parallel-orchestration/SKILL.md index a638420..77e0663 100644 --- a/.claude/skills/parallel-orchestration/SKILL.md +++ b/.claude/skills/parallel-orchestration/SKILL.md @@ -23,13 +23,28 @@ The scheduler produces real-time streaming output as phases start and finish, an 1. **Phase IDs** -- ordered list of phase IDs to execute (e.g., `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]`). 2. **Prior context** -- artifacts from earlier sequential phases: - - `build-spec.json` (component list, appType, outputTarget, E2E flows) + - `build-spec.json` (component list, appType, `renderer`, E2E flows) - `design-tokens.lock.json` (locked token values) - Test files from tdd-scaffold phase 3. **Pipeline config** -- `.claude/pipeline.config.json`, specifically the `orchestration` section. +4. **Renderer manifest** -- the resolved manifest for the build-spec's `renderer`, used to drop excluded phases and select the converter (see Step 0 and Step 5). ## Algorithm +### Step 0: Resolve Renderer and Exclude Phases + +Before scheduling, read `renderer` from `build-spec.json` and resolve its manifest: + +```bash +node scripts/renderer-registry.js resolve --json +``` + +Read `manifest.phases.exclude` (an array, absent/empty for most renderers) and **drop every listed phase from the requested phase set before building the dependency graph.** Excluded phases never enter the scheduler — they are not dispatched, not tracked, and not awaited. + +Example: the `expo` renderer excludes `visual-diff`, `cross-browser`, `responsive`, and `dark-mode` (no browser rendering), so those phases are removed up front and only `component-build`, `storybook`, `e2e-tests`, `quality-gate`, and `report` schedule. When a dependent phase's dependency was excluded, treat that dependency as pre-satisfied (same as a phase completed externally). + +This replaces any per-framework phase-skipping logic — the manifest is the single source of truth for which phases a renderer supports. + ### Step 1: Load Configuration Read `.claude/pipeline.config.json` and extract the `orchestration` section: @@ -125,7 +140,7 @@ function hasResourceConflict(candidatePhase, runningPhases): | Phase | Dispatch Method | |-------|----------------| -| `component-build` | **Agent:** invoke figma-to-react-workflow skill (or vue-converter / svelte-converter / react-native-converter based on `outputTarget` in build-spec.json) | +| `component-build` | **Agent:** dispatch the converter named by the resolved renderer manifest. For React renderers the calling command supplies the source-appropriate converter (figma/screenshot → figma-react-converter via the figma-to-react-workflow skill, canva → canva-react-converter); otherwise dispatch `manifest.converter` (e.g. react-native-converter for expo, future vue-converter / svelte-converter) | | `storybook` | **Bash:** `./scripts/generate-stories.sh` | | `visual-diff` | **Agent:** invoke visual-qa-verification skill with pixel-diff loop (max iterations from `iterationLoop.maxVisualIterations`) | | `dark-mode` | **Bash:** `./scripts/check-dark-mode.sh http://localhost:3000` | @@ -233,10 +248,11 @@ Invoke parallel-orchestration with phases: "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"] Context provided: - - build-spec.json (appType, outputTarget, component list, E2E flows) + - build-spec.json (appType, renderer, component list, E2E flows) - design-tokens.lock.json - Test files from phase 3 - Pipeline config + - Resolved renderer manifest (drives phase exclusion + converter selection) ``` -The parallel scheduler respects the dependency graph within the handed-off phases. For example, `component-build` has no unmet deps (its dep `tdd-scaffold` was completed in the sequential block), so it starts immediately. Phases like `visual-diff`, `storybook`, `dark-mode`, `quality-gate`, `cross-browser`, and `responsive` all depend on `component-build`, so they fan out once it completes. Finally, `report` waits for `quality-gate` and `e2e-tests` before running. +Before scheduling, the scheduler resolves the renderer manifest and drops any phase in `manifest.phases.exclude` (Step 0). The parallel scheduler then respects the dependency graph within the remaining handed-off phases. For example, `component-build` has no unmet deps (its dep `tdd-scaffold` was completed in the sequential block), so it starts immediately. Phases like `visual-diff`, `storybook`, `dark-mode`, `quality-gate`, `cross-browser`, and `responsive` all depend on `component-build`, so they fan out once it completes. Finally, `report` waits for `quality-gate` and `e2e-tests` before running. diff --git a/.claude/skills/screenshot-intake/SKILL.md b/.claude/skills/screenshot-intake/SKILL.md index acb982b..44c05a5 100644 --- a/.claude/skills/screenshot-intake/SKILL.md +++ b/.claude/skills/screenshot-intake/SKILL.md @@ -190,16 +190,14 @@ Store extracted data in working memory for Step 4 (questions) and Step 5 (build- ### Step 3: Local Project Scan ``` -1. Detect framework (in order): - - next.config.* → Next.js (outputTarget: "react") - - remix.config.* → Remix (outputTarget: "react") - - nuxt.config.* → Nuxt (outputTarget: "vue") - - svelte.config.* → SvelteKit (outputTarget: "svelte") - - app.json with "expo" → Expo (outputTarget: "react-native") - - vite.config.* + vue in deps → Vite+Vue (outputTarget: "vue") - - vite.config.* + svelte in deps → Vite+Svelte (outputTarget: "svelte") - - vite.config.* → Vite+React (outputTarget: "react") - - None → ask user (Q3 below) +1. Detect framework via the renderer registry: + - Run: node scripts/renderer-registry.js detect . --json + - On { "renderer": "", "language": "" }: + set build-spec renderer = + set build-spec outputTarget = (react | vue | svelte | react-native) + - On { "renderer": null }: + no framework detected → ask user (Q3 below) + Do not hand-sniff config files or package.json deps; the registry owns detection. 2. Detect app type: - manifest.json with "manifest_version" → chrome-extension @@ -240,12 +238,11 @@ Only ask what cannot be derived from captures or local scan. Use `AskUserQuestio > Since detection is vision-based, low-confidence rows are worth a second look. **Q3 — Output target (only if no framework detected):** -> What framework should I build this in? -> a) React (Next.js / Vite / Remix) -> b) Vue 3 (Nuxt / Vite) -> c) Svelte (SvelteKit / Vite) -> d) React Native (Expo) -> Default: React + Vite for new projects. +> Run `node scripts/renderer-registry.js list --json` and present the returned +> renderer names as the choices (each entry has `name` and `language`): +> "Which renderer should I build this in? [numbered list of registry renderers]" +> Default: `vite` (React) for new projects. +> Set build-spec `renderer` = the chosen name and `outputTarget` = its `language`. **Q4 — Component reuse (only if existing components detected):** > I found N existing components that match detected components. @@ -271,7 +268,8 @@ Write `.claude/plans/build-spec.json`. The schema is consumed by `canva-token-in { "version": "1.0.0", "source": "screenshot", - "outputTarget": "react", + "renderer": "vite", // registry renderer name (from `renderer-registry list`): "nextjs" | "vite" | "sveltekit" | "expo" | "astro" | ... + "outputTarget": "react", // resolved language; equals the renderer's language "createdAt": "2026-05-21T14:30:00Z", "screenshot": { "inputType": "url", @@ -288,7 +286,7 @@ Write `.claude/plans/build-spec.json`. The schema is consumed by `canva-token-in }, "appType": "web-app", "framework": { - "type": "vite", + "type": "vite", // DEPRECATED — superseded by top-level `renderer`. Retained for back-compat only. "version": "6.0.0", "outputDir": "src" }, @@ -372,6 +370,12 @@ Write `.claude/plans/build-spec.json`. The schema is consumed by `canva-token-in **Manual-fallback variant:** set `captureMode` to `"manual"`. +**Renderer fields:** +- `renderer` (string) is the authoritative framework field. Valid values are the renderer names from `node scripts/renderer-registry.js list --json` (currently `nextjs`, `vite`, `sveltekit`, `expo`, `astro`). +- `outputTarget` is retained and **equals the resolved renderer's `language`** (react / vue / svelte / react-native). Set both together from the registry `detect`/`resolve` output. +- `framework.type` is **deprecated** — folded into `renderer`. Keep it only for back-compat with older specs; `renderer` wins on any conflict. +- **Back-compat rule:** a build-spec carrying only `outputTarget` (no `renderer`) resolves to that language's DEFAULT renderer: `react → vite`, `svelte → sveltekit`, `react-native → expo`. (`vue` has no renderer yet — its default is unsupported/future.) + ### Step 6: Confirm and Proceed Present a build plan summary and wait for confirmation: diff --git a/.claude/skills/tdd-from-figma/SKILL.md b/.claude/skills/tdd-from-figma/SKILL.md index 64ef15d..dd4a071 100644 --- a/.claude/skills/tdd-from-figma/SKILL.md +++ b/.claude/skills/tdd-from-figma/SKILL.md @@ -435,11 +435,24 @@ describe("Service Worker", () => { 4. ALWAYS: Generate standard component tests (existing behavior) ``` -## Output-Target-Aware Test Generation +## Renderer-Aware Test Generation -Read `build-spec.json` field `outputTarget` to determine test library and component patterns. Default is `"react"` (existing behavior above). +Resolve the build-spec's `renderer` manifest to determine the test runner and library: -### Vue 3 Tests (outputTarget: "vue") +```bash +node scripts/renderer-registry.js resolve --json +``` + +Read `manifest.test`: + +- `runner` — `vitest` or `jest` +- `library` — e.g. `@testing-library/react`, `@vue/test-utils`, `@testing-library/svelte`, `@testing-library/react-native` +- `setup` (optional) — test setup file to wire up +- `containerApi` (optional) — when `true`, the framework supports server/static container rendering (used by Astro static `.astro` components; render via the framework's Container API rather than a DOM testing library) + +The component patterns below are grouped by `manifest.language`. Default is React (`@testing-library/react` + Vitest, the existing behavior above). + +### Vue 3 Tests (language: "vue", library: @vue/test-utils) Use `@vue/test-utils` + Vitest: @@ -533,7 +546,7 @@ it("renders named slots", () => { }); ``` -### Svelte Tests (outputTarget: "svelte") +### Svelte Tests (language: "svelte", library: @testing-library/svelte) Use `@testing-library/svelte` + Vitest: @@ -602,9 +615,9 @@ it("navigation has correct landmark", () => { }); ``` -### React Native Tests (outputTarget: "react-native") +### React Native Tests (language: "react-native", runner: jest, library: @testing-library/react-native) -Use `@testing-library/react-native` + Jest (Expo default): +Use `@testing-library/react-native` + Jest (Expo default — `manifest.test.runner` is `jest`): #### Rendering Tests ```typescript @@ -680,18 +693,33 @@ it("renders primary variant styling", () => { ### Conditional Test Generation Logic (Updated) ``` -1. Read build-spec.json → outputTarget, appType -2. Select test library based on outputTarget: - - "react" → @testing-library/react + vitest (existing) - - "vue" → @vue/test-utils + vitest - - "svelte" → @testing-library/svelte + vitest - - "react-native" → @testing-library/react-native + jest -3. Generate component tests using the appropriate library patterns -4. THEN apply app-type-specific tests (existing chrome-extension/pwa logic) +1. Read build-spec.json → renderer, appType +2. Resolve the renderer manifest: renderer-registry.js resolve --json +3. Select the test runner + library directly from manifest.test: + - runner: manifest.test.runner (vitest | jest) + - library: manifest.test.library (@testing-library/react | @vue/test-utils | + @testing-library/svelte | @testing-library/react-native | ...) + - setup: manifest.test.setup (wire up if present) + - containerApi: manifest.test.containerApi (static container rendering, see Astro note) +4. Generate component tests using the patterns for manifest.language +5. THEN apply app-type-specific tests (existing chrome-extension/pwa logic) - Note: chrome-extension and pwa app types only apply to web targets (react/vue/svelte) - react-native does not use chrome-extension or pwa test templates ``` +### Astro Test Split + +For `renderer: "astro"`, `manifest.language` is `react` and `manifest.test.containerApi` +is `true`. Split tests by what is under test: + +- **Islands** (interactive React/Vue/Svelte components) → the island's framework + runner + library from `manifest.test` (e.g. Vitest + `@testing-library/react`). +- **Static `.astro` components** → Vitest + the Astro Container API + (`manifest.test.containerApi === true`): render the component to a string/fragment + and assert on the output rather than using a DOM testing library. +- **Page-level interactivity** (hydration, cross-island behavior) → Playwright E2E, + generated in Phase 6 (e2e-test-generator), not here. + ## Output | File | Purpose | diff --git a/.claude/test-fixtures/astro-hybrid.build-spec.json b/.claude/test-fixtures/astro-hybrid.build-spec.json new file mode 100644 index 0000000..19d4d0e --- /dev/null +++ b/.claude/test-fixtures/astro-hybrid.build-spec.json @@ -0,0 +1,56 @@ +{ + "_comment": "Reference fixture documenting the astro-converter island/static split contract. The underscore-prefixed component fields (_astroKind, _astroClient, _astroNote) are fixture annotations documenting the EXPECTED island/static split for assertions. They are NOT inputs the astro-converter reads — the converter derives island vs static from action/category/businessLogic.", + "version": "1.0.0", + "source": "screenshot", + "renderer": "astro", + "outputTarget": "react", + "createdAt": "2026-05-28T00:00:00Z", + "screenshot": { + "sourceType": "url", + "url": "https://example.com", + "capturedScreenshots": [] + }, + "appType": "web-app", + "framework": { "type": "astro", "version": "5.18.2", "outputDir": "src" }, + "styling": { "approach": "tailwind", "uiLibrary": null, "existingTokens": false }, + "pages": [ + { + "screenshotPath": "", + "name": "Home", + "route": "/", + "sections": ["hero", "search"] + } + ], + "components": [ + { + "detectedName": "Hero Banner", + "confidence": "high", + "reactName": "Hero", + "category": "sections", + "action": "generate", + "existingPath": null, + "variants": [], + "props": ["title", "subtitle"], + "_astroKind": "static", + "_astroNote": "Presentational, no interactivity -> zero-JS .astro component (frontmatter interface Props)." + }, + { + "detectedName": "Search Box", + "confidence": "high", + "reactName": "SearchBox", + "category": "forms", + "action": "search", + "existingPath": null, + "variants": [], + "props": ["placeholder", "onSearch"], + "_astroKind": "island", + "_astroClient": "client:load", + "_astroNote": "Interactive (forms category + behavioral action + participates in businessLogic) -> React island .tsx hydrated with client:load above the fold." + } + ], + "textContent": { "hero-heading": "Find Anything", "hero-subheading": "Search across everything" }, + "businessLogic": { "forms": ["search"], "apiCalls": ["runSearch"], "auth": null, "stateManagement": null }, + "e2e": { "strategy": "navigate-interact-verify", "flows": [] }, + "testStrategy": { "unit": true, "e2e": true, "visual": true, "crossBrowser": false, "coverageThreshold": 80 }, + "options": { "componentReuse": "generate", "integration": "standalone" } +} diff --git a/.claude/test-fixtures/canva-dashboard.build-spec.json b/.claude/test-fixtures/canva-dashboard.build-spec.json index 6e3ddc3..ca07d29 100644 --- a/.claude/test-fixtures/canva-dashboard.build-spec.json +++ b/.claude/test-fixtures/canva-dashboard.build-spec.json @@ -1,6 +1,7 @@ { "version": "1.0.0", "source": "canva", + "renderer": "nextjs", "outputTarget": "react", "createdAt": "2026-03-21T00:00:00Z", "canva": { diff --git a/.claude/test-fixtures/canva-landing-page.build-spec.json b/.claude/test-fixtures/canva-landing-page.build-spec.json index d9dc136..5d9aab4 100644 --- a/.claude/test-fixtures/canva-landing-page.build-spec.json +++ b/.claude/test-fixtures/canva-landing-page.build-spec.json @@ -1,6 +1,7 @@ { "version": "1.0.0", "source": "canva", + "renderer": "vite", "outputTarget": "react", "createdAt": "2026-03-21T00:00:00Z", "canva": { diff --git a/.claude/test-fixtures/canva-nested-groups.build-spec.json b/.claude/test-fixtures/canva-nested-groups.build-spec.json index 9f4d354..f22b83a 100644 --- a/.claude/test-fixtures/canva-nested-groups.build-spec.json +++ b/.claude/test-fixtures/canva-nested-groups.build-spec.json @@ -1,6 +1,7 @@ { "version": "1.0.0", "source": "canva", + "renderer": "vite", "outputTarget": "react", "createdAt": "2026-03-21T00:00:00Z", "canva": { diff --git a/.gitignore b/.gitignore index 8de24ef..2cfae73 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ playwright-report/ test-results/ scripts/__tests__/fixtures/* !scripts/__tests__/fixtures/agent-plugins/ +!scripts/__tests__/fixtures/renderers/ +!scripts/__tests__/fixtures/projects/ # Environment .env diff --git a/CLAUDE.md b/CLAUDE.md index cc48782..3f0e67c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,12 +17,13 @@ The framework is designed for: ``` project-root/ ├── .claude/ # Claude Code configuration -│ ├── agents/ # 53 specialized agents +│ ├── agents/ # 54 specialized agents │ ├── skills/ # 20 React-specific skills │ ├── commands/ # Custom slash commands │ ├── hooks/ # Hook scripts (automated hooks configured in settings.json) │ └── pipeline.config.json # Pipeline thresholds, iteration limits, app types ├── scripts/ # Development automation scripts +├── renderers/ # Pluggable framework renderer manifests (renderer.json + schema) ├── templates/ # Starter configs (ESLint, Tailwind, Vitest, Chrome ext, PWA, etc.) ├── docs/ # Documentation │ ├── figma-to-react/ # Figma conversion pipeline docs @@ -122,6 +123,10 @@ node scripts/validate-pipeline-config.js --config --schema # Export generated components as a publishable design-system workspace ./scripts/export-design-system.sh [--scope @org] [--output dir] [--framework ] [--dry-run] [--json] +# Renderer registry: list / resolve / detect framework renderers (see docs/multi-framework/renderers.md) +node scripts/renderer-registry.js (list | resolve | detect [dir]) [--json] +node scripts/validate-renderer.js --dir # or --all [--renderers-root ] + # Author / validate / install / test custom agents as versioned plugins node scripts/create-agent-plugin.js [--description ...] [--model ...] [--tools ...] [--with-hooks] node scripts/validate-agent-plugin.js --dir # or --all [--plugins-root ] @@ -205,15 +210,15 @@ pnpm tsc --noEmit # Type check without emitting --- -### Custom Agents (53 Total) +### Custom Agents (54 Total) -53 specialized agents covering the full product lifecycle: +54 specialized agents covering the full product lifecycle: | Category | Count | Key Agents | |----------|-------|------------| | Engineering | 12 | frontend-developer, backend-architect, rapid-prototyper, test-writer-fixer, error-boundary-architect, migration-specialist, i18n-engineer, animation-optimizer, bundle-analyzer | | Design | 5 | ui-designer, ux-researcher, brand-guardian | -| Design-to-Code | 6 | figma-react-converter, canva-react-converter, asset-cataloger, vue-converter, svelte-converter, react-native-converter | +| Design-to-Code | 7 | figma-react-converter, canva-react-converter, astro-converter, asset-cataloger, vue-converter, svelte-converter, react-native-converter | | Testing & QA | 7 | visual-qa-agent, accessibility-auditor, api-tester, performance-benchmarker | | Product | 3 | sprint-prioritizer, feedback-synthesizer, trend-researcher | | Marketing | 7 | content-creator, growth-hacker, app-store-optimizer | @@ -557,6 +562,12 @@ gh issue create # Create issue ./scripts/verify-all.sh --ci # CI mode: JSON output, exit 1 on any failure ``` +**Renderers** (pluggable framework renderers — see `docs/multi-framework/renderers.md`): +```bash +node scripts/renderer-registry.js (list | resolve | detect [dir]) [--json] +node scripts/validate-renderer.js --dir # or --all +``` + **Agent Plugins** (custom agents as versioned plugins — see `docs/guides/agent-plugins.md`): ```bash node scripts/create-agent-plugin.js [--description ...] [--model ...] [--tools ...] [--with-hooks] @@ -580,6 +591,6 @@ node scripts/metrics-dashboard.js summary # Quick metrics summary --- **Last Updated:** 2026-05-28 -**Architecture:** 53 agents, 20 skills, 4 plugins + gh CLI, Figma + Canva + Playwright MCP, 38 scripts, 8 hooks +**Architecture:** 54 agents, 20 skills, 4 plugins + gh CLI, Figma + Canva + Playwright MCP, 40 scripts, 8 hooks, 5 renderers (nextjs, vite, astro, sveltekit, expo) > **Keeping counts in sync:** When adding or removing agents, skills, scripts, or hooks, update all count references across the project. Search for the old count number in `*.md` files to find all references: `CLAUDE.md`, `README.md`, `CONTRIBUTING.md`, `docs/onboarding/`, `docs/react-development/`, and `.claude/AGENT-NAMING-GUIDE.md`. The agent and skill counts are enforced automatically by `scripts/check-doc-counts.sh` (run in CI and on pre-commit), which recounts `.claude/agents/` and `.claude/skills/` and fails on any documented count that disagrees. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a8d3a2..dc15cbe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -137,7 +137,7 @@ Because the bump is derived from commit history, **conventional commit messages ## Claude Code Agents -Aurelius includes 53 specialized Claude Code agents and 20 skills that automate significant portions of the development workflow — from design-to-code conversion to testing, accessibility, and deployment. +Aurelius includes 54 specialized Claude Code agents and 20 skills that automate significant portions of the development workflow — from design-to-code conversion to testing, accessibility, and deployment. If you have Claude Code installed, these agents and skills are available to you automatically when working in this repository. They can assist with component development, test writing, visual QA, and much more. diff --git a/README.md b/README.md index f0b14c2..075cb08 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A Claude Code-integrated multi-framework app development framework with TypeScri ## What This Framework Provides -- **53 Custom Agents** -- Specialized AI agents for engineering, design, testing, marketing, operations, and more +- **54 Custom Agents** -- Specialized AI agents for engineering, design, testing, marketing, operations, and more - **20 Development Skills** -- Automated workflows for Figma/Canva conversion, TDD, E2E testing, visual QA, state management, forms, auth, animation, SEO, and more - **10-Phase Design-to-React Pipeline** -- Convert Figma or Canva designs into fully working, tested React apps with a single command - **App-Type Awareness** -- Tailored build and test strategies for web apps, Chrome extensions, and PWAs @@ -85,7 +85,7 @@ project-root/ │ ├── canva-to-react/ # Canva pipeline guide │ └── react-development/ # Development standards ├── .claude/ # Claude Code configuration -│ ├── agents/ # 53 custom agents +│ ├── agents/ # 54 custom agents │ ├── skills/ # 20 development skills │ ├── commands/ # Slash commands (/build-from-figma, /lint, /test) │ ├── pipeline.config.json # Pipeline thresholds and app-type definitions @@ -136,7 +136,7 @@ All thresholds and behavior are configurable in `.claude/pipeline.config.json`: - Lighthouse minimums (performance: 80, accessibility: 90) - App-type-specific E2E strategies -## 53 Custom Agents +## 54 Custom Agents Agents are auto-selected by Claude Code based on your task: @@ -144,7 +144,7 @@ Agents are auto-selected by Claude Code based on your task: |----------|-------|------------| | Engineering | 12 | frontend-developer, backend-architect, rapid-prototyper, test-writer-fixer, error-boundary-architect, migration-specialist, i18n-engineer, animation-optimizer, bundle-analyzer | | Design | 5 | ui-designer, ux-researcher, brand-guardian | -| Design-to-Code | 6 | figma-react-converter, canva-react-converter, vue-converter, svelte-converter, react-native-converter, asset-cataloger | +| Design-to-Code | 7 | figma-react-converter, canva-react-converter, astro-converter, vue-converter, svelte-converter, react-native-converter, asset-cataloger | | Testing & QA | 7 | visual-qa-agent, accessibility-auditor, api-tester, performance-benchmarker | | Product | 3 | sprint-prioritizer, feedback-synthesizer, trend-researcher | | Marketing | 7 | content-creator, growth-hacker, app-store-optimizer | @@ -270,14 +270,14 @@ Details: `.claude/PLUGINS-REFERENCE.md` |----------|----------|-------------| | **Developer onboarding** | `docs/onboarding/README.md` | Start here -- quickstart, architecture, configuration, troubleshooting | | Quickstart guide | `docs/onboarding/quickstart.md` | Clone to running project in 10 minutes | -| Architecture overview | `docs/onboarding/architecture.md` | All 53 agents, 20 skills, 3 pipelines, and how they connect | +| Architecture overview | `docs/onboarding/architecture.md` | All 54 agents, 20 skills, 3 pipelines, and how they connect | | Pipeline configuration | `docs/onboarding/pipeline-configuration.md` | Every setting in pipeline.config.json explained | | Troubleshooting FAQ | `docs/onboarding/troubleshooting.md` | Common issues and solutions | | Project instructions | `CLAUDE.md` | Full project config for Claude Code | | Figma pipeline guide | `docs/figma-to-react/README.md` | Pipeline overview and troubleshooting | | React standards | `docs/react-development/README.md` | TypeScript, Tailwind, testing conventions | | Canva pipeline guide | `docs/canva-to-react/README.md` | Canva pipeline overview and troubleshooting | -| Agent catalog | `.claude/CUSTOM-AGENTS-GUIDE.md` | All 53 agents with use cases | +| Agent catalog | `.claude/CUSTOM-AGENTS-GUIDE.md` | All 54 agents with use cases | | Skills catalog | `.claude/skills/README.md` | All 20 skills with triggers | | Plugin reference | `.claude/PLUGINS-REFERENCE.md` | Plugin configuration and commands | | Scripts reference | `scripts/README.md` | All scripts with usage examples | diff --git a/docs/guides/agent-creation.md b/docs/guides/agent-creation.md index ae4504f..1697af3 100644 --- a/docs/guides/agent-creation.md +++ b/docs/guides/agent-creation.md @@ -2,7 +2,7 @@ Agents are specialized Markdown files with YAML frontmatter that live in `.claude/agents/`. Each agent defines a persona, a set of allowed tools, and detailed instructions that shape how Claude Code behaves when the agent is selected. Claude Code reads the `description` field to decide which agent best matches a given task, then loads that agent's instructions as the system prompt for the session. -This framework ships with 53 agents covering engineering, design, testing, marketing, and operations. You can add your own by following the conventions below. +This framework ships with 54 agents covering engineering, design, testing, marketing, and operations. You can add your own by following the conventions below. ## File Location diff --git a/docs/multi-framework/README.md b/docs/multi-framework/README.md index 577b10e..b55a1dc 100644 --- a/docs/multi-framework/README.md +++ b/docs/multi-framework/README.md @@ -2,34 +2,57 @@ The pipeline supports generating code for multiple frontend frameworks from any design source (Figma, Canva, or screenshots/URLs). -## The `outputTarget` Field +## The `renderer` and `outputTarget` Fields -The `outputTarget` field in `build-spec.json` controls which framework the pipeline generates code for: +The `renderer` field in `build-spec.json` is the **authoritative** field controlling which framework the pipeline generates code for. Its valid values are the renderer names from the renderer registry (`node scripts/renderer-registry.js list --json`) — currently `nextjs`, `vite`, `astro`, `sveltekit`, `expo`. ```json { "source": "figma", "appType": "web-app", - "outputTarget": "vue", + "renderer": "vite", + "outputTarget": "react", "components": [...] } ``` -Valid values: `"react"` (default), `"vue"`, `"svelte"`, `"react-native"`. +The `outputTarget` field is **retained** and **equals the resolved `renderer`'s `language`**. Each renderer manifest declares a `language`; resolving a renderer yields the matching `outputTarget`: + +| Renderer | `language` (= `outputTarget`) | +|----------|------------------------------| +| `nextjs` | `react` | +| `vite` | `react` | +| `astro` | `react` | +| `sveltekit` | `svelte` | +| `expo` | `react-native` | + +Valid `outputTarget` values: `"react"` (default), `"vue"`, `"svelte"`, `"react-native"`. + +> **`framework.type` is deprecated.** It has been folded into `renderer`. Older specs may still carry `framework.type`; it is kept for back-compat only and `renderer` wins on any conflict. + +### Back-compat: resolving `outputTarget` without `renderer` + +A build-spec carrying only `outputTarget` (no `renderer`) resolves to that language's **default renderer**: + +| `outputTarget` | Default renderer | +|----------------|------------------| +| `react` | `vite` | +| `svelte` | `sveltekit` | +| `react-native` | `expo` | +| `vue` | _(no renderer yet — future/unsupported)_ | ## Framework Auto-Detection -If `outputTarget` is not explicitly set during intake, the pipeline detects the framework from the project context: +If `renderer` is not explicitly set during intake, the pipeline detects the framework from the project context via the renderer registry: -| Signal | Detected Target | -|--------|----------------| -| `next.config.*` or `react-dom` in `package.json` | `react` | -| `vue` in `package.json` dependencies | `vue` | -| `svelte.config.*` or `svelte` in `package.json` | `svelte` | -| `app.json` with Expo config or `react-native` in `package.json` | `react-native` | -| No project context (greenfield) | `react` (default) | +```bash +node scripts/renderer-registry.js detect . --json +# → { "renderer": "", "language": "" } or { "renderer": null } +``` -The intake skills (`figma-intake`, `canva-intake`, `screenshot-intake`) also ask the user to confirm or override the detected target during the interview phase. +When a renderer is detected, both `renderer` (the detected name) and `outputTarget` (the resolved `language`) are written to the build-spec. The registry owns all detection logic — the intake skills no longer hand-sniff config files or `package.json` dependencies. When detection returns `null` (greenfield), the intake skills present the registry's renderer list to the user; the greenfield React default is `vite`. + +The intake skills (`figma-intake`, `canva-intake`, `screenshot-intake`) also ask the user to confirm or override the detected renderer during the interview phase. ## Output Targets @@ -41,6 +64,27 @@ The intake skills (`figma-intake`, `canva-intake`, `screenshot-intake`) also ask - **Templates:** `templates/nextjs/` (Next.js App Router) or `templates/vite/` (Vite + React) - **Component pattern:** Functional components with TypeScript, props interfaces, `children`/`className` passthrough +### Astro (hybrid islands) + +- **Converter agent:** `astro-converter` +- **Renderer:** `astro` (`language`/`outputTarget` = `react`) +- **Styling:** Tailwind CSS via `@astrojs/tailwind` +- **Test library:** Vitest + @testing-library/react (islands) + Astro Container API (`.astro` statics) +- **Template:** `templates/astro/` (`@astrojs/react` islands + `@astrojs/tailwind`) +- **Component pattern:** Hybrid — zero-JS static `.astro` files for presentational components, React islands (`.tsx`) for interactive ones, composed under file-based `src/pages/*.astro` routes. + +The `astro-converter` agent classifies every component from `build-spec.json`: +- A component with an `action`, an interactive `category`, or any + `businessLogic` involvement → a **React island** (`.tsx`), referenced from the + page with a `client:*` directive (`client:load` above the fold, + `client:visible` below). +- Otherwise → a **static `.astro`** component (zero JS), props typed via the + frontmatter `interface Props`. + +Islands are tested with Vitest + @testing-library/react (the React path); +static `.astro` components are tested with the Astro Container API +(`experimental_AstroContainer` from `astro/container`). + ### Vue 3 - **Converter agent:** `vue-converter` @@ -100,7 +144,7 @@ Most pipeline phases are shared across all output targets. Only Phase 4 (Build) | [1] Intake | Shared | Produces `outputTarget` in build-spec.json | | [2] Token Lock/Infer | Shared | Tokens map to Tailwind config (or NativeWind for React Native) | | [3] TDD (Gate) | Target-specific | Test file format and library vary by target | -| [4] Build | **Target-specific** | Dispatches to `vue-converter`, `svelte-converter`, `react-native-converter`, or React converter | +| [4] Build | **Target-specific** | Dispatches to the renderer manifest's `converter` (e.g. `vue-converter`, `svelte-converter`, `react-native-converter`, `astro-converter`, or a React converter) | | [4.5] Storybook | React/Vue only | Svelte uses SvelteKit stories; React Native skips | | [5] Visual Diff | Shared | Compares screenshots regardless of framework | | [5.5] Dark Mode | Shared | Theme token verification | @@ -120,20 +164,25 @@ The `tdd-from-figma` skill generates framework-appropriate test files: | Vue | Vitest | @vue/test-utils | `.test.ts` | | Svelte | Vitest | @testing-library/svelte | `.test.ts` | | React Native | Jest | @testing-library/react-native | `.test.tsx` | +| Astro | Vitest | @testing-library/react (islands) + Container API (static `.astro`) | `.test.tsx` / `.test.ts` | ## Phase 4: Agent Dispatch Table -| outputTarget | Source: Figma | Source: Canva | Source: Screenshot | +Phase 4 dispatch now resolves through the renderer manifest: the pipeline reads `manifest.converter` for the resolved `renderer` rather than keying off `outputTarget` directly (see [`renderers.md`](./renderers.md)). The table below lists the converter each renderer's manifest currently points to. + +| renderer (outputTarget) | Source: Figma | Source: Canva | Source: Screenshot | |-------------|--------------|--------------|-------------------| -| `react` | figma-react-converter | canva-react-converter | figma-react-converter | -| `vue` | vue-converter | vue-converter | vue-converter | -| `svelte` | svelte-converter | svelte-converter | svelte-converter | -| `react-native` | react-native-converter | react-native-converter | react-native-converter | +| `nextjs` / `vite` (`react`) | figma-react-converter | canva-react-converter | figma-react-converter | +| `sveltekit` (`svelte`) | svelte-converter | svelte-converter | svelte-converter | +| `expo` (`react-native`) | react-native-converter | react-native-converter | react-native-converter | +| `astro` (`react`) | astro-converter | astro-converter | astro-converter | +| (`vue`) | vue-converter | vue-converter | vue-converter | -For Figma and screenshot sources with non-React targets, the converter agent reads the design tokens and build-spec, then generates framework-specific components directly (no intermediate React step). +For non-React targets (and for Astro's hybrid `.astro` + React islands output), the converter agent reads the design tokens and build-spec, then generates framework-specific components directly (no intermediate React step). ## Related Documentation +- [`renderers.md`](./renderers.md) -- The renderer model (three-axis: outputTarget/renderer/appType), manifest field reference, registry CLI + validator, and how to add a renderer - `docs/figma-to-react/README.md` -- Figma conversion pipeline - `docs/canva-to-react/README.md` -- Canva conversion pipeline - `docs/screenshot-to-app/README.md` -- Screenshot/URL conversion pipeline diff --git a/docs/multi-framework/renderers.md b/docs/multi-framework/renderers.md new file mode 100644 index 0000000..4879e7f --- /dev/null +++ b/docs/multi-framework/renderers.md @@ -0,0 +1,192 @@ +# Renderers + +A **renderer** is a pluggable description of a meta-framework (Next.js, Vite, +SvelteKit, Expo, Astro, ...). Each renderer lives in its own directory under +`renderers//` with a `renderer.json` manifest. The manifest is the single +source of truth for how the pipeline scaffolds, builds, tests, and converts +into that framework. + +## The three-axis model + +The pipeline separates three concerns that older specs conflated into a single +`framework.type` field: + +| Axis | `build-spec.json` field | What it answers | Examples | +|------|-------------------------|-----------------|----------| +| **Language** | `outputTarget` | What language/component model does generated code use? | `react`, `vue`, `svelte`, `react-native` | +| **Renderer** | `renderer` | Which pluggable meta-framework renders that language? | `nextjs`, `vite`, `sveltekit`, `expo`, `astro` | +| **App type** | `appType` | What deployment shape is being produced? | `web-app`, `chrome-extension`, `pwa`, `mobile-app` | + +These axes are independent. The same `outputTarget` (`react`) is served by +several renderers (`nextjs`, `vite`, `astro`); the same renderer can target +multiple app types. `outputTarget` is always **derivable from** the renderer — +it equals the resolved renderer's `language` — so the `renderer` field is +authoritative and `outputTarget` is retained for back-compat and convenience. + +``` +appType ── deployment shape (web-app | chrome-extension | pwa | mobile-app) + │ +renderer ── pluggable meta-framework (nextjs | vite | sveltekit | expo | astro) + │ +outputTarget ── language / component model (react | vue | svelte | react-native) + = the renderer's `language` +``` + +## Manifest field reference + +Every `renderers//renderer.json` is validated against +`renderers/renderer.schema.json` (JSON Schema 2020-12, `additionalProperties: +false`). Fields: + +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `name` | string | yes | Unique renderer id; **must equal the directory basename**. | +| `language` | enum | yes | One of `react`, `vue`, `svelte`, `react-native`. Becomes the resolved `outputTarget`. | +| `detect.configFiles` | string[] | yes | Glob strings matched against project file **basenames** (e.g. `next.config.*`). | +| `detect.dependencies` | string[] | yes | Package names matched against the project's `dependencies`/`devDependencies`. | +| `detect.priority` | integer | no (default `0`) | Higher wins when multiple renderers match; ties broken by name ascending. | +| `template` | string | yes | Path (relative to repo root) to the starter template dir, e.g. `templates/astro`. | +| `component.ext` | string | yes | Primary component file extension, e.g. `.tsx`, `.svelte`, `.astro`. | +| `component.islandExt` | string | no | Extension for interactive islands when the renderer is hybrid (Astro: `.tsx`). | +| `component.dir` | string | no | Conventional component directory, e.g. `src/components`. | +| `component.pageRouting` | enum | no | `app-router`, `pages`, `file-based`, or `screens`. | +| `test.runner` | string | yes | Test runner, e.g. `vitest`, `jest`. | +| `test.library` | string | yes | Testing library, e.g. `@testing-library/react`. | +| `test.setup` | string | no | Optional test setup file. | +| `test.containerApi` | boolean | no | `true` when statics are tested via a container API (Astro Container API). | +| `converter` | string | yes | Converter **agent** name; an agent file must exist at `.claude/agents/.md`. | +| `commands.dev` / `.build` / `.test` | string | yes | Canonical dev/build/test commands. | +| `phases.exclude` | string[] | no | Pipeline phases this renderer skips (e.g. Expo excludes `cross-browser`, `responsive`). | +| `capabilities.islands` / `.ssr` / `.darkMode` | boolean | no | Feature flags the pipeline uses to gate work. | + +### Example manifest (Astro) + +```json +{ + "name": "astro", + "language": "react", + "detect": { "configFiles": ["astro.config.*"], "dependencies": ["astro"], "priority": 10 }, + "template": "templates/astro", + "component": { "ext": ".astro", "islandExt": ".tsx", "dir": "src/components", "pageRouting": "file-based" }, + "test": { "runner": "vitest", "library": "@testing-library/react", "containerApi": true }, + "converter": "astro-converter", + "commands": { "dev": "pnpm dev", "build": "pnpm build", "test": "pnpm vitest run" }, + "capabilities": { "islands": true, "ssr": true, "darkMode": true } +} +``` + +## The registry CLI + +`scripts/renderer-registry.js` is a read-only query surface over the manifests. +It never mutates state. + +```bash +# List available renderers (name + language) +node scripts/renderer-registry.js list [--json] + +# Print one renderer's full manifest +node scripts/renderer-registry.js resolve [--json] + +# Detect which renderer matches a project directory +node scripts/renderer-registry.js detect [] [--json] +``` + +- **`list`** — emits `{ renderers: [{ name, language }] }`, sorted by name. +- **`resolve `** — emits the full manifest, or exits `2` with + `unknown renderer` for an unknown name. +- **`detect `** — ranks renderers by `detect.priority` (ties by name), + matches a renderer if any `configFiles` glob hits a file basename **or** any + `dependencies` entry appears in the project's deps/devDeps, and emits + `{ renderer, language }` (or `{ renderer: null }` for a greenfield dir). + +Exit codes: `0` ok · `1` invalid/validation failure · `2` usage / unknown +name / IO error. `--renderers-root ` overrides the renderers root (used by +tests). + +### Validation + +`scripts/validate-renderer.js` validates a manifest against the schema **plus** +cross-reference checks the schema cannot express: + +```bash +node scripts/validate-renderer.js --dir renderers/ [--json] +node scripts/validate-renderer.js --all [--renderers-root ] [--json] +``` + +It verifies that: the manifest passes the JSON Schema; `name` matches the +directory basename; `language` is one of the four supported values; the +`template` path exists; and `converter` names an existing agent at +`.claude/agents/.md`. Exit `0` valid · `1` invalid · `2` usage/IO. + +`validate-renderer.js --all` is wired into `verify-all` via +`scripts/verify-renderers.sh`, so any renderer added under `renderers/` is +validated automatically: + +```bash +./scripts/verify-all.sh --include renderers +``` + +## Back-compat: `outputTarget`-only specs + +A `build-spec.json` carrying only `outputTarget` (no `renderer`) resolves to +that language's **default renderer**: + +| `outputTarget` | Default renderer | +|----------------|------------------| +| `react` | `vite` | +| `svelte` | `sveltekit` | +| `react-native` | `expo` | +| `vue` | _(no renderer yet — future/unsupported)_ | + +When both fields are present, `renderer` wins. The legacy `framework.type` +field is deprecated and folded into `renderer`. + +## Worked example: the Astro hybrid model + +Astro is the clearest illustration of why renderer and `outputTarget` are +distinct axes. Its `language`/`outputTarget` is `react`, but it renders that +React in a **hybrid islands** model rather than a single-page React app: + +- **Static `.astro` components** (`component.ext` = `.astro`) — zero-JS, + presentational. Props are typed via a frontmatter `interface Props`. Tested + with the **Astro Container API** (`test.containerApi: true`). +- **React islands** (`component.islandExt` = `.tsx`) — interactive components, + referenced from a page with a `client:*` directive (`client:load` above the + fold, `client:visible` below). Tested with **Vitest + + @testing-library/react**, the standard React path. + +The `astro-converter` agent classifies each component from `build-spec.json`: a +component with an `action`, an interactive `category`, or any `businessLogic` +involvement becomes a React island; everything else becomes a static `.astro` +file. So a single Astro build spec produces both `react`-language islands and +`.astro` statics — one renderer, one `outputTarget`, two component models — which +a flat `framework.type` field could never express. + +(See `.claude/test-fixtures/astro-hybrid.build-spec.json` for a fixture that +declares `renderer: "astro"`, `outputTarget: "react"`, `appType: "web-app"`, +and carries one island and one static component.) + +## How to add a renderer + +1. **Author the manifest directory.** Create `renderers//renderer.json` + with all required fields. Set `name` to `` (it must match the + directory). Pick a sensible `detect.priority` relative to existing renderers. +2. **Add a template.** Create `templates//` (or point `template` at an + existing one) with the starter config the scaffold should copy. Shared config + lives in `templates/shared/`. +3. **Set the converter agent.** Point `converter` at an agent file that exists + at `.claude/agents/.md` (create the agent if needed). +4. **Validate.** Run + `node scripts/validate-renderer.js --dir renderers/` and fix any + reported issues (name mismatch, missing template/agent, schema errors). +5. **It's wired into verify-all automatically.** `validate-renderer.js --all` + runs under `./scripts/verify-all.sh --include renderers`, and + `setup-project.sh --renderer ` plus the intake skills pick the new + renderer up from the registry with no further code changes. + +## Related documentation + +- [Multi-framework output overview](./README.md) +- `renderers/renderer.schema.json` — the manifest JSON Schema +- `scripts/renderer-registry.js` / `scripts/validate-renderer.js` — registry CLI + validator +- `docs/figma-to-react/README.md` — Figma conversion pipeline diff --git a/docs/onboarding/README.md b/docs/onboarding/README.md index 8b688e3..d210ab4 100644 --- a/docs/onboarding/README.md +++ b/docs/onboarding/README.md @@ -11,7 +11,7 @@ This guide will get you productive with the framework quickly, whether you are b | Document | What You Will Learn | |----------|-------------------| | [Quickstart Guide](quickstart.md) | Clone, install, create your first project, and run your first pipeline in under 10 minutes | -| [Architecture Overview](architecture.md) | How the 53 agents, 20 skills, 3 pipelines, and 8 hooks fit together | +| [Architecture Overview](architecture.md) | How the 54 agents, 20 skills, 3 pipelines, and 8 hooks fit together | | [Pipeline Configuration](pipeline-configuration.md) | Every setting in `pipeline.config.json` explained, with examples | | [Troubleshooting FAQ](troubleshooting.md) | Common issues, error messages, and how to resolve them | | [Framework Guides](../guides/README.md) | Deep dives into design tokens, visual QA, caching, hooks, error recovery, agent creation, and framework-specific workflows | @@ -52,7 +52,7 @@ Optional (for specific workflows): - [Main README](../../README.md) -- Project overview - [Contributing Guide](../../CONTRIBUTING.md) -- Branch naming, PR process, commit conventions -- [Agent Catalog](../../.claude/CUSTOM-AGENTS-GUIDE.md) -- All 53 agents with use cases +- [Agent Catalog](../../.claude/CUSTOM-AGENTS-GUIDE.md) -- All 54 agents with use cases - [Skills Catalog](../../.claude/skills/README.md) -- All 20 skills with triggers - [Plugin Reference](../../.claude/PLUGINS-REFERENCE.md) -- Installed plugins and commands - [Pipeline Config](../../.claude/pipeline.config.json) -- Thresholds and app-type definitions diff --git a/docs/onboarding/architecture.md b/docs/onboarding/architecture.md index 8a2f52d..d76dfc2 100644 --- a/docs/onboarding/architecture.md +++ b/docs/onboarding/architecture.md @@ -15,7 +15,7 @@ This document explains how Aurelius is structured and how its components work to ┌────────────────────┼─────────────────────┐ │ │ │ ┌───────▼──────┐ ┌────────▼────────┐ ┌────────▼────────┐ - │ 53 Agents │ │ 20 Skills │ │ 4 Plugins │ + │ 54 Agents │ │ 20 Skills │ │ 4 Plugins │ │ (specialized │ │ (workflow │ │ (extensions: │ │ task workers) │ │ automation) │ │ memory, git, │ └───────┬──────┘ └────────┬────────┘ │ superpowers) │ @@ -37,7 +37,7 @@ This document explains how Aurelius is structured and how its components work to --- -## Agents (53 Total) +## Agents (54 Total) Agents are specialized Claude Code sub-processes that handle complex, multi-step tasks. Each agent is a markdown file in `.claude/agents/` with frontmatter defining its tools, capabilities, and instructions. Claude Code selects agents automatically based on your task context. @@ -68,7 +68,7 @@ Agents are specialized Claude Code sub-processes that handle complex, multi-step | `visual-storyteller` | Create data visualizations, infographics, presentations | | `whimsy-injector` | Add micro-interactions and delightful UI details (runs proactively after UI changes) | -### Design-to-Code Agents (6) +### Design-to-Code Agents (7) | Agent | Purpose | Output | |-------|---------|--------| @@ -77,6 +77,7 @@ Agents are specialized Claude Code sub-processes that handle complex, multi-step | `vue-converter` | Convert designs to Vue 3 components | Vue 3 + `