sbuilder-mcp 0.49.0 → 0.51.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,17 @@ 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.51.0] - 2026-09-15
10
+
11
+ ### Added
12
+ - `sb_page_list` now reports which of the pages most sites carry — login, register, forgot-password, contact, about, and policy pages — this site appears to be missing, matched by name against untyped `page` rows since none of them has a page type of its own, alongside a note naming the suggestion as advice rather than a defect.
13
+
14
+ ## [0.50.0] - 2026-09-15
15
+
16
+ ### Changed
17
+ - `sb_catalog_search` raises its `limit` ceiling from 30 to 60 so a category can be read whole; the `basic` category alone holds 39 element types, and a 30-cap silently dropped the nine an agent had never used, the same failure browsing exists to fix.
18
+ - `sb_catalog_search`'s browse note now tells the caller to pass a category name with `limit` 60 to read that whole group's descriptions at once, on top of passing a type for its fields.
19
+
9
20
  ## [0.49.0] - 2026-09-15
10
21
 
11
22
  ### Added
package/CHANGELOG.vi.md CHANGED
@@ -6,6 +6,17 @@ 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.51.0] - 2026-09-15
10
+
11
+ ### Added
12
+ - `sb_page_list` giờ báo cáo site này có vẻ đang thiếu những trang mà hầu hết các site thường có — đăng nhập, đăng ký, quên mật khẩu, liên hệ, giới thiệu và các trang chính sách — bằng cách so khớp theo tên với các trang loại `page` không có kiểu riêng, kèm ghi chú nói rõ đây là gợi ý chứ không phải lỗi.
13
+
14
+ ## [0.50.0] - 2026-09-15
15
+
16
+ ### Changed
17
+ - `sb_catalog_search` nâng trần `limit` từ 30 lên 60 để có thể đọc trọn một category; riêng category `basic` đã có 39 loại phần tử, và mức trần 30 âm thầm bỏ sót chín phần tử mà agent chưa từng dùng đến — đúng lỗi mà tính năng duyệt catalog vốn sinh ra để khắc phục.
18
+ - Ghi chú duyệt catalog của `sb_catalog_search` giờ hướng dẫn người gọi truyền tên một category cùng `limit` 60 để đọc toàn bộ mô tả của nhóm đó một lần, bên cạnh việc truyền một loại phần tử để xem các trường lựa chọn của nó.
19
+
9
20
  ## [0.49.0] - 2026-09-15
10
21
 
11
22
  ### Added
@@ -36,6 +36,18 @@ export function catalogBrowse() {
36
36
  out[k].sort();
37
37
  return out;
38
38
  }
