similarbuild 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 (76) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/LICENSE +21 -0
  3. package/README.md +301 -0
  4. package/bin/install.js +256 -0
  5. package/lib/copy-templates.mjs +52 -0
  6. package/lib/install-deps.mjs +62 -0
  7. package/lib/prompt-config.mjs +83 -0
  8. package/lib/verify-env.mjs +19 -0
  9. package/package.json +63 -0
  10. package/scripts/sync-templates.mjs +71 -0
  11. package/templates/commands/build-page.md +490 -0
  12. package/templates/commands/build-site.md +548 -0
  13. package/templates/commands/clip-section.md +519 -0
  14. package/templates/memory/anti-patterns.md +212 -0
  15. package/templates/memory/design-knowledge.md +225 -0
  16. package/templates/memory/fixes.md +163 -0
  17. package/templates/memory/patterns.md +681 -0
  18. package/templates/presets/shopify-section.yaml +51 -0
  19. package/templates/presets/wp-elementor.yaml +49 -0
  20. package/templates/reports/fixtures/mock-run-1.json +115 -0
  21. package/templates/reports/fixtures/mock-run-2.json +72 -0
  22. package/templates/reports/report-renderer.mjs +218 -0
  23. package/templates/reports/report-template.html +571 -0
  24. package/templates/skills/sb-build-shopify/SKILL.md +104 -0
  25. package/templates/skills/sb-build-shopify/references/shopify-build-rules.md +563 -0
  26. package/templates/skills/sb-build-shopify/scripts/build-shopify.mjs +637 -0
  27. package/templates/skills/sb-build-shopify/scripts/tests/test-build-shopify.mjs +424 -0
  28. package/templates/skills/sb-build-wp/SKILL.md +83 -0
  29. package/templates/skills/sb-build-wp/references/wp-build-rules.md +376 -0
  30. package/templates/skills/sb-build-wp/scripts/build-wp.mjs +327 -0
  31. package/templates/skills/sb-build-wp/scripts/tests/test-build-wp.mjs +224 -0
  32. package/templates/skills/sb-compare-visual/SKILL.md +121 -0
  33. package/templates/skills/sb-compare-visual/scripts/compare-visual.mjs +387 -0
  34. package/templates/skills/sb-compare-visual/scripts/lib/compare-tokens.mjs +273 -0
  35. package/templates/skills/sb-compare-visual/scripts/tests/test-compare-tokens.mjs +350 -0
  36. package/templates/skills/sb-compare-visual/scripts/tests/test-compare-visual.mjs +626 -0
  37. package/templates/skills/sb-crawl-and-list/SKILL.md +99 -0
  38. package/templates/skills/sb-crawl-and-list/scripts/crawl-and-list.mjs +437 -0
  39. package/templates/skills/sb-crawl-and-list/scripts/lib/blocklist-filter.mjs +176 -0
  40. package/templates/skills/sb-crawl-and-list/scripts/lib/fallback-crawler.mjs +107 -0
  41. package/templates/skills/sb-crawl-and-list/scripts/lib/page-classifier.mjs +89 -0
  42. package/templates/skills/sb-crawl-and-list/scripts/lib/sitemap-parser.mjs +118 -0
  43. package/templates/skills/sb-crawl-and-list/scripts/tests/test-blocklist-filter.mjs +204 -0
  44. package/templates/skills/sb-crawl-and-list/scripts/tests/test-crawl-and-list.mjs +276 -0
  45. package/templates/skills/sb-crawl-and-list/scripts/tests/test-fallback-crawler.mjs +243 -0
  46. package/templates/skills/sb-crawl-and-list/scripts/tests/test-page-classifier.mjs +120 -0
  47. package/templates/skills/sb-crawl-and-list/scripts/tests/test-sitemap-parser.mjs +157 -0
  48. package/templates/skills/sb-extract-assets/SKILL.md +112 -0
  49. package/templates/skills/sb-extract-assets/scripts/extract-assets.mjs +484 -0
  50. package/templates/skills/sb-extract-assets/scripts/tests/test-extract-assets.mjs +112 -0
  51. package/templates/skills/sb-inspect-live/SKILL.md +105 -0
  52. package/templates/skills/sb-inspect-live/scripts/inspect-live.mjs +693 -0
  53. package/templates/skills/sb-inspect-live/scripts/tests/test-inspect-live.mjs +181 -0
  54. package/templates/skills/sb-review-checks/SKILL.md +113 -0
  55. package/templates/skills/sb-review-checks/references/review-rules.md +195 -0
  56. package/templates/skills/sb-review-checks/scripts/lib/anti-patterns.mjs +379 -0
  57. package/templates/skills/sb-review-checks/scripts/lib/cross-reference.mjs +115 -0
  58. package/templates/skills/sb-review-checks/scripts/lib/design-quality.mjs +541 -0
  59. package/templates/skills/sb-review-checks/scripts/review-checks.mjs +250 -0
  60. package/templates/skills/sb-review-checks/scripts/tests/test-anti-patterns.mjs +343 -0
  61. package/templates/skills/sb-review-checks/scripts/tests/test-cross-reference.mjs +170 -0
  62. package/templates/skills/sb-review-checks/scripts/tests/test-design-quality.mjs +493 -0
  63. package/templates/skills/sb-review-checks/scripts/tests/test-review-checks.mjs +267 -0
  64. package/templates/skills/sb-tweak/SKILL.md +130 -0
  65. package/templates/skills/sb-tweak/references/tweak-patterns.md +157 -0
  66. package/templates/skills/sb-tweak/scripts/lib/diff-summarizer.mjs +140 -0
  67. package/templates/skills/sb-tweak/scripts/lib/element-locator.mjs +507 -0
  68. package/templates/skills/sb-tweak/scripts/lib/intent-parser.mjs +324 -0
  69. package/templates/skills/sb-tweak/scripts/tests/test-diff-summarizer.mjs +248 -0
  70. package/templates/skills/sb-tweak/scripts/tests/test-element-locator.mjs +418 -0
  71. package/templates/skills/sb-tweak/scripts/tests/test-intent-parser.mjs +496 -0
  72. package/templates/skills/sb-tweak/scripts/tests/test-tweak.mjs +407 -0
  73. package/templates/skills/sb-tweak/scripts/tweak.mjs +656 -0
  74. package/templates/skills/sb-validate-render/SKILL.md +120 -0
  75. package/templates/skills/sb-validate-render/scripts/tests/test-validate-render.mjs +304 -0
  76. package/templates/skills/sb-validate-render/scripts/validate-render.mjs +645 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,110 @@
