heraspec 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +57 -0
  3. package/bin/heraspec.js +3803 -0
  4. package/bin/heraspec.js.map +7 -0
  5. package/dist/core/templates/skills/CHANGELOG.md +117 -0
  6. package/dist/core/templates/skills/README-template.md +58 -0
  7. package/dist/core/templates/skills/README.md +36 -0
  8. package/dist/core/templates/skills/content-optimization-skill.md +104 -0
  9. package/dist/core/templates/skills/data/charts.csv +26 -0
  10. package/dist/core/templates/skills/data/colors.csv +97 -0
  11. package/dist/core/templates/skills/data/landing.csv +31 -0
  12. package/dist/core/templates/skills/data/pages-proposed.csv +22 -0
  13. package/dist/core/templates/skills/data/pages.csv +10 -0
  14. package/dist/core/templates/skills/data/products.csv +97 -0
  15. package/dist/core/templates/skills/data/prompts.csv +24 -0
  16. package/dist/core/templates/skills/data/stacks/flutter.csv +53 -0
  17. package/dist/core/templates/skills/data/stacks/html-tailwind.csv +56 -0
  18. package/dist/core/templates/skills/data/stacks/nextjs.csv +53 -0
  19. package/dist/core/templates/skills/data/stacks/react-native.csv +52 -0
  20. package/dist/core/templates/skills/data/stacks/react.csv +54 -0
  21. package/dist/core/templates/skills/data/stacks/svelte.csv +54 -0
  22. package/dist/core/templates/skills/data/stacks/swiftui.csv +51 -0
  23. package/dist/core/templates/skills/data/stacks/vue.csv +50 -0
  24. package/dist/core/templates/skills/data/styles.csv +59 -0
  25. package/dist/core/templates/skills/data/typography.csv +58 -0
  26. package/dist/core/templates/skills/data/ux-guidelines.csv +100 -0
  27. package/dist/core/templates/skills/documents-skill.md +114 -0
  28. package/dist/core/templates/skills/e2e-test-skill.md +119 -0
  29. package/dist/core/templates/skills/integration-test-skill.md +118 -0
  30. package/dist/core/templates/skills/module-codebase-skill.md +110 -0
  31. package/dist/core/templates/skills/scripts/CODE_EXPLANATION.md +394 -0
  32. package/dist/core/templates/skills/scripts/SEARCH_ALGORITHMS_COMPARISON.md +421 -0
  33. package/dist/core/templates/skills/scripts/SEARCH_MODES_GUIDE.md +238 -0
  34. package/dist/core/templates/skills/scripts/core.py +385 -0
  35. package/dist/core/templates/skills/scripts/search.py +73 -0
  36. package/dist/core/templates/skills/suggestion-skill.md +118 -0
  37. package/dist/core/templates/skills/templates/accessibility-checklist.md +40 -0
  38. package/dist/core/templates/skills/templates/example-prompt-full-theme.md +333 -0
  39. package/dist/core/templates/skills/templates/page-types-guide.md +338 -0
  40. package/dist/core/templates/skills/templates/pages-proposed-summary.md +273 -0
  41. package/dist/core/templates/skills/templates/pre-delivery-checklist.md +42 -0
  42. package/dist/core/templates/skills/templates/prompt-template-full-theme.md +313 -0
  43. package/dist/core/templates/skills/templates/responsive-design.md +40 -0
  44. package/dist/core/templates/skills/ui-ux-skill.md +584 -0
  45. package/dist/core/templates/skills/unit-test-skill.md +111 -0
  46. package/dist/index.js +1736 -0
  47. package/package.json +71 -0