39
+ /**
40
+ * The biggest category, which is what `limit` has to clear for a caller to read
41
+ * one group WHOLE.
42
+ *
43
+ * A group query that silently returns its first 30 of 39 is the worst answer
44
+ * available here: it looks like the whole group, and the nine it dropped are
45
+ * exactly the elements nobody knew to look for. `catalog-browse.test.ts` fails
46
+ * when a category outgrows the cap, which is the only way anyone would notice.
47
+ */
48
+ export function largestCategorySize() {
49
+ return Math.max(...Object.values(catalogBrowse()).map((g) => g.length));
50
+ }
39
51
  /**
40
52
  * Four fields to CHOOSE by.
41
53
  *
@@ -0,0 +1,84 @@
1
+ /**
2
+ * THE PAGES A SITE HAS THAT THE PLATFORM CANNOT NAME.
3
+ *
4
+ * `readinessGaps` already reports every page the storefront ROUTES BY TYPE —
5
+ * product, category, search, checkout, complete, account, error. Each of those
6
+ * has a named consequence when it is absent, which is what makes it a defect.
7
+ *
8
+ * The rest of a website has no type at all. Login, register, forgot-password,
9
+ * contact, about and the policies are ordinary pages of type "page", so nothing
10
+ * anywhere can tell a site that has them from a site that does not — and an
11
+ * agent building a store therefore ships whatever it happened to think of. A
12
+ * store built with these tools came out with a home page, a product list and a
13
+ * category grid, and no way to contact the shop, no policy a shopper could
14
+ * read, and no /login for its own header to link to.
15
+ *
16
+ * ADVICE, NOT A DEFECT, AND IT SAYS SO. `readinessGaps` is a list of things
17
+ * that are broken; this is a list of things that are usually there. They are
18
+ * kept apart deliberately: a check that reports a judgement as a defect is one
19
+ * an author learns to ignore, and readiness.ts's own header says exactly that.
20
+ *
21
+ * MATCHED BY NAME, WHICH IS A GUESS, AND THE RESULT SAYS SO. There is no type,
22
+ * no flag and no API that identifies a contact page, so the only signal is what
23
+ * the merchant called it. A page under an unusual name therefore reads as
24
+ * absent. That fails in the safe direction — a line of advice about a page you
25
+ * already have costs a sentence; the reverse ships a shop nobody can reach.
26
+ */
27
+ export const USUAL_PAGES = [
28
+ {
29
+ key: 'login',
30
+ match: ['login', 'signin', 'sign-in', 'dang-nhap', 'đăng nhập'],
31
+ why: 'Nothing for a header, an order email or /account\'s signed-out state to link to. ' +
32
+ 'Seed it with sb_store action:"form" template "login" on a page of type "page".',
33
+ },
34
+ {
35
+ key: 'register',
36
+ match: ['register', 'signup', 'sign-up', 'dang-ky', 'đăng ký'],
37
+ why: 'A shopper cannot open an account, so order history, addresses and any member-gated ' +
38
+ 'page are unreachable. Template "register".',
39
+ },
40
+ {
41
+ key: 'forgot',
42
+ match: ['forgot', 'reset', 'quen-mat-khau', 'quên mật khẩu', 'doi-mat-khau'],
43
+ why: 'A customer who forgets a password has no way back in and writes to support instead. ' +
44
+ 'Template "forgot".',
45
+ },
46
+ {
47
+ key: 'contact',
48
+ match: ['contact', 'lien-he', 'liên hệ'],
49
+ why: 'No address, phone or form anywhere, so a shopper with a question about an order has ' +
50
+ 'nowhere to put it. Template "contact".',
51
+ },
52
+ {
53
+ key: 'about',
54
+ match: ['about', 'gioi-thieu', 'giới thiệu', 've-chung-toi'],
55
+ why: 'Nothing says who the shop is, which is the page a first-time buyer opens before paying.',
56
+ },
57
+ {
58
+ key: 'policy',
59
+ match: [
60
+ 'policy', 'policies', 'chinh-sach', 'chính sách', 'dieu-khoan', 'điều khoản',
61
+ 'terms', 'privacy', 'bao-mat', 'bảo mật', 'doi-tra', 'đổi trả', 'return',
62
+ 'shipping', 'van-chuyen', 'vận chuyển', 'giao-hang', 'giao hàng', 'refund',
63
+ ],
64
+ why: 'No delivery, return or privacy terms a shopper can read before paying — the pages a ' +
65
+ 'marketplace and a payment provider both ask for.',
66
+ },
67
+ ];
68
+ /**
69
+ * Which of the usual pages this site appears not to have.
70
+ *
71
+ * Only `page`-typed rows are searched: a product TEMPLATE named "Chi tiết sản
72
+ * phẩm" is not an about page, and letting a template satisfy one of these would
73
+ * report a site as complete on the strength of a page that answers a different
74
+ * address entirely.
75
+ */
76
+ export function missingUsualPages(pages) {
77
+ if (!pages)
78
+ return [];
79
+ const hay = pages
80
+ .filter((p) => (typeof p.type === 'string' ? p.type === 'page' : true))
81
+ .map((p) => `${typeof p.slug === 'string' ? p.slug : ''} ${typeof p.name === 'string' ? p.name : ''}`.toLowerCase())
82
+ .join('\n');
83
+ return USUAL_PAGES.filter((u) => !u.match.some((m) => hay.includes(m)));
84
+ }
@@ -20,6 +20,7 @@ import { readinessGaps, READINESS_NOTICE } from '../domains/site/readiness.js';
20
20
  import { gatherReadiness } from '../domains/site/readiness-fetch.js';
21
21
  import { globalWarning, restampPatches, RESPONSIVE_NOTICE } from '../domains/site/traps.js';
22
22
  import { catalogBrowse, catalogMatches, traitsFor } from '../catalog/element-search.js';
