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.
- package/CHANGELOG.md +110 -0
- package/LICENSE +21 -0
- package/README.md +301 -0
- package/bin/install.js +256 -0
- package/lib/copy-templates.mjs +52 -0
- package/lib/install-deps.mjs +62 -0
- package/lib/prompt-config.mjs +83 -0
- package/lib/verify-env.mjs +19 -0
- package/package.json +63 -0
- package/scripts/sync-templates.mjs +71 -0
- package/templates/commands/build-page.md +490 -0
- package/templates/commands/build-site.md +548 -0
- package/templates/commands/clip-section.md +519 -0
- package/templates/memory/anti-patterns.md +212 -0
- package/templates/memory/design-knowledge.md +225 -0
- package/templates/memory/fixes.md +163 -0
- package/templates/memory/patterns.md +681 -0
- package/templates/presets/shopify-section.yaml +51 -0
- package/templates/presets/wp-elementor.yaml +49 -0
- package/templates/reports/fixtures/mock-run-1.json +115 -0
- package/templates/reports/fixtures/mock-run-2.json +72 -0
- package/templates/reports/report-renderer.mjs +218 -0
- package/templates/reports/report-template.html +571 -0
- package/templates/skills/sb-build-shopify/SKILL.md +104 -0
- package/templates/skills/sb-build-shopify/references/shopify-build-rules.md +563 -0
- package/templates/skills/sb-build-shopify/scripts/build-shopify.mjs +637 -0
- package/templates/skills/sb-build-shopify/scripts/tests/test-build-shopify.mjs +424 -0
- package/templates/skills/sb-build-wp/SKILL.md +83 -0
- package/templates/skills/sb-build-wp/references/wp-build-rules.md +376 -0
- package/templates/skills/sb-build-wp/scripts/build-wp.mjs +327 -0
- package/templates/skills/sb-build-wp/scripts/tests/test-build-wp.mjs +224 -0
- package/templates/skills/sb-compare-visual/SKILL.md +121 -0
- package/templates/skills/sb-compare-visual/scripts/compare-visual.mjs +387 -0
- package/templates/skills/sb-compare-visual/scripts/lib/compare-tokens.mjs +273 -0
- package/templates/skills/sb-compare-visual/scripts/tests/test-compare-tokens.mjs +350 -0
- package/templates/skills/sb-compare-visual/scripts/tests/test-compare-visual.mjs +626 -0
- package/templates/skills/sb-crawl-and-list/SKILL.md +99 -0
- package/templates/skills/sb-crawl-and-list/scripts/crawl-and-list.mjs +437 -0
- package/templates/skills/sb-crawl-and-list/scripts/lib/blocklist-filter.mjs +176 -0
- package/templates/skills/sb-crawl-and-list/scripts/lib/fallback-crawler.mjs +107 -0
- package/templates/skills/sb-crawl-and-list/scripts/lib/page-classifier.mjs +89 -0
- package/templates/skills/sb-crawl-and-list/scripts/lib/sitemap-parser.mjs +118 -0
- package/templates/skills/sb-crawl-and-list/scripts/tests/test-blocklist-filter.mjs +204 -0
- package/templates/skills/sb-crawl-and-list/scripts/tests/test-crawl-and-list.mjs +276 -0
- package/templates/skills/sb-crawl-and-list/scripts/tests/test-fallback-crawler.mjs +243 -0
- package/templates/skills/sb-crawl-and-list/scripts/tests/test-page-classifier.mjs +120 -0
- package/templates/skills/sb-crawl-and-list/scripts/tests/test-sitemap-parser.mjs +157 -0
- package/templates/skills/sb-extract-assets/SKILL.md +112 -0
- package/templates/skills/sb-extract-assets/scripts/extract-assets.mjs +484 -0
- package/templates/skills/sb-extract-assets/scripts/tests/test-extract-assets.mjs +112 -0
- package/templates/skills/sb-inspect-live/SKILL.md +105 -0
- package/templates/skills/sb-inspect-live/scripts/inspect-live.mjs +693 -0
- package/templates/skills/sb-inspect-live/scripts/tests/test-inspect-live.mjs +181 -0
- package/templates/skills/sb-review-checks/SKILL.md +113 -0
- package/templates/skills/sb-review-checks/references/review-rules.md +195 -0
- package/templates/skills/sb-review-checks/scripts/lib/anti-patterns.mjs +379 -0
- package/templates/skills/sb-review-checks/scripts/lib/cross-reference.mjs +115 -0
- package/templates/skills/sb-review-checks/scripts/lib/design-quality.mjs +541 -0
- package/templates/skills/sb-review-checks/scripts/review-checks.mjs +250 -0
- package/templates/skills/sb-review-checks/scripts/tests/test-anti-patterns.mjs +343 -0
- package/templates/skills/sb-review-checks/scripts/tests/test-cross-reference.mjs +170 -0
- package/templates/skills/sb-review-checks/scripts/tests/test-design-quality.mjs +493 -0
- package/templates/skills/sb-review-checks/scripts/tests/test-review-checks.mjs +267 -0
- package/templates/skills/sb-tweak/SKILL.md +130 -0
- package/templates/skills/sb-tweak/references/tweak-patterns.md +157 -0
- package/templates/skills/sb-tweak/scripts/lib/diff-summarizer.mjs +140 -0
- package/templates/skills/sb-tweak/scripts/lib/element-locator.mjs +507 -0
- package/templates/skills/sb-tweak/scripts/lib/intent-parser.mjs +324 -0
- package/templates/skills/sb-tweak/scripts/tests/test-diff-summarizer.mjs +248 -0
- package/templates/skills/sb-tweak/scripts/tests/test-element-locator.mjs +418 -0
- package/templates/skills/sb-tweak/scripts/tests/test-intent-parser.mjs +496 -0
- package/templates/skills/sb-tweak/scripts/tests/test-tweak.mjs +407 -0
- package/templates/skills/sb-tweak/scripts/tweak.mjs +656 -0
- package/templates/skills/sb-validate-render/SKILL.md +120 -0
- package/templates/skills/sb-validate-render/scripts/tests/test-validate-render.mjs +304 -0
- 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
|
+
[](https://www.npmjs.com/package/similarbuild)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
[](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
|
+
});
|