x
This commit is contained in:
1 parent
20f43bd58d
commit
1ac727f4e5
10 files changed
+306
-122
No files matched your search
@@ -260,6 +260,54 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
},
|
||||
required: ["sectionId"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "update_footer_content",
|
||||
description: "Update the content and links of the 4 Footer Blocks (Brand, Explore, Collections, Newsletter)",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
brandDescription: { type: "string", description: "Text for Block 1 (Brand tagline)" },
|
||||
socialLinks: {
|
||||
type: "object",
|
||||
description: "URLs for facebook, instagram, tiktok (e.g. { facebookUrl: '...' })",
|
||||
properties: {
|
||||
facebookUrl: { type: "string" },
|
||||
instagramUrl: { type: "string" },
|
||||
tiktokUrl: { type: "string" }
|
||||
}
|
||||
},
|
||||
exploreLinks: {
|
||||
type: "array",
|
||||
description: "Array of { label, url, order } for Block 2 (Explore)",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: { label: { type: "string" }, url: { type: "string" }, order: { type: "number" } }
|
||||
}
|
||||
},
|
||||
collectionLinks: {
|
||||
type: "array",
|
||||
description: "Array of { label, url, order } for Block 3 (Collections)",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: { label: { type: "string" }, url: { type: "string" }, order: { type: "number" } }
|
||||
}
|
||||
},
|
||||
supportLinks: {
|
||||
type: "array",
|
||||
description: "Array of { label, url, order } for Block 4 (Support/Legal)",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: { label: { type: "string" }, url: { type: "string" }, order: { type: "number" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "audit_missing_pages",
|
||||
description: "Audit all menus and find links that do not have a corresponding dynamic page or hardcoded route",
|
||||
inputSchema: { type: "object", properties: {} }
|
||||
}
|
||||
],
|
||||
};
|
||||
@@ -421,6 +469,98 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const res = await api.delete(`/pages/sections/${params.sectionId}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "update_footer_content": {
|
||||
const results = [];
|
||||
|
||||
if (params.brandDescription !== undefined || params.socialLinks) {
|
||||
const settingsPayload: any = {};
|
||||
if (params.brandDescription !== undefined) settingsPayload.footerDescription = params.brandDescription;
|
||||
if (params.socialLinks?.facebookUrl !== undefined) settingsPayload.facebookUrl = params.socialLinks.facebookUrl;
|
||||
if (params.socialLinks?.instagramUrl !== undefined) settingsPayload.instagramUrl = params.socialLinks.instagramUrl;
|
||||
if (params.socialLinks?.tiktokUrl !== undefined) settingsPayload.tiktokUrl = params.socialLinks.tiktokUrl;
|
||||
|
||||
if (Object.keys(settingsPayload).length > 0) {
|
||||
// First fetch existing settings because the backend requires full payload validation
|
||||
const currentSettingsRes = await api.get("/settings");
|
||||
const currentSettings = currentSettingsRes.data || {};
|
||||
|
||||
const mergedSettings = { ...currentSettings, ...settingsPayload };
|
||||
// Remove null values so Elysia validation doesn't fail on t.Optional(t.String())
|
||||
for (const key in mergedSettings) {
|
||||
if (mergedSettings[key] === null) {
|
||||
delete mergedSettings[key];
|
||||
}
|
||||
}
|
||||
await api.put("/settings", mergedSettings);
|
||||
results.push({ type: "settings", status: "success" });
|
||||
}
|
||||
}
|
||||
|
||||
if (params.exploreLinks) {
|
||||
await api.put("/menus/footer-explore", { items: params.exploreLinks });
|
||||
results.push({ type: "explore_links", status: "success" });
|
||||
}
|
||||
|
||||
if (params.collectionLinks) {
|
||||
await api.put("/menus/footer-collections", { items: params.collectionLinks });
|
||||
results.push({ type: "collection_links", status: "success" });
|
||||
}
|
||||
|
||||
if (params.supportLinks) {
|
||||
await api.put("/menus/footer-support", { items: params.supportLinks });
|
||||
results.push({ type: "support_links", status: "success" });
|
||||
}
|
||||
|
||||
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
||||
}
|
||||
case "audit_missing_pages": {
|
||||
// 1. Fetch all menus
|
||||
const menusRes = await api.get("/menus");
|
||||
const menus = menusRes.data || [];
|
||||
|
||||
// 2. Fetch all dynamic pages
|
||||
const pagesRes = await api.get("/pages");
|
||||
const pages = pagesRes.data || [];
|
||||
const createdSlugs = pages.map((p: any) => `/${p.slug}`);
|
||||
|
||||
// 3. Known SPA Hardcoded Routes
|
||||
const hardcodedRoutes = [
|
||||
"/", "/shop", "/login", "/cart", "/checkout", "/account", "/search", "/contact"
|
||||
];
|
||||
|
||||
const missingLinks: any[] = [];
|
||||
|
||||
// 4. Audit
|
||||
menus.forEach((menu: any) => {
|
||||
if (menu.items && Array.isArray(menu.items)) {
|
||||
menu.items.forEach((item: any) => {
|
||||
const url = item.url;
|
||||
if (!url) return;
|
||||
|
||||
// Skip external links
|
||||
if (url.startsWith("http") || url.startsWith("mailto:") || url.startsWith("tel:")) return;
|
||||
|
||||
// Skip SPA Hardcoded routes
|
||||
if (hardcodedRoutes.includes(url)) return;
|
||||
|
||||
// Skip dynamic collection routes natively handled by SPA (e.g. /collections/...)
|
||||
if (url.startsWith("/collections/")) return;
|
||||
|
||||
// Check if it exists in created dynamic pages
|
||||
if (!createdSlugs.includes(url)) {
|
||||
missingLinks.push({
|
||||
menuName: menu.name,
|
||||
label: item.label,
|
||||
url: url,
|
||||
suggestedSlug: url.startsWith("/") ? url.substring(1) : url
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return { content: [{ type: "text", text: JSON.stringify({ missingPages: missingLinks }, null, 2) }] };
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user