sbuilder-mcp 0.50.0 → 0.52.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,20 @@ 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.52.0] - 2026-09-15
10
+
11
+ ### Added
12
+ - `sb_page_list`'s `usually_also` advisory now names a missing `faq` page.
13
+ - `sb_page_list`'s `usually_also` advisory now names a missing blog listing page, but only on a site that already has a `post` (article) template to list — a site with no articles is no longer told to build one.
14
+
15
+ ### Changed
16
+ - `sb_page_list`'s `usually_also` advisory splits the single `policy` entry into `policy-delivery` (shipping and returns) and `policy-privacy` (privacy and terms of use), so a site carrying only one of the two no longer reads as having both.
17
+
18
+ ## [0.51.0] - 2026-09-15
19
+
20
+ ### Added
21
+ - `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.
22
+
9
23
  ## [0.50.0] - 2026-09-15
10
24
 
11
25
  ### Changed
package/CHANGELOG.vi.md CHANGED
@@ -6,6 +6,20 @@ 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.52.0] - 2026-09-15
10
+
11
+ ### Added
12
+ - Gợi ý `usually_also` của `sb_page_list` giờ nêu tên trang `faq` nếu site còn thiếu.
13
+ - Gợi ý `usually_also` của `sb_page_list` giờ nêu tên trang danh sách blog nếu site còn thiếu, nhưng chỉ khi site đã có template bài viết (`post`) để liệt kê — site chưa có bài viết nào thì không còn bị nhắc xây trang này.
14
+
15
+ ### Changed
16
+ - Gợi ý `usually_also` của `sb_page_list` tách mục `policy` duy nhất thành `policy-delivery` (giao hàng và đổi trả) và `policy-privacy` (bảo mật và điều khoản sử dụng), để một site chỉ có một trong hai trang không còn bị đọc nhầm là đã có đủ cả hai.
17
+
18
+ ## [0.51.0] - 2026-09-15
19
+
20
+ ### Added
21
+ - `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.
22
+
9
23
  ## [0.50.0] - 2026-09-15
10
24
 
11
25
  ### Changed
@@ -0,0 +1,115 @@
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
+ // TWO POLICIES, NOT ONE BUCKET. These were a single entry, and it read a shop
58
+ // carrying only "Chính sách giao hàng & đổi trả" as complete — which is
59
+ // exactly the shop that was measured, and it had no privacy terms at all. One
60
+ // policy page satisfying a check about all of them is the check answering a
61
+ // question it was not asked.
62
+ {
63
+ key: 'policy-delivery',
64
+ match: [
65
+ 'doi-tra', 'đổi trả', 'return', 'refund', 'hoan-tien', 'hoàn tiền',
66
+ 'shipping', 'van-chuyen', 'vận chuyển', 'giao-hang', 'giao hàng', 'delivery',
67
+ ],
68
+ why: 'No delivery or return terms a shopper can read before paying. This is the page a buyer ' +
69
+ 'looks for when the parcel is late and the one a dispute is settled against.',
70
+ },
71
+ {
72
+ key: 'policy-privacy',
73
+ match: [
74
+ 'privacy', 'bao-mat', 'bảo mật', 'dieu-khoan', 'điều khoản', 'terms',
75
+ 'quy-dinh', 'quy định',
76
+ ],
77
+ why: 'No privacy policy or terms of use. Payment providers and marketplaces ask for both ' +
78
+ 'before they will list a shop, and a checkout form collects personal data either way.',
79
+ },
80
+ {
81
+ key: 'faq',
82
+ match: ['faq', 'cau-hoi', 'câu hỏi', 'hoi-dap', 'hỏi đáp', 'help', 'tro-giup', 'trợ giúp'],
83
+ why: 'The same handful of questions reach support one message at a time, with no page to link ' +
84
+ 'an answer to. The accordion element is what this page is built from.',
85
+ },
86
+ {
87
+ key: 'blog',
88
+ // ONLY ONCE THERE IS SOMETHING TO LIST. `post` is the ARTICLE template —
89
+ // it answers /blog/{slug} and has no address of its own — so a site with
90
+ // one can publish articles that nothing on the site links to. A site
91
+ // without one has no articles, and telling it to build a listing page is
92
+ // advice about a section it never asked for.
93
+ when: (pages) => pages.some((x) => x.type === 'post'),
94
+ match: ['blog', 'tin-tuc', 'tin tức', 'news', 'bai-viet', 'bài viết', 'kien-thuc', 'cẩm nang'],
95
+ why: 'This site has an article template, so /blog/{slug} works — but no page LISTS the ' +
96
+ 'articles, so each one is reachable only by someone who already has its URL.',
97
+ },
98
+ ];
99
+ /**
100
+ * Which of the usual pages this site appears not to have.
101
+ *
102
+ * Only `page`-typed rows are searched: a product TEMPLATE named "Chi tiết sản
103
+ * phẩm" is not an about page, and letting a template satisfy one of these would
104
+ * report a site as complete on the strength of a page that answers a different
105
+ * address entirely.
106
+ */
107
+ export function missingUsualPages(pages) {
108
+ if (!pages)
109
+ return [];
110
+ const hay = pages
111
+ .filter((p) => (typeof p.type === 'string' ? p.type === 'page' : true))
112
+ .map((p) => `${typeof p.slug === 'string' ? p.slug : ''} ${typeof p.name === 'string' ? p.name : ''}`.toLowerCase())
113
+ .join('\n');
114
+ return USUAL_PAGES.filter((u) => (u.when ? u.when(pages) : true) && !u.match.some((m) => hay.includes(m)));
115
+ }
@@ -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';
@@ -1159,13 +1160,33 @@ export function registerPageTools(server, ctx) {
1159
1160
  description: "Every page on the site, with its slug and whether it is live.",
1160
1161
  inputSchema: { site_id: z.string().optional() },
1161
1162
  annotations: { readOnlyHint: true },
1162
- }, async ({ site_id: given }) => text(projectList(await request({
1163
- base: ctx.base,
1164
- method: 'GET',
1165
- path: `/api/sites/${encodeURIComponent(siteFor(ctx, given))}/pages`,
1166
- token: siteToken(ctx),
1167
- fetchImpl: ctx.fetchImpl,
1168
- }), '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
+ });
1169
1190
  server.registerTool('sb_page_create', {
1170
1191
  description: `A store type (${seededTypes().join(', ')}) arrives with the document the editor ` +
1171
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.50.0",
3
+ "version": "0.52.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",