From cc8c56e42de18cd9a3e0849183d47dd57d499576 Mon Sep 17 00:00:00 2001 From: Srivats Venkataraman <42980667+srivats22@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:11:48 -0500 Subject: [PATCH] Stitch to flutter component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is my first Attempt at creating a Skill... wasnt sure how to test it but happy for pointers... Thanks in advance for reviewing šŸ˜€ --- skills/flutter-components/README.md | 36 +++++++++ skills/flutter-components/SKILL.md | 44 +++++++++++ skills/flutter-components/package.json | 12 +++ .../resources/architecture-checklist.md | 18 +++++ .../resources/component-template.dart | 22 ++++++ .../scripts/fetch-stitch.sh | 30 ++++++++ skills/flutter-components/scripts/validate.js | 77 +++++++++++++++++++ 7 files changed, 239 insertions(+) create mode 100644 skills/flutter-components/README.md create mode 100644 skills/flutter-components/SKILL.md create mode 100644 skills/flutter-components/package.json create mode 100644 skills/flutter-components/resources/architecture-checklist.md create mode 100644 skills/flutter-components/resources/component-template.dart create mode 100644 skills/flutter-components/scripts/fetch-stitch.sh create mode 100644 skills/flutter-components/scripts/validate.js diff --git a/skills/flutter-components/README.md b/skills/flutter-components/README.md new file mode 100644 index 0000000..030cba7 --- /dev/null +++ b/skills/flutter-components/README.md @@ -0,0 +1,36 @@ +# Stitch to Flutter Skill + +## Install + +```bash +npx add-skill google-labs-code/stitch-skills --skill flutter:components --global +``` + +## Example Prompt + +```text +Convert my Landing Page screen in my Podcast Stitch Project to a Flutter Page. +``` + +## 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/flutter-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 11-point architecture checklist. diff --git a/skills/flutter-components/SKILL.md b/skills/flutter-components/SKILL.md new file mode 100644 index 0000000..4a28f39 --- /dev/null +++ b/skills/flutter-components/SKILL.md @@ -0,0 +1,44 @@ +--- +name: flutter:components +description: Converts Stitch designs into a flutter Screen/Widget using system-level networking and logic-based validation. +allowed-tools: + - "stitch*:*" + - "run_command" + - "view_file" + - "write_to_file" + - "read_url_content" +--- + +# Stitch to Flutter Components + +You are a Flutter frontend engineer focused on transforming designs into clean Flutter & Dart code. You follow a Single-file approach and use automated tools to ensure code quality. + +## Retrieval and networking +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` to retrieve the design JSON. +3. **High-reliability download**: Internal AI fetch tools can sometimes fail on specific domains. + - Use the `run_command` tool to run: `bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html"`. + - This script handles the necessary redirects and security handshakes. +4. **Visual audit**: Check `screenshot.downloadUrl` to confirm the design intent and layout details. + +## Architectural rules +* **Single file**: Generate a single .dart file for the component. This file should always be a `StatefulWidget`. +* **Logic isolation**: Logic should be encapsulated in its own functions with proper comments within the State class. +* **Project specific**: Focus on the target project's needs and constraints. Ensure the code is production-ready for the Flutter SDK. +* **Style mapping**: + * Extract the `tailwind.config` from the HTML ``. + * Map these styles to Flutter's `ThemeData` or custom constants. + * Use Material 3 components by default. + +## Execution steps +1. **Environment setup**: If `node_modules` is missing in the skill directory, run `npm install` to enable validation tools. +2. **Data layer**: Create `lib/component.dart` based on the design content. +3. **Component drafting**: Use `resources/component-template.dart` as a base. Find and replace all instances of `StitchPage` and `StitchPageState` with the actual name of your component. +4. **Application wiring**: Update the project entry point (like `main.dart`) to render the new component. +5. **Quality check**: + * Run `npm run validate ` for each component. + * Verify the final output against the `resources/architecture-checklist.md`. + +## Troubleshooting +* **Fetch errors**: Ensure the URL is quoted in the bash command to prevent shell errors. +* **Validation errors**: Review the validation report and fix any missing constructors or hardcoded hex colors. \ No newline at end of file diff --git a/skills/flutter-components/package.json b/skills/flutter-components/package.json new file mode 100644 index 0000000..b5e61ff --- /dev/null +++ b/skills/flutter-components/package.json @@ -0,0 +1,12 @@ +{ + "name": "flutter-components", + "version": "1.0.0", + "description": "Validation for Flutter components", + "type": "module", + "scripts": { + "validate": "node scripts/validate.js" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/skills/flutter-components/resources/architecture-checklist.md b/skills/flutter-components/resources/architecture-checklist.md new file mode 100644 index 0000000..b6b062e --- /dev/null +++ b/skills/flutter-components/resources/architecture-checklist.md @@ -0,0 +1,18 @@ +# Flutter Component Architecture Checklist + +## State Management +- [ ] Component extends `StatefulWidget`. +- [ ] Logic is isolated into helper methods within the `State` class. +- [ ] Proper use of `setState` for UI updates. + +## UI & Styling +- [ ] No hardcoded hex color codes (use `Theme.of(context)` where possible). +- [ ] Responsive layout using `LayoutBuilder` or `MediaQuery` if needed. +- [ ] Material 3 design principles followed. +- [ ] Typography extracted from Design JSON. + +## Code Quality +- [ ] All TODOs resolved. +- [ ] Proper indentation and formatting. +- [ ] Public constructor with optional parameters. +- [ ] No unused imports. diff --git a/skills/flutter-components/resources/component-template.dart b/skills/flutter-components/resources/component-template.dart new file mode 100644 index 0000000..f23574e --- /dev/null +++ b/skills/flutter-components/resources/component-template.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +class StitchPage extends StatefulWidget { + const StitchPage({super.key}); + + @override + State createState() => _StitchPageState(); +} + +class _StitchPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Stitch Component'), + ), + body: const Center( + child: Text('Generate content here'), + ), + ); + } +} diff --git a/skills/flutter-components/scripts/fetch-stitch.sh b/skills/flutter-components/scripts/fetch-stitch.sh new file mode 100644 index 0000000..4472144 --- /dev/null +++ b/skills/flutter-components/scripts/fetch-stitch.sh @@ -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 " + 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 diff --git a/skills/flutter-components/scripts/validate.js b/skills/flutter-components/scripts/validate.js new file mode 100644 index 0000000..693e18f --- /dev/null +++ b/skills/flutter-components/scripts/validate.js @@ -0,0 +1,77 @@ +/** + * 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 fs from 'node:fs'; +import path from 'node:path'; + +async function validateFlutterComponent(filePath) { + const code = fs.readFileSync(filePath, 'utf-8'); + const filename = path.basename(filePath); + + console.log(`šŸ” Scanning Flutter Component: ${filename}...`); + + let issues = []; + + // 1. Check for StatefulWidget requirement (from SKILL.md) + const isStateful = /extends\s+StatefulWidget/.test(code); + + // 2. Check for "Props" (Constructor with parameters) + // In Flutter, we look for a constructor that isn't just the default one. + const hasConstructorWithParams = /[\w]+\(\{[\s\S]*?\}\)/.test(code); + + // 3. Check for hardcoded hex colors + // Matches: 0xFFRRGGBB, 0xRRGGBB, #RRGGBB + const hexPattern = /0x([0-9A-Fa-f]{6,8})|#([0-9A-Fa-f]{6})/g; + let match; + let hexIssues = []; + while ((match = hexPattern.exec(code)) !== null) { + hexIssues.push(match[0]); + } + + console.log(`--- Validation for: ${filename} ---`); + + if (isStateful) { + console.log("āœ… Component is a StatefulWidget."); + } else { + console.error("āŒ MISSING: Must be a StatefulWidget (as per SKILL.md)."); + issues.push("Not a StatefulWidget"); + } + + if (hasConstructorWithParams) { + console.log("āœ… Constructor with parameters found (Props equivalent)."); + } else { + console.error("āŒ MISSING: Constructor with parameters (Props)."); + issues.push("Missing constructor parameters"); + } + + if (hexIssues.length === 0) { + console.log("āœ… No hardcoded hex values found."); + } else { + console.error(`āŒ STYLE: Found ${hexIssues.length} hardcoded hex codes.`); + hexIssues.forEach(hex => console.error(` - ${hex}`)); + issues.push("Hardcoded hex codes"); + } + + if (issues.length === 0) { + console.log("\n✨ FLUTTER COMPONENT VALID."); + process.exit(0); + } else { + console.error("\n🚫 VALIDATION FAILED."); + process.exit(1); + } +} + +validateFlutterComponent(process.argv[2]);