初始化项目版本
This commit is contained in:
36
.agents/skills/stitch-react-components/README.md
Normal file
36
.agents/skills/stitch-react-components/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Stitch to React Components Skill
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npx skills add google-labs-code/stitch-skills --skill react:components --global
|
||||
```
|
||||
|
||||
## Example Prompt
|
||||
|
||||
```text
|
||||
Convert my Landing Page screen in my Podcast Stitch Project to a React component system.
|
||||
```
|
||||
|
||||
## Skill Structure
|
||||
|
||||
This repository follows the **Agent Skills** open standard. Each skill is self-contained with its own logic, validation scripts, and design tokens.
|
||||
|
||||
```text
|
||||
skills/react-components/
|
||||
├── SKILL.md — Core instructions & workflow
|
||||
├── package.json — Validator dependencies
|
||||
├── scripts/ — Networking & AST validation
|
||||
├── resources/ — Style guides & API references
|
||||
└── examples/ — Gold-standard code samples
|
||||
```
|
||||
|
||||
## How it Works
|
||||
|
||||
When activated, the agent follows a high-fidelity engineering pipeline:
|
||||
|
||||
1. **Retrieval**: Uses a system-level `curl` script to bypass TLS/SNI issues on Google Cloud Storage.
|
||||
2. **Mapping**: Cross-references Stitch metadata with the local `style-guide.json` to ensure token consistency.
|
||||
3. **Generation**: Scaffolds components using a strict Atomic Design pattern.
|
||||
4. **Validation**: Runs an automated AST check using `@swc/core` to prevent hardcoded hex values or missing interfaces.
|
||||
5. **Audit**: Performs a final self-correction check against a 20-point architecture checklist.
|
||||
110
.agents/skills/stitch-react-components/SKILL.md
Normal file
110
.agents/skills/stitch-react-components/SKILL.md
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
name: stitch::react-components
|
||||
description: >-
|
||||
Converts Stitch designs into modular Vite and React components, or syncs/updates
|
||||
existing React components to align with the latest Stitch designs, using system-level
|
||||
networking and AST-based validation.
|
||||
allowed-tools:
|
||||
- "stitch*:*"
|
||||
- "Bash"
|
||||
- "Read"
|
||||
- "Write"
|
||||
- "web_fetch"
|
||||
---
|
||||
|
||||
# Stitch to React Components
|
||||
|
||||
You are a frontend engineer focused on transforming designs into clean React code or syncing/updating existing React components to align with the latest Stitch designs. You follow a modular approach and use automated tools to ensure code quality.
|
||||
|
||||
> **CRITICAL: Every step in this skill is MANDATORY. Do NOT skip any step or take shortcuts. Each section contains a GATE that must be satisfied before proceeding.**
|
||||
|
||||
## Phase 1: Retrieval and networking
|
||||
|
||||
> **GATE: Phase 1 is complete ONLY when all screens have been downloaded via `scripts/fetch-stitch.sh` AND visually audited. Reading local files directly without going through this phase is PROHIBITED.**
|
||||
|
||||
1. **Namespace discovery**: Run `list_tools` to find the Stitch MCP prefix. Use this prefix (e.g., `stitch:`) for all subsequent calls.
|
||||
2. **Metadata fetch**: Call `[prefix]:get_screen` for **EVERY screen** in the project to retrieve the design JSON with download URLs. Do NOT skip any screen.
|
||||
3. **Check for existing designs**: Before downloading, check if `.stitch/designs/{page}.html` and `.stitch/designs/{page}.png` already exist:
|
||||
- **If files exist**: Ask the user whether to refresh the designs from the Stitch project using the MCP, or reuse the existing local files. **You MUST ask — do not assume.** Only re-download if the user confirms.
|
||||
- **If files do not exist**: Proceed to step 4.
|
||||
4. **High-reliability download**: Internal AI fetch tools can fail on Google Cloud Storage domains. You MUST use the provided script.
|
||||
- **HTML**: `bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" ".stitch/designs/{page}.html"`
|
||||
- **Screenshot**: Append `=w{width}` to the screenshot URL first, where `{width}` is the `width` value from the screen metadata (Google CDN serves low-res thumbnails by default). Then run: `bash scripts/fetch-stitch.sh "[screenshot.downloadUrl]=w{width}" ".stitch/designs/{page}.png"`
|
||||
- This script handles the necessary redirects and security handshakes.
|
||||
5. **Visual audit**: Review the downloaded screenshot (`.stitch/designs/{page}.png`) to confirm design intent and layout details. **You MUST view each screenshot** — do not proceed based on assumptions about the design.
|
||||
6. **Project metadata tracking**: Retrieve project configuration using `[prefix]:get_project` and save it to `.stitch/metadata.json` (inside the app folder, and mirrored in the workspace root). Ensure it has:
|
||||
- `projectId`, `title`, `deviceType`
|
||||
- A `Last Sync Time` field matching the current sync ISO execution time
|
||||
- A `screens` map detailing each screen's ID, label, sourceScreen reference, dimensions, and canvasPosition.
|
||||
|
||||
### Anti-patterns for Phase 1
|
||||
- ❌ Reading `.stitch/designs/*.html` directly without calling MCP `get_screen` first.
|
||||
- ❌ Skipping the `fetch-stitch.sh` download script.
|
||||
- ❌ Not asking the user when existing files are found.
|
||||
- ❌ Skipping the visual audit of `.png` screenshots.
|
||||
- ❌ Failing to generate or update `.stitch/metadata.json` and its `Last Sync Time` field upon syncing.
|
||||
|
||||
## Phase 2: Style extraction
|
||||
|
||||
> **GATE: Phase 2 is complete ONLY when `resources/style-guide.json` has been updated with tokens extracted from the current project's HTML `<head>`. Tokens from a previous project are NOT acceptable.**
|
||||
|
||||
1. **Extract `tailwind.config`**: Open each downloaded HTML file and locate the `tailwind.config` object in the `<head>` `<script>` block. Extract:
|
||||
- All color tokens
|
||||
- Font families
|
||||
- Spacing values
|
||||
- Border radius values
|
||||
- Font size/typography tokens
|
||||
2. **Sync `resources/style-guide.json`**: Overwrite the file with the extracted tokens from THIS project. The style guide MUST match the Stitch project being converted.
|
||||
3. **Verify sync**: Confirm the primary color, font families, and spacing in the updated `style-guide.json` match what you extracted.
|
||||
|
||||
### Anti-patterns for Phase 2
|
||||
- ❌ Using `style-guide.json` as-is without verifying it matches the current project.
|
||||
- ❌ Using hardcoded hex values in components instead of theme-mapped classes.
|
||||
|
||||
## Phase 3: Architectural rules
|
||||
|
||||
> **GATE: Every component MUST satisfy ALL of the following rules. Violations will cause `npm run validate` to fail.**
|
||||
|
||||
* **Modular components**: Break the design into independent files. **Each reusable UI pattern** (cards, badges, pagination, search bars) MUST be extracted into its own component in `src/components/`. Monolithic page files that contain everything are PROHIBITED.
|
||||
* **Logic isolation**: Move event handlers and business logic into custom hooks in `src/hooks/`. Examples: pagination logic → `usePagination`, filtering → `useFilter`.
|
||||
* **Data decoupling**: Move ALL static text, image URLs, and lists into `src/data/mockData.ts`. No hardcoded content in components.
|
||||
* **Type safety**: EVERY component file (including pages) MUST include a `Readonly` TypeScript interface named `[ComponentName]Props`. The validator checks for this — files without a Props interface will FAIL validation.
|
||||
* **Project specific**: Focus on the target project's needs and constraints. Leave Google license headers out of the generated React components.
|
||||
* **Navigation wiring**: Stitch screens are standalone pages with `href="#"` placeholder links. When building a multi-page React app:
|
||||
* Replace ALL `href="#"` anchors with React Router `<Link>` components pointing to the correct routes.
|
||||
* **Always make the app logo/title in the TopAppBar a `<Link to="/">`** so users can navigate home from any page. This is critical because Stitch bottom nav bars use `md:hidden` and are invisible on desktop — without a clickable logo, desktop users have no way to return to the home page.
|
||||
* Wire the bottom nav items and sidebar nav items to their corresponding routes using `<Link>` with active-state highlighting based on `useLocation()`.
|
||||
* **Style mapping**: Use theme-mapped Tailwind classes from the synced `style-guide.json`. No arbitrary hex codes.
|
||||
* **Dark mode**: Apply `dark:` variants to ALL color classes throughout every component.
|
||||
|
||||
### Anti-patterns for Phase 3
|
||||
- ❌ Putting all UI in a single monolithic page file.
|
||||
- ❌ Inline event handlers or business logic without hooks.
|
||||
- ❌ Hardcoding text, URLs, or data in component files.
|
||||
- ❌ Components without a `[Name]Props` interface.
|
||||
- ❌ Using hex color values instead of theme tokens.
|
||||
- ❌ Leaving `href="#"` links unconverted.
|
||||
|
||||
## Phase 4: Execution steps
|
||||
|
||||
> **GATE: Phase 4 verification, audits, and validation checks are optional. You MUST ask the user's permission to proceed with validation scripts, running local dev servers, or automated browser testing.**
|
||||
|
||||
1. **Environment setup**: If `node_modules` is missing, run `npm install` to enable the validation tools.
|
||||
2. **Data layer**: Create `src/data/mockData.ts` based on the design content.
|
||||
3. **Component drafting**: Use `resources/component-template.tsx` as a base. Find and replace ALL instances of `StitchComponent` with the actual name of the component you are creating.
|
||||
4. **Application wiring**: Update the project entry point (like `App.tsx`) to render the new components.
|
||||
5. **Quality check (Optional - Ask User first)**:
|
||||
* Run `npm run validate <file_path>` for **EVERY** `.tsx` file in `src/components/` and `src/pages/` to report component validity.
|
||||
* Run `tsc --noEmit` to verify TypeScript compile status.
|
||||
* Check output against `resources/architecture-checklist.md`.
|
||||
* Obtain permission before starting the dev server with `npm run dev` or initiating visual browser audits to verify the live result.
|
||||
|
||||
### Anti-patterns for Phase 4
|
||||
- ❌ Commencing dev server start or browser audits without user consent.
|
||||
- ❌ Declaring task "done" without verifying code compiles.
|
||||
|
||||
## Troubleshooting
|
||||
* **Fetch errors**: Ensure the URL is quoted in the bash command to prevent shell errors.
|
||||
* **Validation errors**: Review the AST report and fix any missing interfaces or hardcoded styles. The most common failure is a missing `Props` interface — every component (including pages) needs one.
|
||||
* **Dead navigation links**: Stitch HTML uses `href="#"` placeholders everywhere. Every `<a href="#">` must be converted to a `<Link to="/route">` with a real route. Verify all nav items are clickable and lead to the correct page.
|
||||
* **Stale style-guide.json**: If colors or fonts look wrong, the `style-guide.json` likely has tokens from a different project. Re-extract from the current HTML `<head>`.
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
import React from 'react';
|
||||
// Note for Agent: The '@' alias refers to the target project's src directory.
|
||||
// Ensure src/data/mockData.ts is created before generating this component.
|
||||
import { cardData } from '../data/mockData';
|
||||
|
||||
/**
|
||||
* Gold Standard: ActivityCard
|
||||
* This file serves as the definitive reference for the agent.
|
||||
*/
|
||||
interface ActivityCardProps {
|
||||
readonly id: string;
|
||||
readonly username: string;
|
||||
readonly action: 'MERGED' | 'COMMIT';
|
||||
readonly timestamp: string;
|
||||
readonly avatarUrl: string;
|
||||
readonly repoName: string;
|
||||
}
|
||||
|
||||
export const ActivityCard: React.FC<ActivityCardProps> = ({
|
||||
username,
|
||||
action,
|
||||
timestamp,
|
||||
avatarUrl,
|
||||
repoName,
|
||||
}) => {
|
||||
const isMerged = action === 'MERGED';
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-4 rounded-lg bg-surface-dark p-4 min-h-14 shadow-sm ring-1 ring-white/10">
|
||||
<div className="flex items-center gap-4 overflow-hidden">
|
||||
<div
|
||||
className="aspect-square h-10 w-10 flex-shrink-0 rounded-full bg-cover bg-center bg-no-repeat"
|
||||
style={{ backgroundImage: `url(${avatarUrl})` }}
|
||||
aria-label={`Avatar for ${username}`}
|
||||
/>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm sm:text-base">
|
||||
<a href="#" className="font-semibold text-primary hover:underline truncate">
|
||||
{username}
|
||||
</a>
|
||||
|
||||
<span className={`inline-block px-2 py-0.5 text-xs font-semibold rounded-full ${isMerged ? 'bg-purple-500/30 text-purple-300' : 'bg-primary/30 text-primary'
|
||||
}`}>
|
||||
{action}
|
||||
</span>
|
||||
|
||||
<span className="text-white/60">in</span>
|
||||
|
||||
<a href="#" className="text-primary hover:underline truncate">
|
||||
{repoName}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0">
|
||||
<p className="text-sm font-normal leading-normal text-white/50">
|
||||
{timestamp}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActivityCard;
|
||||
231
.agents/skills/stitch-react-components/package-lock.json
generated
Normal file
231
.agents/skills/stitch-react-components/package-lock.json
generated
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"name": "stitch-to-react-pro",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "stitch-to-react-pro",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@swc/core": "^1.3.100"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.8.tgz",
|
||||
"integrity": "sha512-T8keoJjXaSUoVBCIjgL6wAnhADIb09GOELzKg10CjNg+vLX48P93SME6jTfte9MZIm5m+Il57H3rTSk/0kzDUw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.3",
|
||||
"@swc/types": "^0.1.25"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin-arm64": "1.15.8",
|
||||
"@swc/core-darwin-x64": "1.15.8",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.15.8",
|
||||
"@swc/core-linux-arm64-gnu": "1.15.8",
|
||||
"@swc/core-linux-arm64-musl": "1.15.8",
|
||||
"@swc/core-linux-x64-gnu": "1.15.8",
|
||||
"@swc/core-linux-x64-musl": "1.15.8",
|
||||
"@swc/core-win32-arm64-msvc": "1.15.8",
|
||||
"@swc/core-win32-ia32-msvc": "1.15.8",
|
||||
"@swc/core-win32-x64-msvc": "1.15.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": ">=0.5.17"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/helpers": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.8.tgz",
|
||||
"integrity": "sha512-M9cK5GwyWWRkRGwwCbREuj6r8jKdES/haCZ3Xckgkl8MUQJZA3XB7IXXK1IXRNeLjg6m7cnoMICpXv1v1hlJOg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-x64": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.8.tgz",
|
||||
"integrity": "sha512-j47DasuOvXl80sKJHSi2X25l44CMc3VDhlJwA7oewC1nV1VsSzwX+KOwE5tLnfORvVJJyeiXgJORNYg4jeIjYQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.8.tgz",
|
||||
"integrity": "sha512-siAzDENu2rUbwr9+fayWa26r5A9fol1iORG53HWxQL1J8ym4k7xt9eME0dMPXlYZDytK5r9sW8zEA10F2U3Xwg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.8.tgz",
|
||||
"integrity": "sha512-o+1y5u6k2FfPYbTRUPvurwzNt5qd0NTumCTFscCNuBksycloXY16J8L+SMW5QRX59n4Hp9EmFa3vpvNHRVv1+Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-musl": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.8.tgz",
|
||||
"integrity": "sha512-koiCqL09EwOP1S2RShCI7NbsQuG6r2brTqUYE7pV7kZm9O17wZ0LSz22m6gVibpwEnw8jI3IE1yYsQTVpluALw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.8.tgz",
|
||||
"integrity": "sha512-4p6lOMU3bC+Vd5ARtKJ/FxpIC5G8v3XLoPEZ5s7mLR8h7411HWC/LmTXDHcrSXRC55zvAVia1eldy6zDLz8iFQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-musl": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.8.tgz",
|
||||
"integrity": "sha512-z3XBnbrZAL+6xDGAhJoN4lOueIxC/8rGrJ9tg+fEaeqLEuAtHSW2QHDHxDwkxZMjuF/pZ6MUTjHjbp8wLbuRLA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.8.tgz",
|
||||
"integrity": "sha512-djQPJ9Rh9vP8GTS/Df3hcc6XP6xnG5c8qsngWId/BLA9oX6C7UzCPAn74BG/wGb9a6j4w3RINuoaieJB3t+7iQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.8.tgz",
|
||||
"integrity": "sha512-/wfAgxORg2VBaUoFdytcVBVCgf1isWZIEXB9MZEUty4wwK93M/PxAkjifOho9RN3WrM3inPLabICRCEgdHpKKQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-x64-msvc": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.8.tgz",
|
||||
"integrity": "sha512-GpMePrh9Sl4d61o4KAHOOv5is5+zt6BEXCOCgs/H0FLGeii7j9bWDE8ExvKFy2GRRZVNR1ugsnzaGWHKM6kuzA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@swc/types": {
|
||||
"version": "0.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz",
|
||||
"integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
.agents/skills/stitch-react-components/package.json
Normal file
16
.agents/skills/stitch-react-components/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "react-components",
|
||||
"version": "1.0.0",
|
||||
"description": "Design-to-code prompt to React components for Stitch MCP",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"validate": "node scripts/validate.js",
|
||||
"fetch": "bash scripts/fetch-stitch.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@swc/core": "^1.3.100"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# Architecture Quality Gate
|
||||
|
||||
### Structural integrity
|
||||
- [ ] Logic extracted to custom hooks in `src/hooks/`.
|
||||
- [ ] No monolithic files; strictly Atomic/Composite modularity.
|
||||
- [ ] All static text/URLs moved to `src/data/mockData.ts`.
|
||||
|
||||
### Type safety and syntax
|
||||
- [ ] Props use `Readonly<T>` interfaces.
|
||||
- [ ] File is syntactically valid TypeScript (no red squiggles).
|
||||
- [ ] Placeholders from templates (e.g., `StitchComponent`) have been replaced with actual names.
|
||||
|
||||
### Styling and theming
|
||||
- [ ] Dark mode (`dark:`) applied to all color classes.
|
||||
- [ ] No hardcoded hex values; use theme-mapped Tailwind classes.
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2026 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
// Use a valid identifier like 'StitchComponent' as the placeholder
|
||||
interface StitchComponentProps {
|
||||
readonly children?: React.ReactNode;
|
||||
readonly className?: string;
|
||||
}
|
||||
|
||||
export const StitchComponent: React.FC<StitchComponentProps> = ({
|
||||
children,
|
||||
className = '',
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<div className={`relative ${className}`} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StitchComponent;
|
||||
@@ -0,0 +1,14 @@
|
||||
# Stitch API reference
|
||||
|
||||
This document describes the data structures returned by the Stitch MCP server to ensure accurate component mapping.
|
||||
|
||||
### Metadata schema
|
||||
When calling `get_screen`, the server returns a JSON object with these key properties:
|
||||
* **htmlCode**: Contains a `downloadUrl`. This is a signed URL that requires a system-level fetch (curl) to handle redirects and security handshakes.
|
||||
* **screenshot**: Includes a `downloadUrl` for the visual design. Use this to verify layout intent that might not be obvious in the raw HTML.
|
||||
* **deviceType**: Usually set to `DESKTOP`. All generated components should prioritize the corresponding viewport (2560px width) as the base layout.
|
||||
|
||||
### Technical mapping rules
|
||||
1. **Element tracking**: Preserve `data-stitch-id` attributes as comments in the TSX to allow for future design synchronization.
|
||||
2. **Asset handling**: Treat background images in the HTML as dynamic data. Extract the URLs into `mockData.ts` rather than hardcoding them into the component styles.
|
||||
3. **Style extraction**: The HTML `<head>` contains a localized `tailwind.config`. This config must be merged with the local project theme to ensure colors like `primary` and `background-dark` render correctly.
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"theme": {
|
||||
"colors": {
|
||||
"primary": "#19e66f",
|
||||
"background": {
|
||||
"light": "#f6f8f7",
|
||||
"dark": "#112118",
|
||||
"elevated": "#1A1A1A"
|
||||
},
|
||||
"accent": {
|
||||
"purple": "#8A2BE2",
|
||||
"lavender": "#D0A9F5"
|
||||
}
|
||||
},
|
||||
"typography": {
|
||||
"display": [
|
||||
"Space Grotesk",
|
||||
"sans-serif"
|
||||
],
|
||||
"icons": "Material Symbols Outlined"
|
||||
},
|
||||
"spacing": {
|
||||
"header-h": "72px",
|
||||
"container-max": "960px"
|
||||
}
|
||||
}
|
||||
}
|
||||
30
.agents/skills/stitch-react-components/scripts/fetch-stitch.sh
Executable file
30
.agents/skills/stitch-react-components/scripts/fetch-stitch.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
URL=$1
|
||||
OUTPUT=$2
|
||||
if [ -z "$URL" ] || [ -z "$OUTPUT" ]; then
|
||||
echo "Usage: $0 <url> <output_path>"
|
||||
exit 1
|
||||
fi
|
||||
echo "Initiating high-reliability fetch for Stitch HTML..."
|
||||
curl -L -f -sS --connect-timeout 10 --compressed "$URL" -o "$OUTPUT"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Successfully retrieved HTML at: $OUTPUT"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Error: Failed to retrieve content. Check TLS/SNI or URL expiration."
|
||||
exit 1
|
||||
fi
|
||||
82
.agents/skills/stitch-react-components/scripts/validate.js
Normal file
82
.agents/skills/stitch-react-components/scripts/validate.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright 2026 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import swc from '@swc/core';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const HEX_COLOR_REGEX = /#[0-9A-Fa-f]{3,8}\b/;
|
||||
|
||||
async function validateComponent(filePath) {
|
||||
if (!filePath) {
|
||||
console.error("Usage: node validate.js <path-to-component>");
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
const code = fs.readFileSync(filePath, 'utf-8');
|
||||
const filename = path.basename(filePath);
|
||||
const ast = await swc.parse(code, { syntax: "typescript", tsx: true });
|
||||
let hasInterface = false;
|
||||
let tailwindIssues = [];
|
||||
|
||||
console.log("🔍 Scanning AST...");
|
||||
|
||||
const walk = (node) => {
|
||||
if (!node || typeof node !== 'object') return;
|
||||
if (Array.isArray(node)) {
|
||||
for (const item of node) walk(item);
|
||||
return;
|
||||
}
|
||||
if (typeof node.type !== 'string') return;
|
||||
if (node.type === 'TsInterfaceDeclaration' && node.id.value.endsWith('Props')) hasInterface = true;
|
||||
if (node.type === 'JSXAttribute' && (node.name?.value === 'className' || node.name?.name === 'className')) {
|
||||
if (node.value?.value && HEX_COLOR_REGEX.test(node.value.value)) tailwindIssues.push(node.value.value);
|
||||
}
|
||||
for (const key in node) {
|
||||
if (key === 'span') continue;
|
||||
if (node[key] && typeof node[key] === 'object') walk(node[key]);
|
||||
}
|
||||
};
|
||||
walk(ast);
|
||||
|
||||
console.log(`--- Validation for: ${filename} ---`);
|
||||
if (hasInterface) {
|
||||
console.log("✅ Props declaration found.");
|
||||
} else {
|
||||
console.error("❌ MISSING: Props interface (must end in 'Props').");
|
||||
}
|
||||
|
||||
if (tailwindIssues.length === 0) {
|
||||
console.log("✅ No hardcoded hex values found.");
|
||||
} else {
|
||||
console.error(`❌ STYLE: Found ${tailwindIssues.length} hardcoded hex codes.`);
|
||||
tailwindIssues.forEach(hex => console.error(` - ${hex}`));
|
||||
}
|
||||
|
||||
if (hasInterface && tailwindIssues.length === 0) {
|
||||
console.log("\n✨ COMPONENT VALID.");
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.error("\n🚫 VALIDATION FAILED.");
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ ERROR:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
validateComponent(process.argv[2]);
|
||||
Reference in New Issue
Block a user