@@ -0,0 +1,385 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ UI/UX Builder Core - BM25 search engine for UI/UX style guides
5
+ """
6
+
7
+ import csv
8
+ import re
9
+ from pathlib import Path
10
+ from math import log
11
+ from collections import defaultdict
12
+
13
+ # Optional dependencies for vector search
14
+ try:
15
+ from sentence_transformers import SentenceTransformer
16
+ import numpy as np
17
+ from sklearn.metrics.pairwise import cosine_similarity
18
+ VECTOR_AVAILABLE = True
19
+ except ImportError:
20
+ VECTOR_AVAILABLE = False
21
+
22
+ # ============ CONFIGURATION ============
23
+ DATA_DIR = Path(__file__).parent.parent / "data"
24
+ MAX_RESULTS = 3
25
+
26
+ CSV_CONFIG = {
27
+ "style": {
28
+ "file": "styles.csv",
29
+ "search_cols": ["Style Category", "Keywords", "Best For", "Type"],
30
+ "output_cols": ["Style Category", "Type", "Keywords", "Primary Colors", "Effects & Animation", "Best For", "Performance", "Accessibility", "Framework Compatibility", "Complexity"]
31
+ },
32
+ "prompt": {
33
+ "file": "prompts.csv",
34
+ "search_cols": ["Style Category", "AI Prompt Keywords (Copy-Paste Ready)", "CSS/Technical Keywords"],
35
+ "output_cols": ["Style Category", "AI Prompt Keywords (Copy-Paste Ready)", "CSS/Technical Keywords", "Implementation Checklist"]
36
+ },
37
+ "color": {
38
+ "file": "colors.csv",
39
+ "search_cols": ["Product Type", "Keywords", "Notes"],
40
+ "output_cols": ["Product Type", "Keywords", "Primary (Hex)", "Secondary (Hex)", "CTA (Hex)", "Background (Hex)", "Text (Hex)", "Border (Hex)", "Notes"]
41
+ },
42
+ "chart": {
43
+ "file": "charts.csv",
44
+ "search_cols": ["Data Type", "Keywords", "Best Chart Type", "Accessibility Notes"],
45
+ "output_cols": ["Data Type", "Keywords", "Best Chart Type", "Secondary Options", "Color Guidance", "Accessibility Notes", "Library Recommendation", "Interactive Level"]
46
+ },
47
+ "landing": {
48
+ "file": "landing.csv",
49
+ "search_cols": ["Pattern Name", "Keywords", "Conversion Optimization", "Section Order"],
50
+ "output_cols": ["Pattern Name", "Keywords", "Section Order", "Primary CTA Placement", "Color Strategy", "Conversion Optimization"]
51
+ },
52
+ "product": {
53
+ "file": "products.csv",
54
+ "search_cols": ["Product Type", "Keywords", "Primary Style Recommendation", "Key Considerations"],
55
+ "output_cols": ["Product Type", "Keywords", "Primary Style Recommendation", "Secondary Styles", "Landing Page Pattern", "Dashboard Style (if applicable)", "Color Palette Focus"]
56
+ },
57
+ "ux": {
58
+ "file": "ux-guidelines.csv",
59
+ "search_cols": ["Category", "Issue", "Description", "Platform"],
60
+ "output_cols": ["Category", "Issue", "Platform", "Description", "Do", "Don't", "Code Example Good", "Code Example Bad", "Severity"]
61
+ },
62
+ "typography": {
63
+ "file": "typography.csv",
64
+ "search_cols": ["Font Pairing Name", "Category", "Mood/Style Keywords", "Best For", "Heading Font", "Body Font"],
65
+ "output_cols": ["Font Pairing Name", "Category", "Heading Font", "Body Font", "Mood/Style Keywords", "Best For", "Google Fonts URL", "CSS Import", "Tailwind Config", "Notes"]
66
+ },
67
+ "pages": {
68
+ "file": "pages.csv",
69
+ "search_cols": ["Page Type", "Keywords", "Section Order", "Key Components", "Layout Pattern", "Best For"],
70
+ "output_cols": ["Page Type", "Keywords", "Section Order", "Key Components", "Layout Pattern", "Color Strategy", "Recommended Effects", "Best For", "Considerations"]
71
+ }
72
+ }
73
+
74
+ STACK_CONFIG = {
75
+ "html-tailwind": {"file": "stacks/html-tailwind.csv"},
76
+ "react": {"file": "stacks/react.csv"},
77
+ "nextjs": {"file": "stacks/nextjs.csv"},
78
+ "vue": {"file": "stacks/vue.csv"},
79
+ "svelte": {"file": "stacks/svelte.csv"},
80
+ "swiftui": {"file": "stacks/swiftui.csv"},
81
+ "react-native": {"file": "stacks/react-native.csv"},
82
+ "flutter": {"file": "stacks/flutter.csv"}
83
+ }
84
+
85
+ # Common columns for all stacks
86
+ _STACK_COLS = {
87
+ "search_cols": ["Category", "Guideline", "Description", "Do", "Don't"],
88
+ "output_cols": ["Category", "Guideline", "Description", "Do", "Don't", "Code Good", "Code Bad", "Severity", "Docs URL"]
89
+ }
90
+
91
+ AVAILABLE_STACKS = list(STACK_CONFIG.keys())
92
+
93
+
94
+ # ============ BM25 IMPLEMENTATION ============
95
+ class BM25:
96
+ """BM25 ranking algorithm for text search"""
97
+
98
+ def __init__(self, k1=1.5, b=0.75):
99
+ self.k1 = k1
100
+ self.b = b
101
+ self.corpus = []
102
+ self.doc_lengths = []
103
+ self.avgdl = 0
104
+ self.idf = {}
105
+ self.doc_freqs = defaultdict(int)
106
+ self.N = 0
107
+
108
+ def tokenize(self, text):
109
+ """Lowercase, split, remove punctuation, filter short words"""
110
+ text = re.sub(r'[^\w\s]', ' ', str(text).lower())
111
+ return [w for w in text.split() if len(w) > 2]
112
+
113
+ def fit(self, documents):
114
+ """Build BM25 index from documents"""
115
+ self.corpus = [self.tokenize(doc) for doc in documents]
116
+ self.N = len(self.corpus)
117
+ if self.N == 0:
118
+ return
119
+ self.doc_lengths = [len(doc) for doc in self.corpus]
120
+ self.avgdl = sum(self.doc_lengths) / self.N
121
+
122
+ for doc in self.corpus:
123
+ seen = set()
124
+ for word in doc:
125
+ if word not in seen:
126
+ self.doc_freqs[word] += 1
127
+ seen.add(word)
128
+
129
+ for word, freq in self.doc_freqs.items():
130
+ self.idf[word] = log((self.N - freq + 0.5) / (freq + 0.5) + 1)
131
+
132
+ def score(self, query):
133
+ """Score all documents against query"""
134
+ query_tokens = self.tokenize(query)
135
+ scores = []
136
+
137
+ for idx, doc in enumerate(self.corpus):
138
+ score = 0
139
+ doc_len = self.doc_lengths[idx]
140
+ term_freqs = defaultdict(int)
141
+ for word in doc:
142
+ term_freqs[word] += 1
143
+
144
+ for token in query_tokens:
145
+ if token in self.idf:
146
+ tf = term_freqs[token]
147
+ idf = self.idf[token]
148
+ numerator = tf * (self.k1 + 1)
149
+ denominator = tf + self.k1 * (1 - self.b + self.b * doc_len / self.avgdl)
150
+ score += idf * numerator / denominator
151
+
152
+ scores.append((idx, score))
153
+
154
+ return sorted(scores, key=lambda x: x[1], reverse=True)
155
+
156
+
157
+ # ============ VECTOR SEARCH IMPLEMENTATION ============
158
+ class VectorSearch:
159
+ """Vector-based semantic search using sentence transformers"""
160
+
161
+ def __init__(self):
162
+ if not VECTOR_AVAILABLE:
163
+ raise ImportError(
164
+ "Vector search requires sentence-transformers and scikit-learn. "
165
+ "Install with: pip install sentence-transformers scikit-learn"
166
+ )
167
+ # Use lightweight, fast model
168
+ self.model = SentenceTransformer('all-MiniLM-L6-v2')
169
+ self.embeddings = None
170
+ self.documents = None
171
+
172
+ def fit(self, documents):
173
+ """Encode documents into vectors"""
174
+ self.documents = documents
175
+ if len(documents) == 0:
176
+ self.embeddings = np.array([])
177
+ return
178
+ # Encode without progress bar for cleaner output
179
+ self.embeddings = self.model.encode(documents, show_progress_bar=False, convert_to_numpy=True)
180
+
181
+ def search(self, query, top_k=3):
182
+ """Search using cosine similarity"""
183
+ if self.embeddings is None or len(self.embeddings) == 0:
184
+ return []
185
+
186
+ # Encode query
187
+ query_embedding = self.model.encode([query], show_progress_bar=False, convert_to_numpy=True)
188
+
189
+ # Calculate cosine similarity
190
+ similarities = cosine_similarity(query_embedding, self.embeddings)[0]
191
+
192
+ # Get top k indices
193
+ top_indices = np.argsort(similarities)[::-1][:top_k]
194
+
195
+ # Return (index, score) tuples
196
+ return [(int(idx), float(similarities[idx])) for idx in top_indices if similarities[idx] > 0]
197
+
198
+
199
+ # ============ SEARCH FUNCTIONS ============
200
+ def _load_csv(filepath):
201
+ """Load CSV and return list of dicts"""
202
+ with open(filepath, 'r', encoding='utf-8') as f:
203
+ return list(csv.DictReader(f))
204
+
205
+
206
+ def _search_csv(filepath, search_cols, output_cols, query, max_results, mode='bm25'):
207
+ """Core search function using BM25, Vector, or Hybrid"""
208
+ if not filepath.exists():
209
+ return []
210
+
211
+ data = _load_csv(filepath)
212
+
213
+ # Build documents from search columns
214
+ documents = [" ".join(str(row.get(col, "")) for col in search_cols) for row in data]
215
+
216
+ if len(documents) == 0:
217
+ return []
218
+
219
+ # Choose search mode
220
+ if mode == 'bm25' or (mode in ['vector', 'hybrid'] and not VECTOR_AVAILABLE):
221
+ # BM25 search (default or fallback)
222
+ bm25 = BM25()
223
+ bm25.fit(documents)
224
+ ranked = bm25.score(query)
225
+
226
+ # Get top results with score > 0
227
+ results = []
228
+ for idx, score in ranked[:max_results]:
229
+ if score > 0:
230
+ row = data[idx]
231
+ results.append({col: row.get(col, "") for col in output_cols if col in row})
232
+
233
+ return results
234
+
235
+ elif mode == 'vector':
236
+ # Vector search
237
+ vector_search = VectorSearch()
238
+ vector_search.fit(documents)
239
+ ranked = vector_search.search(query, top_k=max_results)
240
+
241
+ results = []
242
+ for idx, score in ranked:
243
+ row = data[idx]
244
+ results.append({col: row.get(col, "") for col in output_cols if col in row})
245
+
246
+ return results
247
+
248
+ elif mode == 'hybrid':
249
+ # Hybrid search: combine BM25 + Vector
250
+ # Get more results from each to combine
251
+ search_count = max_results * 2
252
+
253
+ # BM25 results
254
+ bm25 = BM25()
255
+ bm25.fit(documents)
256
+ bm25_ranked = bm25.score(query)
257
+ bm25_scores = {idx: score for idx, score in bm25_ranked[:search_count] if score > 0}
258
+
259
+ # Vector results
260
+ vector_search = VectorSearch()
261
+ vector_search.fit(documents)
262
+ vector_ranked = vector_search.search(query, top_k=search_count)
263
+ vector_scores = {idx: score for idx, score in vector_ranked}
264
+
265
+ # Normalize scores to 0-1 range
266
+ max_bm25 = max(bm25_scores.values()) if bm25_scores else 1.0
267
+ max_vector = max(vector_scores.values()) if vector_scores else 1.0
268
+
269
+ # Combine scores (alpha = 0.5 for balanced, can be adjusted)
270
+ alpha = 0.5
271
+ combined_scores = {}
272
+ all_indices = set(bm25_scores.keys()) | set(vector_scores.keys())
273
+
274
+ for idx in all_indices:
275
+ bm25_norm = (bm25_scores.get(idx, 0) / max_bm25) if max_bm25 > 0 else 0
276
+ vector_norm = (vector_scores.get(idx, 0) / max_vector) if max_vector > 0 else 0
277
+ combined_scores[idx] = alpha * bm25_norm + (1 - alpha) * vector_norm
278
+
279
+ # Sort by combined score
280
+ sorted_indices = sorted(combined_scores.items(), key=lambda x: x[1], reverse=True)
281
+
282
+ # Get top results
283
+ results = []
284
+ for idx, score in sorted_indices[:max_results]:
285
+ if score > 0:
286
+ row = data[idx]
287
+ results.append({col: row.get(col, "") for col in output_cols if col in row})
288
+
289
+ return results
290
+
291
+ else:
292
+ # Unknown mode, fallback to BM25
293
+ return _search_csv(filepath, search_cols, output_cols, query, max_results, mode='bm25')
294
+
295
+
296
+ def detect_domain(query):
297
+ """Auto-detect the most relevant domain from query"""
298
+ query_lower = query.lower()
299
+
300
+ domain_keywords = {
301
+ "color": ["color", "palette", "hex", "#", "rgb"],
302
+ "chart": ["chart", "graph", "visualization", "trend", "bar", "pie", "scatter", "heatmap", "funnel"],
303
+ "landing": ["landing", "page", "cta", "conversion", "hero", "testimonial", "pricing", "section"],
304
+ "product": ["saas", "ecommerce", "e-commerce", "fintech", "healthcare", "gaming", "portfolio", "crypto", "dashboard"],
305
+ "prompt": ["prompt", "css", "implementation", "variable", "checklist", "tailwind"],
306
+ "style": ["style", "design", "ui", "minimalism", "glassmorphism", "neumorphism", "brutalism", "dark mode", "flat", "aurora"],
307
+ "ux": ["ux", "usability", "accessibility", "wcag", "touch", "scroll", "animation", "keyboard", "navigation", "mobile"],
308
+ "typography": ["font", "typography", "heading", "serif", "sans"],
309
+ "pages": ["page", "home", "homepage", "about", "post", "article", "blog", "category", "pricing", "faq", "contact", "product", "shop", "catalog", "details", "single"]
310
+ }
311
+
312
+ scores = {domain: sum(1 for kw in keywords if kw in query_lower) for domain, keywords in domain_keywords.items()}
313
+ best = max(scores, key=scores.get)
314
+ return best if scores[best] > 0 else "style"
315
+
316
+
317
+ def search(query, domain=None, max_results=MAX_RESULTS, mode='bm25'):
318
+ """
319
+ Main search function with auto-domain detection
320
+
321
+ Args:
322
+ query: Search query string
323
+ domain: Domain to search (auto-detected if None)
324
+ max_results: Maximum number of results
325
+ mode: Search mode - 'bm25' (default), 'vector', or 'hybrid'
326
+
327
+ Returns:
328
+ Dictionary with search results
329
+ """
330
+ if domain is None:
331
+ domain = detect_domain(query)
332
+
333
+ config = CSV_CONFIG.get(domain, CSV_CONFIG["style"])
334
+ filepath = DATA_DIR / config["file"]
335
+
336
+ if not filepath.exists():
337
+ return {"error": f"File not found: {filepath}", "domain": domain}
338
+
339
+ # Validate mode
340
+ if mode not in ['bm25', 'vector', 'hybrid']:
341
+ mode = 'bm25'
342
+
343
+ # Fallback to BM25 if vector dependencies not available
344
+ if mode in ['vector', 'hybrid'] and not VECTOR_AVAILABLE:
345
+ mode = 'bm25'
346
+
347
+ results = _search_csv(filepath, config["search_cols"], config["output_cols"], query, max_results, mode)
348
+
349
+ return {
350
+ "domain": domain,
351
+ "query": query,
352
+ "file": config["file"],
353
+ "mode": mode,
354
+ "count": len(results),
355
+ "results": results
356
+ }
357
+
358
+
359
+ def search_stack(query, stack, max_results=MAX_RESULTS, mode='bm25'):
360
+ """Search stack-specific guidelines"""
361
+ if stack not in STACK_CONFIG:
362
+ return {"error": f"Unknown stack: {stack}. Available: {', '.join(AVAILABLE_STACKS)}"}
363
+
364
+ filepath = DATA_DIR / STACK_CONFIG[stack]["file"]
365
+
366
+ if not filepath.exists():
367
+ return {"error": f"Stack file not found: {filepath}", "stack": stack}
368
+
369
+ # Validate mode and fallback if needed
370
+ if mode not in ['bm25', 'vector', 'hybrid']:
371
+ mode = 'bm25'
372
+ if mode in ['vector', 'hybrid'] and not VECTOR_AVAILABLE:
373
+ mode = 'bm25'
374
+
375
+ results = _search_csv(filepath, _STACK_COLS["search_cols"], _STACK_COLS["output_cols"], query, max_results, mode)
376
+
377
+ return {
378
+ "domain": "stack",
379
+ "stack": stack,
380
+ "query": query,
381
+ "file": STACK_CONFIG[stack]["file"],
382
+ "mode": mode,
383
+ "count": len(results),
384
+ "results": results
385
+ }
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ UI/UX Builder Search - BM25, Vector, and Hybrid search engine for UI/UX style guides
5
+ Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--mode <mode>] [--max-results 3]
6
+
7
+ Domains: style, prompt, color, chart, landing, product, ux, typography, pages
8
+ Stacks: html-tailwind, react, nextjs, vue, svelte, swiftui, react-native, flutter
9
+ Modes: bm25 (default), vector, hybrid
10
+
11
+ Note: Vector and hybrid modes require: pip install sentence-transformers scikit-learn
12
+ """
13
+
14
+ import argparse
15
+ from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack, VECTOR_AVAILABLE
16
+
17
+
18
+ def format_output(result):
19
+ """Format results for Claude consumption (token-optimized)"""
20
+ if "error" in result:
21
+ return f"Error: {result['error']}"
22
+
23
+ output = []
24
+ mode_info = f" | **Mode:** {result.get('mode', 'bm25')}"
25
+ if result.get("stack"):
26
+ output.append(f"## UI/UX Builder Stack Guidelines")
27
+ output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}{mode_info}")
28
+ else:
29
+ output.append(f"## UI/UX Builder Search Results")
30
+ output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}{mode_info}")
31
+ output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
32
+
33
+ for i, row in enumerate(result['results'], 1):
34
+ output.append(f"### Result {i}")
35
+ for key, value in row.items():
36
+ value_str = str(value)
37
+ if len(value_str) > 300:
38
+ value_str = value_str[:300] + "..."
39
+ output.append(f"- **{key}:** {value_str}")
40
+ output.append("")
41
+
42
+ return "\n".join(output)
43
+
44
+
45
+ if __name__ == "__main__":
46
+ parser = argparse.ArgumentParser(description="UI/UX Builder Search")
47
+ parser.add_argument("query", help="Search query")
48
+ parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
49
+ parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help="Stack-specific search")
50
+ parser.add_argument("--mode", "-m", choices=['bm25', 'vector', 'hybrid'], default='bm25',
51
+ help="Search mode: bm25 (default, keyword-based), vector (semantic), hybrid (best of both)")
52
+ parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
53
+ parser.add_argument("--json", action="store_true", help="Output as JSON")
54
+
55
+ args = parser.parse_args()
56
+
57
+ # Check if vector mode is requested but not available
58
+ if args.mode in ['vector', 'hybrid'] and not VECTOR_AVAILABLE:
59
+ print("Warning: Vector/Hybrid mode requires sentence-transformers and scikit-learn.")
60
+ print("Falling back to BM25 mode. Install with: pip install sentence-transformers scikit-learn")
61
+ args.mode = 'bm25'
62
+
63
+ # Stack search takes priority
64
+ if args.stack:
65
+ result = search_stack(args.query, args.stack, args.max_results, args.mode)
66
+ else:
67
+ result = search(args.query, args.domain, args.max_results, args.mode)
68
+
69
+ if args.json:
70
+ import json
71
+ print(json.dumps(result, indent=2, ensure_ascii=False))
72
+ else:
73
+ print(format_output(result))
@@ -0,0 +1,118 @@
1
+ # Skill: Feature Suggestion (Cross-Cutting)
2
+
3
+ ## Purpose
4
+
5
+ This skill is used to analyze existing project structure and suggest new features that would integrate well with the current codebase. It helps identify opportunities for enhancements and new functionality based on existing patterns and architecture.
6
+
7
+ ## When to Use
8
+
9
+ - When planning new features for a project
10
+ - When identifying gaps in functionality
11
+ - When analyzing project structure for enhancement opportunities
12
+ - When proposing improvements based on existing patterns
13
+ - When suggesting features that align with project architecture
14
+
15
+ ## Step-by-Step Process
16
+
17
+ ### Step 1: Analyze Project Structure
18
+ - Read and understand `heraspec/project.md`
19
+ - Review existing specs in `heraspec/specs/`
20
+ - Analyze existing changes and their patterns
21
+ - Identify project type and tech stack
22
+ - Map current feature set
23
+
24
+ ### Step 2: Identify Integration Points
25
+ - Find logical places for new features
26
+ - Identify patterns in existing code
27
+ - Determine appropriate project structure locations
28
+ - Consider dependencies and relationships
29
+ - Map feature hierarchy
30
+
31
+ ### Step 3: Generate Suggestions
32
+ - Create feature suggestions based on analysis
33
+ - Ensure suggestions align with project type
34
+ - Consider existing patterns and conventions
35
+ - Propose features that enhance current functionality
36
+ - Suggest improvements and extensions
37
+
38
+ ### Step 4: Organize Suggestions
39
+ - Group suggestions by category/domain
40
+ - Prioritize based on feasibility and value
41
+ - Create suggestion files in appropriate locations
42
+ - Link suggestions to existing features
43
+ - Document integration points
44
+
45
+ ### Step 5: Review and Refine
46
+ - Review suggestions for consistency
47
+ - Ensure suggestions follow project conventions
48
+ - Verify integration points are correct
49
+ - Refine based on project requirements
50
+ - Prepare for implementation planning
51
+
52
+ ## Required Input
53
+
54
+ - **Project structure**: Understanding of project organization
55
+ - **Existing specs**: Current feature specifications
56
+ - **Project type**: Type of project (plugin, module, app, etc.)
57
+ - **Tech stack**: Technologies used in the project
58
+ - **Domain context**: Business domain and requirements
59
+
60
+ ## Expected Output
61
+
62
+ - Feature suggestion files
63
+ - Suggestions organized by category
64
+ - Integration points identified
65
+ - Suggestions linked to existing features
66
+ - Documentation of suggested enhancements
67
+
68
+ ## Tone & Rules
69
+
70
+ ### Suggestion Quality
71
+ - Suggest features that add value
72
+ - Align with project type and architecture
73
+ - Consider existing patterns and conventions
74
+ - Propose realistic and feasible features
75
+ - Enhance rather than replace existing functionality
76
+
77
+ ### Integration
78
+ - Identify appropriate locations for features
79
+ - Consider dependencies and relationships
80
+ - Follow existing project structure
81
+ - Maintain consistency with current patterns
82
+ - Document integration approach
83
+
84
+ ### Documentation
85
+ - Clearly describe suggested features
86
+ - Explain integration points
87
+ - Link to related existing features
88
+ - Provide context and rationale
89
+ - Include implementation considerations
90
+
91
+ ### Limitations
92
+ - ❌ DO NOT suggest features that conflict with existing architecture
93
+ - ❌ DO NOT ignore project conventions
94
+ - ❌ DO NOT suggest overly complex features
95
+ - ❌ DO NOT duplicate existing functionality
96
+ - ❌ DO NOT suggest features without considering integration
97
+
98
+ ## Available Templates
99
+
100
+ - `templates/suggestion-template.md` - Template for feature suggestions
101
+ - `templates/suggestion-category-template.md` - Template for organizing suggestions by category
102
+
103
+ ## Available Scripts
104
+
105
+ - `scripts/analyze-project-structure.py` - Analyze project structure for suggestion opportunities
106
+
107
+ ## Examples
108
+
109
+ See `examples/` directory for reference:
110
+ - `good-suggestions/` - Well-structured feature suggestions
111
+ - `bad-suggestions/` - Examples to avoid
112
+
113
+ ## Links to Other Skills
114
+
115
+ - **documents**: Use to document suggestion rationale
116
+ - **unit-test**: Consider testability when suggesting features
117
+ - **integration-test**: Consider integration testing when suggesting features
118
+
@@ -0,0 +1,40 @@
1
+ # Accessibility Checklist (WCAG 2.1 AA)
2
+
3
+ ## Perceivable
4
+
5
+ - [ ] All images have descriptive alt text
6
+ - [ ] Color is not the only means of conveying information
7
+ - [ ] Text contrast ratio meets 4.5:1 for normal text, 3:1 for large text
8
+ - [ ] Content can be resized up to 200% without loss of functionality
9
+
10
+ ## Operable
11
+
12
+ - [ ] All functionality available via keyboard
13
+ - [ ] No keyboard traps
14
+ - [ ] Focus indicators visible
15
+ - [ ] Sufficient time limits (if any) can be extended
16
+ - [ ] No content that causes seizures (flashing)
17
+ - [ ] Touch targets at least 44x44px
18
+
19
+ ## Understandable
20
+
21
+ - [ ] Page titles are descriptive
22
+ - [ ] Form inputs have labels
23
+ - [ ] Error messages are clear and helpful
24
+ - [ ] Language of page is declared
25
+ - [ ] Navigation is consistent
26
+
27
+ ## Robust
28
+
29
+ - [ ] Valid HTML markup
30
+ - [ ] ARIA attributes used correctly (if needed)
31
+ - [ ] Screen reader compatible
32
+ - [ ] Works with assistive technologies
33
+
34
+ ## Additional Best Practices
35
+
36
+ - [ ] `prefers-reduced-motion` respected
37
+ - [ ] Skip links for keyboard navigation
38
+ - [ ] Logical tab order
39
+ - [ ] Focus management for modals/dialogs
40
+