launchframe 0.1.7 → 0.1.9
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/README.md +238 -229
- package/package.json +2 -1
- package/packages/extract/dom-crawler.ts +521 -521
- package/packages/extract/emit.ts +534 -466
- package/packages/extract/extract.ts +443 -441
- package/packages/extract/mirror-emit.ts +617 -617
- package/packages/extract/reference-dump.ts +431 -230
- package/packages/extract/types.ts +311 -311
package/README.md
CHANGED
|
@@ -1,229 +1,238 @@
|
|
|
1
|
-
# launchframe
|
|
2
|
-
|
|
3
|
-
> Point Launchframe at SaaS sites you admire. Get back a drop-in
|
|
4
|
-
> shadcn/ui design system you can build your own UI on top of —
|
|
5
|
-
> with a ready-made handoff for Cursor or Claude Code.
|
|
6
|
-
|
|
7
|
-
`launchframe` opens each URL in headless Chromium, harvests the
|
|
8
|
-
**computed appearance** of the rendered page (colors, type, spacing,
|
|
9
|
-
radii, shadows), and synthesizes an original design system as
|
|
10
|
-
`tailwind.config.ts` + `globals.css` + `tokens.json` + a Markdown
|
|
11
|
-
report and an AI-handoff file.
|
|
12
|
-
|
|
13
|
-
It also crawls the rendered DOM into a typed `SiteLayout` and emits a
|
|
14
|
-
**layout-mirror page** per source: a Next.js component that reconstructs
|
|
15
|
-
the source's section tree, grid, and density from typed primitives, with
|
|
16
|
-
`<TextSlot>` / `<MediaSlot>` placeholders where the source had copy,
|
|
17
|
-
logos, illustrations, or product imagery. The mirror does **not** embed
|
|
18
|
-
the source's copy text, brand assets, or product screenshots — fill those
|
|
19
|
-
slots with your own content before shipping. Proprietary type families
|
|
20
|
-
are substituted with open-source equivalents.
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Quick start (any folder)
|
|
25
|
-
|
|
26
|
-
The design system is written to **`./output/<runId>/`** in whatever
|
|
27
|
-
directory you run the command from — not inside the package.
|
|
28
|
-
|
|
29
|
-
**One time per machine** (Chromium for Playwright):
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx playwright install chromium
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**Every time you want a new theme:**
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
cd path/to/your-app-or-empty-folder
|
|
39
|
-
npx launchframe@latest https://site-a.example https://site-b.example
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
When it finishes, every source URL has produced a **layout-mirror
|
|
43
|
-
page** under `output/<runId>/mirror/<host>/page.tsx`, plus a synthesized
|
|
44
|
-
design system at the run root.
|
|
45
|
-
|
|
46
|
-
```txt
|
|
47
|
-
output/<runId>/
|
|
48
|
-
├── FOR_AI.md ← paste / @-attach this for your AI (handoff instructions)
|
|
49
|
-
├── tokens.json ← every aggregated value, machine-readable
|
|
50
|
-
├── tailwind.config.ts ← drop-in Tailwind theme
|
|
51
|
-
├── globals.css ← drop-in shadcn-compatible CSS variables
|
|
52
|
-
├── theme-preview.tsx ← render this to eyeball the system
|
|
53
|
-
├── REPORT.md ← what was extracted, from where, why
|
|
54
|
-
├── run.json ← full run metadata (sources, timing, status)
|
|
55
|
-
├── screenshots/ ← captured PNGs
|
|
56
|
-
├── raw/ ← per-site raw token + SiteLayout JSON
|
|
57
|
-
├── reference/ ← verbatim DOM + copy for AI
|
|
58
|
-
│ └── <host>/
|
|
59
|
-
│ ├── page.html
|
|
60
|
-
│ ├──
|
|
61
|
-
│ ├──
|
|
62
|
-
│ ├──
|
|
63
|
-
│ ├──
|
|
64
|
-
│
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
| `--
|
|
103
|
-
| `--
|
|
104
|
-
| `--
|
|
105
|
-
| `--
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
npm
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
├──
|
|
172
|
-
│
|
|
173
|
-
|
|
174
|
-
│ ├──
|
|
175
|
-
│ ├──
|
|
176
|
-
│ ├──
|
|
177
|
-
│
|
|
178
|
-
├──
|
|
179
|
-
|
|
180
|
-
├──
|
|
181
|
-
├──
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
npm run
|
|
191
|
-
npm run
|
|
192
|
-
npm run
|
|
193
|
-
npm run
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
1
|
+
# launchframe
|
|
2
|
+
|
|
3
|
+
> Point Launchframe at SaaS sites you admire. Get back a drop-in
|
|
4
|
+
> shadcn/ui design system you can build your own UI on top of —
|
|
5
|
+
> with a ready-made handoff for Cursor or Claude Code.
|
|
6
|
+
|
|
7
|
+
`launchframe` opens each URL in headless Chromium, harvests the
|
|
8
|
+
**computed appearance** of the rendered page (colors, type, spacing,
|
|
9
|
+
radii, shadows), and synthesizes an original design system as
|
|
10
|
+
`tailwind.config.ts` + `globals.css` + `tokens.json` + a Markdown
|
|
11
|
+
report and an AI-handoff file.
|
|
12
|
+
|
|
13
|
+
It also crawls the rendered DOM into a typed `SiteLayout` and emits a
|
|
14
|
+
**layout-mirror page** per source: a Next.js component that reconstructs
|
|
15
|
+
the source's section tree, grid, and density from typed primitives, with
|
|
16
|
+
`<TextSlot>` / `<MediaSlot>` placeholders where the source had copy,
|
|
17
|
+
logos, illustrations, or product imagery. The mirror does **not** embed
|
|
18
|
+
the source's copy text, brand assets, or product screenshots — fill those
|
|
19
|
+
slots with your own content before shipping. Proprietary type families
|
|
20
|
+
are substituted with open-source equivalents.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick start (any folder)
|
|
25
|
+
|
|
26
|
+
The design system is written to **`./output/<runId>/`** in whatever
|
|
27
|
+
directory you run the command from — not inside the package.
|
|
28
|
+
|
|
29
|
+
**One time per machine** (Chromium for Playwright):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx playwright install chromium
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Every time you want a new theme:**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cd path/to/your-app-or-empty-folder
|
|
39
|
+
npx launchframe@latest https://site-a.example https://site-b.example
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
When it finishes, every source URL has produced a **layout-mirror
|
|
43
|
+
page** under `output/<runId>/mirror/<host>/page.tsx`, plus a synthesized
|
|
44
|
+
design system at the run root.
|
|
45
|
+
|
|
46
|
+
```txt
|
|
47
|
+
output/<runId>/
|
|
48
|
+
├── FOR_AI.md ← paste / @-attach this for your AI (handoff instructions)
|
|
49
|
+
├── tokens.json ← every aggregated value, machine-readable
|
|
50
|
+
├── tailwind.config.ts ← drop-in Tailwind theme
|
|
51
|
+
├── globals.css ← drop-in shadcn-compatible CSS variables
|
|
52
|
+
├── theme-preview.tsx ← render this to eyeball the system
|
|
53
|
+
├── REPORT.md ← what was extracted, from where, why
|
|
54
|
+
├── run.json ← full run metadata (sources, timing, status)
|
|
55
|
+
├── screenshots/ ← captured PNGs
|
|
56
|
+
├── raw/ ← per-site raw token + SiteLayout JSON
|
|
57
|
+
├── reference/ ← verbatim DOM + **exact structure JSON** + copy for AI
|
|
58
|
+
│ └── <host>/
|
|
59
|
+
│ ├── page.html
|
|
60
|
+
│ ├── dom-structure.json ← canonical body tree (tags, attrs, text nodes)
|
|
61
|
+
│ ├── structure-outline.txt ← tag skeleton for quick scanning
|
|
62
|
+
│ ├── visible-text.txt
|
|
63
|
+
│ ├── visible-text.json
|
|
64
|
+
│ ├── media.json
|
|
65
|
+
│ ├── meta.json
|
|
66
|
+
│ └── FOR_AI_REFERENCE.md
|
|
67
|
+
└── mirror/
|
|
68
|
+
└── <host>/
|
|
69
|
+
├── page.tsx ← Next.js: Motion + Phosphor + image/video patterns
|
|
70
|
+
├── layout.json
|
|
71
|
+
└── MIRROR_NOTES.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Hand the output to your AI
|
|
77
|
+
|
|
78
|
+
1. Run the command above so `output/<runId>/` exists.
|
|
79
|
+
2. Attach **`reference/<host>/`**, especially **`dom-structure.json`** (exact tree) and **`visible-text.*`**, plus **`page.html`** and **`media.json`** so the model sees **exact structure and copy** from the crawl.
|
|
80
|
+
3. Pick the mirror folder: `output/<runId>/mirror/<host>/`.
|
|
81
|
+
4. Either:
|
|
82
|
+
- **Cursor:** `@`-attach `reference/<host>/`, `mirror/<host>/`, `FOR_AI.md`, and
|
|
83
|
+
`tokens.json`, then ask the agent to port copy from `visible-text.txt` into
|
|
84
|
+
`page.tsx` and wire media from `media.json`.
|
|
85
|
+
- **Claude Code:** copy both folders into your project, then ask the same.
|
|
86
|
+
5. The AI's authority order is **`dom-structure.json` (nesting) → `structure-outline.txt` / `page.html` → `visible-text.*` →
|
|
87
|
+
MIRROR_NOTES.md → mirror `page.tsx` → tokens.json → tailwind.config.ts + globals.css**. It must:
|
|
88
|
+
- Keep the section tree, grid composition, density, Motion, and Phosphor usage in `page.tsx`.
|
|
89
|
+
- Map strings from `visible-text.txt` into the right `<TextSlot>` slots (or replace slots with plain JSX).
|
|
90
|
+
- Use `media.json` for image/video `src` / `poster` (respect licensing; prefer your own assets).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## CLI reference
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx launchframe <url> [<url> ...] [options]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
| Flag | Default | Notes |
|
|
101
|
+
| -------------- | -------------------- | -------------------------------------------------------- |
|
|
102
|
+
| `--out <dir>` | `./output/<runId>` (under **current working directory**) | Absolute or relative path for the run folder |
|
|
103
|
+
| `--name <slug>`| _(unset)_ | Append a slug to the runId for findability |
|
|
104
|
+
| `--no-robots` | _(off)_ | Skip robots.txt check (not recommended) |
|
|
105
|
+
| `--rate <n>` | `15` | Per-domain requests per minute |
|
|
106
|
+
| `--width <px>` | `1440` | Viewport width |
|
|
107
|
+
| `--height <px>`| `900` | Viewport height |
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx launchframe https://example.com --name my-brand
|
|
111
|
+
npx launchframe https://a.example https://b.example https://c.example --width 1280
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## What the extractor actually does
|
|
117
|
+
|
|
118
|
+
For each URL:
|
|
119
|
+
|
|
120
|
+
1. Open the page in headless Chromium at a 1440 × 900 desktop viewport.
|
|
121
|
+
2. Take a full-page screenshot.
|
|
122
|
+
3. Walk the rendered DOM and harvest **computed styles** for every
|
|
123
|
+
visible element:
|
|
124
|
+
- Text and background colors, weighted by area
|
|
125
|
+
- Font families, sizes, weights, line-heights, letter-spacing
|
|
126
|
+
- Padding, gap, and margin values (snapped to a 4 px grid)
|
|
127
|
+
- Border radii (mode-picked across the page)
|
|
128
|
+
- Box-shadow stacks
|
|
129
|
+
- Dominant container width (the layout signal)
|
|
130
|
+
4. Save the raw observations as JSON.
|
|
131
|
+
|
|
132
|
+
After every site is captured, the synthesizer:
|
|
133
|
+
|
|
134
|
+
1. Clusters all colors into a representative palette and derives a full
|
|
135
|
+
shadcn-compatible ramp (`--background`, `--foreground`, `--primary`,
|
|
136
|
+
…) for both light and dark themes.
|
|
137
|
+
2. Picks a body base size from the count-weighted mode of body-range
|
|
138
|
+
font sizes, then fits a single scale ratio that lands the largest
|
|
139
|
+
observed heading at the `6xl` step. Substitutes proprietary type
|
|
140
|
+
families (e.g. SF Pro, Söhne, Circular, Graphik) with open-source
|
|
141
|
+
equivalents.
|
|
142
|
+
3. Snaps spacing values to a 4 px scale, takes the most-used buckets,
|
|
143
|
+
and computes a recommended container width from the median dominant
|
|
144
|
+
block width across the corpus.
|
|
145
|
+
4. Picks a representative radius and emits a tasteful three-stop shadow
|
|
146
|
+
scale.
|
|
147
|
+
5. Writes drop-in files plus a Markdown report attributing every source.
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
URLs ──▶ Playwright ──▶ raw tokens.json ──▶ synthesize ──▶ DesignSystem ──▶ emit
|
|
151
|
+
(per site) (one corpus)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Run inside this repo (contributors)
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
git clone https://github.com/evangruhlkey/launchframe
|
|
160
|
+
cd launchframe
|
|
161
|
+
npm install
|
|
162
|
+
npx playwright install chromium
|
|
163
|
+
npm run extract -- https://site-a.example https://site-b.example
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The repo is a monorepo that also contains a research framework for
|
|
167
|
+
classifying SaaS UI patterns and generating original shadcn blocks:
|
|
168
|
+
|
|
169
|
+
```txt
|
|
170
|
+
launchframe/
|
|
171
|
+
├── apps/
|
|
172
|
+
│ └── studio/ # Next.js dashboard for browsing patterns/blocks
|
|
173
|
+
├── packages/
|
|
174
|
+
│ ├── extract/ # ← the published CLI
|
|
175
|
+
│ ├── capture/ # Playwright screenshot capture (lower level)
|
|
176
|
+
│ ├── analysis/ # Layout-tree extraction & section classifier
|
|
177
|
+
│ ├── patterns/ # Typed pattern schemas + atlas registry loader
|
|
178
|
+
│ ├── blocks/ # Shadcn/ui blocks + TextSlot / MediaSlot primitives
|
|
179
|
+
│ └── evaluation/ # Coherence + responsiveness/a11y evaluator
|
|
180
|
+
├── pattern-atlas/ # Pattern catalog per category (block-composition mode)
|
|
181
|
+
├── prompts/ # Markdown prompts for AI agents
|
|
182
|
+
├── rules/ # Design / copy / a11y rules
|
|
183
|
+
├── registry/ # shadcn-compatible custom registry manifest
|
|
184
|
+
└── output/ # ← every `extract` run lands here
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Other commands (repo-only):
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm run studio # Next.js dashboard at localhost:3000
|
|
191
|
+
npm run capture # Lower-level Playwright capture pipeline
|
|
192
|
+
npm run analyze # Run section classifier on captured screenshots
|
|
193
|
+
npm run formalize # Validate the pattern-atlas/*.json files
|
|
194
|
+
npm run evaluate # Grade a generated page (coherence + a11y)
|
|
195
|
+
npm run typecheck # Project-wide TypeScript check
|
|
196
|
+
npm run sync:agents # Regenerate Copilot / Cline / Continue / Amazon Q stubs from AGENTS.md
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### AI agents in this repo
|
|
200
|
+
|
|
201
|
+
- **`AGENTS.md`** (root) is the **single source of truth** for how agents should work here (extract handoff, structure fidelity, compliance). **`docs/research/INSPECTION_GUIDE.md`** is inlined into derived configs when you run `npm run sync:agents`.
|
|
202
|
+
- **Cursor:** `.cursor/rules/project.mdc` points at `AGENTS.md`.
|
|
203
|
+
- **Claude Code / Gemini CLI:** `CLAUDE.md` and `GEMINI.md` import `AGENTS.md`.
|
|
204
|
+
- Edit `AGENTS.md`, then run `npm run sync:agents` (or `bash scripts/sync-agent-rules.sh`) to refresh `.github/copilot-instructions.md`, `.clinerules`, `.continue/rules/project.md`, and `.amazonq/rules/project.md`.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## What this is not
|
|
209
|
+
|
|
210
|
+
- **Not the source site's frontend bundle.** The **layout mirror** is React
|
|
211
|
+
code emitted from a typed `SiteLayout` (section tree, composition,
|
|
212
|
+
density) — not a dump of the origin's original components or stylesheets.
|
|
213
|
+
- **Not a substitute for legal clearance.** `reference/<host>/` may contain
|
|
214
|
+
serialized DOM and visible text for tooling **you** run on pages you are
|
|
215
|
+
allowed to analyze. You are responsible for trademarks, copy licenses, and
|
|
216
|
+
`robots.txt`/ToS compliance when using those artifacts.
|
|
217
|
+
- **Not a component library replacement.** Launchframe sits *alongside*
|
|
218
|
+
shadcn/ui: theme files, reference dumps, and slot-driven mirror pages —
|
|
219
|
+
you integrate into your own app.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Responsible use in one paragraph
|
|
224
|
+
|
|
225
|
+
Launchframe is intended for layout research and design-system seeding
|
|
226
|
+
against pages you have permission to analyze (your own products, sites
|
|
227
|
+
where the operator has permission, or pages where structural analysis is
|
|
228
|
+
permitted by `robots.txt`). The crawler respects `robots.txt` by default
|
|
229
|
+
and rate-limits per domain. Output includes synthesized theme files, a
|
|
230
|
+
typed **mirror** page scaffold, and (per capture) a **reference** bundle
|
|
231
|
+
(DOM snapshot, visible text, media URLs) for AI-assisted reconstruction.
|
|
232
|
+
Operators remain responsible for how they use copy, media, and branding.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
MIT. See [`LICENSE`](./LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "launchframe",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Point Launchframe at SaaS sites you admire and get back a drop-in shadcn/ui design system (tokens, Tailwind theme, CSS variables, AI handoff) you can build your own UI on top of.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Evan Gruhlkey",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"analyze": "tsx packages/analysis/analyze-screenshot.ts",
|
|
47
47
|
"formalize": "tsx packages/patterns/pattern-registry.ts",
|
|
48
48
|
"evaluate": "tsx packages/evaluation/evaluate-page.ts",
|
|
49
|
+
"sync:agents": "node scripts/sync-agent-rules.mjs",
|
|
49
50
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
50
51
|
"format:check": "prettier --check ."
|
|
51
52
|
},
|