@lugom.io/hefesto 0.3.0 → 1.0.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 (73) hide show
  1. package/agents/hefesto-argos.md +51 -237
  2. package/agents/hefesto-athena.md +59 -339
  3. package/agents/hefesto-hermes.md +39 -71
  4. package/bin/install.js +105 -69
  5. package/hooks/hefesto-check-update.cjs +32 -11
  6. package/hooks/hefesto-statusline.cjs +8 -17
  7. package/hooks/hefesto-workflow.cjs +68 -0
  8. package/package.json +12 -2
  9. package/skills/hefesto-context/SKILL.md +59 -26
  10. package/skills/hefesto-debug/SKILL.md +54 -0
  11. package/skills/hefesto-design/SKILL.md +133 -143
  12. package/skills/hefesto-execute/SKILL.md +133 -0
  13. package/skills/hefesto-init/SKILL.md +94 -59
  14. package/skills/hefesto-init/references/api.md +116 -0
  15. package/skills/hefesto-init/references/cli.md +91 -0
  16. package/skills/hefesto-init/references/mobile.md +69 -0
  17. package/skills/hefesto-init/references/web.md +246 -0
  18. package/skills/hefesto-new-feature/SKILL.md +75 -41
  19. package/skills/hefesto-security/SKILL.md +89 -0
  20. package/skills/hefesto-security/references/boundaries-and-bypasses.md +152 -0
  21. package/skills/hefesto-security/references/secrets-detection.md +121 -0
  22. package/skills/hefesto-security/references/severity-and-judgment.md +176 -0
  23. package/skills/hefesto-simplify/SKILL.md +82 -0
  24. package/templates/TPL-CLAUDE.md +54 -0
  25. package/templates/TPL-CONFIG.json +19 -0
  26. package/templates/TPL-DESIGN.md +305 -0
  27. package/templates/{FEATURE.md → TPL-FEATURE.md} +13 -6
  28. package/templates/TPL-PROJECT.md +50 -0
  29. package/templates/{RECON.md → TPL-RECON.md} +10 -4
  30. package/templates/{RESEARCH.md → TPL-RESEARCH.md} +15 -15
  31. package/templates/TPL-SECURITY.md +42 -0
  32. package/templates/TPL-SIMPLIFY.md +40 -0
  33. package/templates/{STATE.md → TPL-STATE.md} +0 -6
  34. package/templates/TPL-VERDICT.md +34 -0
  35. package/skills/hefesto-design/data/animations.csv +0 -21
  36. package/skills/hefesto-design/data/anti-patterns.csv +0 -41
  37. package/skills/hefesto-design/data/charts.csv +0 -26
  38. package/skills/hefesto-design/data/colors.csv +0 -108
  39. package/skills/hefesto-design/data/components.csv +0 -31
  40. package/skills/hefesto-design/data/google-fonts.csv +0 -56
  41. package/skills/hefesto-design/data/icons.csv +0 -23
  42. package/skills/hefesto-design/data/landing-pages.csv +0 -28
  43. package/skills/hefesto-design/data/products.csv +0 -46
  44. package/skills/hefesto-design/data/spacing.csv +0 -16
  45. package/skills/hefesto-design/data/styles.csv +0 -53
  46. package/skills/hefesto-design/data/typography.csv +0 -41
  47. package/skills/hefesto-design/data/ux-rules.csv +0 -61
  48. package/skills/hefesto-design/references/accessibility.md +0 -335
  49. package/skills/hefesto-design/references/aesthetics.md +0 -343
  50. package/skills/hefesto-design/references/anti-patterns.md +0 -107
  51. package/skills/hefesto-design/references/checklist.md +0 -66
  52. package/skills/hefesto-design/references/color-psychology.md +0 -203
  53. package/skills/hefesto-design/references/component-specs.md +0 -318
  54. package/skills/hefesto-design/references/polish.md +0 -339
  55. package/skills/hefesto-design/references/token-architecture.md +0 -394
  56. package/skills/hefesto-design/references/ux-rules.md +0 -349
  57. package/skills/hefesto-design/scripts/__pycache__/audit.cpython-314.pyc +0 -0
  58. package/skills/hefesto-design/scripts/__pycache__/contrast.cpython-314.pyc +0 -0
  59. package/skills/hefesto-design/scripts/__pycache__/core.cpython-314.pyc +0 -0
  60. package/skills/hefesto-design/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  61. package/skills/hefesto-design/scripts/__pycache__/search.cpython-314.pyc +0 -0
  62. package/skills/hefesto-design/scripts/__pycache__/validate_tokens.cpython-314.pyc +0 -0
  63. package/skills/hefesto-design/scripts/audit.py +0 -450
  64. package/skills/hefesto-design/scripts/contrast.py +0 -195
  65. package/skills/hefesto-design/scripts/core.py +0 -155
  66. package/skills/hefesto-design/scripts/design_system.py +0 -311
  67. package/skills/hefesto-design/scripts/search.py +0 -235
  68. package/skills/hefesto-design/scripts/validate_tokens.py +0 -274
  69. package/skills/hefesto-update/SKILL.md +0 -34
  70. package/templates/DESIGN.md +0 -137
  71. package/templates/PROJECT.md +0 -28
  72. package/templates/ROADMAP.md +0 -23
  73. package/templates/VERDICT.md +0 -52
