sbuilder-mcp 0.69.0 → 0.70.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 CHANGED
@@ -6,6 +6,14 @@ All notable changes to this project are documented in this file.
6
6
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
7
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.70.0] - 2026-09-26
10
+
11
+ ### Added
12
+ - `sb_review` warns once per site (`cartDrawerThumbnail`) when a cart drawer seeded before the platform fixed its seed renders a line's thumbnail as a gallery (feature image plus a thumbs strip) squeezed into a 64px line, and `sb_store` action `cart` with `relocalize: true` now also fixes it, setting that thumbnail to a single image through the open page's save.
13
+
14
+ ### Changed
15
+ - `sb_store` action `cart`'s `relocalize` no longer requires `settings.locale` to be set when the only thing left to fix is a gallery thumbnail; it still refuses when there is neither a locale word nor a thumbnail to relocalize.
16
+
9
17
  ## [0.69.0] - 2026-09-26
10
18
 
11
19
  ### Added
package/CHANGELOG.vi.md CHANGED
@@ -6,6 +6,14 @@ Mọi thay đổi đáng chú ý của dự án được ghi lại trong file n
6
6
  Định dạng dựa trên [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
7
  và dự án tuân theo [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.70.0] - 2026-09-26
10
+
11
+ ### Added
12
+ - `sb_review` cảnh báo một lần cho mỗi site (`cartDrawerThumbnail`) khi cart drawer được gieo trước khi nền tảng sửa lại seed hiện thumbnail của một line dưới dạng gallery (ảnh chính cộng dải ảnh thu nhỏ) bị nhồi vào một line cao 64px, và action `cart` của `sb_store` với `relocalize: true` giờ cũng sửa luôn, đặt thumbnail đó thành một ảnh duy nhất thông qua lần lưu của trang đang mở.
13
+
14
+ ### Changed
15
+ - `relocalize` của action `cart` trong `sb_store` không còn yêu cầu `settings.locale` phải được đặt khi thứ duy nhất cần sửa là thumbnail dạng gallery; nó vẫn từ chối khi không có cả từ ngôn ngữ lẫn thumbnail nào cần relocalize.
16
+
9
17
  ## [0.69.0] - 2026-09-26
10
18
 
11
19
  ### Added
@@ -56,3 +56,18 @@ export function cartRelocalize(doc, rootId, locale) {
56
56
  });
57
57
  return out;
58
58
  }
59
+ /**
60
+ * A CART LINE THUMBNAIL SEEDED AS A GALLERY. Drawers seeded before
61
+ * web_builder `3e5efbb52` carry a childless `media-dataset` with no `layout`,
62
+ * which renders the feature image PLUS a thumbs strip inside a 64px line. The
63
+ * seed now says `single`; a layout the merchant chose explicitly is theirs.
64
+ */
65
+ export function cartGalleryThumbs(doc, rootId) {
66
+ const out = [];
67
+ walk(doc, rootId, (n) => {
68
+ const layout = n.config?.layout;
69
+ if (n.data.type === 'media-dataset' && !(n.data.nodes ?? []).length && (layout === undefined || layout === 'bottom'))
70
+ out.push(n.id);
71
+ });
72
+ return out;
73
+ }
@@ -16,7 +16,7 @@
16
16
  * fetched reports nothing rather than a gap the store may not have. A warning
17
17
  * that fires on a correctly built site is one the reader learns to ignore.
18
18
  */
19
- import { cartRelocalize, cartSeedLocale } from './cartlang.js';
19
+ import { cartGalleryThumbs, cartRelocalize, cartSeedLocale } from './cartlang.js';
20
20
  /** The purchase binding an Add-to-cart / Buy-now button carries. */
21
21
  const PRODUCT_ACTION_BINDING_ID = 'bind-product-action';
22
22
  /** Element types that only make sense in a store. */
@@ -280,6 +280,15 @@ export function readinessGaps(input) {
280
280
  });
281
281
  }
282
282
  }
283
+ if (input.cartOverlay?.root_node_id && cartGalleryThumbs(input.cartOverlay, input.cartOverlay.root_node_id).length) {
284
+ gaps.push({
285
+ id: 'cartDrawerThumbnail',
286
+ draft: false,
287
+ problem: 'The cart drawer\'s line thumbnail is a GALLERY (feature image plus a thumbs strip) squeezed ' +
288
+ 'into a 64px line — a drawer seeded before the platform fixed its seed.',
289
+ fix: 'Open any page of this site, then sb_store action:"cart" relocalize:true dry_run:false — it sets that thumbnail to a single image.',
290
+ });
291
+ }
283
292
  if (!isStore(input))
284
293
  return gaps;