23
+ import { missingUsualPages } from '../domains/site/inventory.js';
23
24
  import { LAYOUT_PATTERNS, PATTERN_BY_ID, THEME_TOKENS, } from '../domains/site/patterns.js';
24
25
  import { tokensFromPage } from '../domains/site/importmap.js';
25
26
  import { middleEnd } from '../domains/site/traps.js';
@@ -561,7 +562,7 @@ export function registerPageTools(server, ctx) {
561
562
  'does sb_traits_for.',
562
563
  inputSchema: {
563
564
  query: z.string().optional(),
564
- limit: z.number().int().min(1).max(30).optional().describe('Default 8'),
565
+ limit: z.number().int().min(1).max(60).optional().describe('Default 8'),
565
566
  detail: z.boolean().optional().describe('Include useWhen / avoidWhen / contentTips per match'),
566
567
  },
567
568
  annotations: { readOnlyHint: true },
@@ -574,8 +575,10 @@ export function registerPageTools(server, ctx) {
574
575
  ? catalogMatches(query, { limit, detail })
575
576
  : {
576
577
  elements: catalogBrowse(),
577
- note: 'Every element type, grouped as the palette groups them. Pass one as query for ' +
578
- 'the fields to choose by, then sb_traits_for for its controls and hints.',
578
+ note: 'Every element type, grouped as the palette groups them. Pass a TYPE as query ' +
579
+ 'for the fields to choose by, or a CATEGORY NAME with limit 60 to read that ' +
580
+ "whole group's descriptions at once — which is how you find out what the ones " +
581
+ 'you have never used are for. sb_traits_for then has the controls and hints.',
579
582
  }));
580
583
  server.registerTool('sb_traits_for', {
581
584
  description: "This element's INSPECTOR, as a person sees it: tabs, groups, and every control name — " +
@@ -1157,13 +1160,33 @@ export function registerPageTools(server, ctx) {
1157
1160
  description: "Every page on the site, with its slug and whether it is live.",
1158
1161
  inputSchema: { site_id: z.string().optional() },
1159
1162
  annotations: { readOnlyHint: true },
1160
- }, async ({ site_id: given }) => text(projectList(await request({
1161
- base: ctx.base,
1162
- method: 'GET',
1163
- path: `/api/sites/${encodeURIComponent(siteFor(ctx, given))}/pages`,
1164
- token: siteToken(ctx),
1165
- fetchImpl: ctx.fetchImpl,
1166
- }), 'pages', PAGE_FIELDS)));
1163
+ }, async ({ site_id: given }) => {
1164
+ const raw = (await request({
1165
+ base: ctx.base,
1166
+ method: 'GET',
1167
+ path: `/api/sites/${encodeURIComponent(siteFor(ctx, given))}/pages`,
1168
+ token: siteToken(ctx),
1169
+ fetchImpl: ctx.fetchImpl,
1170
+ }));
1171
+ // WHAT A SITE USUALLY ALSO HAS, said where an agent is orienting rather
1172
+ // than after it has finished. sb_review reports the pages the storefront
1173
+ // ROUTES BY TYPE; these have no type at all — login, register, forgot,
1174
+ // contact, about, the policies are ordinary "page" rows — so nothing else
1175
+ // in this server can tell a site that has them from one that does not.
1176
+ // See ./inventory.ts: advice, matched by name, and the note says both.
1177
+ const missing = missingUsualPages(raw.pages ?? null);
1178
+ return text({
1179
+ ...projectList(raw, 'pages', PAGE_FIELDS),
1180
+ ...(missing.length
1181
+ ? {
1182
+ usually_also: Object.fromEntries(missing.map((m) => [m.key, m.why])),
1183
+ usually_also_note: 'Pages most sites have that this one appears not to, found by NAME because they ' +
1184
+ 'have no type — one you named unusually will show here anyway. Advice, not ' +
1185
+ 'defects: sb_review reports the pages the storefront routes by type.',
1186
+ }
1187
+ : {}),
1188
+ });
1189
+ });
1167
1190
  server.registerTool('sb_page_create', {
1168
1191
  description: `A store type (${seededTypes().join(', ')}) arrives with the document the editor ` +
1169
1192
  'gives a merchant — product carries the whole bound buy box; seed:false for blank. ' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbuilder-mcp",
3
- "version": "0.49.0",
3
+ "version": "0.51.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",