📦 deps(skills): sync thirdparty skills

This commit is contained in:
ci[bot] 2026-04-03 16:03:11 +00:00
parent 60108dd75a
commit 3ed5052e61
2 changed files with 150 additions and 69 deletions

View File

@ -18,7 +18,7 @@ CSV_CONFIG = {
"style": {
"file": "styles.csv",
"search_cols": ["Style Category", "Keywords", "Best For", "Type", "AI Prompt Keywords"],
"output_cols": ["Style Category", "Type", "Keywords", "Primary Colors", "Effects & Animation", "Best For", "Performance", "Accessibility", "Framework Compatibility", "Complexity", "AI Prompt Keywords", "CSS/Technical Keywords", "Implementation Checklist", "Design System Variables"]
"output_cols": ["Style Category", "Type", "Keywords", "Primary Colors", "Effects & Animation", "Best For", "Light Mode ✓", "Dark Mode ✓", "Performance", "Accessibility", "Framework Compatibility", "Complexity", "AI Prompt Keywords", "CSS/Technical Keywords", "Implementation Checklist", "Design System Variables"]
},
"color": {
"file": "colors.csv",

View File

@ -211,15 +211,25 @@ class DesignSystemGenerator:
"keywords": best_style.get("Keywords", ""),
"best_for": best_style.get("Best For", ""),
"performance": best_style.get("Performance", ""),
"accessibility": best_style.get("Accessibility", "")
"accessibility": best_style.get("Accessibility", ""),
"light_mode": best_style.get("Light Mode ✓", ""),
"dark_mode": best_style.get("Dark Mode ✓", ""),
},
"colors": {
"primary": best_color.get("Primary (Hex)", "#2563EB"),
"secondary": best_color.get("Secondary (Hex)", "#3B82F6"),
"cta": best_color.get("CTA (Hex)", "#F97316"),
"background": best_color.get("Background (Hex)", "#F8FAFC"),
"text": best_color.get("Text (Hex)", "#1E293B"),
"notes": best_color.get("Notes", "")
"primary": best_color.get("Primary", "#2563EB"),
"on_primary": best_color.get("On Primary", ""),
"secondary": best_color.get("Secondary", "#3B82F6"),
"accent": best_color.get("Accent", "#F97316"),
"background": best_color.get("Background", "#F8FAFC"),
"foreground": best_color.get("Foreground", "#1E293B"),
"muted": best_color.get("Muted", ""),
"border": best_color.get("Border", ""),
"destructive": best_color.get("Destructive", ""),
"ring": best_color.get("Ring", ""),
"notes": best_color.get("Notes", ""),
# Keep legacy keys for backward compat in MASTER.md
"cta": best_color.get("Accent", "#F97316"),
"text": best_color.get("Foreground", "#1E293B"),
},
"typography": {
"heading": best_typography.get("Heading Font", "Inter"),
@ -239,8 +249,38 @@ class DesignSystemGenerator:
# ============ OUTPUT FORMATTERS ============
BOX_WIDTH = 90 # Wider box for more content
def hex_to_ansi(hex_color: str) -> str:
"""Convert hex color to ANSI True Color swatch (██) with fallback."""
if not hex_color or not hex_color.startswith('#'):
return ""
colorterm = os.environ.get('COLORTERM', '')
if colorterm not in ('truecolor', '24bit'):
return ""
hex_color = hex_color.lstrip('#')
if len(hex_color) != 6:
return ""
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
return f"\033[38;2;{r};{g};{b}m██\033[0m "
def ansi_ljust(s: str, width: int) -> str:
"""Like str.ljust but accounts for zero-width ANSI escape sequences."""
import re
visible_len = len(re.sub(r'\033\[[0-9;]*m', '', s))
pad = width - visible_len
return s + (" " * max(0, pad))
def section_header(name: str, width: int) -> str:
"""Create a Unicode section separator: ├─── NAME ───...┤"""
label = f"─── {name} "
fill = "" * (width - len(label) - 1)
return f"{label}{fill}"
def format_ascii_box(design_system: dict) -> str:
"""Format design system as ASCII box with emojis (MCP-style)."""
"""Format design system as Unicode box with ANSI color swatches."""
project = design_system.get("project_name", "PROJECT")
pattern = design_system.get("pattern", {})
style = design_system.get("style", {})
@ -275,77 +315,93 @@ def format_ascii_box(design_system: dict) -> str:
lines = []
w = BOX_WIDTH - 1
lines.append("+" + "-" * w + "+")
lines.append(f"| TARGET: {project} - RECOMMENDED DESIGN SYSTEM".ljust(BOX_WIDTH) + "|")
lines.append("+" + "-" * w + "+")
lines.append("|" + " " * BOX_WIDTH + "|")
# Header with double-line box
lines.append("" + "" * w + "")
lines.append(ansi_ljust(f"║ TARGET: {project} - RECOMMENDED DESIGN SYSTEM", BOX_WIDTH) + "")
lines.append("" + "" * w + "")
lines.append("" + "" * w + "")
# Pattern section
lines.append(f"| PATTERN: {pattern.get('name', '')}".ljust(BOX_WIDTH) + "|")
lines.append(section_header("PATTERN", BOX_WIDTH + 1))
lines.append(f"│ Name: {pattern.get('name', '')}".ljust(BOX_WIDTH) + "")
if pattern.get('conversion'):
lines.append(f"| Conversion: {pattern.get('conversion', '')}".ljust(BOX_WIDTH) + "|")
lines.append(f" Conversion: {pattern.get('conversion', '')}".ljust(BOX_WIDTH) + "")
if pattern.get('cta_placement'):
lines.append(f"| CTA: {pattern.get('cta_placement', '')}".ljust(BOX_WIDTH) + "|")
lines.append("| Sections:".ljust(BOX_WIDTH) + "|")
lines.append(f" CTA: {pattern.get('cta_placement', '')}".ljust(BOX_WIDTH) + "")
lines.append(" Sections:".ljust(BOX_WIDTH) + "")
for i, section in enumerate(sections, 1):
lines.append(f"| {i}. {section}".ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
lines.append(f"{i}. {section}".ljust(BOX_WIDTH) + "")
# Style section
lines.append(f"| STYLE: {style.get('name', '')}".ljust(BOX_WIDTH) + "|")
lines.append(section_header("STYLE", BOX_WIDTH + 1))
lines.append(f"│ Name: {style.get('name', '')}".ljust(BOX_WIDTH) + "")
light = style.get("light_mode", "")
dark = style.get("dark_mode", "")
if light or dark:
lines.append(f"│ Mode Support: Light {light} Dark {dark}".ljust(BOX_WIDTH) + "")
if style.get("keywords"):
for line in wrap_text(f"Keywords: {style.get('keywords', '')}", "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
for line in wrap_text(f"Keywords: {style.get('keywords', '')}", " ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
if style.get("best_for"):
for line in wrap_text(f"Best For: {style.get('best_for', '')}", "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
for line in wrap_text(f"Best For: {style.get('best_for', '')}", " ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
if style.get("performance") or style.get("accessibility"):
perf_a11y = f"Performance: {style.get('performance', '')} | Accessibility: {style.get('accessibility', '')}"
lines.append(f"| {perf_a11y}".ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
lines.append(f"{perf_a11y}".ljust(BOX_WIDTH) + "")
# Colors section
lines.append("| COLORS:".ljust(BOX_WIDTH) + "|")
lines.append(f"| Primary: {colors.get('primary', '')}".ljust(BOX_WIDTH) + "|")
lines.append(f"| Secondary: {colors.get('secondary', '')}".ljust(BOX_WIDTH) + "|")
lines.append(f"| CTA: {colors.get('cta', '')}".ljust(BOX_WIDTH) + "|")
lines.append(f"| Background: {colors.get('background', '')}".ljust(BOX_WIDTH) + "|")
lines.append(f"| Text: {colors.get('text', '')}".ljust(BOX_WIDTH) + "|")
# Colors section (extended palette with ANSI swatches)
lines.append(section_header("COLORS", BOX_WIDTH + 1))
color_entries = [
("Primary", "primary", "--color-primary"),
("On Primary", "on_primary", "--color-on-primary"),
("Secondary", "secondary", "--color-secondary"),
("Accent/CTA", "accent", "--color-accent"),
("Background", "background", "--color-background"),
("Foreground", "foreground", "--color-foreground"),
("Muted", "muted", "--color-muted"),
("Border", "border", "--color-border"),
("Destructive", "destructive", "--color-destructive"),
("Ring", "ring", "--color-ring"),
]
for label, key, css_var in color_entries:
hex_val = colors.get(key, "")
if not hex_val:
continue
swatch = hex_to_ansi(hex_val)
content = f"{swatch}{label + ':':14s} {hex_val:10s} ({css_var})"
lines.append(ansi_ljust(content, BOX_WIDTH) + "")
if colors.get("notes"):
for line in wrap_text(f"Notes: {colors.get('notes', '')}", "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
for line in wrap_text(f"Notes: {colors.get('notes', '')}", "", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
# Typography section
lines.append(f"| TYPOGRAPHY: {typography.get('heading', '')} / {typography.get('body', '')}".ljust(BOX_WIDTH) + "|")
lines.append(section_header("TYPOGRAPHY", BOX_WIDTH + 1))
lines.append(f"{typography.get('heading', '')} / {typography.get('body', '')}".ljust(BOX_WIDTH) + "")
if typography.get("mood"):
for line in wrap_text(f"Mood: {typography.get('mood', '')}", "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
for line in wrap_text(f"Mood: {typography.get('mood', '')}", " ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
if typography.get("best_for"):
for line in wrap_text(f"Best For: {typography.get('best_for', '')}", "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
for line in wrap_text(f"Best For: {typography.get('best_for', '')}", " ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
if typography.get("google_fonts_url"):
lines.append(f"| Google Fonts: {typography.get('google_fonts_url', '')}".ljust(BOX_WIDTH) + "|")
lines.append(f" Google Fonts: {typography.get('google_fonts_url', '')}".ljust(BOX_WIDTH) + "")
if typography.get("css_import"):
lines.append(f"| CSS Import: {typography.get('css_import', '')[:70]}...".ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
lines.append(f"│ CSS Import: {typography.get('css_import', '')[:70]}...".ljust(BOX_WIDTH) + "")
# Key Effects section
if effects:
lines.append("| KEY EFFECTS:".ljust(BOX_WIDTH) + "|")
for line in wrap_text(effects, "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
lines.append(section_header("KEY EFFECTS", BOX_WIDTH + 1))
for line in wrap_text(effects, "", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
# Anti-patterns section
if anti_patterns:
lines.append("| AVOID (Anti-patterns):".ljust(BOX_WIDTH) + "|")
for line in wrap_text(anti_patterns, "| ", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
lines.append(section_header("AVOID", BOX_WIDTH + 1))
for line in wrap_text(anti_patterns, "", BOX_WIDTH):
lines.append(line.ljust(BOX_WIDTH) + "")
# Pre-Delivery Checklist section
lines.append("| PRE-DELIVERY CHECKLIST:".ljust(BOX_WIDTH) + "|")
lines.append(section_header("PRE-DELIVERY CHECKLIST", BOX_WIDTH + 1))
checklist_items = [
"[ ] No emojis as icons (use SVG: Heroicons/Lucide)",
"[ ] cursor-pointer on all clickable elements",
@ -356,10 +412,9 @@ def format_ascii_box(design_system: dict) -> str:
"[ ] Responsive: 375px, 768px, 1024px, 1440px"
]
for item in checklist_items:
lines.append(f"| {item}".ljust(BOX_WIDTH) + "|")
lines.append("|" + " " * BOX_WIDTH + "|")
lines.append(f"{item}".ljust(BOX_WIDTH) + "")
lines.append("+" + "-" * w + "+")
lines.append("" + "" * w + "")
return "\n".join(lines)
@ -393,6 +448,10 @@ def format_markdown(design_system: dict) -> str:
# Style section
lines.append("### Style")
lines.append(f"- **Name:** {style.get('name', '')}")
light = style.get("light_mode", "")
dark = style.get("dark_mode", "")
if light or dark:
lines.append(f"- **Mode Support:** Light {light} | Dark {dark}")
if style.get('keywords'):
lines.append(f"- **Keywords:** {style.get('keywords', '')}")
if style.get('best_for'):
@ -401,15 +460,26 @@ def format_markdown(design_system: dict) -> str:
lines.append(f"- **Performance:** {style.get('performance', '')} | **Accessibility:** {style.get('accessibility', '')}")
lines.append("")
# Colors section
# Colors section (extended palette)
lines.append("### Colors")
lines.append(f"| Role | Hex |")
lines.append(f"|------|-----|")
lines.append(f"| Primary | {colors.get('primary', '')} |")
lines.append(f"| Secondary | {colors.get('secondary', '')} |")
lines.append(f"| CTA | {colors.get('cta', '')} |")
lines.append(f"| Background | {colors.get('background', '')} |")
lines.append(f"| Text | {colors.get('text', '')} |")
lines.append("| Role | Hex | CSS Variable |")
lines.append("|------|-----|--------------|")
md_color_entries = [
("Primary", "primary", "--color-primary"),
("On Primary", "on_primary", "--color-on-primary"),
("Secondary", "secondary", "--color-secondary"),
("Accent/CTA", "accent", "--color-accent"),
("Background", "background", "--color-background"),
("Foreground", "foreground", "--color-foreground"),
("Muted", "muted", "--color-muted"),
("Border", "border", "--color-border"),
("Destructive", "destructive", "--color-destructive"),
("Ring", "ring", "--color-ring"),
]
for label, key, css_var in md_color_entries:
hex_val = colors.get(key, "")
if hex_val:
lines.append(f"| {label} | `{hex_val}` | `{css_var}` |")
if colors.get("notes"):
lines.append(f"\n*Notes: {colors.get('notes', '')}*")
lines.append("")
@ -578,11 +648,22 @@ def format_master_md(design_system: dict) -> str:
lines.append("")
lines.append("| Role | Hex | CSS Variable |")
lines.append("|------|-----|--------------|")
lines.append(f"| Primary | `{colors.get('primary', '#2563EB')}` | `--color-primary` |")
lines.append(f"| Secondary | `{colors.get('secondary', '#3B82F6')}` | `--color-secondary` |")
lines.append(f"| CTA/Accent | `{colors.get('cta', '#F97316')}` | `--color-cta` |")
lines.append(f"| Background | `{colors.get('background', '#F8FAFC')}` | `--color-background` |")
lines.append(f"| Text | `{colors.get('text', '#1E293B')}` | `--color-text` |")
master_color_entries = [
("Primary", "primary", "--color-primary"),
("On Primary", "on_primary", "--color-on-primary"),
("Secondary", "secondary", "--color-secondary"),
("Accent/CTA", "accent", "--color-accent"),
("Background", "background", "--color-background"),
("Foreground", "foreground", "--color-foreground"),
("Muted", "muted", "--color-muted"),
("Border", "border", "--color-border"),
("Destructive", "destructive", "--color-destructive"),
("Ring", "ring", "--color-ring"),
]
for label, key, css_var in master_color_entries:
hex_val = colors.get(key, "")
if hex_val:
lines.append(f"| {label} | `{hex_val}` | `{css_var}` |")
lines.append("")
if colors.get("notes"):
lines.append(f"**Color Notes:** {colors.get('notes', '')}")