@cmo-so/mcp 0.12.14 → 0.12.15
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/cmo-mcp.mjs +66 -7
- package/package.json +1 -1
package/dist/cmo-mcp.mjs
CHANGED
|
@@ -7199,7 +7199,7 @@ var require_dist = __commonJS({
|
|
|
7199
7199
|
// package.json
|
|
7200
7200
|
var package_default = {
|
|
7201
7201
|
name: "@cmo-so/cli",
|
|
7202
|
-
version: "0.12.
|
|
7202
|
+
version: "0.12.15",
|
|
7203
7203
|
description: "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
7204
7204
|
type: "module",
|
|
7205
7205
|
license: "MIT",
|
|
@@ -15165,6 +15165,47 @@ async function partSet(site, slug, change) {
|
|
|
15165
15165
|
counts.social = (counts.social ?? 0) + links2.length;
|
|
15166
15166
|
}
|
|
15167
15167
|
}
|
|
15168
|
+
if (change.footer_links && slug === "footer") {
|
|
15169
|
+
const isRow = (b) => String(b.attrs.className ?? "").split(/\s+/).includes("maggie-footer-links");
|
|
15170
|
+
const items3 = change.footer_links.filter((l) => l?.label && l?.url).slice(0, 20).map(
|
|
15171
|
+
(l) => `<!-- wp:paragraph {"fontSize":"small"} -->
|
|
15172
|
+
<p class="has-small-font-size"><a href="${escAttr(l.url)}">${escAttr(l.label)}</a></p>
|
|
15173
|
+
<!-- /wp:paragraph -->`
|
|
15174
|
+
).join("\n\n");
|
|
15175
|
+
const row = items3 ? blockOf(
|
|
15176
|
+
`<!-- wp:group {"className":"maggie-footer-links","style":{"spacing":{"margin":{"bottom":"var:preset|spacing|40"}}},"layout":{"type":"flex","flexWrap":"wrap"}} -->
|
|
15177
|
+
<div class="wp-block-group maggie-footer-links" style="margin-bottom:var(--wp--preset--spacing--40)">${items3}</div>
|
|
15178
|
+
<!-- /wp:group -->`
|
|
15179
|
+
) : null;
|
|
15180
|
+
const old = find(blocks, isRow);
|
|
15181
|
+
if (old) {
|
|
15182
|
+
const top = blocks.indexOf(old);
|
|
15183
|
+
if (top >= 0) blocks.splice(top, 1, ...row ? [row] : []);
|
|
15184
|
+
else {
|
|
15185
|
+
const parent = find(blocks, (b) => b.inner.includes(old));
|
|
15186
|
+
const k = parent.inner.indexOf(old);
|
|
15187
|
+
if (row) parent.inner[k] = row;
|
|
15188
|
+
else {
|
|
15189
|
+
parent.inner.splice(k, 1);
|
|
15190
|
+
let seen = -1;
|
|
15191
|
+
const at = parent.content.findIndex((c) => c === null && ++seen === k);
|
|
15192
|
+
parent.content.splice(at, parent.content[at + 1] === "\n\n" ? 2 : 1);
|
|
15193
|
+
}
|
|
15194
|
+
touchPath(blocks, parent);
|
|
15195
|
+
}
|
|
15196
|
+
} else if (row) {
|
|
15197
|
+
const outer = blocks.find((b) => b.name === "core/group");
|
|
15198
|
+
if (outer?.inner.length) {
|
|
15199
|
+
const k = outer.inner.length - 1;
|
|
15200
|
+
outer.inner.splice(k, 0, row);
|
|
15201
|
+
let seen = -1;
|
|
15202
|
+
const at = outer.content.findIndex((c) => c === null && ++seen === k);
|
|
15203
|
+
outer.content.splice(at, 0, null, "\n\n");
|
|
15204
|
+
touchPath(blocks, outer);
|
|
15205
|
+
} else blocks.push(row);
|
|
15206
|
+
} else throw new Error("footer_links: give at least one { label, url }.");
|
|
15207
|
+
counts.footer_links = change.footer_links.length;
|
|
15208
|
+
}
|
|
15168
15209
|
const content = serialize(blocks);
|
|
15169
15210
|
if (content === p.content) return { slug, changed: false, counts };
|
|
15170
15211
|
await call(site, { method: "POST", path: `/wp/v2/template-parts/${p.id}`, body: { content } });
|
|
@@ -17316,6 +17357,11 @@ async function linksPlan(site, o = {}) {
|
|
|
17316
17357
|
);
|
|
17317
17358
|
const footer = await partGet(site, "footer").catch(() => null);
|
|
17318
17359
|
const footerPaths = footer ? contentLinks(footer.content, base) : /* @__PURE__ */ new Set();
|
|
17360
|
+
const rowHtml = /maggie-footer-links[^>]*>([\s\S]*?)<\/div>\s*<!-- \/wp:group -->/.exec(footer?.content ?? "")?.[1] ?? "";
|
|
17361
|
+
const footerRow = [...rowHtml.matchAll(/<a[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/g)].map((m) => ({
|
|
17362
|
+
url: m[1],
|
|
17363
|
+
label: strip(m[2])
|
|
17364
|
+
}));
|
|
17319
17365
|
const header = await partGet(site, "header").catch(() => null);
|
|
17320
17366
|
const headerPaths = header ? contentLinks(header.content, base) : /* @__PURE__ */ new Set();
|
|
17321
17367
|
const chrome = /* @__PURE__ */ new Set([...menuPaths, ...footerPaths, ...headerPaths]);
|
|
@@ -17378,14 +17424,16 @@ async function linksPlan(site, o = {}) {
|
|
|
17378
17424
|
type: "menu",
|
|
17379
17425
|
why: "Main pages every visitor should reach in one click.",
|
|
17380
17426
|
add: wantMenu.slice(0, 6).map((d) => ({ label: d.title, url: d.url })),
|
|
17381
|
-
tool: "wp_menu_set"
|
|
17427
|
+
tool: "wp_menu_set",
|
|
17428
|
+
args: { add: wantMenu.slice(0, 6).map((d) => ({ label: d.title, url: d.path })) }
|
|
17382
17429
|
});
|
|
17383
17430
|
if (postDocs.length && blogPage && !chrome.has(blogPage.path))
|
|
17384
17431
|
actions.push({
|
|
17385
17432
|
type: "menu",
|
|
17386
17433
|
why: "The blog isn't reachable from the menu.",
|
|
17387
17434
|
add: [{ label: blogPage.title || "Blog", url: blogPage.url }],
|
|
17388
|
-
tool: "wp_menu_set"
|
|
17435
|
+
tool: "wp_menu_set",
|
|
17436
|
+
args: { add: [{ label: blogPage.title || "Blog", url: blogPage.path }] }
|
|
17389
17437
|
});
|
|
17390
17438
|
const legal = pageDocs.filter(
|
|
17391
17439
|
(d) => /privacy|terms|cookie|legal|impressum|datenschutz|accessib/i.test(`${d.path} ${d.title}`)
|
|
@@ -17397,7 +17445,14 @@ async function linksPlan(site, o = {}) {
|
|
|
17397
17445
|
type: "footer",
|
|
17398
17446
|
why: "Legal, contact and about pages belong in the footer of every page (trust, and Google's quality raters look for them).",
|
|
17399
17447
|
add: footerMissing.slice(0, 8).map((d) => ({ label: d.title, url: d.url })),
|
|
17400
|
-
tool: "wp_footer_set"
|
|
17448
|
+
tool: "wp_footer_set",
|
|
17449
|
+
// The footer's own row (if this tool made one) plus the missing pages, ready for wp_footer_set.
|
|
17450
|
+
args: {
|
|
17451
|
+
footer_links: [
|
|
17452
|
+
...footerRow,
|
|
17453
|
+
...footerMissing.slice(0, 8).filter((d) => !footerRow.some((r) => sitePath(r.url, base) === d.path)).map((d) => ({ label: d.title, url: d.path }))
|
|
17454
|
+
]
|
|
17455
|
+
}
|
|
17401
17456
|
});
|
|
17402
17457
|
for (const hub of hubs) {
|
|
17403
17458
|
const kids = pageDocs.filter((c) => c.parent === hub.id);
|
|
@@ -17520,8 +17575,8 @@ function relatedBlock(heading2, links2) {
|
|
|
17520
17575
|
const items3 = links2.map((l) => `<!-- wp:list-item -->
|
|
17521
17576
|
<li><a href="${esc(l.url)}">${esc(l.label)}</a></li>
|
|
17522
17577
|
<!-- /wp:list-item -->`).join("\n");
|
|
17523
|
-
return `<!-- wp:group {"metadata":{"name":"Related links","maggie":{"type":"related-links","version":1}},"align":"wide","className":"maggie-related-links","layout":{"type":"constrained"}} -->
|
|
17524
|
-
<div class="wp-block-group alignwide maggie-related-links"><!-- wp:heading {"level":2} -->
|
|
17578
|
+
return `<!-- wp:group {"metadata":{"name":"Related links","maggie":{"type":"related-links","version":1}},"align":"wide","className":"maggie-related-links","style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained","contentSize":"var(--wp--style--global--wide-size)"}} -->
|
|
17579
|
+
<div class="wp-block-group alignwide maggie-related-links" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)"><!-- wp:heading {"level":2} -->
|
|
17525
17580
|
<h2 class="wp-block-heading">${esc(heading2)}</h2>
|
|
17526
17581
|
<!-- /wp:heading -->
|
|
17527
17582
|
|
|
@@ -19484,12 +19539,16 @@ var elementTools = [
|
|
|
19484
19539
|
}),
|
|
19485
19540
|
tool({
|
|
19486
19541
|
name: "wp_footer_set",
|
|
19487
|
-
description: "Change the footer: any text (address, hours, copyright), link or picture, social profile links by service; reset goes back to the theme's own footer.",
|
|
19542
|
+
description: "Change the footer: any text (address, hours, copyright), link or picture, social profile links by service, the row of page links (footer_links); reset goes back to the theme's own footer.",
|
|
19488
19543
|
parameters: {
|
|
19489
19544
|
type: "object",
|
|
19490
19545
|
properties: {
|
|
19491
19546
|
...EDITS.properties ?? {},
|
|
19492
19547
|
social: obj('Social links by service: { "facebook": "https://\u2026", "instagram": "" (remove) }.'),
|
|
19548
|
+
footer_links: arr(
|
|
19549
|
+
"The footer's row of page links, in order (replaces the row set before; [] removes it): legal, contact, about, main pages.",
|
|
19550
|
+
obj("", { label: str2(""), url: str2("Relative for own pages: /contact/.") })
|
|
19551
|
+
),
|
|
19493
19552
|
reset: bool("Drop the site's changes: back to the theme's footer.")
|
|
19494
19553
|
}
|
|
19495
19554
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/mcp",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.15",
|
|
4
4
|
"description": "CMO.so's MCP server for Claude Desktop, Cursor, VS Code and other MCP clients: manage your websites, blog posts, LinkedIn queue and results with Maggie.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|