webcake-storefront-mcp 1.17.1 → 1.18.1
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/dist/api.js +42 -1
- package/dist/builder/guide.js +43 -0
- package/dist/builder/page.js +21 -2
- package/dist/changelog.json +14 -14
- package/dist/server.js +6 -2
- package/dist/tools/builder.js +4 -1
- package/dist/tools/catalog-write.js +3 -1
- package/dist/tools/context.js +20 -0
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -208,9 +208,48 @@ export class WebcakeCmsApi {
|
|
|
208
208
|
saveSite(params = {}) {
|
|
209
209
|
return this.request("POST", `/api/v1/site/${this.siteId}/save`, { body: params, timeout: 60000 });
|
|
210
210
|
}
|
|
211
|
+
/** Rebuild every page's compiled CSS (page_source.app_css) by replaying the builder's
|
|
212
|
+
* /save pipeline — the ONLY path that regenerates the storefront's dynamic CSS. The
|
|
213
|
+
* backend builds CSS per page in `params["pages"]` from that page's `source`; /publish
|
|
214
|
+
* does NOT do this, so a site changed only through the MCP renders with stale/empty CSS
|
|
215
|
+
* until this runs. Sends each page's CURRENT saved source (stringified) + current
|
|
216
|
+
* settings; empty global arrays leave globals/popups untouched. */
|
|
217
|
+
async rebuildSiteCss(settings) {
|
|
218
|
+
const res = await this.listPages();
|
|
219
|
+
const list = (res && res.data) || res || [];
|
|
220
|
+
const pages = (Array.isArray(list) ? list : [])
|
|
221
|
+
.map((p) => {
|
|
222
|
+
const src = p && p.source && p.source.source;
|
|
223
|
+
if (src == null || src === "")
|
|
224
|
+
return null;
|
|
225
|
+
return {
|
|
226
|
+
id: p.id,
|
|
227
|
+
source: typeof src === "string" ? src : JSON.stringify(src),
|
|
228
|
+
settings: JSON.stringify(p.settings || {}),
|
|
229
|
+
custom_code: p.custom_code || {},
|
|
230
|
+
};
|
|
231
|
+
})
|
|
232
|
+
.filter(Boolean);
|
|
233
|
+
if (!pages.length)
|
|
234
|
+
return { rebuilt: 0 };
|
|
235
|
+
let s = settings;
|
|
236
|
+
if (s === undefined)
|
|
237
|
+
s = await this.getSiteSettings().catch(() => ({}));
|
|
238
|
+
const settingsStr = typeof s === "string" ? s : JSON.stringify(s || {});
|
|
239
|
+
const changes = {};
|
|
240
|
+
for (const p of pages)
|
|
241
|
+
changes[p.id] = 1;
|
|
242
|
+
await this.request("POST", `/api/v1/site/${this.siteId}/save`, {
|
|
243
|
+
body: { pages, settings: settingsStr, changes, global_sources: [], global_sections: [], page_contents: [] },
|
|
244
|
+
timeout: 120000,
|
|
245
|
+
});
|
|
246
|
+
return { rebuilt: pages.length };
|
|
247
|
+
}
|
|
211
248
|
/** Publish the site live. /publish runs the full "save" pipeline, which OVERWRITES
|
|
212
249
|
* site.settings with the body's `settings` — so we send the CURRENT settings (else
|
|
213
|
-
* they'd be nulled, disabling use_store/use_blog/etc.). Other collections default to [].
|
|
250
|
+
* they'd be nulled, disabling use_store/use_blog/etc.). Other collections default to [].
|
|
251
|
+
* We ALSO rebuild every page's CSS first (rebuildSiteCss) because /publish alone does
|
|
252
|
+
* not regenerate the storefront's dynamic CSS — without it the live site looks unstyled. */
|
|
214
253
|
async publishSite(params = {}) {
|
|
215
254
|
let settings = params.settings;
|
|
216
255
|
if (settings === undefined) {
|
|
@@ -219,6 +258,8 @@ export class WebcakeCmsApi {
|
|
|
219
258
|
// The save pipeline stores site.settings as a JSON STRING — an object body is
|
|
220
259
|
// rejected (422). Stringify unless the caller already passed a string.
|
|
221
260
|
const settingsStr = typeof settings === "string" ? settings : JSON.stringify(settings || {});
|
|
261
|
+
// Regenerate compiled CSS for every page before publishing (no-op-safe on failure).
|
|
262
|
+
await this.rebuildSiteCss(settingsStr).catch(() => { });
|
|
222
263
|
return this.request("POST", `/api/v1/site/${this.siteId}/publish`, {
|
|
223
264
|
body: { global_sources: [], global_sections: [], page_contents: [], ...params, settings: settingsStr },
|
|
224
265
|
timeout: 60000,
|
package/dist/builder/guide.js
CHANGED
|
@@ -158,6 +158,49 @@ Rule of thumb: if the page shows products, a cart, customer/order data, or blog
|
|
|
158
158
|
set \`type\` accordingly so the binding source is turned on. A binding target like
|
|
159
159
|
\`product::product_price\` REQUIRES its page to be the matching type.
|
|
160
160
|
|
|
161
|
+
## Build the WHOLE storefront — every page to the SAME standard (NOT just the home page)
|
|
162
|
+
A shop is multi-page. Build EACH page to a real e-commerce standard with the same palette,
|
|
163
|
+
spacing and header/footer — never leave the home page rich and the rest as bare stubs.
|
|
164
|
+
\`scaffold_store_pages\` creates FUNCTIONAL but MINIMAL pages (a heading + the binding element);
|
|
165
|
+
treat them as STARTERS to enrich, not the finished page. After scaffolding, rebuild each page's
|
|
166
|
+
source so it looks designed:
|
|
167
|
+
- Category (collections, type store): banner + heading + grid-product (+ optional intro/CTA).
|
|
168
|
+
- Product detail (products, type store): 2-col [product-gallery | info: text-dataset
|
|
169
|
+
product::product_name + product_price/original_price + short_description, quantity-input,
|
|
170
|
+
"Thêm vào giỏ" (add_to_cart) + "Mua ngay" (buy_now), trust badges] then a description/feature
|
|
171
|
+
band then a related grid-product ("Có thể bạn cũng thích").
|
|
172
|
+
- Cart (cart, type store): heading + 2-col [cart-items | order-summary card with a
|
|
173
|
+
"Tiến hành thanh toán" button -> { action:"open_page", open_page_id:<checkout> }] + continue link.
|
|
174
|
+
- Checkout (checkout, type store): heading + 2-col [form{type:form_order} with input/
|
|
175
|
+
phone-number/email/address + submit-button "Đặt hàng" | order summary (cart-items)].
|
|
176
|
+
- Thank-you (complete, type store): centred confirmation + order-items + continue-shopping.
|
|
177
|
+
- Optional: About / Contact (custom), Blog (type blog: post-list) + Post.
|
|
178
|
+
Reuse the SAME section helpers, palette and card styling as the home page so the whole site
|
|
179
|
+
feels like ONE design.
|
|
180
|
+
|
|
181
|
+
## Global Header & Footer — create them for EVERY site (don't inline per page)
|
|
182
|
+
A header (logo/nav/cart) and footer (links/contact/copyright) belong on EVERY page, so make them
|
|
183
|
+
GLOBAL, not copied into each page. Build a header section + a footer section (new_section, same as
|
|
184
|
+
any section), then:
|
|
185
|
+
create_global_section({ type:"header", name:"Header", section:<headerSection> }) // top of every page
|
|
186
|
+
create_global_section({ type:"footer", name:"Footer", section:<footerSection> }) // bottom of every page
|
|
187
|
+
(omit page_ids to apply to ALL pages). ORDER MATTERS: build/save the page CONTENT first, THEN
|
|
188
|
+
create the globals — they embed into each page's source. If you later overwrite a page's source
|
|
189
|
+
(update_page_source/build_page) you WIPE its embedded header/footer, so re-create the globals
|
|
190
|
+
(delete_global_section by the section NODE id, then create once) to re-embed cleanly. Edit a global
|
|
191
|
+
later with update_global_section_element(s) and it updates on every page at once.
|
|
192
|
+
|
|
193
|
+
## Popups (newsletter / promo / age-gate)
|
|
194
|
+
A popup is a GLOBAL SOURCE, not a page section. Build it, store it, then trigger it:
|
|
195
|
+
1. Build the popup body (new_section: heading + text + form/input + a close button), then wrap it:
|
|
196
|
+
new_element("popup", { children:[<that section>], specials:{ /* trigger + overlay */ } }).
|
|
197
|
+
Trigger/behaviour (auto-open after a delay, exit-intent, only-once, overlay) lives in specials.
|
|
198
|
+
2. Save it: create_global_source({ component:"popup", source:{ sections:[<popupNode>] } }) -> returns its id.
|
|
199
|
+
3. Open/close from any element via events: a button { action:"open_popup", popup_id:"<id>", popup_overlay:true };
|
|
200
|
+
a close button inside { action:"close_popup", popup_id:"<id>" }; a form can auto-close on its
|
|
201
|
+
success trigger ({ eventName:"success", action:"close_popup", popup_id:"<id>" }).
|
|
202
|
+
List existing popups with list_global_sources({component:"popup"}); edit via update_global_source(_element).
|
|
203
|
+
|
|
161
204
|
## Workflow (do this every time)
|
|
162
205
|
1. Intake: confirm goal, brand, colours, sections wanted (ask 3-5 questions if unclear).
|
|
163
206
|
2. list_elements / get_element to pick the right component types.
|
package/dist/builder/page.js
CHANGED
|
@@ -51,6 +51,25 @@ export function reassignIds(node) {
|
|
|
51
51
|
* finalizeForRender() later expands `runtime` into the per-breakpoint keys the
|
|
52
52
|
* storefront actually reads (bp1..bp4).
|
|
53
53
|
*/
|
|
54
|
+
/**
|
|
55
|
+
* Element types that must FILL their grid cell's width to lay out correctly — the
|
|
56
|
+
* storefront renderer turns a single-value `constraintX` ("centerLeft") into
|
|
57
|
+
* `justify-self: center`, which shrinks the element to its content width. For repeaters
|
|
58
|
+
* (a grid-product then computes `repeat(auto-fit, minmax(min, 1fr))` against that width)
|
|
59
|
+
* that collapses the whole grid to ONE column. Giving them `["left","right"]` makes the
|
|
60
|
+
* renderer emit `justify-self: stretch` so they span the full content column.
|
|
61
|
+
*/
|
|
62
|
+
const FILL_WIDTH_TYPES = new Set([
|
|
63
|
+
"grid-product", "slider-product", "cart-items", "order-items", "post-list",
|
|
64
|
+
"grid-category", "grid-blog", "product-gallery", "product-image-carousel",
|
|
65
|
+
"custom-layout", "layout-dataset", "form",
|
|
66
|
+
]);
|
|
67
|
+
/** Default horizontal constraint for a child: stretch for fill-width components,
|
|
68
|
+
* else the builder's usual centred placement. Respects an explicit constraintX. */
|
|
69
|
+
function defaultConstraintX(child) {
|
|
70
|
+
return ((child.runtime && child.runtime.config && child.runtime.config.constraintX) ||
|
|
71
|
+
(FILL_WIDTH_TYPES.has(child.type) ? ["left", "right"] : ["centerLeft"]));
|
|
72
|
+
}
|
|
54
73
|
export function stackChildren(container, children, opts = {}) {
|
|
55
74
|
const gridCols = opts.gridCols || 1;
|
|
56
75
|
const colStart = opts.contentColStart || 1;
|
|
@@ -76,7 +95,7 @@ export function stackChildren(container, children, opts = {}) {
|
|
|
76
95
|
columnEnd: colEnd,
|
|
77
96
|
rowStart: i + 1,
|
|
78
97
|
rowEnd: i + 2,
|
|
79
|
-
constraintX: (child
|
|
98
|
+
constraintX: defaultConstraintX(child),
|
|
80
99
|
constraintY: (child.runtime.config && child.runtime.config.constraintY) || ["top"],
|
|
81
100
|
loaded: true,
|
|
82
101
|
};
|
|
@@ -124,7 +143,7 @@ export function rowChildren(container, children, opts = {}) {
|
|
|
124
143
|
columnEnd: i + 2,
|
|
125
144
|
rowStart: 1,
|
|
126
145
|
rowEnd: 2,
|
|
127
|
-
constraintX: (child
|
|
146
|
+
constraintX: defaultConstraintX(child),
|
|
128
147
|
constraintY: (child.runtime.config && child.runtime.config.constraintY) || ["top"],
|
|
129
148
|
loaded: true,
|
|
130
149
|
__cell: { index: i, ...meta },
|
package/dist/changelog.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"v": "1.18.1",
|
|
4
|
+
"d": "25/06/2026",
|
|
5
|
+
"type": "Changed",
|
|
6
|
+
"en": "get_build_guide now includes three new sections: \"Build the WHOLE storefront\" with per-page recipes for enriching category, product detail, cart,…",
|
|
7
|
+
"vi": "get_build_guide nay bổ sung ba mục mới: \"Build the WHOLE storefront\" — công thức từng trang để nâng cấp danh mục, trang chi tiết sản phẩm, giỏ hàng,…"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"v": "1.18.0",
|
|
11
|
+
"d": "25/06/2026",
|
|
12
|
+
"type": "Added",
|
|
13
|
+
"en": "New get_intake_guide tool returns a step-by-step questionnaire and recommended build flow (create_site → products → build_page → global sections →…",
|
|
14
|
+
"vi": "Tool mới get_intake_guide trả về bảng câu hỏi từng bước và quy trình build được khuyến nghị (create_site → sản phẩm → build_page → global sections →…"
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"v": "1.17.1",
|
|
4
18
|
"d": "25/06/2026",
|
|
@@ -26,19 +40,5 @@
|
|
|
26
40
|
"type": "Fixed",
|
|
27
41
|
"en": "update_page_element, update_page_elements, update_global_source_element, and update_global_source_elements now normalize events and bindings arrays…",
|
|
28
42
|
"vi": "update_page_element, update_page_elements, update_global_source_element và update_global_source_elements nay chuẩn hóa mảng events và bindings khi…"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"v": "1.15.0",
|
|
32
|
-
"d": "24/06/2026",
|
|
33
|
-
"type": "Added",
|
|
34
|
-
"en": "New get_global_section tool returns a compact tree representation of a single global section (Header/Footer/block), listing each element's id, type,…",
|
|
35
|
-
"vi": "Tool mới get_global_section trả về cây phần tử dạng compact của một global section (Header/Footer/block), liệt kê id, type, text, class, binding và…"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"v": "1.14.0",
|
|
39
|
-
"d": "24/06/2026",
|
|
40
|
-
"type": "Added",
|
|
41
|
-
"en": "New list_events tool returns the authoritative interaction-events catalog: 9 triggers (click, hover, submit, success, ...) and 38 actions…",
|
|
42
|
-
"vi": "Tool mới list_events trả về danh mục sự kiện tương tác đầy đủ: 9 trigger (click, hover, submit, success, ...) và 38 action (open_page, scroll_to,…"
|
|
43
43
|
}
|
|
44
44
|
]
|
package/dist/server.js
CHANGED
|
@@ -8,12 +8,16 @@ Tool discovery: the common tools (pages, builder, products, orders, blog, custom
|
|
|
8
8
|
|
|
9
9
|
You can also BUILD pages: use get_build_guide, list_elements, get_element to learn the BuilderX component model, new_section/new_element to compose, validate_page to check, then build_page (dry_run first) to create. Publishing is site-level via publish_site.
|
|
10
10
|
|
|
11
|
+
Build the WHOLE site, not just the home page: enrich EVERY page (category, product detail, cart, checkout, thank-you, …) to the same e-commerce standard with the same palette/header/footer — scaffold_store_pages makes MINIMAL starter pages, so design them properly afterwards. Make the Header and Footer GLOBAL (create_global_section type:"header"/"footer") so they're consistent on every page — don't inline them per page. For newsletter/promo offers, build a popup (a "popup" global_source) and open it with an open_popup event. See get_build_guide for the per-page recipes, the global-section order rules, and the popup workflow.
|
|
12
|
+
|
|
11
13
|
To make a generated site look real, also CREATE DATA so dataset bindings resolve: create_product_category + create_product (storefront), create_blog_category + create_article (blog). Get image URLs from search_images / upload_images first, then reference them. A good flow for a fresh site: create_site → create a few categories → create products in them → build_page (home + store/blog pages) → publish_site.
|
|
12
14
|
|
|
15
|
+
INTAKE FIRST — when the user asks to BUILD/CREATE a site, store, or page (a fresh build, not a small edit or a data question), do NOT jump straight to create_site/build_page on the same turn. Act as a professional shop-website designer doing client work: first ask ONE short batch of questions (call get_intake_guide for the exact list), restate the plan you'll build, get a "yes", THEN build. The shop owner is an ORDINARY person, not a designer — ask in plain words and visual outcomes ("tông nâu ấm, ảnh sản phẩm to"), never jargon. Ask the essentials (with sensible defaults so they answer fast): what they sell + a few products & prices, brand/shop name, primary color/style, which pages they need, real contact info (hotline/Zalo, address, email, hours) + the main call-to-action, and any promotion. NEVER invent or silently placeholder real data (shop name, products, prices, phone, address) — ask for it; placeholder only what the user explicitly skips, and tell them what to fill in. Skip intake only when the user already gave the brief, says "just do it / tự quyết", or it's a tiny edit.
|
|
16
|
+
|
|
13
17
|
Workflow:
|
|
14
|
-
1. On first interaction, call get_current_context. The site is NOT set from env — if no site is selected yet, call list_my_sites and ask the user which site to work on, then switch_site (the choice is saved and reused next session). To start from scratch, create_site makes a new site and switches to it; then build a homepage with build_page (type:'main', is_homepage:true).
|
|
18
|
+
1. On first interaction, call get_current_context. The site is NOT set from env — if no site is selected yet, call list_my_sites and ask the user which site to work on, then switch_site (the choice is saved and reused next session). To start from scratch, run the INTAKE above (get_intake_guide), then create_site makes a new site and switches to it; then build a homepage with build_page (type:'main', is_homepage:true).
|
|
15
19
|
2. Before answering a site-specific question, query the relevant tool (use search_tools if it isn't loaded directly).
|
|
16
|
-
3. When building a page, read get_build_guide first and validate before saving.
|
|
20
|
+
3. When building a page, read get_build_guide first and validate before saving. After saving/editing, call publish_site to take changes live — it also rebuilds the storefront CSS (a plain page-source save alone does not).
|
|
17
21
|
4. Always reply in the user's language; keep Vietnamese with full diacritics.`;
|
|
18
22
|
function makeResult(data) {
|
|
19
23
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
package/dist/tools/builder.js
CHANGED
|
@@ -197,7 +197,10 @@ product/category/cart from any page lands on a real page instead of a 404.
|
|
|
197
197
|
Creates only the ones MISSING (matched by slug): Category (collections), Product (products),
|
|
198
198
|
Cart (cart), Checkout (checkout), Thank-you (complete) — all type 'store' (enables use_store),
|
|
199
199
|
plus optional member (login/register/profile) and blog (blog/post) pages.
|
|
200
|
-
Run this right after you create products/categories. dry_run=true (default) previews
|
|
200
|
+
Run this right after you create products/categories. dry_run=true (default) previews.
|
|
201
|
+
NOTE: these are MINIMAL STARTER pages (a heading + the binding element) — you MUST then
|
|
202
|
+
enrich EACH one to the same standard as the home page (see get_build_guide "Build the WHOLE
|
|
203
|
+
storefront"), and add a GLOBAL header/footer (create_global_section). Don't leave them bare.`, {
|
|
201
204
|
include_member: z.boolean().default(false).describe("Also create login/register/profile (type member, use_member)"),
|
|
202
205
|
include_blog: z.boolean().default(false).describe("Also create blog list + post pages (type blog, use_blog)"),
|
|
203
206
|
dry_run: z.boolean().default(true).describe("Preview (true) or actually create the missing pages (false)"),
|
|
@@ -70,10 +70,12 @@ Images must be HOSTED URLs — get them from search_images or upload_images firs
|
|
|
70
70
|
name,
|
|
71
71
|
variations: vars,
|
|
72
72
|
// These MUST be arrays — the backend does Enum.reduce over them and 500s on nil.
|
|
73
|
+
// (product_attributes is reduced by get_all_attrs on the storefront product-attrs
|
|
74
|
+
// endpoint, so it must be [] — never omitted — even for a no-variation product.)
|
|
73
75
|
categories: category_ids || [],
|
|
74
76
|
ribbons: [],
|
|
77
|
+
product_attributes: attributes || [],
|
|
75
78
|
...(description ? { description } : {}),
|
|
76
|
-
...(attributes ? { product_attributes: attributes } : {}),
|
|
77
79
|
...(images && images.length ? { image: images[0] } : {}),
|
|
78
80
|
};
|
|
79
81
|
const res = await api.createProduct(productParams);
|
package/dist/tools/context.js
CHANGED
|
@@ -20,6 +20,26 @@ export function getConfirmMode() {
|
|
|
20
20
|
}
|
|
21
21
|
// ── Tools ──
|
|
22
22
|
export function registerContextTools(server, api, handle) {
|
|
23
|
+
server.tool("get_intake_guide", "Get the INTAKE questionnaire + build flow to run BEFORE creating a new site/store/page. Call this at the start of any fresh build: ask the user this one short batch (plain words, with defaults), restate the plan, get a yes, THEN build. Skip only for tiny edits, data questions, or when the user already gave the brief / says 'just do it'.", {}, () => handle(async () => ({
|
|
24
|
+
how_to_use: "Ask these as ONE friendly batch in the user's language (Vietnamese = full diacritics). Talk like a shop-website consultant to a non-designer: plain words and visual outcomes, no jargon. Offer the defaults so they can answer fast or just say 'theo gợi ý'. Then restate the plan (shop name + pages + colour/tone + main CTA) and WAIT for confirmation before building. Never invent or silently placeholder real data — ask for it; only placeholder what the user explicitly skips and tell them what to fill in.",
|
|
25
|
+
questions: [
|
|
26
|
+
{ key: "business", ask: "Bạn bán gì? Kể 3–6 sản phẩm tiêu biểu kèm giá (và giá gốc nếu có khuyến mãi).", why: "Tạo danh mục + sản phẩm thật để lưới sản phẩm hiển thị đúng.", required: true },
|
|
27
|
+
{ key: "brand", ask: "Tên shop/thương hiệu là gì? Có logo hay slogan không?", default: "Dùng tên bạn cung cấp; chưa có logo thì để chữ.", required: true },
|
|
28
|
+
{ key: "look", ask: "Bạn thích tông màu / phong cách nào? (ví dụ: nâu ấm cà phê, pastel nhẹ nhàng, tối hiện đại)", default: "Gợi ý một tông hợp ngành hàng để bạn duyệt.", required: false },
|
|
29
|
+
{ key: "pages", ask: "Cần những trang nào? Mặc định: Trang chủ + Cửa hàng (danh mục, chi tiết SP, giỏ hàng, thanh toán, cảm ơn). Thêm Giới thiệu / Blog / Liên hệ?", default: "Trang chủ + bộ trang cửa hàng chuẩn.", required: false },
|
|
30
|
+
{ key: "contact", ask: "Thông tin liên hệ thật: hotline/Zalo, địa chỉ, email, giờ mở cửa — và nút hành động chính (Mua ngay / Gọi đặt / Nhắn Zalo)?", why: "Hiển thị ở header/footer/CTA — không bịa.", required: true },
|
|
31
|
+
{ key: "promo", ask: "Có khuyến mãi hay điểm bán hàng nổi bật để làm CTA không? (ví dụ: giảm 10% đơn đầu, freeship từ 300k)", default: "Bỏ qua nếu chưa có.", required: false },
|
|
32
|
+
],
|
|
33
|
+
recommended_flow: [
|
|
34
|
+
"create_site (tên + slug) → tự chuyển sang site mới",
|
|
35
|
+
"create_product_category + create_product cho từng sản phẩm (ảnh từ search_images/upload_images trước)",
|
|
36
|
+
"build_page trang chủ (type:'main', is_homepage:true) với hero, lưới sản phẩm, câu chuyện, CTA, …",
|
|
37
|
+
"scaffold_store_pages để tạo trang danh mục/chi tiết/giỏ/thanh toán/cảm ơn",
|
|
38
|
+
"Tách Header/Footer thành global section (create_global_section) để dùng chung mọi trang",
|
|
39
|
+
"publish_site (cũng rebuild CSS storefront)",
|
|
40
|
+
],
|
|
41
|
+
notes: "Sau khi build xong, QA trên builder editor (app_base/editor/:site_id) hoặc storefront đã publish; publish_site sẽ rebuild CSS để hết tình trạng trang thiếu style.",
|
|
42
|
+
})));
|
|
23
43
|
server.tool("get_current_context", "Show current connection context: which site_id, API URL, session, and account info. Call this first to confirm you're working on the right site", {}, () => handle(async () => {
|
|
24
44
|
const [me, site] = await Promise.all([
|
|
25
45
|
api.getMe().catch(() => null),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-storefront-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.1",
|
|
4
4
|
"description": "MCP server for the WebCake/StoreCake storefront builder — page CRUD, page authoring, products, orders, and more",
|
|
5
5
|
"mcpName": "io.github.vuluu2k/webcake-storefront-mcp",
|
|
6
6
|
"license": "MIT",
|