webcake-landing-mcp 1.0.4 → 1.0.5
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 +47 -1
- package/README.vi.md +608 -0
- package/dist/factory.js +4 -34
- package/dist/library.js +15 -0
- package/dist/smoke.js +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,50 @@
|
|
|
1
|
-
# WebCake Landing MCP
|
|
1
|
+
# 🍰 WebCake Landing MCP
|
|
2
|
+
|
|
3
|
+
**English** · [Tiếng Việt](./README.vi.md)
|
|
4
|
+
|
|
5
|
+
> **Describe a landing page in plain words — your AI builds it, checks it, and ships it straight to WebCake.**
|
|
6
|
+
|
|
7
|
+
> *"Build a landing page for my coffee shop — a hero with a sign-up button, a 3-feature section, and a lead form. Save it to my workspace."*
|
|
8
|
+
|
|
9
|
+
…and a real, **editable** WebCake page appears in your account. No dragging boxes, no learning the schema, no hand-writing JSON.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🧩 How it works
|
|
14
|
+
|
|
15
|
+
This server is the **bridge** between your AI assistant and WebCake. The AI never *guesses* what a WebCake
|
|
16
|
+
page looks like — it asks this MCP, which knows the entire element model, validates the result, and saves it for you.
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
You AI assistant webcake-landing MCP WebCake
|
|
20
|
+
┌──────┐ prompt ┌────────────┐ tools ┌──────────────────────┐ API ┌──────────┐
|
|
21
|
+
│ idea │ ───────► │ Claude / │ ──────► │ • knows the element │ ────► │ a real │
|
|
22
|
+
│ │ │ Cursor / │ │ model + AI hints │ │ editable │
|
|
23
|
+
│ │ ◄─────── │ Windsurf │ ◄────── │ • builds + validates │ ◄──── │ page in │
|
|
24
|
+
└──────┘ page URL └────────────┘ result │ • saves to your acct │ │ WebCake │
|
|
25
|
+
└──────────────────────┘ └──────────┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
1. **You ask** in plain language — goal, brand, sections, CTA, form fields.
|
|
29
|
+
2. **The AI learns the model** from the MCP: the element catalog, the absolute-positioning canvas, the event vocabulary — so it builds a *real* WebCake page, not a guess.
|
|
30
|
+
3. **It assembles + validates** the full `{ page, popup, settings, options }` JSON. `validate_page` catches off-canvas boxes, dangling CTAs, and missing form fields **before** anything is saved.
|
|
31
|
+
4. **It persists** to your WebCake account — dry-run preview first, then for real.
|
|
32
|
+
5. **You get an editor link** — open it, tweak, publish. The AI did the heavy lifting.
|
|
33
|
+
|
|
34
|
+
### Why it's reliable
|
|
35
|
+
|
|
36
|
+
| | |
|
|
37
|
+
|---|---|
|
|
38
|
+
| 📚 **Knows the real model** | Serves WebCake's actual element catalog (40+ types — hero, form, countdown, gallery, product list…), each with its exact `specials` and AI hints, drawn straight from the editor's renderers. |
|
|
39
|
+
| ✅ **Validates before saving** | Structural + semantic checks (unique ids, on-canvas layout, working CTAs, unique form fields) so the page isn't broken when it lands. |
|
|
40
|
+
| 🛡️ **Safe by default** | Every write is **dry-run first** (preview the request, token masked) — nothing touches your account until you confirm. |
|
|
41
|
+
| ✏️ **Edits surgically** | Ask for one change ("make the CTA green") and it edits *only* that element — every other id, coordinate, and block stays exactly as it was. |
|
|
42
|
+
|
|
43
|
+
> 💡 **Lead-gen, events, invitations, app promos** — or **selling COD/online**? It speaks WebCake's commerce model too (product lists, variations, cart).
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Under the hood
|
|
2
48
|
|
|
3
49
|
MCP (Model Context Protocol) server that teaches AI agents how to build a complete
|
|
4
50
|
**WebCake landing-page source JSON** from a requirement — and persist it to a WebCake backend.
|
package/README.vi.md
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# 🍰 WebCake Landing MCP
|
|
2
|
+
|
|
3
|
+
[English](./README.md) · **Tiếng Việt**
|
|
4
|
+
|
|
5
|
+
> **Mô tả landing page bằng lời nói — AI tự dựng, tự kiểm tra và đẩy thẳng lên WebCake.**
|
|
6
|
+
|
|
7
|
+
> *"Dựng cho tôi một landing page quán cà phê — một hero có nút đăng ký, một mục 3 tính năng, và một form thu lead. Lưu vào workspace của tôi."*
|
|
8
|
+
|
|
9
|
+
…và một trang WebCake **thật, sửa được** hiện ra trong tài khoản của bạn. Không kéo-thả từng khối, không cần học schema, không phải tự viết JSON.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🧩 Mô hình hoạt động
|
|
14
|
+
|
|
15
|
+
Server này là **cầu nối** giữa trợ lý AI và WebCake. AI không *đoán* trang WebCake trông thế nào —
|
|
16
|
+
nó hỏi MCP (vốn nắm trọn mô hình element), kiểm tra hợp lệ, rồi lưu giúp bạn.
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
Bạn Trợ lý AI webcake-landing MCP WebCake
|
|
20
|
+
┌──────┐ yêu cầu┌────────────┐ tools ┌──────────────────────┐ API ┌──────────┐
|
|
21
|
+
│ ý │ ───────►│ Claude / │ ──────► │ • nắm mô hình element│ ────► │ trang │
|
|
22
|
+
│ tưởng│ │ Cursor / │ │ + gợi ý cho AI │ │ thật, │
|
|
23
|
+
│ │ ◄───────│ Windsurf │ ◄────── │ • dựng + kiểm tra │ ◄──── │ sửa được│
|
|
24
|
+
└──────┘ link └────────────┘ kết quả │ • lưu vào tài khoản │ │ trên │
|
|
25
|
+
trang └──────────────────────┘ │ WebCake │
|
|
26
|
+
└──────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
1. **Bạn yêu cầu** bằng lời — mục tiêu, thương hiệu, các section, nút CTA, trường form.
|
|
30
|
+
2. **AI học mô hình** từ MCP: danh mục element, canvas toạ độ tuyệt đối, bộ sự kiện — nên nó dựng trang WebCake *thật*, không phải đoán.
|
|
31
|
+
3. **Dựng + kiểm tra** trọn JSON `{ page, popup, settings, options }`. `validate_page` bắt lỗi (element lệch khung, CTA trỏ sai, thiếu trường form) **trước khi** lưu.
|
|
32
|
+
4. **Lưu** vào tài khoản WebCake — xem trước dry-run, rồi mới lưu thật.
|
|
33
|
+
5. **Nhận link editor** — mở, chỉnh, publish. AI lo phần nặng.
|
|
34
|
+
|
|
35
|
+
### Vì sao đáng tin
|
|
36
|
+
|
|
37
|
+
| | |
|
|
38
|
+
|---|---|
|
|
39
|
+
| 📚 **Nắm đúng mô hình** | Cung cấp danh mục element thật của WebCake (40+ loại — hero, form, đếm ngược, gallery, danh sách sản phẩm…), mỗi loại kèm `specials` chính xác và gợi ý cho AI, rút thẳng từ renderer của editor. |
|
|
40
|
+
| ✅ **Kiểm tra trước khi lưu** | Kiểm tra cấu trúc + ngữ nghĩa (id duy nhất, layout trong khung, CTA hoạt động, trường form không trùng) để trang không hỏng khi lưu. |
|
|
41
|
+
| 🛡️ **An toàn mặc định** | Mọi thao tác ghi đều **dry-run trước** (xem trước request, token được che) — không đụng tài khoản của bạn cho tới khi bạn xác nhận. |
|
|
42
|
+
| ✏️ **Sửa đúng chỗ** | Yêu cầu một thay đổi ("đổi nút CTA sang xanh") thì nó chỉ sửa *đúng* element đó — mọi id, toạ độ, khối khác giữ nguyên. |
|
|
43
|
+
|
|
44
|
+
> 💡 **Thu lead, sự kiện, thiệp mời, quảng bá app** — hay **bán hàng COD/online**? Nó hiểu cả mô hình thương mại của WebCake (danh sách sản phẩm, biến thể, giỏ hàng).
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Bản chất kỹ thuật
|
|
49
|
+
|
|
50
|
+
Server MCP (Model Context Protocol) dạy AI cách dựng trọn **JSON nguồn (page_source) của landing page WebCake**
|
|
51
|
+
từ một yêu cầu — và lưu nó về backend WebCake.
|
|
52
|
+
|
|
53
|
+
Nó expose danh mục element, gợi ý dùng từng element + `specials`, JSON Schema đầy đủ của trang, skeleton
|
|
54
|
+
element/trang hợp lệ, bộ kiểm tra trang, và các tool để tạo/sửa trang trên backend. AI dựng trọn JSON
|
|
55
|
+
`{ page, popup, settings, options, cartConfigs }`; `create_page` lưu nó (chỉ-source — trang mở trong editor,
|
|
56
|
+
lưu lại sẽ render).
|
|
57
|
+
|
|
58
|
+
## Hai cách chạy
|
|
59
|
+
|
|
60
|
+
| Chế độ | Lệnh | Khi nào |
|
|
61
|
+
|------|------|------|
|
|
62
|
+
| **CDN / npx** (không clone) | `npx -y webcake-landing-mcp` | Khởi động nhanh nhất — npm tự tải & chạy, không cần clone hay build. Tự cập nhật bản mới nhất. |
|
|
63
|
+
| **Local** (clone & build) | `node /abs/path/dist/index.js` | Khi đang sửa server, offline, hoặc cần ghim một bản build cụ thể. Chạy `npm run build` trước. |
|
|
64
|
+
|
|
65
|
+
Cả hai cùng expose y hệt các tool. Mọi cấu hình IDE bên dưới dùng dạng **local**; để dùng **CDN**, chỉ cần
|
|
66
|
+
đổi `command`/`args` sang dạng npx (xem [Chạy không cần clone (npx)](#chạy-không-cần-clone-npx)).
|
|
67
|
+
|
|
68
|
+
## Cài nhanh (Khuyến nghị)
|
|
69
|
+
|
|
70
|
+
Chạy script tự cài — lo trọn gói: clone, cài dependencies, build, và cấu hình IDE của bạn.
|
|
71
|
+
|
|
72
|
+
### macOS / Linux
|
|
73
|
+
|
|
74
|
+
Nếu bạn đã clone repo:
|
|
75
|
+
```bash
|
|
76
|
+
./install.sh
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Hoặc tải & chạy trực tiếp:
|
|
80
|
+
```bash
|
|
81
|
+
curl -fsSL https://raw.githubusercontent.com/vuluu2k/webcake-landing-mcp/main/install.sh -o install.sh && bash install.sh
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Trình cài tương tác: hỏi nơi cài (mặc định `~/.webcake-landing-mcp`), hỏi các biến môi trường
|
|
85
|
+
(`WEBCAKE_API_BASE`, `WEBCAKE_JWT`, `WEBCAKE_ORG_ID` — đều tuỳ chọn, Enter để bỏ qua), rồi cho bạn chọn
|
|
86
|
+
IDE cần cấu hình: `claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment`, `codex`, hoặc tất cả.
|
|
87
|
+
|
|
88
|
+
Gỡ cài (xoá entry MCP server khỏi mọi IDE đã cấu hình):
|
|
89
|
+
```bash
|
|
90
|
+
./install.sh --uninstall
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Windows (PowerShell)
|
|
94
|
+
|
|
95
|
+
Nếu bạn đã clone repo:
|
|
96
|
+
```powershell
|
|
97
|
+
.\install.ps1
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Hoặc tải & chạy trực tiếp:
|
|
101
|
+
```powershell
|
|
102
|
+
irm https://raw.githubusercontent.com/vuluu2k/webcake-landing-mcp/main/install.ps1 -OutFile install.ps1; .\install.ps1
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Gỡ cài:
|
|
106
|
+
```powershell
|
|
107
|
+
.\install.ps1 --uninstall
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Cập nhật
|
|
113
|
+
|
|
114
|
+
Cập nhật lên bản mới nhất:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
cd ~/.webcake-landing-mcp # hoặc nơi bạn đã cài
|
|
118
|
+
git pull
|
|
119
|
+
npm install
|
|
120
|
+
npm run build
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Rồi khởi động lại IDE.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Chạy không cần clone (npx)
|
|
128
|
+
|
|
129
|
+
Sau khi đã publish lên npm, server chạy thẳng từ registry — không clone, không build:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx -y webcake-landing-mcp
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Hoặc chạy bản mới nhất từ GitHub (npx tự clone + build qua script `prepare`):
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npx -y github:vuluu2k/webcake-landing-mcp
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Tự cấu hình IDE (lệnh con `install`)
|
|
142
|
+
|
|
143
|
+
`npx` chỉ **chạy** server — khác với `install.sh`/`install.ps1`, nó không ghi cấu hình MCP vào IDE.
|
|
144
|
+
Lệnh con `install` đi kèm sẽ làm hộ bạn bước đó, không cần clone:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Tương tác — hỏi env + chọn IDE từng bước
|
|
148
|
+
npx -y webcake-landing-mcp install
|
|
149
|
+
|
|
150
|
+
# Không tương tác — cấu hình mọi IDE hỗ trợ cùng lúc
|
|
151
|
+
npx -y webcake-landing-mcp install --ide all --jwt <your-jwt> --api-base http://localhost:5800
|
|
152
|
+
|
|
153
|
+
# Chỉ một IDE
|
|
154
|
+
npx -y webcake-landing-mcp install --ide cursor --jwt <your-jwt>
|
|
155
|
+
|
|
156
|
+
# Gỡ server khỏi mọi cấu hình IDE
|
|
157
|
+
npx -y webcake-landing-mcp uninstall
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Nó ghi entry `webcake-landing` (dùng dạng khởi chạy `npx` bên dưới) vào đúng file cấu hình của từng IDE:
|
|
161
|
+
`claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment` (VS Code), `codex`, hoặc `all`. Cờ:
|
|
162
|
+
`--ide`, `--api-base`, `--jwt`, `--org-id`, `--host`, `--app-base`, `--npx`/`--local`, `-y`. Chạy
|
|
163
|
+
`npx -y webcake-landing-mcp --help` để xem đầy đủ.
|
|
164
|
+
|
|
165
|
+
### Cấu hình thủ công
|
|
166
|
+
|
|
167
|
+
Cấu hình MCP giống bản local, chỉ khác `command`/`args` trỏ tới `npx` thay vì file đã build:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"webcake-landing": {
|
|
173
|
+
"command": "npx",
|
|
174
|
+
"args": ["-y", "webcake-landing-mcp"],
|
|
175
|
+
"env": {
|
|
176
|
+
"WEBCAKE_API_BASE": "http://localhost:5800",
|
|
177
|
+
"WEBCAKE_JWT": "<your-jwt>"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
> npx cache lại package sau lần chạy đầu, nên các lần sau khởi động nhanh. Dùng phiên bản ghim
|
|
185
|
+
> (`webcake-landing-mcp@1.0.0`) nếu cần build tái lập được.
|
|
186
|
+
|
|
187
|
+
## Cài thủ công (local)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
git clone https://github.com/vuluu2k/webcake-landing-mcp.git
|
|
191
|
+
cd webcake-landing-mcp
|
|
192
|
+
npm install # postinstall `prepare` tự build dist/
|
|
193
|
+
npm run build # (re)build: tsc -> dist/ + copy page-schema.json
|
|
194
|
+
npm run smoke # self-test offline của factory + validator (in "ALL GOOD")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Các tool tham chiếu/kiểm tra chạy với **zero config**. Biến môi trường chỉ cần cho các tool lưu trữ
|
|
198
|
+
(`create_page`, `update_page`, `list_pages`, `get_page`, `list_organizations`).
|
|
199
|
+
|
|
200
|
+
## Biến môi trường
|
|
201
|
+
|
|
202
|
+
| Biến | Bắt buộc | Mô tả |
|
|
203
|
+
|----------|----------|-------------|
|
|
204
|
+
| `WEBCAKE_API_BASE` | Không* | Base URL backend, ví dụ `http://localhost:5800`. Cần để lưu trang. |
|
|
205
|
+
| `WEBCAKE_JWT` | Không* | JWT tài khoản (auth dashboard). Cần để lưu trang — sẽ hết hạn, làm mới khi cần. |
|
|
206
|
+
| `WEBCAKE_ORG_ID` | Không | Organization mặc định cho `create_page` (bị ghi đè bởi tham số `organization_id`). Bỏ trống → trang cá nhân. |
|
|
207
|
+
| `WEBCAKE_HOST` | Không | Header `Host` tuỳ chọn (Phoenix route theo host, ví dụ `builder.localhost`). |
|
|
208
|
+
| `WEBCAKE_APP_BASE` | Không | Base tuỳ chọn để dựng URL editor/preview trong kết quả. |
|
|
209
|
+
|
|
210
|
+
> \* `WEBCAKE_API_BASE` và `WEBCAKE_JWT` chỉ cần cho các tool lưu trữ. Các tool tham chiếu và kiểm tra
|
|
211
|
+
> (`get_generation_guide`, `list_elements`, `get_element`, `validate_page`, …) chạy không cần chúng.
|
|
212
|
+
|
|
213
|
+
> Lưu trang sẽ ghi một trang thật vào nơi `WEBCAKE_API_BASE` trỏ tới, dùng JWT làm tài khoản đó.
|
|
214
|
+
> Hãy bắt đầu với local/staging.
|
|
215
|
+
|
|
216
|
+
### Cách lấy `WEBCAKE_JWT`
|
|
217
|
+
|
|
218
|
+
1. Mở dashboard builder WebCake và đăng nhập
|
|
219
|
+
2. Mở DevTools (`F12` hoặc `Cmd + Option + I`)
|
|
220
|
+
3. Vào tab **Network** > click một trang bất kỳ
|
|
221
|
+
4. Tìm một request API (ví dụ `@me`, `organizations`…)
|
|
222
|
+
5. Trong **Request Headers**, copy giá trị sau `Authorization: Bearer ` → đó là `WEBCAKE_JWT`
|
|
223
|
+
6. Dùng tool `list_organizations` để liệt kê org và chọn `WEBCAKE_ORG_ID`
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Cấu hình theo IDE / công cụ AI
|
|
228
|
+
|
|
229
|
+
> Thay `/absolute-path/webcake-landing-mcp/dist/index.js` bên dưới bằng đường dẫn thật nơi bạn đã
|
|
230
|
+
> clone/build repo. Ví dụ: `/Users/username/webcake-landing-mcp/dist/index.js`.
|
|
231
|
+
> Chạy `npm run build` trước để `dist/` tồn tại.
|
|
232
|
+
|
|
233
|
+
### 1. Claude Desktop
|
|
234
|
+
|
|
235
|
+
Mở Settings > Developer > Edit Config, hoặc sửa file trực tiếp:
|
|
236
|
+
|
|
237
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
238
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
239
|
+
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"mcpServers": {
|
|
244
|
+
"webcake-landing": {
|
|
245
|
+
"command": "node",
|
|
246
|
+
"args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
|
|
247
|
+
"env": {
|
|
248
|
+
"WEBCAKE_API_BASE": "http://localhost:5800",
|
|
249
|
+
"WEBCAKE_JWT": "<your-jwt>",
|
|
250
|
+
"WEBCAKE_HOST": "builder.localhost",
|
|
251
|
+
"WEBCAKE_APP_BASE": "http://builder.localhost:5800"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Khởi động lại Claude Desktop. Các tool MCP sẽ hiện trong ô chat (biểu tượng búa).
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### 2. Claude Code (CLI)
|
|
263
|
+
|
|
264
|
+
Chạy trong terminal — bản **local**:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
claude mcp add webcake-landing \
|
|
268
|
+
-e WEBCAKE_API_BASE=http://localhost:5800 \
|
|
269
|
+
-e WEBCAKE_JWT=<your-jwt> \
|
|
270
|
+
-e WEBCAKE_HOST=builder.localhost \
|
|
271
|
+
-- node /absolute-path/webcake-landing-mcp/dist/index.js
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Hoặc **CDN / npx** (không clone):
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
claude mcp add webcake-landing \
|
|
278
|
+
-e WEBCAKE_API_BASE=http://localhost:5800 \
|
|
279
|
+
-e WEBCAKE_JWT=<your-jwt> \
|
|
280
|
+
-- npx -y webcake-landing-mcp
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Hoặc tạo `.claude.json` ở thư mục gốc dự án (hoặc `~/.claude.json` toàn cục):
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"mcpServers": {
|
|
288
|
+
"webcake-landing": {
|
|
289
|
+
"command": "node",
|
|
290
|
+
"args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
|
|
291
|
+
"env": {
|
|
292
|
+
"WEBCAKE_API_BASE": "http://localhost:5800",
|
|
293
|
+
"WEBCAKE_JWT": "<your-jwt>"
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Kiểm tra:
|
|
301
|
+
```bash
|
|
302
|
+
claude mcp list
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### 3. Cursor
|
|
308
|
+
|
|
309
|
+
Tạo `.cursor/mcp.json` ở gốc dự án (hoặc `~/.cursor/mcp.json` toàn cục):
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"mcpServers": {
|
|
314
|
+
"webcake-landing": {
|
|
315
|
+
"command": "node",
|
|
316
|
+
"args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
|
|
317
|
+
"env": {
|
|
318
|
+
"WEBCAKE_API_BASE": "http://localhost:5800",
|
|
319
|
+
"WEBCAKE_JWT": "<your-jwt>"
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Khởi động lại Cursor và xem Settings > MCP Servers để thấy trạng thái **"Connected"**.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### 4. Windsurf
|
|
331
|
+
|
|
332
|
+
Tạo `~/.codeium/windsurf/mcp_config.json`:
|
|
333
|
+
|
|
334
|
+
```json
|
|
335
|
+
{
|
|
336
|
+
"mcpServers": {
|
|
337
|
+
"webcake-landing": {
|
|
338
|
+
"command": "node",
|
|
339
|
+
"args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
|
|
340
|
+
"env": {
|
|
341
|
+
"WEBCAKE_API_BASE": "http://localhost:5800",
|
|
342
|
+
"WEBCAKE_JWT": "<your-jwt>"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Khởi động lại Windsurf. Gõ `@` trong chat Cascade để thấy các tool `webcake-landing`.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### 5. Augment (Extension VS Code)
|
|
354
|
+
|
|
355
|
+
Mở Command Palette: `Cmd + Shift + P` > **"Augment: Edit MCP Settings"**, rồi thêm:
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"mcpServers": {
|
|
360
|
+
"webcake-landing": {
|
|
361
|
+
"command": "node",
|
|
362
|
+
"args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
|
|
363
|
+
"env": {
|
|
364
|
+
"WEBCAKE_API_BASE": "http://localhost:5800",
|
|
365
|
+
"WEBCAKE_JWT": "<your-jwt>"
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Khởi động lại VS Code.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### 6. Codex (OpenAI CLI)
|
|
377
|
+
|
|
378
|
+
Thêm vào `~/.codex/config.toml`:
|
|
379
|
+
|
|
380
|
+
```toml
|
|
381
|
+
[mcp_servers.webcake-landing]
|
|
382
|
+
command = "node"
|
|
383
|
+
args = ["/absolute-path/webcake-landing-mcp/dist/index.js"]
|
|
384
|
+
env = { "WEBCAKE_API_BASE" = "http://localhost:5800", "WEBCAKE_JWT" = "<your-jwt>" }
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Kiểm tra:
|
|
388
|
+
```bash
|
|
389
|
+
codex mcp list
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Ví dụ sử dụng
|
|
395
|
+
|
|
396
|
+
### Ví dụ 1: Dựng landing page mới từ một brief
|
|
397
|
+
|
|
398
|
+
**Prompt:**
|
|
399
|
+
```
|
|
400
|
+
Dựng cho tôi một landing page WebCake cho "Acme Coffee" — một hero có CTA, một mục 3 tính năng,
|
|
401
|
+
và một form đăng ký. Lưu vào org mặc định của tôi.
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**AI sẽ tự động:**
|
|
405
|
+
|
|
406
|
+
**Bước 1** — Gọi `get_generation_guide` để học quy ước (canvas, hệ toạ độ, sự kiện, workflow)
|
|
407
|
+
|
|
408
|
+
**Bước 2** — Gọi `new_page_skeleton` để có source top-level rỗng, rồi `get_element` cho từng loại element nó dùng:
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
get_element({ type: "section" })
|
|
412
|
+
get_element({ type: "text-block" })
|
|
413
|
+
get_element({ type: "button" })
|
|
414
|
+
get_element({ type: "form" })
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Bước 3** — Lắp trọn JSON `{ page, popup, settings, options, cartConfigs }`, rồi kiểm tra:
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
validate_page({ source })
|
|
421
|
+
→ { ok: false, errors: ["BUTTON-2: event target 'POPUP-9' not found"] } # sửa hết lỗi, validate lại
|
|
422
|
+
validate_page({ source })
|
|
423
|
+
→ { ok: true, errors: [] }
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Bước 4** — Lưu (dry-run trước, rồi mới thật):
|
|
427
|
+
|
|
428
|
+
```
|
|
429
|
+
list_organizations({}) → chọn org
|
|
430
|
+
create_page({ source }) → xem trước dry-run (JWT được che)
|
|
431
|
+
create_page({ source, dry_run: false }) → { page_id, editor_url, preview_url }
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Mở trang trong editor và lưu lại để render `app`/`app_css`.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
### Ví dụ 2: Sửa một trang có sẵn
|
|
439
|
+
|
|
440
|
+
**Prompt:**
|
|
441
|
+
```
|
|
442
|
+
Trên landing page "Acme Coffee" của tôi, đổi headline hero thành "Freshly Roasted Daily"
|
|
443
|
+
và làm nút CTA màu xanh lá.
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**AI sửa đúng chỗ — không bao giờ dựng lại cả cây:**
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
# Bước 1: tìm trang
|
|
450
|
+
list_pages({})
|
|
451
|
+
→ [{ id: "page_42", name: "Acme Coffee", organization_id: "org_1", ... }]
|
|
452
|
+
|
|
453
|
+
# Bước 2: lấy cây source đã decode
|
|
454
|
+
get_page({ page_id: "page_42" })
|
|
455
|
+
|
|
456
|
+
# Bước 3: chỉ đổi text headline + màu nút, giữ mọi id/toạ độ khác,
|
|
457
|
+
# rồi validate và ghi lại
|
|
458
|
+
validate_page({ source }) → ok
|
|
459
|
+
update_page({ page_id: "page_42", source }) → xem trước dry-run
|
|
460
|
+
update_page({ page_id: "page_42", source, dry_run: false })
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
### Ví dụ 3: Xem chi tiết một loại element trước khi dùng
|
|
466
|
+
|
|
467
|
+
**Prompt:**
|
|
468
|
+
```
|
|
469
|
+
Một element form cần những specials gì, và cho tôi xem một ví dụ hợp lệ.
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**AI gọi:**
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
get_element({ type: "form" })
|
|
476
|
+
→ {
|
|
477
|
+
hints: "Mỗi input cần một specials.field_name duy nhất…",
|
|
478
|
+
specials: { ... },
|
|
479
|
+
skeleton: { ... }, # node mặc định hợp lệ về cấu trúc
|
|
480
|
+
example: { ... } # ví dụ đã điền, thực tế
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## Hướng dẫn dùng tool chi tiết
|
|
487
|
+
|
|
488
|
+
Các tool chia thành ba nhóm: **tham chiếu** (học mô hình — không cần config),
|
|
489
|
+
**generation** (dựng node hợp lệ), và **lưu trữ** (ghi về backend — cần biến môi trường).
|
|
490
|
+
|
|
491
|
+
### Bước 1: Đọc guide trước — `get_generation_guide`
|
|
492
|
+
|
|
493
|
+
Luôn gọi cái này **đầu tiên**. Nó trả về hình dạng output, hệ toạ độ (desktop ≈ 960px,
|
|
494
|
+
mobile ≈ 420px), bộ từ vựng sự kiện, và workflow đầu-cuối.
|
|
495
|
+
|
|
496
|
+
```
|
|
497
|
+
get_generation_guide({})
|
|
498
|
+
→ "## Output shape… ## Canvas… ## Events… ## Workflow…"
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Bước 2: Duyệt danh mục element — `list_elements` / `get_element`
|
|
502
|
+
|
|
503
|
+
```
|
|
504
|
+
# Mọi loại element theo nhóm (tóm tắt + khi nào dùng + có phải container?)
|
|
505
|
+
list_elements({})
|
|
506
|
+
→ { categories: { layout: [...], content: [...], form: [...], ... } }
|
|
507
|
+
|
|
508
|
+
# Xem sâu một loại — hints, specials chính, skeleton mặc định, ví dụ đã điền
|
|
509
|
+
get_element({ type: "button" })
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Bước 3: Lấy khối dựng hợp lệ — `new_element` / `new_page_skeleton`
|
|
513
|
+
|
|
514
|
+
```
|
|
515
|
+
# Một node mặc định hợp lệ về cấu trúc cho một loại (id mới)
|
|
516
|
+
new_element({ type: "section" })
|
|
517
|
+
|
|
518
|
+
# Một source top-level rỗng nhưng đầy đủ
|
|
519
|
+
new_page_skeleton({})
|
|
520
|
+
→ { page: [], popup: [], settings: {…}, options: { currency, mobileOnly, versionID }, cartConfigs: {} }
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Bước 4: Xem / kiểm tra — `get_page_schema` / `validate_page`
|
|
524
|
+
|
|
525
|
+
```
|
|
526
|
+
# JSON Schema đầy đủ (Draft 2020-12) của một page source
|
|
527
|
+
get_page_schema({})
|
|
528
|
+
|
|
529
|
+
# Kiểm tra cấu trúc + ngữ nghĩa — sửa hết lỗi trước khi lưu
|
|
530
|
+
validate_page({ source })
|
|
531
|
+
→ { ok: false, errors: [...], warnings: [...] }
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
`validate_page` **errors là chặn**; warnings (event target lửng lơ, thiếu `field_name`) chỉ là khuyến cáo.
|
|
535
|
+
|
|
536
|
+
### Bước 5: Lưu — `list_organizations` / `create_page` / `update_page`
|
|
537
|
+
|
|
538
|
+
```
|
|
539
|
+
# Liệt kê các organization của tài khoản — hỏi dùng cái nào; mặc định = org is_default
|
|
540
|
+
list_organizations({})
|
|
541
|
+
→ [{ id: "org_1", name: "Acme", is_default: true }, ...]
|
|
542
|
+
|
|
543
|
+
# Tạo trang MỚI (chỉ-source). Mặc định dry_run=true.
|
|
544
|
+
create_page({ source, organization_id: "org_1" }) # xem trước
|
|
545
|
+
create_page({ source, dry_run: false }) # tạo thật
|
|
546
|
+
|
|
547
|
+
# Sửa một trang CÓ SẴN
|
|
548
|
+
list_pages({}) # tìm trang
|
|
549
|
+
get_page({ page_id }) # lấy source đã decode
|
|
550
|
+
update_page({ page_id, source, dry_run: false }) # ghi đè (mặc định dry_run=true)
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
`create_page` gọi **`POST {WEBCAKE_API_BASE}/api/v1/ai/create_page_from_source`** trên backend.
|
|
554
|
+
Cả `create_page` và `update_page` đều **mặc định `dry_run=true`** (kiểm tra và trả về request nó *sẽ*
|
|
555
|
+
gửi, JWT được che); đặt `dry_run=false` để ghi thật. Kết quả trả về `page_id` + URL editor/preview.
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Prompt gợi ý
|
|
560
|
+
|
|
561
|
+
> Dựng cho tôi một landing page WebCake cho <thương hiệu/ưu đãi>. Dùng MCP webcake-landing:
|
|
562
|
+
> gọi `get_generation_guide`, `new_page_skeleton`, rồi `get_element` cho từng loại element bạn dùng,
|
|
563
|
+
> lắp JSON `{ page, popup, settings, options }`, `validate_page` đến khi 0 lỗi,
|
|
564
|
+
> rồi `create_page` (dry-run trước).
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## Danh sách tool
|
|
569
|
+
|
|
570
|
+
### Tham chiếu (không cần config)
|
|
571
|
+
| Tool | Mô tả |
|
|
572
|
+
|------|-------------|
|
|
573
|
+
| `get_generation_guide` | **Đọc ĐẦU TIÊN.** Hình dạng output, hệ toạ độ, bộ sự kiện, workflow. |
|
|
574
|
+
| `list_elements` | Mọi loại element theo nhóm (tóm tắt + khi nào dùng + container?). |
|
|
575
|
+
| `get_element` | Một loại: hints, `specials` chính, skeleton mặc định, ví dụ đã điền. |
|
|
576
|
+
| `get_page_schema` | JSON Schema đầy đủ (Draft 2020-12) của một page source. |
|
|
577
|
+
|
|
578
|
+
### Generation
|
|
579
|
+
| Tool | Mô tả |
|
|
580
|
+
|------|-------------|
|
|
581
|
+
| `new_element` | Một node mặc định hợp lệ về cấu trúc cho một loại (id mới). |
|
|
582
|
+
| `new_page_skeleton` | Một source top-level rỗng nhưng đầy đủ `{ page, popup, settings, options, cartConfigs }`. |
|
|
583
|
+
| `validate_page` | Kiểm tra cấu trúc + ngữ nghĩa (ids, event targets, containers, `field_name`). |
|
|
584
|
+
|
|
585
|
+
### Lưu trữ (cần `WEBCAKE_API_BASE` + `WEBCAKE_JWT`)
|
|
586
|
+
| Tool | Mô tả |
|
|
587
|
+
|------|-------------|
|
|
588
|
+
| `list_organizations` | Liệt kê organization của tài khoản (id, name, is_default). Mặc định = org `is_default`. |
|
|
589
|
+
| `create_page` | Lưu một source đã sinh thành trang mới (chỉ-source). **Mặc định `dry_run=true`.** |
|
|
590
|
+
| `list_pages` | Liệt kê các trang của tài khoản (id, name, organization_id, updated_at) để chọn cái cần sửa. |
|
|
591
|
+
| `get_page` | Lấy cây source đã decode của một trang có sẵn để sửa. |
|
|
592
|
+
| `update_page` | Ghi đè source của một trang có sẵn bằng cây đã sửa. **Mặc định `dry_run=true`.** |
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## Ghi chú về mô hình
|
|
597
|
+
|
|
598
|
+
- **Canvas toạ độ tuyệt đối:** mỗi phần tử con mang `top/left/width/height` dạng số theo từng breakpoint;
|
|
599
|
+
section xếp dọc và tự giữ `height`. Nội dung nằm trong `specials` (`text`, `src`, …), không bao giờ trong `styles`.
|
|
600
|
+
- **Source top-level:** `{ page: [sections], popup: [popups], settings: {…}, options: { currency, mobileOnly, versionID }, cartConfigs: {} }`.
|
|
601
|
+
Popup là một mảng top-level **riêng**, không lồng trong `page`.
|
|
602
|
+
- Animation theo breakpoint nằm trong `config.animation = { name, delay, duration, repeat }`.
|
|
603
|
+
- Màu dạng `rgba()`; `top/left/width/height/fontSize` là số (px); input form cần một `specials.field_name` duy nhất.
|
|
604
|
+
|
|
605
|
+
Tham khảo: [docs/page-element-schema.md](docs/page-element-schema.md),
|
|
606
|
+
[docs/element-specials-reference.md](docs/element-specials-reference.md) (tham chiếu đầy đủ mọi specials/event),
|
|
607
|
+
và [src/page-schema.json](src/page-schema.json) (JSON Schema, Draft 2020-12). Schema phản ánh đúng
|
|
608
|
+
hình dạng `page_source` thật của editor.
|
package/dist/factory.js
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* the sizes / specials the real editor seeds. Used by the `new_element` tool so
|
|
5
5
|
* Claude always starts from a structurally-correct node.
|
|
6
6
|
*/
|
|
7
|
+
import { CONTAINER_TYPES, FIELD_TYPES } from "./library.js";
|
|
8
|
+
// Re-exported for back-compat: these are defined alongside LIBRARY in library.ts
|
|
9
|
+
// (the single source of truth) but historically imported from factory.
|
|
10
|
+
export { CONTAINER_TYPES, FIELD_TYPES };
|
|
7
11
|
const ALNUM = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
8
12
|
export function randomId(len = 8) {
|
|
9
13
|
let s = "";
|
|
@@ -19,40 +23,6 @@ export function randomId(len = 8) {
|
|
|
19
23
|
export function imgPlaceholder(w = 600, h = 400, label = "Image") {
|
|
20
24
|
return `https://placehold.co/${Math.round(w)}x${Math.round(h)}?text=${encodeURIComponent(label)}`;
|
|
21
25
|
}
|
|
22
|
-
/** Types that carry a `children` array. */
|
|
23
|
-
export const CONTAINER_TYPES = new Set([
|
|
24
|
-
"section",
|
|
25
|
-
"dynamic_page",
|
|
26
|
-
"group",
|
|
27
|
-
"grid",
|
|
28
|
-
"grid-item",
|
|
29
|
-
"carousel",
|
|
30
|
-
"slide",
|
|
31
|
-
"popup",
|
|
32
|
-
"form",
|
|
33
|
-
// NOTE: "gallery" is intentionally NOT here — gallery.js reads specials.media only,
|
|
34
|
-
// it never reads vm.children. gallery is a leaf element.
|
|
35
|
-
"checkbox-group",
|
|
36
|
-
"radio",
|
|
37
|
-
"group-select",
|
|
38
|
-
]);
|
|
39
|
-
/** Form input types that require a unique specials.field_name. */
|
|
40
|
-
export const FIELD_TYPES = new Set([
|
|
41
|
-
"input",
|
|
42
|
-
"textarea",
|
|
43
|
-
"select",
|
|
44
|
-
"checkbox",
|
|
45
|
-
"checkbox-group",
|
|
46
|
-
"radio",
|
|
47
|
-
"address",
|
|
48
|
-
"country-select",
|
|
49
|
-
"quantity_input",
|
|
50
|
-
"input-datetime",
|
|
51
|
-
"input-file",
|
|
52
|
-
"signature",
|
|
53
|
-
"verify-code",
|
|
54
|
-
"group-select-item",
|
|
55
|
-
]);
|
|
56
26
|
/** Default per-breakpoint animation block (matches real page_source). */
|
|
57
27
|
export function defaultAnimation() {
|
|
58
28
|
return { name: "none", delay: 0, duration: 3, repeat: null };
|
package/dist/library.js
CHANGED
|
@@ -701,6 +701,21 @@ export const LIBRARY = {
|
|
|
701
701
|
keySpecials: {},
|
|
702
702
|
},
|
|
703
703
|
};
|
|
704
|
+
/**
|
|
705
|
+
* Structural flags — single source of truth, co-located with LIBRARY so adding or
|
|
706
|
+
* editing an element happens HERE (one entry) instead of being mirrored across
|
|
707
|
+
* files. factory.ts re-exports both; validate.ts consumes them.
|
|
708
|
+
* - CONTAINER_TYPES is DERIVED from each entry's `container` flag (no second list
|
|
709
|
+
* to keep in sync).
|
|
710
|
+
* - FIELD_TYPES lists the form inputs that submit a value and therefore need a
|
|
711
|
+
* unique specials.field_name.
|
|
712
|
+
*/
|
|
713
|
+
export const CONTAINER_TYPES = new Set(Object.keys(LIBRARY).filter((t) => LIBRARY[t].container));
|
|
714
|
+
export const FIELD_TYPES = new Set([
|
|
715
|
+
"input", "textarea", "select", "checkbox", "checkbox-group", "radio",
|
|
716
|
+
"address", "country-select", "quantity_input", "input-datetime",
|
|
717
|
+
"input-file", "signature", "verify-code", "group-select-item",
|
|
718
|
+
]);
|
|
704
719
|
export const GENERATION_GUIDE = `You are generating the JSON source of a Webcake landing page that the editor renders directly.
|
|
705
720
|
|
|
706
721
|
OUTPUT (top-level page source — matches the real editor shape)
|
package/dist/smoke.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createElement, CONTAINER_TYPES } from "./factory.js";
|
|
6
6
|
import { LIBRARY } from "./library.js";
|
|
7
|
-
import { validatePage } from "./validate.js";
|
|
7
|
+
import { validatePage, pageSchema } from "./validate.js";
|
|
8
8
|
let failures = 0;
|
|
9
9
|
const check = (name, cond, extra) => {
|
|
10
10
|
if (cond) {
|
|
@@ -118,6 +118,11 @@ for (const [type, doc] of Object.entries(LIBRARY)) {
|
|
|
118
118
|
const rr = validatePage(wrapped);
|
|
119
119
|
check(`example ${type} valid`, rr.valid, rr.errors);
|
|
120
120
|
}
|
|
121
|
+
console.log("== schema enum stays in sync with LIBRARY (single source of truth) ==");
|
|
122
|
+
const enumTypes = pageSchema.$defs?.elementType?.enum ?? [];
|
|
123
|
+
const libTypes = Object.keys(LIBRARY);
|
|
124
|
+
check("every LIBRARY type is in the schema enum", libTypes.every((t) => enumTypes.includes(t)), libTypes.filter((t) => !enumTypes.includes(t)));
|
|
125
|
+
check("every schema enum type is in LIBRARY", enumTypes.every((t) => libTypes.includes(t)), enumTypes.filter((t) => !libTypes.includes(t)));
|
|
121
126
|
console.log("== validate: form-data binding checks ==");
|
|
122
127
|
const mkBox = () => ({ desktop: { config: {}, styles: {} }, mobile: { config: {}, styles: {} } });
|
|
123
128
|
const bindingsBad = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-landing-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|