285
294
  if (pages && !published(pages, 'checkout')) {
@@ -57,7 +57,7 @@ import { siteToken } from './credentialpick.js';
57
57
  import { setKeys } from '../domains/site/builder.js';
58
58
  import { CART_SEEDS, OVERLAY_SEEDS } from '../catalog/overlays.generated.js';
59
59
  import { withFreshIds } from '../domains/site/ids.js';
60
- import { cartRelocalize, cartSeedLocale } from '../domains/site/cartlang.js';
60
+ import { cartGalleryThumbs, cartRelocalize, cartSeedLocale } from '../domains/site/cartlang.js';
61
61
  const KIND_NAME = {
62
62
  popup: 'Pop-up',
63
63
  quickview: 'Quick view',
@@ -363,29 +363,34 @@ export async function relocalizeCartDrawer(ctx, session, siteId, dryRun) {
363
363
  throw new Error('sbuilder: this site has no cart drawer — sb_store action:"cart" without relocalize creates one.');
364
364
  const settings = (await get(`/api/sites/${site}/settings`));
365
365
  const raw = settings.settings?.locale;
366
- if (typeof raw !== 'string' || !raw) {
367
- throw new Error('sbuilder: settings.locale is unset, so there is no site language to relocalize to — set it with sb_theme locale first.');
368
- }
369
- const language = cartSeedLocale(raw);
366
+ // No locale means no language to move the WORDS to; the thumbnail needs none.
367
+ const language = typeof raw === 'string' && raw ? cartSeedLocale(raw) : null;
370
368
  const open = session.peek() ? session.location() : null;
371
369
  const composed = open?.siteId === siteId
372
370
  ? Object.values(session.current().doc.nodes).find((n) => n.specials?.overlayId === cart.id)
373
371
  : undefined;
374
- const changes = composed
375
- ? cartRelocalize(session.current().doc, composed.id, language)
372
+ const target = composed
373
+ ? { doc: session.current().doc, root: composed.id }
376
374
  : cart.document?.root_node_id
377
- ? cartRelocalize(cart.document, cart.document.root_node_id, language)
378
- : [];
379
- if (dryRun || changes.length === 0) {
375
+ ? { doc: cart.document, root: cart.document.root_node_id }
376
+ : null;
377
+ const changes = target && language ? cartRelocalize(target.doc, target.root, language) : [];
378
+ const thumbnails = target ? cartGalleryThumbs(target.doc, target.root) : [];
379
+ if (!language && thumbnails.length === 0) {
380
+ throw new Error('sbuilder: settings.locale is unset, so there is no site language to relocalize to — set it with sb_theme locale first.');
381
+ }
382
+ const thumbNote = thumbnails.length ? { thumbnails, thumbnails_note: 'These line thumbnails become a single image (config.layout "single").' } : {};
383
+ if (dryRun || changes.length + thumbnails.length === 0) {
380
384
  return {
381
385
  ...(dryRun ? { dry_run: true } : {}),
382
386
  overlay_id: cart.id,
383
387
  language,
384
388
  changes,
385
- ...(changes.length === 0
386
- ? { note: 'Nothing to change — no seed word from another language is left in the drawer.' }
389
+ ...thumbNote,
390
+ ...(changes.length + thumbnails.length === 0
391
+ ? { note: 'Nothing to change — no seed word from another language and no gallery thumbnail is left in the drawer.' }
387
392
  : {
388
- plan: redact([{ step: 1, what: 'rewrite those strings in the composed drawer and save the open page', method: 'PUT', path: `/api/sites/${site}/pages/{open page}/source` }]),
393
+ plan: redact([{ step: 1, what: 'apply those changes to the composed drawer and save the open page', method: 'PUT', path: `/api/sites/${site}/pages/{open page}/source` }]),
389
394
  note: 'Nothing was sent. Re-call with dry_run:false; it writes through the open page\'s save.',
390
395
  }),
391
396
  };
@@ -393,11 +398,15 @@ export async function relocalizeCartDrawer(ctx, session, siteId, dryRun) {
393
398
  if (!composed) {
394
399
  throw new Error(`sbuilder: the drawer is written through a page save, so relocalize needs a page of site "${siteId}" open — sb_page_open one, then re-run.`);
395
400
  }
396
- await session.applyAndSave(changes.map((c) => ({ op: 'set', path: ['nodes', c.node_id, 'specials', c.key], value: c.to })));
401
+ await session.applyAndSave([
402
+ ...changes.map((c) => ({ op: 'set', path: ['nodes', c.node_id, 'specials', c.key], value: c.to })),
403
+ ...thumbnails.map((id) => ({ op: 'set', path: ['nodes', id, 'config', 'layout'], value: 'single' })),
404
+ ]);
397
405
  return {
398
406
  overlay_id: cart.id,
399
407
  language,
400
408
  changes,
409
+ ...thumbNote,
401
410
  next: 'Publish the pages: the drawer reaches a shopper through each published page.',
402
411
  };
403
412
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * THE STORE FLOWS THAT MUST BE ORDERED.
3
3
  *
4
- * `sb_review` names EIGHTEEN readiness gaps (`ReadinessGapId`). Most are one
4
+ * `sb_review` names its readiness gaps (`ReadinessGapId`). Most are one
5
5
  * call each — a delivery option, a payment gateway, a product, a page of the
6
6
  * right type — because `REQUEST_SHAPES` tells the caller what those calls take.
7
7
  * The ones that are not are the flows in this file: each is several writes in
@@ -533,7 +533,8 @@ export function registerStoreTools(server, ctx, session) {
533
533
  .boolean()
534
534
  .optional()
535
535
  .describe('action:"cart" — rewrite an EXISTING drawer\'s seed words that are in another language ' +
536
- 'to the site locale\'s (edited text untouched); needs a page of the site open'),
536
+ 'to the site locale\'s (edited text untouched), and turn a gallery line thumbnail into a ' +
537
+ 'single image; needs a page of the site open'),
537
538
  dry_run: z.boolean().optional(),
538
539
  },
539
540
  annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbuilder-mcp",
3
- "version": "0.69.0",
3
+ "version": "0.70.0",
4
4
  "description": "MCP server that designs and operates a Store Builder site — pages, data, theme and publish — through the platform's own API and live-edit protocol.",
5
5
  "mcpName": "io.github.vuluu2k/sbuilder-mcp",
6
6
  "type": "module",