@@ -1,235 +0,0 @@
1
- #!/usr/bin/env python3
2
- """CLI de busca multi-domínio para o sistema de design do Hefesto.
3
-
4
- Busca em CSVs de estilos, cores, tipografia, componentes, UX, anti-patterns,
5
- espaçamento e animações usando BM25.
6
- """
7
-
8
- import argparse
9
- import json
10
- import sys
11
- from pathlib import Path
12
-
13
- # Resolve import do core.py no mesmo diretório
14
- _SCRIPT_DIR = Path(__file__).resolve().parent
15
- sys.path.insert(0, str(_SCRIPT_DIR))
16
-
17
- from core import BM25
18
-
19
- DATA_DIR = _SCRIPT_DIR.parent / "data"
20
-
21
- DOMAINS = {
22
- "style": {
23
- "csv": "styles.csv",
24
- "fields": ["name", "keywords_pt", "keywords_en", "description", "mood", "best_for"],
25
- "label": "Estilos",
26
- },
27
- "color": {
28
- "csv": "colors.csv",
29
- "fields": ["name", "industry", "mood", "description"],
30
- "label": "Paletas de Cores",
31
- },
32
- "typography": {
33
- "csv": "typography.csv",
34
- "fields": ["name", "mood", "best_for", "display_font", "body_font", "pairing_reason"],
35
- "label": "Tipografia",
36
- },
37
- "component": {
38
- "csv": "components.csv",
39
- "fields": ["name", "category", "variants", "description"],
40
- "label": "Componentes",
41
- },
42
- "ux": {
43
- "csv": "ux-rules.csv",
44
- "fields": ["name", "category", "rule", "standard", "reasoning"],
45
- "label": "Regras de UX",
46
- },
47
- "anti-pattern": {
48
- "csv": "anti-patterns.csv",
49
- "fields": ["name", "category", "description", "why_bad"],
50
- "label": "Anti-Patterns",
51
- },
52
- "spacing": {
53
- "csv": "spacing.csv",
54
- "fields": ["name", "style", "description", "density"],
55
- "label": "Espaçamento",
56
- },
57
- "animation": {
58
- "csv": "animations.csv",
59
- "fields": ["name", "context", "description"],
60
- "label": "Animações",
61
- },
62
- "product": {
63
- "csv": "products.csv",
64
- "fields": ["name", "category", "audience", "recommended_style", "key_components", "layout_pattern", "description"],
65
- "label": "Tipos de Produto",
66
- },
67
- "chart": {
68
- "csv": "charts.csv",
69
- "fields": ["name", "category", "best_for", "data_type", "a11y_notes", "description"],
70
- "label": "Gráficos e Visualização",
71
- },
72
- "landing": {
73
- "csv": "landing-pages.csv",
74
- "fields": ["name", "section_type", "purpose", "key_elements", "copywriting_pattern", "description"],
75
- "label": "Landing Pages",
76
- },
77
- "icon": {
78
- "csv": "icons.csv",
79
- "fields": ["name", "style", "best_for", "avoid_with", "description"],
80
- "label": "Icon Sets",
81
- },
82
- "font": {
83
- "csv": "google-fonts.csv",
84
- "fields": ["name", "category", "mood", "best_for", "pair_with", "description"],
85
- "label": "Google Fonts",
86
- },
87
- }
88
-
89
-
90
- def _get_engine(domain_key):
91
- """Cria um BM25 engine para o domínio dado."""
92
- domain = DOMAINS[domain_key]
93
- csv_path = DATA_DIR / domain["csv"]
94
- if not csv_path.exists():
95
- print(f"Erro: arquivo não encontrado: {csv_path}", file=sys.stderr)
96
- sys.exit(1)
97
- return BM25(str(csv_path), domain["fields"])
98
-
99
-
100
- def _display_columns(results):
101
- """Determina colunas visíveis (exclui internas e muito longas)."""
102
- if not results:
103
- return []
104
- skip = {"_score"}
105
- return [k for k in results[0].keys() if k not in skip]
106
-
107
-
108
- def _format_table(results, domain_label, max_col_width=40):
109
- """Formata resultados como tabela alinhada."""
110
- if not results:
111
- return f" Nenhum resultado encontrado para '{domain_label}'."
112
-
113
- cols = _display_columns(results)
114
- cols_with_score = cols + ["score"]
115
-
116
- # Calcula largura de cada coluna
117
- widths = {}
118
- for col in cols_with_score:
119
- header_len = len(col)
120
- max_val = 0
121
- for r in results:
122
- val = str(r.get("_score", "")) if col == "score" else str(r.get(col, ""))
123
- if len(val) > max_col_width:
124
- val = val[:max_col_width - 3] + "..."
125
- max_val = max(max_val, len(val))
126
- widths[col] = max(header_len, min(max_val, max_col_width))
127
-
128
- # Header
129
- header = " | ".join(col.ljust(widths[col]) for col in cols_with_score)
130
- separator = "-+-".join("-" * widths[col] for col in cols_with_score)
131
-
132
- lines = [f"\n === {domain_label} ===\n", f" {header}", f" {separator}"]
133
-
134
- for r in results:
135
- row_parts = []
136
- for col in cols_with_score:
137
- val = str(r.get("_score", "")) if col == "score" else str(r.get(col, ""))
138
- if len(val) > max_col_width:
139
- val = val[:max_col_width - 3] + "..."
140
- row_parts.append(val.ljust(widths[col]))
141
- lines.append(" " + " | ".join(row_parts))
142
-
143
- return "\n".join(lines)
144
-
145
-
146
- def _search_domain(domain_key, query, max_results):
147
- """Busca em um domínio e retorna resultados."""
148
- engine = _get_engine(domain_key)
149
- return engine.search(query, max_results)
150
-
151
-
152
- def _list_domains():
153
- """Lista todos os domínios disponíveis."""
154
- print("\nDomínios disponíveis:\n")
155
- for key, info in DOMAINS.items():
156
- csv_path = DATA_DIR / info["csv"]
157
- exists = "OK" if csv_path.exists() else "FALTANDO"
158
- print(f" {key:15s} {info['label']:25s} [{exists}] {info['csv']}")
159
- print()
160
-
161
-
162
- def main():
163
- parser = argparse.ArgumentParser(
164
- description="Busca multi-domínio no sistema de design Hefesto.",
165
- formatter_class=argparse.RawDescriptionHelpFormatter,
166
- epilog="""Exemplos:
167
- python3 search.py "fintech modern" --domain style
168
- python3 search.py "luxury serif" --domain typography
169
- python3 search.py "wellness calm" --all
170
- python3 search.py --list-domains
171
- """,
172
- )
173
- parser.add_argument("query", nargs="?", default=None, help="Termos de busca")
174
- parser.add_argument(
175
- "--domain", "-d",
176
- choices=list(DOMAINS.keys()),
177
- help="Domínio para buscar",
178
- )
179
- parser.add_argument("--all", "-a", action="store_true", help="Buscar em todos os domínios")
180
- parser.add_argument("--list-domains", action="store_true", help="Listar domínios disponíveis")
181
- parser.add_argument(
182
- "-f", "--format",
183
- choices=["table", "json"],
184
- default="table",
185
- help="Formato de saída (padrão: table)",
186
- )
187
- parser.add_argument(
188
- "-n", "--max-results",
189
- type=int,
190
- default=5,
191
- help="Número máximo de resultados por domínio (padrão: 5)",
192
- )
193
-
194
- args = parser.parse_args()
195
-
196
- if args.list_domains:
197
- _list_domains()
198
- return
199
-
200
- if not args.query:
201
- parser.error("Informe os termos de busca ou use --list-domains.")
202
-
203
- if not args.domain and not args.all:
204
- parser.error("Informe --domain DOMÍNIO ou --all para buscar em todos.")
205
-
206
- domains_to_search = list(DOMAINS.keys()) if args.all else [args.domain]
207
-
208
- all_results = {}
209
- for domain_key in domains_to_search:
210
- try:
211
- results = _search_domain(domain_key, args.query, args.max_results)
212
- if results:
213
- all_results[domain_key] = results
214
- except FileNotFoundError:
215
- if not args.all:
216
- print(f"Erro: CSV do domínio '{domain_key}' não encontrado.", file=sys.stderr)
217
- sys.exit(1)
218
-
219
- if args.format == "json":
220
- output = {}
221
- for domain_key, results in all_results.items():
222
- output[domain_key] = results
223
- print(json.dumps(output, indent=2, ensure_ascii=False))
224
- else:
225
- if not all_results:
226
- print("\n Nenhum resultado encontrado.\n")
227
- return
228
- for domain_key, results in all_results.items():
229
- label = DOMAINS[domain_key]["label"]
230
- print(_format_table(results, label))
231
- print()
232
-
233
-
234
- if __name__ == "__main__":
235
- main()
@@ -1,274 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Validador de uso de design tokens para o Hefesto.
3
-
4
- Verifica se tokens definidos no DESIGN.md são usados no código-fonte e
5
- identifica valores hardcoded que deveriam usar tokens.
6
- """
7
-
8
- import argparse
9
- import json
10
- import os
11
- import re
12
- import sys
13
-
14
-
15
- SCANNABLE_EXTENSIONS = {
16
- ".tsx", ".jsx", ".vue", ".svelte", ".css", ".scss",
17
- ".html", ".astro", ".ts", ".js",
18
- }
19
-
20
-
21
- def _is_binary(filepath):
22
- """Verifica se o arquivo parece ser binário."""
23
- try:
24
- with open(filepath, "rb") as f:
25
- chunk = f.read(1024)
26
- return b"\x00" in chunk
27
- except (IOError, OSError):
28
- return True
29
-
30
-
31
- def parse_tokens(design_path):
32
- """Extrai tokens de design da seção 'Tokens de Design' do DESIGN.md.
33
-
34
- Retorna dict: {token_name: token_value}
35
- Ex: {"--color-primary": "#6366f1", "--space-md": "16px"}
36
- """
37
- try:
38
- with open(design_path, "r", encoding="utf-8") as f:
39
- content = f.read()
40
- except FileNotFoundError:
41
- print(f"Erro: arquivo não encontrado: {design_path}", file=sys.stderr)
42
- sys.exit(1)
43
-
44
- tokens = {}
45
- in_section = False
46
-
47
- for line in content.split("\n"):
48
- # Detecta início da seção de tokens
49
- if re.match(r"^#{1,4}\s+.*[Tt]okens\s+de\s+[Dd]esign", line):
50
- in_section = True
51
- continue
52
- # Detecta fim da seção (próximo heading de mesmo nível ou superior)
53
- if in_section and re.match(r"^#{1,3}\s+", line) and "token" not in line.lower():
54
- break
55
- if not in_section:
56
- continue
57
-
58
- # Extrai custom properties CSS: --nome: valor
59
- token_match = re.search(r"(--[\w-]+)\s*:\s*([^;}\n]+)", line)
60
- if token_match:
61
- name = token_match.group(1).strip()
62
- value = token_match.group(2).strip().rstrip(";")
63
- tokens[name] = value
64
- continue
65
-
66
- # Também captura tokens em formato de tabela markdown: | --nome | valor |
67
- table_match = re.search(r"\|\s*(--[\w-]+)\s*\|\s*([^|]+)\s*\|", line)
68
- if table_match:
69
- name = table_match.group(1).strip()
70
- value = table_match.group(2).strip()
71
- tokens[name] = value
72
- continue
73
-
74
- # Formato com backtick: `--nome` → `valor` ou `--nome`: `valor`
75
- backtick_match = re.search(r"`(--[\w-]+)`\s*[:\u2192→=]\s*`?([^`\n]+)`?", line)
76
- if backtick_match:
77
- name = backtick_match.group(1).strip()
78
- value = backtick_match.group(2).strip().rstrip("`")
79
- tokens[name] = value
80
-
81
- return tokens
82
-
83
-
84
- def walk_source(src_dir):
85
- """Percorre diretório fonte e retorna arquivos escaneáveis."""
86
- files = []
87
- for root, _dirs, filenames in os.walk(src_dir):
88
- parts = root.split(os.sep)
89
- if any(p in {"node_modules", ".git", "dist", "build", ".next", "__pycache__"} for p in parts):
90
- continue
91
- for fname in filenames:
92
- ext = os.path.splitext(fname)[1].lower()
93
- if ext in SCANNABLE_EXTENSIONS:
94
- files.append(os.path.join(root, fname))
95
- return files
96
-
97
-
98
- def validate_tokens(design_path, src_dir):
99
- """Valida uso de tokens no código-fonte.
100
-
101
- Retorna dict com:
102
- tokens_defined: total de tokens definidos
103
- tokens_used: set de tokens encontrados no código
104
- tokens_unused: set de tokens não encontrados
105
- hardcoded_matches: lista de {file, line, token_name, hardcoded_value}
106
- coverage: percentual de cobertura
107
- """
108
- tokens = parse_tokens(design_path)
109
- if not tokens:
110
- print("Aviso: nenhum token encontrado na seção 'Tokens de Design'.", file=sys.stderr)
111
- return {
112
- "tokens_defined": 0,
113
- "tokens_used": set(),
114
- "tokens_unused": set(),
115
- "hardcoded_matches": [],
116
- "coverage": 0.0,
117
- }
118
-
119
- files = walk_source(src_dir)
120
- tokens_used = set()
121
- hardcoded_matches = []
122
-
123
- # Pré-computa mapeamento valor → nomes de token (para detectar hardcoded)
124
- value_to_tokens = {}
125
- for name, value in tokens.items():
126
- val_normalized = value.strip().lower()
127
- if val_normalized and len(val_normalized) >= 2:
128
- value_to_tokens.setdefault(val_normalized, []).append(name)
129
-
130
- for filepath in files:
131
- if _is_binary(filepath):
132
- continue
133
- try:
134
- with open(filepath, "r", encoding="utf-8", errors="replace") as f:
135
- lines = f.readlines()
136
- except (IOError, OSError):
137
- continue
138
-
139
- file_content = "".join(lines)
140
-
141
- # Verifica quais tokens são usados
142
- for token_name in tokens:
143
- if token_name in file_content:
144
- tokens_used.add(token_name)
145
-
146
- # Busca valores hardcoded que correspondem a valores de tokens
147
- for lineno, line in enumerate(lines, 1):
148
- # Ignora linhas de comentário
149
- stripped = line.strip()
150
- if (stripped.startswith("//") or stripped.startswith("/*")
151
- or stripped.startswith("*") or stripped.startswith("#")
152
- or stripped.startswith("<!--")):
153
- continue
154
-
155
- line_lower = line.lower()
156
-
157
- for val_normalized, token_names in value_to_tokens.items():
158
- # Use word boundary matching to avoid substring false positives
159
- # e.g., token value "16" should not match "216px"
160
- # Build a pattern that matches the value with surrounding context
161
- escaped_val = re.escape(val_normalized)
162
- # Match value with word boundaries or common delimiters
163
- boundary_pattern = re.compile(
164
- r"(?:^|[\s:=,;({\[])%s(?:$|[\s;,)}\]px%%rem em])" % escaped_val,
165
- re.IGNORECASE,
166
- )
167
- if boundary_pattern.search(line_lower):
168
- # Verifica se não está dentro de var() ou é definição do próprio token
169
- is_var_usage = re.search(r"var\(\s*" + re.escape(token_names[0]), line)
170
- is_definition = any(tn in line for tn in token_names)
171
- if not is_var_usage and not is_definition:
172
- hardcoded_matches.append({
173
- "file": filepath,
174
- "line": lineno,
175
- "token_name": ", ".join(token_names),
176
- "hardcoded_value": val_normalized,
177
- })
178
-
179
- tokens_unused = set(tokens.keys()) - tokens_used
180
- total = len(tokens)
181
- coverage = (len(tokens_used) / total * 100) if total > 0 else 0.0
182
-
183
- return {
184
- "tokens_defined": total,
185
- "tokens_used": tokens_used,
186
- "tokens_unused": tokens_unused,
187
- "hardcoded_matches": hardcoded_matches,
188
- "coverage": coverage,
189
- }
190
-
191
-
192
- def format_report(result, fmt="table"):
193
- """Formata e imprime relatório de validação."""
194
- if fmt == "json":
195
- output = {
196
- "tokens_defined": result["tokens_defined"],
197
- "tokens_used": sorted(result["tokens_used"]),
198
- "tokens_unused": sorted(result["tokens_unused"]),
199
- "hardcoded_matches": result["hardcoded_matches"],
200
- "coverage": round(result["coverage"], 1),
201
- }
202
- print(json.dumps(output, indent=2, ensure_ascii=False))
203
- return
204
-
205
- print(f"\n{'='*50}")
206
- print(f" RELATÓRIO DE TOKENS DE DESIGN")
207
- print(f"{'='*50}\n")
208
-
209
- total = result["tokens_defined"]
210
- used = len(result["tokens_used"])
211
- unused = len(result["tokens_unused"])
212
-
213
- print(f" Tokens definidos: {total}")
214
- print(f" Tokens utilizados: {used}")
215
- print(f" Tokens não usados: {unused}")
216
- print(f" Cobertura: {result['coverage']:.1f}%\n")
217
-
218
- if result["tokens_unused"]:
219
- print(" TOKENS NÃO UTILIZADOS:")
220
- for token in sorted(result["tokens_unused"]):
221
- print(f" - {token}")
222
- print()
223
-
224
- if result["hardcoded_matches"]:
225
- print(f" VALORES HARDCODED ({len(result['hardcoded_matches'])} ocorrências):")
226
- for match in result["hardcoded_matches"]:
227
- print(f" {match['file']}:{match['line']}")
228
- print(f" Valor: {match['hardcoded_value']}")
229
- print(f" Use: var({match['token_name']})")
230
- print()
231
-
232
- if not result["tokens_unused"] and not result["hardcoded_matches"]:
233
- print(" Todos os tokens estão sendo utilizados corretamente!\n")
234
-
235
- print(f"{'='*50}\n")
236
-
237
-
238
- def main():
239
- parser = argparse.ArgumentParser(
240
- description="Validador de uso de design tokens.",
241
- epilog="""Exemplos:
242
- python3 validate_tokens.py --design .hefesto/DESIGN.md --src src/
243
- python3 validate_tokens.py --design .hefesto/DESIGN.md --src src/ -f json
244
- """,
245
- )
246
- parser.add_argument("--design", required=True, help="Caminho para DESIGN.md")
247
- parser.add_argument("--src", required=True, help="Diretório fonte para escanear")
248
- parser.add_argument(
249
- "-f", "--format",
250
- choices=["table", "json"],
251
- default="table",
252
- help="Formato de saída (padrão: table)",
253
- )
254
-
255
- args = parser.parse_args()
256
-
257
- if not os.path.isfile(args.design):
258
- print(f"Erro: DESIGN.md não encontrado: {args.design}", file=sys.stderr)
259
- sys.exit(1)
260
-
261
- if not os.path.isdir(args.src):
262
- print(f"Erro: diretório fonte não encontrado: {args.src}", file=sys.stderr)
263
- sys.exit(1)
264
-
265
- result = validate_tokens(args.design, args.src)
266
- format_report(result, args.format)
267
-
268
- # Exit code não-zero se há tokens não usados ou valores hardcoded
269
- if result["tokens_unused"] or result["hardcoded_matches"]:
270
- sys.exit(1)
271
-
272
-
273
- if __name__ == "__main__":
274
- main()
@@ -1,34 +0,0 @@
1
- ---
2
- name: hefesto-update
3
- description: "Atualiza o Hefesto para a versão mais recente. Use /hefesto-update para atualizar skills, hooks e templates sem perder o estado do projeto."
4
- user-invocable: true
5
- disable-model-invocation: true
6
- ---
7
-
8
- # Hefesto Update
9
-
10
- Atualiza o toolkit Hefesto para a versão mais recente do npm.
11
-
12
- ## Pré-requisitos
13
-
14
- Verificar se `.hefesto/` existe. Se não existir, informar que o projeto não foi inicializado e sugerir `/hefesto-init`.
15
-
16
- ## O que fazer
17
-
18
- 1. Ler `.hefesto/config.json` e anotar a versão atual (`version`).
19
- 2. Executar o comando de atualização:
20
- ```bash
21
- npx @lugom.io/hefesto@latest
22
- ```
23
- 3. Verificar o output do comando. Se houver erro, informar o usuário e sugerir ação corretiva.
24
- 4. Ler `.hefesto/config.json` novamente e comparar a versão com a anterior.
25
- 5. Informar o resultado ao usuário:
26
- - Se atualizou: mostrar versão anterior → nova versão
27
- - Se já estava na última versão: informar que está atualizado
28
-
29
- ## Notas
30
-
31
- - O installer preserva `.hefesto/` existente (PROJECT.md, STATE.md, ROADMAP.md, features/, config.json).
32
- - O que é atualizado: skills, hooks, templates.
33
- - Não usar `--global` a menos que o usuário peça explicitamente.
34
- - Se o usuário pedir para atualizar um runtime específico (ex: `--gemini`), passar a flag correspondente.
@@ -1,137 +0,0 @@
1
- ---
2
- status: draft
3
- depth: {{DESIGN_DEPTH}}
4
- created: {{DATE}}
5
- updated: {{DATE}}
6
- ---
7
-
8
- # Design — {{PROJECT_NAME}}
9
-
10
- ## Direção Estética
11
-
12
- **Estilo:** {{STYLE_NAME}}
13
- **Propósito:** {{INTERFACE_PURPOSE}}
14
- **Tom:** {{VISUAL_TONE}}
15
- **Diferencial:** {{MEMORABLE_ELEMENT}}
16
-
17
- > {{STYLE_DESCRIPTION}}
18
-
19
- ## Contrato de Cores
20
-
21
- | Papel | Cor | Uso | % |
22
- |-------|-----|-----|---|
23
- | Dominante | {{DOMINANT_COLOR}} | {{DOMINANT_USE}} | 60% |
24
- | Secundária | {{SECONDARY_COLOR}} | {{SECONDARY_USE}} | 30% |
25
- | Acento | {{ACCENT_COLOR}} | **Reservado para:** {{ACCENT_RESERVED_LIST}} | 10% |
26
-
27
- **Texto sobre dominante:** {{ON_DOMINANT}}
28
- **Texto sobre secundária:** {{ON_SECONDARY}}
29
- **Texto sobre acento:** {{ON_ACCENT}}
30
-
31
- ### Dark Mode
32
-
33
- | Papel | Light | Dark |
34
- |-------|-------|------|
35
- | Dominante | {{DOMINANT_LIGHT}} | {{DOMINANT_DARK}} |
36
- | Secundária | {{SECONDARY_LIGHT}} | {{SECONDARY_DARK}} |
37
- | Acento | {{ACCENT_LIGHT}} | {{ACCENT_DARK}} |
38
-
39
- **Contraste AA verificado:** {{CONTRAST_VERIFIED}}
40
-
41
- ## Contrato de Tipografia
42
-
43
- | Nível | Font | Size | Weight | Line Height | Uso |
44
- |-------|------|------|--------|-------------|-----|
45
- | Display | {{DISPLAY_FONT}} | {{DISPLAY_SIZE}} | {{DISPLAY_WEIGHT}} | {{DISPLAY_LH}} | {{DISPLAY_USE}} |
46
- | Heading | {{HEADING_FONT}} | {{HEADING_SIZE}} | {{HEADING_WEIGHT}} | {{HEADING_LH}} | {{HEADING_USE}} |
47
- | Body | {{BODY_FONT}} | {{BODY_SIZE}} | {{BODY_WEIGHT}} | {{BODY_LH}} | {{BODY_USE}} |
48
- | Small | {{SMALL_FONT}} | {{SMALL_SIZE}} | {{SMALL_WEIGHT}} | {{SMALL_LH}} | {{SMALL_USE}} |
49
-
50
- > Max 4 tamanhos. Max 2 pesos. Sem exceções.
51
-
52
- **Fontes bloqueadas:** Inter, Roboto, Arial, system-ui (a menos que justificado no estilo)
53
-
54
- ## Contrato de Espaçamento
55
-
56
- **Escala:** `{{SPACING_SCALE}}`
57
- **Unidade base:** {{BASE_UNIT}}px
58
- **Touch targets:** mínimo {{TOUCH_MIN}}px
59
-
60
- > Valor fora da escala = bug. Sem exceções.
61
-
62
- ## Copywriting
63
-
64
- | Elemento | Texto |
65
- |----------|-------|
66
- | CTA primário | {{PRIMARY_CTA}} |
67
- | CTA secundário | {{SECONDARY_CTA}} |
68
- | Empty state | {{EMPTY_STATE}} |
69
- | Error state | {{ERROR_STATE}} |
70
- | Loading state | {{LOADING_STATE}} |
71
- | Confirmação destrutiva | {{DESTRUCTIVE_CONFIRM}} |
72
-
73
- **Tom de voz:** {{VOICE_TONE}}
74
-
75
- <!-- standard+ -->
76
-
77
- ## Referências Visuais
78
-
79
- | Referência | URL | O que extrair |
80
- |------------|-----|---------------|
81
- | {{REF_NAME}} | {{REF_URL}} | {{REF_EXTRACT}} |
82
-
83
- ## Tokens de Design
84
-
85
- ### Primitivos (Core)
86
-
87
- ```css
88
- :root {
89
- {{PRIMITIVE_TOKENS}}
90
- }
91
- ```
92
-
93
- ### Semânticos
94
-
95
- ```css
96
- :root {
97
- {{SEMANTIC_TOKENS}}
98
- }
99
- ```
100
-
101
- ### Componente
102
-
103
- ```css
104
- {{COMPONENT_TOKENS}}
105
- ```
106
-
107
- ## Overrides por Contexto
108
-
109
- > Overrides são exceções justificadas ao contrato principal. Max 3 contextos.
110
- > Exemplos: admin vs público, onboarding vs app, marketing vs produto.
111
-
112
- | Contexto | O que muda | Valores | Justificativa |
113
- |----------|-----------|---------|---------------|
114
- | {{CONTEXT_NAME}} | {{WHAT_CHANGES}} | {{OVERRIDE_VALUES}} | {{JUSTIFICATION}} |
115
-
116
- <!-- deep -->
117
-
118
- ## Specs de Componentes
119
-
120
- | Componente | Nível | Variantes | Estados | A11y | Animação |
121
- |------------|-------|-----------|---------|------|----------|
122
- | {{COMP_NAME}} | {{ATOMIC_LEVEL}} | {{VARIANTS}} | {{STATES}} | {{A11Y}} | {{ANIMATION}} |
123
-
124
- ## Prompts para Ferramentas AI
125
-
126
- ### v0.dev / Lovable / Bolt
127
-
128
- ```
129
- {{AI_PROMPT}}
130
- ```
131
-
132
- <!-- /deep -->
133
- <!-- /standard+ -->
134
-
135
- ## Anti-Padrões Bloqueados
136
-
137
- - [ ] {{ANTI_PATTERN_CHECK}}