@cmo-so/cli 0.12.7 → 0.12.9
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.mjs +250 -23
- package/package.json +1 -1
package/dist/cmo.mjs
CHANGED
|
@@ -14658,6 +14658,54 @@ function replace(blocks, ref, next, synced = {}) {
|
|
|
14658
14658
|
function sectionAt(blocks, ref, synced = {}) {
|
|
14659
14659
|
return pick(locate(blocks), ref, synced);
|
|
14660
14660
|
}
|
|
14661
|
+
function widthValue(width) {
|
|
14662
|
+
const w = String(width ?? "").trim();
|
|
14663
|
+
if (w === "content") return null;
|
|
14664
|
+
if (w === "wide") return "var(--wp--style--global--wide-size)";
|
|
14665
|
+
if (/^\d{2,4}(\.\d+)?(px|rem|em|vw|%)$/.test(w)) return w;
|
|
14666
|
+
throw new Error('width: "content", "wide" or a CSS length such as 1240px.');
|
|
14667
|
+
}
|
|
14668
|
+
var NARROW_PX = 700;
|
|
14669
|
+
var sizePx = (v) => {
|
|
14670
|
+
const m = /^(\d+(?:\.\d+)?)(px|rem|em)$/.exec(v);
|
|
14671
|
+
return m ? Number(m[1]) * (m[2] === "px" ? 1 : 16) : null;
|
|
14672
|
+
};
|
|
14673
|
+
function setSectionWidth(b, width) {
|
|
14674
|
+
const size = widthValue(width);
|
|
14675
|
+
const before = [];
|
|
14676
|
+
const visit = (x, top) => {
|
|
14677
|
+
let changed = false;
|
|
14678
|
+
for (const c of x.inner) if (visit(c, false)) changed = true;
|
|
14679
|
+
const lay = x.attrs.layout;
|
|
14680
|
+
const constrained = lay?.type === "constrained";
|
|
14681
|
+
const cur = lay?.contentSize;
|
|
14682
|
+
const px = cur ? sizePx(cur) : null;
|
|
14683
|
+
const eligible = constrained && (!cur || cur.includes("--wp--style--global") || px == null || px >= NARROW_PX);
|
|
14684
|
+
if (eligible || top && !lay && (x.name === "core/group" || x.name === "core/cover")) {
|
|
14685
|
+
if ((cur ?? null) !== size) {
|
|
14686
|
+
before.push(cur ?? "content");
|
|
14687
|
+
const next = { ...lay ?? {}, type: "constrained" };
|
|
14688
|
+
if (size) next.contentSize = size;
|
|
14689
|
+
else delete next.contentSize;
|
|
14690
|
+
x.attrs = { ...x.attrs, layout: next };
|
|
14691
|
+
changed = true;
|
|
14692
|
+
}
|
|
14693
|
+
}
|
|
14694
|
+
if (changed) delete x.raw;
|
|
14695
|
+
return changed;
|
|
14696
|
+
};
|
|
14697
|
+
visit(b, true);
|
|
14698
|
+
return { containers: before.length, before };
|
|
14699
|
+
}
|
|
14700
|
+
function refreshRaw(list3) {
|
|
14701
|
+
let any = false;
|
|
14702
|
+
for (const b of list3) {
|
|
14703
|
+
const inner = refreshRaw(b.inner);
|
|
14704
|
+
if (inner) delete b.raw;
|
|
14705
|
+
if (inner || b.raw == null) any = true;
|
|
14706
|
+
}
|
|
14707
|
+
return any;
|
|
14708
|
+
}
|
|
14661
14709
|
var escRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14662
14710
|
function applyEdits(b, e) {
|
|
14663
14711
|
let m = serializeBlock(b);
|
|
@@ -15195,6 +15243,15 @@ async function styleGet(site) {
|
|
|
15195
15243
|
fonts: (user.settings?.typography?.fontFamilies?.theme ?? []).map((f) => f.slug)
|
|
15196
15244
|
},
|
|
15197
15245
|
contrast: contrastReport(Object.fromEntries([...palette.values()].map((c) => [c.slug, c.color]))),
|
|
15246
|
+
layout: {
|
|
15247
|
+
content: user.settings?.layout?.contentSize ?? base.settings?.layout?.contentSize ?? null,
|
|
15248
|
+
wide: user.settings?.layout?.wideSize ?? base.settings?.layout?.wideSize ?? null,
|
|
15249
|
+
padding: {
|
|
15250
|
+
left: user.styles?.spacing?.padding?.left ?? base.styles?.spacing?.padding?.left ?? null,
|
|
15251
|
+
right: user.styles?.spacing?.padding?.right ?? base.styles?.spacing?.padding?.right ?? null
|
|
15252
|
+
}
|
|
15253
|
+
},
|
|
15254
|
+
css: user.styles?.css ?? "",
|
|
15198
15255
|
_palette: [...palette.values()],
|
|
15199
15256
|
_fonts: [...fonts.values()],
|
|
15200
15257
|
_user: user
|
|
@@ -15235,6 +15292,17 @@ function contrastReport(colors) {
|
|
|
15235
15292
|
});
|
|
15236
15293
|
}
|
|
15237
15294
|
async function styleSet(site, change, force = false) {
|
|
15295
|
+
const len = (v, what) => {
|
|
15296
|
+
const t = String(v ?? "").trim();
|
|
15297
|
+
if (!/^(0|\d{1,4}(\.\d+)?(px|rem|em|vw|%)|var\(--wp--preset--spacing--[a-z0-9-]+\)|clamp\([0-9a-z.,%+\-\s()]+\))$/i.test(
|
|
15298
|
+
t
|
|
15299
|
+
))
|
|
15300
|
+
throw new Error(`${what}: "${t}" isn't a CSS length like 1240px, 2rem or var(--wp--preset--spacing--50).`);
|
|
15301
|
+
return t;
|
|
15302
|
+
};
|
|
15303
|
+
for (const css of [change.css, change.css_append])
|
|
15304
|
+
if (css != null && /<\/?style|<\?|<script|@import\s+url\(\s*['"]?(?!https:)/i.test(css))
|
|
15305
|
+
throw new Error("css: plain CSS only (no <style>, <script>, PHP or non-https imports).");
|
|
15238
15306
|
const cur = await styleGet(site);
|
|
15239
15307
|
const palette = cur._palette.map((c) => ({ ...c }));
|
|
15240
15308
|
for (const [slug, color] of Object.entries(change.colors ?? {})) {
|
|
@@ -15259,15 +15327,48 @@ async function styleSet(site, change, force = false) {
|
|
|
15259
15327
|
);
|
|
15260
15328
|
const user = cur._user;
|
|
15261
15329
|
const settings2 = { ...user.settings ?? {} };
|
|
15330
|
+
const styles = { ...user.styles ?? {} };
|
|
15262
15331
|
if (change.colors) settings2.color = { ...settings2.color ?? {}, palette: { theme: palette } };
|
|
15263
15332
|
if (change.fonts)
|
|
15264
15333
|
settings2.typography = { ...settings2.typography ?? {}, fontFamilies: { theme: fonts } };
|
|
15334
|
+
if (change.layout) {
|
|
15335
|
+
const layout = { ...settings2.layout ?? {} };
|
|
15336
|
+
if (change.layout.content != null) layout.contentSize = len(change.layout.content, "layout.content");
|
|
15337
|
+
if (change.layout.wide != null) layout.wideSize = len(change.layout.wide, "layout.wide");
|
|
15338
|
+
settings2.layout = layout;
|
|
15339
|
+
}
|
|
15340
|
+
if (change.padding) {
|
|
15341
|
+
const spacing = { ...styles.spacing ?? {} };
|
|
15342
|
+
const pad = { ...spacing.padding ?? {} };
|
|
15343
|
+
if (change.padding.left != null) pad.left = len(change.padding.left, "padding.left");
|
|
15344
|
+
if (change.padding.right != null) pad.right = len(change.padding.right, "padding.right");
|
|
15345
|
+
styles.spacing = { ...spacing, padding: pad };
|
|
15346
|
+
settings2.useRootPaddingAwareAlignments = true;
|
|
15347
|
+
}
|
|
15348
|
+
if (change.css != null) styles.css = change.css;
|
|
15349
|
+
if (change.css_append)
|
|
15350
|
+
styles.css = `${String(styles.css ?? "").trimEnd()}
|
|
15351
|
+
|
|
15352
|
+
${change.css_append.trim()}
|
|
15353
|
+
`.trimStart();
|
|
15265
15354
|
await call(site, {
|
|
15266
15355
|
method: "POST",
|
|
15267
15356
|
path: `/wp/v2/global-styles/${cur.id}`,
|
|
15268
|
-
body: { settings: settings2, styles
|
|
15357
|
+
body: { settings: settings2, styles }
|
|
15269
15358
|
});
|
|
15359
|
+
const changedLayout = change.layout || change.padding;
|
|
15270
15360
|
return {
|
|
15361
|
+
...changedLayout ? {
|
|
15362
|
+
layout: {
|
|
15363
|
+
before: cur.layout,
|
|
15364
|
+
after: {
|
|
15365
|
+
content: settings2.layout?.contentSize ?? cur.layout.content,
|
|
15366
|
+
wide: settings2.layout?.wideSize ?? cur.layout.wide,
|
|
15367
|
+
padding: change.padding ? { ...cur.layout.padding, ...change.padding } : cur.layout.padding
|
|
15368
|
+
}
|
|
15369
|
+
}
|
|
15370
|
+
} : {},
|
|
15371
|
+
...change.css != null || change.css_append ? { css: { before: cur.css.length, after: String(styles.css ?? "").length, before_text: cur.css } } : {},
|
|
15271
15372
|
colors: Object.fromEntries(
|
|
15272
15373
|
Object.entries(change.colors ?? {}).map(([k, v]) => [k, { before: cur.colors[k], after: v }])
|
|
15273
15374
|
),
|
|
@@ -16386,7 +16487,7 @@ var siteTools = [
|
|
|
16386
16487
|
}),
|
|
16387
16488
|
tool({
|
|
16388
16489
|
name: "wp_style_get",
|
|
16389
|
-
description: "The
|
|
16490
|
+
description: "The site's look: colours (by name: canvas, panel, soft, ink, muted, olive, accent\u2026), fonts (display, body), layout widths (content, wide) and page padding, the extra CSS, and the text contrast of each colour pair.",
|
|
16390
16491
|
parameters: { type: "object", properties: {} },
|
|
16391
16492
|
group: "site",
|
|
16392
16493
|
need: READ,
|
|
@@ -16394,7 +16495,14 @@ var siteTools = [
|
|
|
16394
16495
|
gates: ["WP"],
|
|
16395
16496
|
run: async (ctx) => {
|
|
16396
16497
|
const s = await styleGet(siteOf(ctx));
|
|
16397
|
-
return {
|
|
16498
|
+
return {
|
|
16499
|
+
colors: s.colors,
|
|
16500
|
+
fonts: s.fonts,
|
|
16501
|
+
layout: s.layout,
|
|
16502
|
+
css: s.css,
|
|
16503
|
+
customized: s.customized,
|
|
16504
|
+
contrast: s.contrast
|
|
16505
|
+
};
|
|
16398
16506
|
}
|
|
16399
16507
|
})
|
|
16400
16508
|
];
|
|
@@ -16836,12 +16944,15 @@ var sectionTools = [
|
|
|
16836
16944
|
}),
|
|
16837
16945
|
tool({
|
|
16838
16946
|
name: "wp_section_update",
|
|
16839
|
-
description:
|
|
16947
|
+
description: 'Change one section. width: line its content up with the header and footer ("wide") or another width, one section or all. edits: change text, links or pictures inside it and keep its design (works on any section, the homepage too). slots: write the section again from new content (generated types; give the complete content). faq: add, remove (1-based numbers) or replace questions.',
|
|
16840
16948
|
parameters: {
|
|
16841
16949
|
type: "object",
|
|
16842
16950
|
properties: {
|
|
16843
16951
|
page: PAGE,
|
|
16844
|
-
section: str2(
|
|
16952
|
+
section: str2('Section id from wp_page_get (s2, m4) or its type (faq); "all" with width only.'),
|
|
16953
|
+
width: str2(
|
|
16954
|
+
`The section's inner width: "content" (the site's content width), "wide" (the site's wide width, as the header and footer) or a CSS length (1240px). Changes the section and its containers wider than 700px; with section "all", every section on the page.`
|
|
16955
|
+
),
|
|
16845
16956
|
edits: EDITS,
|
|
16846
16957
|
slots: obj("Complete new content for the section (same type unless type is given)."),
|
|
16847
16958
|
markup: str2(
|
|
@@ -16870,6 +16981,19 @@ var sectionTools = [
|
|
|
16870
16981
|
),
|
|
16871
16982
|
run: (ctx, a) => changePage(ctx, a, (blocks, kit) => {
|
|
16872
16983
|
const ref = String(a.section);
|
|
16984
|
+
if (a.width != null && a.width !== "") {
|
|
16985
|
+
const targets = ref === "all" ? locate(blocks) : [sectionAt(blocks, ref, kit.syncedTitles)];
|
|
16986
|
+
const changed = {};
|
|
16987
|
+
for (const t of targets) {
|
|
16988
|
+
if (t.block.name === "core/block") continue;
|
|
16989
|
+
const r = setSectionWidth(t.block, a.width);
|
|
16990
|
+
if (r.containers) changed[t.id] = r;
|
|
16991
|
+
}
|
|
16992
|
+
refreshRaw(blocks);
|
|
16993
|
+
if (!Object.keys(changed).length) throw new Error("Those sections already have that width.");
|
|
16994
|
+
return { blocks, note: { width: String(a.width), sections: changed } };
|
|
16995
|
+
}
|
|
16996
|
+
if (ref === "all") throw new Error('section "all" works with width only.');
|
|
16873
16997
|
const target = sectionAt(blocks, ref, kit.syncedTitles);
|
|
16874
16998
|
const type = classify(target.block, target.region, kit.syncedTitles);
|
|
16875
16999
|
let next;
|
|
@@ -17304,7 +17428,7 @@ var childTools = [
|
|
|
17304
17428
|
files[`assets/fonts/${name}`] = btoa(bin);
|
|
17305
17429
|
let fam = fams.find((x) => x.slug === f.slug);
|
|
17306
17430
|
const stack = `"${f.family}", ${f.fallback || "sans-serif"}`;
|
|
17307
|
-
if (!fam
|
|
17431
|
+
if (!fam?.fontFamily.includes(`"${f.family}"`)) {
|
|
17308
17432
|
const keep = fam ? fams.indexOf(fam) : -1;
|
|
17309
17433
|
fam = { slug: f.slug, name: f.family, fontFamily: stack, fontFace: [] };
|
|
17310
17434
|
if (keep >= 0) fams[keep] = fam;
|
|
@@ -17775,23 +17899,41 @@ var elementTools = [
|
|
|
17775
17899
|
}),
|
|
17776
17900
|
tool({
|
|
17777
17901
|
name: "wp_style_set",
|
|
17778
|
-
description: "Change brand colours (by name, hex)
|
|
17902
|
+
description: "Change the whole site's look: brand colours (by name, hex), fonts (by name, CSS font-family), layout widths (content: the width sections and text use; wide: the header, footer and wide blocks), the left and right page padding, and extra CSS. Saved in the site's Global Styles (works on any block theme; returns before and after). Refuses colours that would make text hard to read (contrast under 4.5:1). One section's width: wp_section_update width.",
|
|
17779
17903
|
parameters: {
|
|
17780
17904
|
type: "object",
|
|
17781
17905
|
properties: {
|
|
17782
17906
|
colors: obj('e.g. { "olive": "#4F5B48", "accent": "#A8834F" }.'),
|
|
17783
|
-
fonts: obj('e.g. { "display": "\\"Playfair Display\\", Georgia, serif" }.')
|
|
17907
|
+
fonts: obj('e.g. { "display": "\\"Playfair Display\\", Georgia, serif" }.'),
|
|
17908
|
+
layout: obj('Widths, e.g. { "content": "1240px", "wide": "1240px" }.', {
|
|
17909
|
+
content: str2("Content width (CSS length)."),
|
|
17910
|
+
wide: str2("Wide width (CSS length).")
|
|
17911
|
+
}),
|
|
17912
|
+
padding: obj('Left and right page padding, e.g. { "left": "24px", "right": "24px" }.', {
|
|
17913
|
+
left: str2(""),
|
|
17914
|
+
right: str2("")
|
|
17915
|
+
}),
|
|
17916
|
+
css: str2("Replace the site's extra CSS (Global Styles \u2192 Additional CSS); plain CSS only."),
|
|
17917
|
+
css_append: str2("Add this CSS after the site's extra CSS.")
|
|
17784
17918
|
}
|
|
17785
17919
|
},
|
|
17786
17920
|
group: "site",
|
|
17787
17921
|
need: WRITE,
|
|
17788
17922
|
risk: "W3",
|
|
17789
17923
|
gates: [...GATES],
|
|
17790
|
-
confirm: (_a3, lang) => say(
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17924
|
+
confirm: (_a3, lang) => say(
|
|
17925
|
+
lang,
|
|
17926
|
+
"Change the website's look for every page (colours, fonts, widths, padding or extra CSS); the result shows before and after.",
|
|
17927
|
+
"\u4FEE\u6539\u7DB2\u7AD9\u6240\u6709\u9801\u9762\u7684\u5916\u89C0\uFF08\u984F\u8272\u3001\u5B57\u9AD4\u3001\u5BEC\u5EA6\u3001\u908A\u8DDD\u6216\u984D\u5916 CSS\uFF09\uFF1B\u7D50\u679C\u6703\u5217\u51FA\u4FEE\u6539\u524D\u5F8C\u3002"
|
|
17928
|
+
),
|
|
17929
|
+
run: async (ctx, a) => styleSet(siteOf(ctx), {
|
|
17930
|
+
colors: a.colors,
|
|
17931
|
+
fonts: a.fonts,
|
|
17932
|
+
layout: a.layout,
|
|
17933
|
+
padding: a.padding,
|
|
17934
|
+
css: typeof a.css === "string" ? a.css : void 0,
|
|
17935
|
+
css_append: typeof a.css_append === "string" ? a.css_append : void 0
|
|
17936
|
+
})
|
|
17795
17937
|
})
|
|
17796
17938
|
];
|
|
17797
17939
|
function checkMarkup(markup, what) {
|
|
@@ -18123,6 +18265,49 @@ var fullTools = [
|
|
|
18123
18265
|
});
|
|
18124
18266
|
}
|
|
18125
18267
|
}),
|
|
18268
|
+
tool({
|
|
18269
|
+
name: "wp_term_delete",
|
|
18270
|
+
description: "Delete a category or tag by id. Posts keep their other terms; posts left without a category go to the default category, which can't be deleted. Terms have no trash: the result gives name, slug and description to recreate it with wp_term_save.",
|
|
18271
|
+
parameters: {
|
|
18272
|
+
type: "object",
|
|
18273
|
+
properties: {
|
|
18274
|
+
taxonomy: { type: "string", enum: ["categories", "tags"], description: "Default categories." },
|
|
18275
|
+
id: int2("The term to delete (from wp_terms_list).")
|
|
18276
|
+
},
|
|
18277
|
+
required: ["id"]
|
|
18278
|
+
},
|
|
18279
|
+
group: "site",
|
|
18280
|
+
need: WRITE,
|
|
18281
|
+
risk: "W3",
|
|
18282
|
+
gates: [...GATES],
|
|
18283
|
+
confirm: (a, lang) => say(
|
|
18284
|
+
lang,
|
|
18285
|
+
`Delete the ${a.taxonomy === "tags" ? "tag" : "category"} #${String(a.id)} from your website (posts stay; it can be recreated, not restored).`,
|
|
18286
|
+
`\u522A\u9664\u7DB2\u7AD9\u7684${a.taxonomy === "tags" ? "\u6A19\u7C64" : "\u5206\u985E"} #${String(a.id)}\uFF08\u6587\u7AE0\u4FDD\u7559\uFF1B\u53EF\u91CD\u65B0\u5EFA\u7ACB\uFF0C\u7121\u6CD5\u9084\u539F\uFF09\u3002`
|
|
18287
|
+
),
|
|
18288
|
+
run: async (ctx, a) => {
|
|
18289
|
+
const site = siteOf(ctx);
|
|
18290
|
+
const tax = a.taxonomy === "tags" ? "tags" : "categories";
|
|
18291
|
+
const id = Number(a.id);
|
|
18292
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error("id: the term id from wp_terms_list.");
|
|
18293
|
+
if (tax === "categories") {
|
|
18294
|
+
const st = await call(site, {
|
|
18295
|
+
path: "/wp/v2/settings",
|
|
18296
|
+
query: { _fields: "default_category" }
|
|
18297
|
+
});
|
|
18298
|
+
if (Number(st.default_category ?? 1) === id)
|
|
18299
|
+
throw new Error("That is the default category; it can't be deleted.");
|
|
18300
|
+
}
|
|
18301
|
+
const before = await call(site, { path: `/wp/v2/${tax}/${id}`, query: { _fields: "id,name,slug,description,count,parent" } });
|
|
18302
|
+
await call(site, { method: "DELETE", path: `/wp/v2/${tax}/${id}`, query: { force: "true" } });
|
|
18303
|
+
return {
|
|
18304
|
+
deleted: true,
|
|
18305
|
+
taxonomy: tax,
|
|
18306
|
+
...before,
|
|
18307
|
+
undo: `wp_term_save ${tax} name "${before.name}" slug ${before.slug}`
|
|
18308
|
+
};
|
|
18309
|
+
}
|
|
18310
|
+
}),
|
|
18126
18311
|
tool({
|
|
18127
18312
|
name: "wp_settings_get",
|
|
18128
18313
|
description: "The site's general settings: title, tagline, search-engine visibility, language, timezone, date and time formats, start of week, posts per page, homepage and posts page, logo and icon.",
|
|
@@ -18208,7 +18393,7 @@ var fullTools = [
|
|
|
18208
18393
|
}),
|
|
18209
18394
|
tool({
|
|
18210
18395
|
name: "wp_plugin_set",
|
|
18211
|
-
description: "Install a plugin from WordPress.org by its slug (e.g. wpforms-lite), and/or activate or
|
|
18396
|
+
description: "Install a plugin from WordPress.org by its slug (e.g. wpforms-lite), and/or activate, deactivate or delete an installed one (plugin id from wp_plugins_list, e.g. akismet/akismet; only an inactive plugin can be deleted, and its settings may go with it). Installing runs the plugin's code on the site: only well-known plugins the owner asked for.",
|
|
18212
18397
|
parameters: {
|
|
18213
18398
|
type: "object",
|
|
18214
18399
|
properties: {
|
|
@@ -18216,8 +18401,8 @@ var fullTools = [
|
|
|
18216
18401
|
plugin: str2("Installed plugin id (folder/file) to change."),
|
|
18217
18402
|
status: {
|
|
18218
18403
|
type: "string",
|
|
18219
|
-
enum: ["active", "inactive"],
|
|
18220
|
-
description: "Activate
|
|
18404
|
+
enum: ["active", "inactive", "deleted"],
|
|
18405
|
+
description: "Activate, deactivate (after installing, default inactive), or deleted: remove an inactive plugin's files (deactivate it first; Maggie Press can't be removed here)."
|
|
18221
18406
|
}
|
|
18222
18407
|
}
|
|
18223
18408
|
},
|
|
@@ -18229,6 +18414,10 @@ var fullTools = [
|
|
|
18229
18414
|
lang,
|
|
18230
18415
|
`Install the plugin ${q2(a.install, "")} from WordPress.org on your website${a.status === "active" ? " and activate it" : ""}.`,
|
|
18231
18416
|
`\u5728\u7DB2\u7AD9\u4E0A\u5B89\u88DD WordPress.org \u63D2\u4EF6 ${q2(a.install, "")}${a.status === "active" ? "\u4E26\u555F\u7528" : ""}\u3002`
|
|
18417
|
+
) : a.status === "deleted" ? say(
|
|
18418
|
+
lang,
|
|
18419
|
+
`Delete the plugin ${q2(a.plugin, "")} from your website (its files are removed; reinstall it from WordPress.org to undo, its settings may be lost).`,
|
|
18420
|
+
`\u5F9E\u7DB2\u7AD9\u522A\u9664\u63D2\u4EF6 ${q2(a.plugin, "")}\uFF08\u6A94\u6848\u6703\u88AB\u79FB\u9664\uFF1B\u53EF\u5F9E WordPress.org \u91CD\u65B0\u5B89\u88DD\uFF0C\u8A2D\u5B9A\u53EF\u80FD\u907A\u5931\uFF09\u3002`
|
|
18232
18421
|
) : say(
|
|
18233
18422
|
lang,
|
|
18234
18423
|
`${a.status === "active" ? "Activate" : "Deactivate"} the plugin ${q2(a.plugin, "")} on your website.`,
|
|
@@ -18249,9 +18438,29 @@ var fullTools = [
|
|
|
18249
18438
|
if (!a.plugin || !a.status) throw new Error("Give install (a slug), or plugin and status.");
|
|
18250
18439
|
if (!/^[a-z0-9._-]+(\/[a-z0-9._-]+)?$/i.test(String(a.plugin)))
|
|
18251
18440
|
throw new Error("plugin: the id from wp_plugins_list, e.g. akismet/akismet.");
|
|
18441
|
+
const id = String(a.plugin).replace(/\.php$/, "");
|
|
18442
|
+
if (a.status === "deleted") {
|
|
18443
|
+
if (/^maggie-?press\//i.test(id))
|
|
18444
|
+
throw new Error("Maggie Press runs the site's styles; it can't be deleted here.");
|
|
18445
|
+
const cur = await call(site, {
|
|
18446
|
+
path: `/wp/v2/plugins/${id}`,
|
|
18447
|
+
query: { _fields: "plugin,name,version,status" }
|
|
18448
|
+
});
|
|
18449
|
+
if (cur.status !== "inactive")
|
|
18450
|
+
throw new Error(`${cur.name} is ${cur.status}: deactivate it first (status inactive), then delete it.`);
|
|
18451
|
+
await call(site, { method: "DELETE", path: `/wp/v2/plugins/${id}` });
|
|
18452
|
+
const slug = id.split("/")[0];
|
|
18453
|
+
return {
|
|
18454
|
+
deleted: true,
|
|
18455
|
+
plugin: cur.plugin,
|
|
18456
|
+
name: cur.name,
|
|
18457
|
+
version: cur.version,
|
|
18458
|
+
undo: `wp_plugin_set install ${slug}`
|
|
18459
|
+
};
|
|
18460
|
+
}
|
|
18252
18461
|
return call(site, {
|
|
18253
18462
|
method: "POST",
|
|
18254
|
-
path: `/wp/v2/plugins/${
|
|
18463
|
+
path: `/wp/v2/plugins/${id}`,
|
|
18255
18464
|
query: { _fields: "plugin,name,version,status" },
|
|
18256
18465
|
body: { status: a.status }
|
|
18257
18466
|
});
|
|
@@ -21699,7 +21908,7 @@ var program = new Command();
|
|
|
21699
21908
|
// package.json
|
|
21700
21909
|
var package_default = {
|
|
21701
21910
|
name: "@cmo-so/cli",
|
|
21702
|
-
version: "0.12.
|
|
21911
|
+
version: "0.12.9",
|
|
21703
21912
|
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.",
|
|
21704
21913
|
type: "module",
|
|
21705
21914
|
license: "MIT",
|
|
@@ -32746,6 +32955,16 @@ function registerWp(program3) {
|
|
|
32746
32955
|
o.preview ? { tool: "wp_section_update", args } : args
|
|
32747
32956
|
);
|
|
32748
32957
|
});
|
|
32958
|
+
section.command("width <page> <section> <width>").description(
|
|
32959
|
+
'line sections up: width "wide" (as the header and footer), "content" or 1240px; section "all" = every section'
|
|
32960
|
+
).option("--preview", "show the result, save nothing").action(async (p, s, w, o, c) => {
|
|
32961
|
+
const args = { page: p, section: s, width: w };
|
|
32962
|
+
await run(
|
|
32963
|
+
g(c),
|
|
32964
|
+
o.preview ? "wp_preview" : "wp_section_update",
|
|
32965
|
+
o.preview ? { tool: "wp_section_update", args } : args
|
|
32966
|
+
);
|
|
32967
|
+
});
|
|
32749
32968
|
pos(section.command("move <page> <section>").description("move a section")).action(
|
|
32750
32969
|
(p, s, o, c) => run(g(c), "wp_section_move", { page: p, section: s, ...posArgs(o) })
|
|
32751
32970
|
);
|
|
@@ -32811,12 +33030,16 @@ ${table(r.issues, ["severity", "code", "path", "detail"])}`;
|
|
|
32811
33030
|
await run(g(c), part === "header" ? "wp_header_set" : "wp_footer_set", args);
|
|
32812
33031
|
});
|
|
32813
33032
|
}
|
|
32814
|
-
const style = wp.command("style").description("brand colours and
|
|
33033
|
+
const style = wp.command("style").description("brand colours, fonts, layout widths, page padding and extra CSS");
|
|
32815
33034
|
style.command("get", { isDefault: true }).action((_o, c) => run(g(c), "wp_style_get", {}));
|
|
32816
|
-
style.command("set [colors...]").description(`e.g. cmo wp style set olive=#4F5B48 --font 'display="Playfair Display", serif'`).option("--font <slug=family...>").action(
|
|
32817
|
-
(colors, o, c) => run(g(c), "wp_style_set", {
|
|
33035
|
+
style.command("set [colors...]").description(`e.g. cmo wp style set olive=#4F5B48 --font 'display="Playfair Display", serif'`).option("--font <slug=family...>").option("--content <width>", "content width, e.g. 1240px").option("--wide <width>", "wide width (header, footer, wide blocks)").option("--padding <length>", "left and right page padding, e.g. 24px").option("--css-file <file>", "replace the site's extra CSS with this file").option("--css-append <file>", "add this CSS file after the site's extra CSS").action(
|
|
33036
|
+
async (colors, o, c) => run(g(c), "wp_style_set", {
|
|
32818
33037
|
colors: colors.length ? Object.fromEntries(pairs(colors)) : void 0,
|
|
32819
|
-
fonts: o.font ? Object.fromEntries(pairs(o.font)) : void 0
|
|
33038
|
+
fonts: o.font ? Object.fromEntries(pairs(o.font)) : void 0,
|
|
33039
|
+
layout: o.content || o.wide ? { content: o.content, wide: o.wide } : void 0,
|
|
33040
|
+
padding: o.padding ? { left: o.padding, right: o.padding } : void 0,
|
|
33041
|
+
css: o.cssFile ? await readFile2(o.cssFile, "utf8") : void 0,
|
|
33042
|
+
css_append: o.cssAppend ? await readFile2(o.cssAppend, "utf8") : void 0
|
|
32820
33043
|
})
|
|
32821
33044
|
);
|
|
32822
33045
|
const media = wp.command("media").description("pictures in the media library");
|
|
@@ -32899,6 +33122,9 @@ ${table(r.issues, ["severity", "code", "path", "detail"])}`;
|
|
|
32899
33122
|
description: o.description
|
|
32900
33123
|
})
|
|
32901
33124
|
);
|
|
33125
|
+
terms.command("delete <id>").option("--tags", "a tag instead of a category").action(
|
|
33126
|
+
(id, o, c) => run(g(c), "wp_term_delete", { taxonomy: o.tags ? "tags" : "categories", id: Number(id) })
|
|
33127
|
+
);
|
|
32902
33128
|
const settings2 = wp.command("settings").description("the site's general settings");
|
|
32903
33129
|
settings2.command("get", { isDefault: true }).action((_o, c) => run(g(c), "wp_settings_get", {}));
|
|
32904
33130
|
settings2.command("set [fields...]").description(
|
|
@@ -32909,13 +33135,14 @@ ${table(r.issues, ["severity", "code", "path", "detail"])}`;
|
|
|
32909
33135
|
args[k] = /^(true|false)$/.test(v) ? v === "true" : /^\d+$/.test(v) && k !== "title" && k !== "description" ? Number(v) : v;
|
|
32910
33136
|
await run(g(c), "wp_settings_set", args);
|
|
32911
33137
|
});
|
|
32912
|
-
const plugins = wp.command("plugins").description("plugins: list, install from WordPress.org, activate, deactivate (
|
|
33138
|
+
const plugins = wp.command("plugins").description("plugins: list, install from WordPress.org, activate, deactivate, delete (inactive only)");
|
|
32913
33139
|
plugins.command("ls", { isDefault: true }).action((_o, c) => run(g(c), "wp_plugins_list", {}));
|
|
32914
33140
|
plugins.command("install <slug>").option("--activate").action(
|
|
32915
33141
|
(slug, o, c) => run(g(c), "wp_plugin_set", { install: slug, status: o.activate ? "active" : "inactive" })
|
|
32916
33142
|
);
|
|
32917
33143
|
plugins.command("activate <plugin>").action((p, _o, c) => run(g(c), "wp_plugin_set", { plugin: p, status: "active" }));
|
|
32918
33144
|
plugins.command("deactivate <plugin>").action((p, _o, c) => run(g(c), "wp_plugin_set", { plugin: p, status: "inactive" }));
|
|
33145
|
+
plugins.command("delete <plugin>").description("remove an inactive plugin's files (reinstall from WordPress.org to undo)").action((p, _o, c) => run(g(c), "wp_plugin_set", { plugin: p, status: "deleted" }));
|
|
32919
33146
|
wp.command("api <route>").description("read any allowed WordPress REST route (GET), e.g. /wp/v2/types").option("--query <json>", "query parameters as JSON").action(
|
|
32920
33147
|
(route, o, c) => run(g(c), "wp_api_read", { route, query: o.query ? JSON.parse(o.query) : void 0 })
|
|
32921
33148
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.9",
|
|
4
4
|
"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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|