1
+ # Changelog
2
+
3
+ Todas as mudanças notáveis deste projeto serão documentadas aqui.
4
+
5
+ O formato segue [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) e o
6
+ versionamento segue [SemVer](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] — 2026-05-05
11
+
12
+ Primeira release pública. **MVP V1** — pipeline completo `live page → paste-ready
13
+ WP/Shopify file`, validado e auto-corrigido, distribuído como plugin npm para
14
+ Claude Code.
15
+
16
+ ### Added
17
+
18
+ #### Entry points (12)
19
+
20
+ - `/build-page <url>` — orchestrator single-page (WP ou Shopify).
21
+ - `/build-site <url>` — orchestrator batch site-wide com checkpoint humano dual
22
+ (Pattern #35).
23
+ - `/clip-section <url> --selector <css>` — orchestrator section-level via CSS
24
+ selector.
25
+ - `sb-inspect-live` — Playwright + stealth, captura DOM/tokens/screenshot/bbox
26
+ da section, mobile-first (iPhone 14, DPR 3).
27
+ - `sb-extract-assets` — download de imagens com strip metadata (EXIF/XMP/IPTC),
28
+ rename via content-hash, dedupe contra assets já em disco.
29
+ - `sb-build-wp` — compositor WordPress/Elementor com defensive specificity,
30
+ mobile-first CSS, a11y/perf defaults.
31
+ - `sb-build-shopify` — compositor Shopify Section `.liquid` com `{% schema %}`
32
+ editável, settings agrupadas, presets, sem `image_picker default`,
33
+ `{{ block.shopify_attributes }}` em iterações.
34
+ - `sb-validate-render` — render offline via preset YAML, captura screenshot +
35
+ probe de tokens; suporta `--assets-map-path` pra Shopify mock context (resolve
36
+ `image_picker` settings via id-keyword × context-substring).
37
+ - `sb-compare-visual` — pixelmatch + token cross-check, scope-aware com
38
+ `--crop-live-bbox` + `--crop-build-bbox` (crops simétricos, Pattern #27).
39
+ - `sb-review-checks` — audit cheerio de 14 anti-patterns + 12 design checks
40
+ (5 a11y + 4 perf + 3 web-standards), confidence-tier no hero detection.
41
+ - `sb-tweak` — edita arquivo entregue via pedido natural PT/EN, exit code 4
42
+ semântico pra needs-human-input, atomic revert em validation failure.
43
+ - `sb-crawl-and-list` — descoberta de páginas sitemap-first com fallback HTML
44
+ crawl, classificação por path heuristic, ordering estável (home first,
45
+ depth ascendente, alfabético).
46
+
47
+ #### Memória versionada (4 markdowns machine-parseable)
48
+
49
+ - `templates/memory/anti-patterns.md` — **14 entries** (9 bootstrap +
50
+ 5 descobertos em smoke tests reais example-store.com WP+Shopify).
51
+ - `templates/memory/patterns.md` — 8 entries A-H com WP+Liquid variants
52
+ side-by-side.
53
+ - `templates/memory/fixes.md` — 11 recipes (#22-#32).
54
+ - `templates/memory/design-knowledge.md` — 12 checks
55
+ (5 a11y + 4 perf + 3 web-standards).
56
+
57
+ Cascata Pattern #21 implementada em todas as skills consumers:
58
+ `<plugin>/templates/memory → ~/.claude/similarbuild-memory → bundled fallback`.
59
+
60
+ #### Decision matrix 2×2 (Pattern #28)
61
+
62
+ Substituiu heurística frágil "diff>50 = catastrophic". Roteamento explícito por
63
+ `review.passed` × `compare.passed`:
64
+
65
+ | review.passed | compare.passed | Ação |
66
+ |---------------|----------------|------------------------------------------|
67
+ | true | true | ✅ entrega |
68
+ | false | true | ⚠️ escalate (audit estrutural) |
69
+ | true | false | ⚠️ escalate (drift visual sem fix) |
70
+ | false | false | 🔄 loop com fixHints (até max iter) |
71
+
72
+ #### Targets
73
+
74
+ - **WordPress / Elementor** — HTML standalone, defensive specificity contra
75
+ Astra/Hello/temas custom.
76
+ - **Shopify Section** — `.liquid` com schema editável, defensivo contra
77
+ Dawn / OS 2.0 / Sense.
78
+
79
+ #### Distribution & infra
80
+
81
+ - `bin/install.js` — CLI `npx similarbuild install` com 5 prompts via
82
+ `readline/promises` nativo (zero dep), idempotente, suporta `update`
83
+ subcommand preservando config + per-user memory.
84
+ - `lib/{verify-env,prompt-config,copy-templates,install-deps}.mjs` —
85
+ modularização do installer (Pattern #1 lazy-import aplicado).
86
+ - `scripts/sync-templates.mjs` — `.claude/{commands,skills/sb-*}` → `templates/`,
87
+ wired em `prepublishOnly`.
88
+ - `templates/presets/{wp-elementor,shopify-section}.yaml` — theme reset CSS +
89
+ wrapper + head_extras + default_probe_root extraídos do fallback hardcoded
90
+ pra YAMLs declarativos.
91
+ - `templates/reports/{report-template.html,report-renderer.mjs}` — single-file
92
+ HTML cumulativo com slider live⇆build interativo (`<input type=range>`,
93
+ keyboard ←/→, ARIA), JSON state embedado como `<script type="application/json">`
94
+ no próprio arquivo (Pattern #41), cap default 20 runs.
95
+
96
+ ### Validação
97
+
98
+ - 153 unit/smoke tests passando (13 inspect-live + 20 validate-render +
99
+ 34 anti-patterns + 15 cross-reference + 12 review-checks + 59 design-quality).
100
+ - Smoke E2E rodado em 3 URLs reais (`iana.org/help/example-domains`,
101
+ `example-store.com --target wp`, `example-store.com --target shopify`).
102
+ - Diff% medida (example-store hero WP track):
103
+ 94.88% → 90.22% → 86.88% → 62.32% → 35.72% (-59.16pp em 4 fixes coordenados:
104
+ Pattern #22 DPR alignment, anti-pattern #10 scope crop, Pattern #27 simmetric
105
+ crop, defaults revisados).
106
+
107
+ ---
108
+
109
+ [Unreleased]: https://github.com/eggonbassoli/similarbuild/compare/v0.1.0...HEAD
110
+ [0.1.0]: https://github.com/eggonbassoli/similarbuild/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SimilarBuild Authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,301 @@
1
+ # SimilarBuild
2
+
3
+ > Visual migration framework para Claude Code — clona uma página live e entrega
4
+ > arquivo pronto pra colar como **WordPress/Elementor HTML widget** ou **Shopify
5
+ > section `.liquid`**, validado e auto-corrigido.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/similarbuild.svg)](https://www.npmjs.com/package/similarbuild)
8
+ [![Node ≥20](https://img.shields.io/badge/node-%E2%89%A520-brightgreen.svg)](https://nodejs.org)
9
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
+
11
+ ---
12
+
13
+ ## O que é
14
+
15
+ SimilarBuild é uma framework distribuída como **plugin de skills do Claude Code**.
16
+ Em vez de você manualmente abrir DevTools, copiar HTML, ajustar CSS, corrigir
17
+ anti-patterns e medir diff visual, a framework orquestra **8 sub-skills
18
+ determinísticas** atrás de **3 slash commands** que entregam o arquivo pronto:
19
+
20
+ - `/build-page <url>` — clona **uma** página live → arquivo pronto.
21
+ - `/build-site <url>` — descobre todas as páginas, confirma com você (único
22
+ checkpoint humano), clona em batch.
23
+ - `/clip-section <url> --selector <css>` — clona **uma section específica** via
24
+ CSS selector → widget HTML / section Liquid.
25
+
26
+ Pipeline padrão (cada step é uma sub-skill):
27
+
28
+ ```
29
+ inspect-live → extract-assets → build-{wp|shopify} → validate-render
30
+ → compare-visual → review-checks → (auto-correct loop) → entrega
31
+ ```
32
+
33
+ Características principais:
34
+
35
+ - **Mobile-first** (iPhone 14, 390×844 CSS px, DPR 3) — alinhado live↔build.
36
+ - **WordPress/Elementor** ou **Shopify Section** (com `{% schema %}` editável).
37
+ - **Auto-correção**: review-checks + compare-visual alimentam fixHints num loop
38
+ determinístico (até `auto_correct_max_iterations`).
39
+ - **Decision matrix 2×2** (review.passed × compare.passed) decide entrega vs
40
+ loop vs escalation — sem heurísticas frágeis baseadas só em diff%.
41
+ - **Memória machine-parseable** (anti-patterns / patterns / fixes /
42
+ design-knowledge) lida via cascata `<plugin> → ~/.claude/similarbuild-memory
43
+ → bundled fallback`.
44
+ - **Cumulative HTML report** com slider live⇆build interativo, history embutido
45
+ como `<script type="application/json">` no próprio arquivo.
46
+
47
+ ---
48
+
49
+ ## Quick start
50
+
51
+ ### Pré-requisitos
52
+
53
+ - **Node.js ≥ 20** (usa `fetch` e `crypto` nativos).
54
+ - **Claude Code** instalado (`claude.ai/code` ou CLI).
55
+ - ~150MB livres pra `npx playwright install chromium`.
56
+
57
+ ### Instalar no seu projeto
58
+
59
+ Dentro de qualquer diretório de projeto onde você quer usar a framework:
60
+
61
+ ```bash
62
+ npx similarbuild install
63
+ ```
64
+
65
+ O installer faz, em ordem:
66
+
67
+ 1. Verifica Node ≥ 20.
68
+ 2. Pergunta 5 configurações (com defaults sensatos):
69
+ - `output_folder` (default: `sb-output`)
70
+ - `default_target` (`wp` | `shopify`, default: `wp`)
71
+ - `default_viewport` (default: `iphone-14`)
72
+ - `auto_correct_max_iterations` (default: `3`)
73
+ - `diff_threshold_percent` (default: `10`)
74
+ 3. Copia templates pra `.claude/{commands,skills,skills/sb-shared/{memory,presets},templates/reports}`.
75
+ 4. Cria `.claude/sb-config.yaml` (seguro re-rodar — preserva config existente).
76
+ 5. Garante `~/.claude/similarbuild-memory/` pra auto-learn per-user.
77
+ 6. Cria stub `package.json` se faltar e instala 10 deps runtime
78
+ (`playwright`, `sharp`, `pixelmatch`, `cheerio`, `liquidjs`, etc.).
79
+ 7. Confirma e roda `npx playwright install chromium`.
80
+
81
+ Flags úteis:
82
+
83
+ | Flag | Quando usar |
84
+ |------------------|-------------------------------------------------------|
85
+ | `--yes`, `-y` | usa defaults sem prompts (CI / re-install rápido) |
86
+ | `--no-deps` | pula `npm install` (deps já instaladas) |
87
+ | `--no-chromium` | pula download do Chromium (~150MB) |
88
+ | `--dry-run` | só imprime o que faria, sem escrever |
89
+
90
+ ### Atualizar
91
+
92
+ ```bash
93
+ npx similarbuild update
94
+ ```
95
+
96
+ Re-baixa templates novos preservando `.claude/sb-config.yaml` e
97
+ `~/.claude/similarbuild-memory/`.
98
+
99
+ ### Primeira execução
100
+
101
+ Abra o projeto no Claude Code e rode:
102
+
103
+ ```
104
+ /build-page https://example.com
105
+ ```
106
+
107
+ A framework dispara o pipeline ponta-a-ponta e entrega o arquivo em
108
+ `<output_folder>/<project-slug>/{slug}/build.{html|liquid}`.
109
+
110
+ ---
111
+
112
+ ## Slash commands
113
+
114
+ ### `/build-page <url> [--target wp|shopify] [--selector <css>]`
115
+
116
+ Clona **uma** página live e entrega arquivo pronto. Se `--selector` for passado,
117
+ só extrai e clona aquele scope (equivalente a `/clip-section` por baixo).
118
+
119
+ **Output:** `{output_folder}/{project-slug}/{page-slug}/build.{html|liquid}`,
120
+ `render.json`, `compare.json`, `review.json`, screenshots, `report.html`.
121
+
122
+ ### `/build-site <url> [--target wp|shopify]`
123
+
124
+ Descobre páginas via `sitemap.xml` (fallback: crawl HTML) → apresenta tabela →
125
+ você aplica filtros (skip/only/exclude/include) → confirma → clona em batch
126
+ sequencial.
127
+
128
+ **Único checkpoint humano da framework.** Confirmação dupla pra reduzir erros em
129
+ batches grandes (Pattern #35).
130
+
131
+ **Output:** mesmo layout do `/build-page` por página, mais `report.html`
132
+ cumulativo agregado e `auto-learn` consolidado no fim.
133
+
134
+ ### `/clip-section <url> --selector <css>`
135
+
136
+ Single-shot section via CSS selector. Validação rigorosa do selector (escala se
137
+ não casar — sem fabrication). Live é element-only (sem `--crop-live-bbox`).
138
+
139
+ ---
140
+
141
+ ## Configuração
142
+
143
+ `.claude/sb-config.yaml` — gerado pelo installer, editável livremente:
144
+
145
+ ```yaml
146
+ output_folder: sb-output
147
+ default_target: wp # ou: shopify
148
+ default_viewport: iphone-14
149
+ auto_correct_max_iterations: 3
150
+ diff_threshold_percent: 10
151
+ ```
152
+
153
+ Skills usam defaults inline se a config estiver ausente — você pode deletar o
154
+ arquivo e tudo continua funcionando.
155
+
156
+ ### Memória
157
+
158
+ Três camadas, lidas em cascata (Pattern #21):
159
+
160
+ 1. `<plugin>/templates/memory/*.md` — versionada, vem com o release npm.
161
+ 2. `~/.claude/similarbuild-memory/*.md` — per-user, populada por `/build-site`
162
+ auto-learn batched.
163
+ 3. `<skill>/references/*.md` — bundled fallback dentro de cada skill.
164
+
165
+ Cada arquivo é machine-parseable (campos
166
+ `id/name/applies-to/applies-when/symptom/fix-recipe/detector/severity/origin`).
167
+
168
+ ---
169
+
170
+ ## Como funciona — sub-skills
171
+
172
+ | Sub-skill | Papel |
173
+ |------------------------|--------------------------------------------------------------------|
174
+ | `sb-inspect-live` | Playwright + stealth → DOM, tokens, screenshot, bbox da section. |
175
+ | `sb-extract-assets` | Baixa imagens, strip metadata (EXIF/XMP/IPTC), dedupe content-hash. |
176
+ | `sb-build-wp` | Compõe HTML/Elementor com defensive specificity + a11y/perf. |
177
+ | `sb-build-shopify` | Compõe `.liquid` com `{% schema %}` editável + shims locais. |
178
+ | `sb-validate-render` | Renderiza fragment offline (preset YAML), captura screenshot+tokens.|
179
+ | `sb-compare-visual` | pixelmatch + token cross-check, scope-aware crops simétricos. |
180
+ | `sb-review-checks` | Cheerio audit de 14 anti-patterns + 12 design checks (a11y/perf/web).|
181
+ | `sb-tweak` | Edita arquivo entregue via pedido natural PT/EN, atomic-revert. |
182
+ | `sb-crawl-and-list` | Sitemap-first + cheerio fallback, classifica + ordena pra UI. |
183
+
184
+ ---
185
+
186
+ ## Targets suportados
187
+
188
+ ### WordPress / Elementor (`--target wp`)
189
+
190
+ Saída: HTML standalone com defensive specificity (`#elementor-editor` /
191
+ `.elementor-widget`), mobile-first CSS, alt text, `loading="lazy"`,
192
+ `fetchpriority="high"` no hero img, `rel="preload"` quando bg-image.
193
+
194
+ Cole no widget HTML do Elementor.
195
+
196
+ ### Shopify Section (`--target shopify`)
197
+
198
+ Saída: `.liquid` com `{% schema %}` editável (settings, presets), imagem hero
199
+ via `image_picker` setting (sem `default` — anti-pattern #12), fallback via
200
+ SVG base64 inline (sem path absoluto — anti-pattern #16), `{{ block.shopify_attributes }}`
201
+ em qualquer iteração, sem Google Fonts `<link>` inline (anti-pattern #14).
202
+
203
+ Cole em `sections/<nome>.liquid` no tema Dawn / OS 2.0 / Sense.
204
+
205
+ ---
206
+
207
+ ## Anti-patterns que a framework previne
208
+
209
+ A v0.1.0 codifica 14 anti-patterns descobertos em smoke tests reais
210
+ (`example-store.com` WP+Shopify track):
211
+
212
+ 1. **`100vh` no hero** — quebra mobile (URL bar dinâmica).
213
+ 2. **Hero `<img>` sem `fetchpriority="high"` + `<link rel="preload">`** quando
214
+ é background-image (detection two-step com confidence-tier).
215
+ 3. **`<img>` sem `alt`** — bloqueia a11y.
216
+ 4. **CSS sem mobile-first** — desktop-first quebra responsive.
217
+ 5. **Defensive specificity ausente** (selectors que vazam pro tema host).
218
+ 6. **Caminho absoluto do dev em fallback** (`/Users/...`, `C:\Users\...`).
219
+ 7. **Schema `image_picker` com `default` fixo** — UX ruim (Shopify).
220
+ 8. **Block iteration sem `{{ block.shopify_attributes }}`** (Shopify).
221
+ 9. **Google Fonts `<link>` inline na section** (Shopify).
222
+ 10. **Inspector full-page com section específica** (scope mismatch no diff).
223
+ 11. **404 silencioso em CDN do source** — comportamento normal, não escalar.
224
+ 12. **Prettier corrompendo `{% schema %}` JSON** — fix via placeholder.
225
+ 13. **`{% style %}/{% javascript %}` em liquidjs vanilla** — shim local.
226
+ 14. **image_picker sem default + mock context vazio** infla diff —
227
+ `--assets-map-path` resolve.
228
+
229
+ Veja `templates/memory/anti-patterns.md` pro contrato machine-parseable.
230
+
231
+ ---
232
+
233
+ ## CI / publishing
234
+
235
+ Releases tagged via GitHub triggam `npm publish` automático
236
+ (`.github/workflows/publish.yml`).
237
+
238
+ **Setup obrigatório no repo (uma vez):**
239
+
240
+ 1. Settings → Secrets and variables → Actions → New repository secret.
241
+ 2. Nome: `NPM_TOKEN`.
242
+ 3. Valor: token gerado em https://www.npmjs.com/settings/<user>/tokens
243
+ (tipo: **Automation** — pula 2FA challenge no publish).
244
+
245
+ Depois disso, `gh release create v0.1.0` (ou Releases → Draft new release →
246
+ Publish) dispara o workflow e publica no npm.
247
+
248
+ `prepublishOnly` roda `scripts/sync-templates.mjs` (`.claude/{commands,skills/sb-*}
249
+ → templates/{commands,skills/}`) — garante que o tarball sempre tem a versão
250
+ mais nova das skills sem precisar lembrar.
251
+
252
+ ---
253
+
254
+ ## Roadmap V2 (próximos)
255
+
256
+ A v0.1.0 cobre **MVP V1**: 12 entry points (3 slash commands + 9 sub-skills),
257
+ 14 anti-patterns codificados, 2 targets (WP + Shopify), decision matrix
258
+ explícita.
259
+
260
+ Itens em consideração pra V2:
261
+
262
+ - **Paralelismo no `/build-site`** — hoje é sequencial (1 página por vez),
263
+ V2 com pool de N workers.
264
+ - **`sb-tweak` em batch** — receber lista de pedidos PT/EN, aplicar todos
265
+ com two-phase confirmation (Pattern #35).
266
+ - **Targets adicionais** — Webflow, Framer, raw HTML standalone, MDX.
267
+ - **`sb-build-react`** — componente `.tsx` em vez de markup serializado.
268
+ - **Detector de anti-pattern #16 em `sb-review-checks`** — regex pra
269
+ paths absolutos (`/Users/`, `/home/`, `C:\Users\\`) no output final.
270
+ - **Visual regression suite** — `report.html` com diff cumulativo de N
271
+ runs, gráfico de evolução do diff%.
272
+ - **i18n no `sb-tweak`** — hoje aceita PT/EN, expandir pra ES/FR.
273
+
274
+ Issues e sugestões: https://github.com/eggonbassoli/similarbuild/issues
275
+
276
+ ---
277
+
278
+ ## Desenvolvimento
279
+
280
+ ```bash
281
+ git clone https://github.com/eggonbassoli/similarbuild
282
+ cd similarbuild
283
+ npm install # instala devDependencies (deps reais das skills)
284
+ npm run sync-templates # .claude/* → templates/*
285
+ npm run smoke:install # bin/install.js --help
286
+ ```
287
+
288
+ Cada sub-skill tem testes em `.claude/skills/sb-<nome>/scripts/tests/`. Rodar:
289
+
290
+ ```bash
291
+ node .claude/skills/sb-inspect-live/scripts/tests/test-inspect-live.mjs
292
+ # ... etc
293
+ ```
294
+
295
+ Total V1: 153 unit/smoke tests passando.
296
+
297
+ ---
298
+
299
+ ## Licença
300
+
301
+ MIT © 2026 SimilarBuild Authors — veja [LICENSE](LICENSE).
package/bin/install.js ADDED
@@ -0,0 +1,256 @@
1
+ #!/usr/bin/env node
2
+ // SimilarBuild installer — `npx similarbuild install` num projeto Claude Code
3
+ // copia templates, cria config, instala deps e deixa a framework pronta pra uso.
4
+ //
5
+ // Pattern #1 — lazy import das libs internas pra `--help` e validação de args funcionarem
6
+ // mesmo se algo no resto do pacote estiver quebrado.
7
+ // Pattern #16 — todos os logs em stderr com prefixo `[similarbuild]`.
8
+
9
+ import path from 'node:path';
10
+ import fs from 'node:fs/promises';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ const PLUGIN_ROOT = path.resolve(__dirname, '..');
15
+ const DEST = process.cwd();
16
+
17
+ const HELP = `\
18
+ similarbuild — installer da framework SimilarBuild
19
+
20
+ Uso:
21
+ npx similarbuild install [flags] instala templates + deps no projeto atual
22
+ npx similarbuild update re-baixa templates novos preservando config + memória per-user
23
+ npx similarbuild --help esta mensagem
24
+
25
+ Flags do install:
26
+ --yes, -y usa defaults sem prompts (CI / re-install rápido)
27
+ --no-deps pula instalação de deps npm (já instaladas)
28
+ --no-chromium pula download do Chromium do Playwright (~150MB)
29
+ --dry-run só imprime o que faria, não escreve nada
30
+ `;
31
+
32
+ function out(msg) { process.stdout.write(msg + '\n'); }
33
+ function err(msg) { process.stderr.write(`[similarbuild] ${msg}\n`); }
34
+
35
+ function parseArgs(argv) {
36
+ const args = { _: [], yes: false, deps: true, chromium: true, dryRun: false, help: false };
37
+ for (const a of argv) {
38
+ if (a === '--help' || a === '-h') args.help = true;
39
+ else if (a === '--yes' || a === '-y') args.yes = true;
40
+ else if (a === '--no-deps') args.deps = false;
41
+ else if (a === '--no-chromium') args.chromium = false;
42
+ else if (a === '--dry-run') args.dryRun = true;
43
+ else if (a.startsWith('-')) { err(`flag desconhecida: ${a}`); process.exit(2); }
44
+ else args._.push(a);
45
+ }
46
+ return args;
47
+ }
48
+
49
+ function yamlEscape(v) {
50
+ // Strings simples não precisam quote; só quote quando contém caractere YAML-significativo.
51
+ if (typeof v === 'number') return String(v);
52
+ if (typeof v === 'boolean') return String(v);
53
+ const s = String(v);
54
+ if (/^[A-Za-z0-9_./-]+$/.test(s)) return s;
55
+ return JSON.stringify(s);
56
+ }
57
+
58
+ async function writeConfig(destRoot, cfg) {
59
+ const lines = [
60
+ '# Generated by `npx similarbuild install`',
61
+ '# Edit livremente — skills usam defaults inline se config ausente.',
62
+ `output_folder: ${yamlEscape(cfg.output_folder)}`,
63
+ `default_target: ${yamlEscape(cfg.default_target)}`,
64
+ `default_viewport: ${yamlEscape(cfg.default_viewport)}`,
65
+ `auto_correct_max_iterations: ${yamlEscape(cfg.auto_correct_max_iterations)}`,
66
+ `diff_threshold_percent: ${yamlEscape(cfg.diff_threshold_percent)}`,
67
+ '',
68
+ ];
69
+ await fs.mkdir(path.join(destRoot, '.claude'), { recursive: true });
70
+ await fs.writeFile(path.join(destRoot, '.claude', 'sb-config.yaml'), lines.join('\n'));
71
+ }
72
+
73
+ async function readConfigIfExists(destRoot) {
74
+ try {
75
+ const text = await fs.readFile(path.join(destRoot, '.claude', 'sb-config.yaml'), 'utf8');
76
+ const cfg = {};
77
+ for (const line of text.split('\n')) {
78
+ const m = line.match(/^([A-Za-z_][\w]*):\s*(.+?)\s*$/);
79
+ if (!m) continue;
80
+ let v = m[2];
81
+ if (v.startsWith('"') && v.endsWith('"')) {
82
+ try { v = JSON.parse(v); } catch {}
83
+ }
84
+ cfg[m[1]] = v;
85
+ }
86
+ return cfg;
87
+ } catch { return null; }
88
+ }
89
+
90
+ function normalizeConfig(raw) {
91
+ const { DEFAULTS } = { DEFAULTS: {
92
+ output_folder: './sb-output',
93
+ default_target: 'wp',
94
+ default_viewport: 390,
95
+ auto_correct_max_iterations: 2,
96
+ diff_threshold_percent: 15,
97
+ } };
98
+ const intOr = (v, def) => {
99
+ const n = parseInt(v, 10);
100
+ return Number.isFinite(n) ? n : def;
101
+ };
102
+ return {
103
+ output_folder: raw.output_folder || DEFAULTS.output_folder,
104
+ default_target: raw.default_target || DEFAULTS.default_target,
105
+ default_viewport: intOr(raw.default_viewport, DEFAULTS.default_viewport),
106
+ auto_correct_max_iterations: intOr(raw.auto_correct_max_iterations, DEFAULTS.auto_correct_max_iterations),
107
+ diff_threshold_percent: intOr(raw.diff_threshold_percent, DEFAULTS.diff_threshold_percent),
108
+ };
109
+ }
110
+
111
+ async function ensureMemoryDir() {
112
+ const home = process.env.HOME || process.env.USERPROFILE;
113
+ if (!home) {
114
+ err('HOME não detectado, pulando memória per-user');
115
+ return null;
116
+ }
117
+ const dir = path.join(home, '.claude', 'similarbuild-memory');
118
+ await fs.mkdir(dir, { recursive: true });
119
+ return dir;
120
+ }
121
+
122
+ async function writeOutputGitignore(destRoot, outputFolder) {
123
+ const dir = path.resolve(destRoot, outputFolder);
124
+ await fs.mkdir(dir, { recursive: true });
125
+ const gi = path.join(dir, '.gitignore');
126
+ try { await fs.access(gi); return false; } catch {}
127
+ await fs.writeFile(gi, '# Outputs derivados — não versione.\n**\n');
128
+ return true;
129
+ }
130
+
131
+ async function cmdInstall(args) {
132
+ const { verifyNode } = await import('../lib/verify-env.mjs');
133
+ if (!verifyNode()) process.exit(1);
134
+
135
+ err(`projeto destino: ${DEST}`);
136
+ if (args.dryRun) err('--dry-run: nada será escrito');
137
+
138
+ // 1. Config: existente ou interativo ou defaults.
139
+ const existing = await readConfigIfExists(DEST);
140
+ let cfg;
141
+ if (existing) {
142
+ err('config existente em .claude/sb-config.yaml — preservando');
143
+ cfg = normalizeConfig(existing);
144
+ } else {
145
+ const { promptConfig } = await import('../lib/prompt-config.mjs');
146
+ cfg = await promptConfig({ yes: args.yes });
147
+ }
148
+
149
+ if (args.dryRun) {
150
+ out('--- dry-run preview ---');
151
+ out(`config: ${JSON.stringify(cfg, null, 2)}`);
152
+ out(`would copy templates from ${PLUGIN_ROOT}/templates → ${DEST}/.claude/{commands,skills,...}`);
153
+ out(`would create ${DEST}/${cfg.output_folder}/.gitignore`);
154
+ out(`would mkdir ~/.claude/similarbuild-memory/`);
155
+ if (args.deps) out('would npm install <deps>');
156
+ if (args.chromium) out('would prompt + npx playwright install chromium');
157
+ return;
158
+ }
159
+
160
+ // 2. Copia templates.
161
+ const { copyTemplates } = await import('../lib/copy-templates.mjs');
162
+ await copyTemplates({ pluginRoot: PLUGIN_ROOT, destRoot: DEST });
163
+
164
+ // 3. Escreve config (se já existia, re-escreve normalizado).
165
+ await writeConfig(DEST, cfg);
166
+
167
+ // 4. .gitignore no output_folder.
168
+ await writeOutputGitignore(DEST, cfg.output_folder);
169
+
170
+ // 5. Memória per-user.
171
+ const memDir = await ensureMemoryDir();
172
+
173
+ // 6. npm install.
174
+ if (args.deps) {
175
+ const { ensurePackageJson, installDeps } = await import('../lib/install-deps.mjs');
176
+ await ensurePackageJson(DEST);
177
+ try {
178
+ await installDeps(DEST);
179
+ } catch (e) {
180
+ err(`npm install falhou: ${e.message}`);
181
+ err('rode `npm install` manualmente quando puder e re-rode `npx similarbuild install --no-deps` se precisar.');
182
+ process.exit(1);
183
+ }
184
+ } else {
185
+ err('--no-deps: pulando npm install');
186
+ }
187
+
188
+ // 7. Chromium.
189
+ if (args.chromium) {
190
+ const { confirm } = await import('../lib/prompt-config.mjs');
191
+ const go = await confirm('Baixar Chromium do Playwright agora (~150MB)?', { defaultYes: true, yes: args.yes });
192
+ if (go) {
193
+ const { installChromium } = await import('../lib/install-deps.mjs');
194
+ try { await installChromium(DEST); }
195
+ catch (e) {
196
+ err(`chromium install falhou: ${e.message}`);
197
+ err('rode `npx playwright install chromium` quando puder.');
198
+ }
199
+ } else {
200
+ err('Chromium pulado. Rode `npx playwright install chromium` quando precisar.');
201
+ }
202
+ }
203
+
204
+ // 8. Próximos passos.
205
+ out('');
206
+ out('✅ SimilarBuild instalado.');
207
+ out(` Config: .claude/sb-config.yaml`);
208
+ out(` Output: ${cfg.output_folder}/`);
209
+ if (memDir) out(` Memória per-user: ${memDir}/`);
210
+ out('');
211
+ out('Próximo: claude → /build-page https://exemplo.com');
212
+ out('Docs: https://github.com/eggonbassoli/similarbuild');
213
+ }
214
+
215
+ async function cmdUpdate(args) {
216
+ const { verifyNode } = await import('../lib/verify-env.mjs');
217
+ if (!verifyNode()) process.exit(1);
218
+
219
+ const existing = await readConfigIfExists(DEST);
220
+ if (!existing) {
221
+ err('nenhum sb-config.yaml encontrado — rode `similarbuild install` primeiro.');
222
+ process.exit(1);
223
+ }
224
+
225
+ err(`atualizando templates em ${DEST}`);
226
+ if (args.dryRun) {
227
+ out(`would re-copy templates from ${PLUGIN_ROOT}/templates → ${DEST}`);
228
+ out(`would preserve .claude/sb-config.yaml + ~/.claude/similarbuild-memory/`);
229
+ return;
230
+ }
231
+
232
+ const { copyTemplates } = await import('../lib/copy-templates.mjs');
233
+ await copyTemplates({ pluginRoot: PLUGIN_ROOT, destRoot: DEST });
234
+ await ensureMemoryDir();
235
+
236
+ out('');
237
+ out('✅ SimilarBuild atualizado.');
238
+ out(' Config preservado em .claude/sb-config.yaml');
239
+ out(' Memória per-user preservada em ~/.claude/similarbuild-memory/');
240
+ }
241
+
242
+ async function main() {
243
+ const args = parseArgs(process.argv.slice(2));
244
+ if (args.help) { out(HELP); return; }
245
+ const sub = args._[0] || 'install';
246
+ if (sub === 'install') return cmdInstall(args);
247
+ if (sub === 'update') return cmdUpdate(args);
248
+ err(`subcommand desconhecido: ${sub}`);
249
+ out(HELP);
250
+ process.exit(2);
251
+ }
252
+
253
+ main().catch((e) => {
254
+ err(`erro fatal: ${e.stack || e.message}`);
255
+ process.exit(1);
256
+ });