@diviops/mcp-server 0.2.23 → 0.2.28
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/README.md +10 -7
- package/dist/compatibility.d.ts +1 -1
- package/dist/compatibility.js +1 -1
- package/dist/index.js +216 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,9 +96,9 @@ The server connects via standard WordPress REST API and works with any environme
|
|
|
96
96
|
|
|
97
97
|
> **WP-CLI note:** `WP_PATH` keeps the existing Local by Flywheel behavior by running `wp` directly on the host filesystem. For Docker-based environments (DDEV, wp-env, DevKinsta, WordPress Studio), set `WP_CLI_CMD` to the wrapper command instead. When `WP_CLI_CMD` is set, the server executes the wrapper from `WP_PATH` if provided, otherwise from its current working directory. The MCP server still validates the requested WP-CLI subcommand against its allowlist before executing either path.
|
|
98
98
|
|
|
99
|
-
## Available Tools (
|
|
99
|
+
## Available Tools (57)
|
|
100
100
|
|
|
101
|
-
### Read (
|
|
101
|
+
### Read (27)
|
|
102
102
|
| Tool | Description |
|
|
103
103
|
|------|-------------|
|
|
104
104
|
| `diviops_test_connection` | Test WordPress connection and Divi version |
|
|
@@ -115,7 +115,7 @@ The server connects via standard WordPress REST API and works with any environme
|
|
|
115
115
|
| `diviops_find_icon` | Search 1,989 icons by keyword (FA + Divi) |
|
|
116
116
|
| `diviops_list_templates` | List available MCP prompt templates |
|
|
117
117
|
| `diviops_get_template` | Get a specific template's block markup |
|
|
118
|
-
| `diviops_preset_audit` | Audit presets with referenced/unreferenced analysis. Walks both page content and in-registry `groupPresets` chains; exposes `block_ref_count`, `group_ref_count`, `referenced_by_presets` |
|
|
118
|
+
| `diviops_preset_audit` | Audit presets with referenced/unreferenced analysis. Walks both page content and in-registry `groupPresets` chains; exposes `block_ref_count`, `group_ref_count`, `referenced_by_presets`. Also reports `orphan_default_pointers` — per-bucket `default` pointers referencing UUIDs missing from `items[]` (legacy damage from past unsafe deletes; clear via `diviops_preset_set_default` in bucket-addressed mode: `type` + `module` + `unset=true`) |
|
|
119
119
|
| `diviops_preset_scan_orphans` | List page-referenced preset UUIDs missing from the D5 registry (separates dangling orphans from D4-legacy refs) |
|
|
120
120
|
| `diviops_list_library` | List saved Divi Library items |
|
|
121
121
|
| `diviops_get_library_item` | Get a library item's block markup |
|
|
@@ -125,10 +125,11 @@ The server connects via standard WordPress REST API and works with any environme
|
|
|
125
125
|
| `diviops_get_tb_layout` | Get a Theme Builder layout's block markup (header/body/footer) |
|
|
126
126
|
| `diviops_list_variables` | List design token variables (filter by type or prefix) |
|
|
127
127
|
| `diviops_variables_scan_orphans` | Find `gvid-`/`gcid-` refs with no backing Variable Manager entry (orphans render as invalid CSS) + unused variables (defined, never referenced). Scans pages, Theme Builder layouts (header/body/footer), Divi Library items, canvas pages, and the preset registry |
|
|
128
|
+
| `diviops_variables_used_on_page` | Detect which `gvid-` (numeric/font) IDs a single page emits — the exact set Divi 5.4.0+ uses to scope selective `:root{--gvid-*}` CSS variable emission. Walks the same content stack the frontend assembles (post_content + active TB header/body/footer + appended canvases + presets). `gcid-` colors are out of scope (separate emission path). Use for per-page orphan validation, preflight before bulk variable rename, or to debug why a numeric/font variable doesn't render on a specific page. Read-only |
|
|
128
129
|
| `diviops_list_canvases` | List all canvas pages |
|
|
129
130
|
| `diviops_get_canvas` | Get canvas content |
|
|
130
131
|
|
|
131
|
-
### Write (
|
|
132
|
+
### Write (28)
|
|
132
133
|
| Tool | Description |
|
|
133
134
|
|------|-------------|
|
|
134
135
|
| `diviops_create_page` | Create a new page with optional Divi content |
|
|
@@ -148,12 +149,13 @@ The server connects via standard WordPress REST API and works with any environme
|
|
|
148
149
|
| `diviops_preset_create` | Write a new preset to the D5 registry (module or group type, supports `divi/column` etc.). Optional `make_default: true` sets it as the bucket's default; optional `priority` controls stack-merge order |
|
|
149
150
|
| `diviops_preset_reassign` | Rewrite `modulePreset` references across pages (dry-run by default; optional `strip_inline` removes redundant inline attrs) |
|
|
150
151
|
| `diviops_preset_update` | Update a specific preset (name, attrs, priority) |
|
|
151
|
-
| `diviops_preset_delete` | Delete a preset by ID |
|
|
152
|
-
| `diviops_preset_set_default` | Set or clear the per-module/group default preset (
|
|
152
|
+
| `diviops_preset_delete` | Delete a preset by ID. Refuses with HTTP 409 `preset_is_default` when the target is the registered default for its bucket — clear the pointer first via `diviops_preset_set_default` with `unset=true`, or pass `force=true` to delete and clear the pointer in one write |
|
|
153
|
+
| `diviops_preset_set_default` | Set or clear the per-module/group default preset. Two modes: by `preset_id` (UUID-addressed; auto-resolves bucket) or by `type` + `module` + `unset=true` (bucket-addressed clear, used to repair orphan default pointers when the UUID is gone from `items[]`). Defaults apply to NEW instances only — use `diviops_preset_reassign` for retroactive swaps |
|
|
153
154
|
| `diviops_save_to_library` | Save block markup to Divi Library |
|
|
154
155
|
| `diviops_update_tb_layout` | Update a Theme Builder layout's block markup |
|
|
155
156
|
| `diviops_create_tb_template` | Create Theme Builder template with header/footer and conditions |
|
|
156
157
|
| `diviops_create_variable` | Create a design token variable. For `type=numbers` fluid tokens, pass `min`+`max` shorthand (anchors default to 320px/1920px) or explicit `targets` like `{"320px":"20px","1920px":"60px"}` — server generates arithmetically-correct `clamp()` instead of hand-written math that silently under-reaches the stated max. All-px inputs emit px (root-agnostic). Rem inputs OR rem output require explicit opt-in: pass `output_unit="rem"` (accepts the 1rem=16px default) or `root_font_size_px:N` (declares your site's actual root font-size, e.g. `10` for `html { font-size: 62.5% }`, `20` for `html { font-size: 20px }`) |
|
|
158
|
+
| `diviops_create_fluid_system` | Batch-emit a fluid typography + spacing + radius variable set in one call. Mirrors Divi 5.4.0's Variable Generator Modal at the algorithm level (clamp() math is identical to `diviops_create_variable`'s fluid mode) but layers profile-selectable anchors over it: `divi-default` (360→1350) matches ET's defaults, `wide` (320→1920) matches the diviops convention, `custom` takes explicit anchors. Each category is independent and optional. Typography uses modular-scale chains (named ratios `major-third`/`perfect-fifth`/`golden`/etc., or raw numbers) — h1 = largest, hN = base. Spacing/radius support `linear` or `geometric` step distributions. `dry_run: true` returns the full plan without persisting; `overwrite: false` (default) skips existing IDs. Single atomic write to the registry — mid-batch failures roll back cleanly |
|
|
157
159
|
| `diviops_delete_variable` | Delete a variable by ID. Returns HTTP 409 when live references exist unless `force=true` (use `diviops_variables_scan_orphans` to find reference locations). Returns HTTP 403 for Divi's customizer-bound defaults (`gcid-primary-color`, `gcid-secondary-color`, `gcid-heading-color`, `gcid-body-color`, `gcid-link-color` — managed via WP Customizer) |
|
|
158
160
|
| `diviops_create_canvas` | Create a canvas page |
|
|
159
161
|
| `diviops_update_canvas` | Update canvas content |
|
|
@@ -248,7 +250,7 @@ The three DEFAULT-tier filesystem commands (`wp export`, `acf export <path>`, `a
|
|
|
248
250
|
|
|
249
251
|
## Safety Patterns
|
|
250
252
|
|
|
251
|
-
High-risk or bulk destructive tools follow one of two conventions to guard against unintended mutation. Both are stateless (no session tokens between calls), but they guard differently: Pattern A is a **stateless gate** — the first call mutates when the safety check passes, refuses with an explanatory error when it fires. Pattern B is **preview-before-commit** — the first call never mutates; an explicit apply step is required. Tools without a gate (e.g., `
|
|
253
|
+
High-risk or bulk destructive tools follow one of two conventions to guard against unintended mutation. Both are stateless (no session tokens between calls), but they guard differently: Pattern A is a **stateless gate** — the first call mutates when the safety check passes, refuses with an explanatory error when it fires. Pattern B is **preview-before-commit** — the first call never mutates; an explicit apply step is required. Tools without a gate (e.g., `diviops_update_page_content`) execute their mutation directly — whether to adopt a pattern is a per-tool design decision, not a retrofit requirement.
|
|
252
254
|
|
|
253
255
|
### Pattern A — `force: false/true` (refuse-with-override)
|
|
254
256
|
|
|
@@ -264,6 +266,7 @@ Tool refuses the operation with an explanatory error when a safety check fails;
|
|
|
264
266
|
| Tool | Guard | Override |
|
|
265
267
|
|------|-------|----------|
|
|
266
268
|
| `diviops_delete_variable` | HTTP 409 when live references exist | `force=true` |
|
|
269
|
+
| `diviops_preset_delete` | HTTP 409 `preset_is_default` when target is the registered default for its bucket | `force=true` (deletes + clears the `default` pointer in the same write) |
|
|
267
270
|
|
|
268
271
|
### Pattern B — `mode: "dry-run"/"apply"` (preview-then-commit)
|
|
269
272
|
|
package/dist/compatibility.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Version compatibility between MCP server and WP plugin.
|
|
3
3
|
*/
|
|
4
4
|
/** Minimum WP plugin version this server requires. */
|
|
5
|
-
export declare const MIN_PLUGIN_VERSION = "1.0.0-beta.
|
|
5
|
+
export declare const MIN_PLUGIN_VERSION = "1.0.0-beta.43";
|
|
6
6
|
/**
|
|
7
7
|
* Compare two semver-like version strings (supports pre-release tags).
|
|
8
8
|
*
|
package/dist/compatibility.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Version compatibility between MCP server and WP plugin.
|
|
3
3
|
*/
|
|
4
4
|
/** Minimum WP plugin version this server requires. */
|
|
5
|
-
export const MIN_PLUGIN_VERSION = '1.0.0-beta.
|
|
5
|
+
export const MIN_PLUGIN_VERSION = '1.0.0-beta.43';
|
|
6
6
|
/**
|
|
7
7
|
* Compare two semver-like version strings (supports pre-release tags).
|
|
8
8
|
*
|
package/dist/index.js
CHANGED
|
@@ -746,7 +746,7 @@ server.registerTool("diviops_create_page", {
|
|
|
746
746
|
});
|
|
747
747
|
// ── Preset Tools ────────────────────────────────────────────────────
|
|
748
748
|
server.registerTool("diviops_preset_audit", {
|
|
749
|
-
description: "Audit all Divi presets (module + group). Each entry reports `block_ref_count` (page-content refs via modulePreset / groupPreset block markup), `group_ref_count` (in-registry chain refs from other presets — module presets via top-level `groupPresets.<slot>.presetId`, group presets via `attrs.groupPreset.<slot>.presetId`), and `referenced` (true if either > 0). Group presets that are chain-referenced also expose `referenced_by_presets` (UUIDs of the presets that wire them in — typically module presets, but type-agnostic). Use this before deleting — orphan-cleanup based only on page refs would silently wipe load-bearing chain-wired group presets (font, border, box-shadow, spacing, button).",
|
|
749
|
+
description: "Audit all Divi presets (module + group). Each entry reports `block_ref_count` (page-content refs via modulePreset / groupPreset block markup), `group_ref_count` (in-registry chain refs from other presets — module presets via top-level `groupPresets.<slot>.presetId`, group presets via `attrs.groupPreset.<slot>.presetId`), and `referenced` (true if either > 0). Group presets that are chain-referenced also expose `referenced_by_presets` (UUIDs of the presets that wire them in — typically module presets, but type-agnostic). Use this before deleting — orphan-cleanup based only on page refs would silently wipe load-bearing chain-wired group presets (font, border, box-shadow, spacing, button). Also reports `orphan_default_pointers`: per-bucket `default` pointers that reference a UUID no longer present in `items[]` (caused by past unsafe deletes). Render-safe but blocks Divi's lazy recreate-on-VB-use path; clear via diviops_preset_set_default with unset=true on the affected module/group.",
|
|
750
750
|
}, async () => {
|
|
751
751
|
const result = await wp.request("/preset-audit");
|
|
752
752
|
return {
|
|
@@ -835,14 +835,21 @@ server.registerTool("diviops_preset_update", {
|
|
|
835
835
|
};
|
|
836
836
|
});
|
|
837
837
|
server.registerTool("diviops_preset_delete", {
|
|
838
|
-
description: "Delete a specific preset by ID. Use diviops_preset_audit first to verify the preset is unreferenced before deleting.",
|
|
838
|
+
description: "Delete a specific preset by ID. Use diviops_preset_audit first to verify the preset is unreferenced before deleting. Refuses with 409 preset_is_default if the target is the registered default for its module/group bucket — clear the pointer first via diviops_preset_set_default with unset=true, or pass force=true to delete and clear the pointer in one write.",
|
|
839
839
|
inputSchema: {
|
|
840
840
|
preset_id: z.string().describe("Preset ID to delete"),
|
|
841
|
+
force: z
|
|
842
|
+
.boolean()
|
|
843
|
+
.optional()
|
|
844
|
+
.describe("When true, deletes the preset even if it is the registered default and clears the default pointer in the same write. Default false (refuse-by-default)."),
|
|
841
845
|
},
|
|
842
|
-
}, async ({ preset_id }) => {
|
|
846
|
+
}, async ({ preset_id, force }) => {
|
|
847
|
+
const body = { preset_id };
|
|
848
|
+
if (force !== undefined)
|
|
849
|
+
body.force = force;
|
|
843
850
|
const result = await wp.request("/preset-delete", {
|
|
844
851
|
method: "POST",
|
|
845
|
-
body
|
|
852
|
+
body,
|
|
846
853
|
});
|
|
847
854
|
return {
|
|
848
855
|
content: [
|
|
@@ -969,18 +976,33 @@ server.registerTool("diviops_preset_scan_orphans", {
|
|
|
969
976
|
};
|
|
970
977
|
});
|
|
971
978
|
server.registerTool("diviops_preset_set_default", {
|
|
972
|
-
description: "Set or clear the per-module/group default preset.
|
|
979
|
+
description: "Set or clear the per-module/group default preset. Two addressing modes: (1) preset_id mode — walks both buckets to locate the preset by UUID, then points the containing module/group's `default` slot at it (or clears it with unset=true). (2) Bucket-addressed clear — pass type + module + unset=true to clear an orphan default pointer when the preset_id no longer exists in items[] (the preset_id walk path can't locate orphans — that's the very state being repaired; surfaced via diviops_preset_audit's `orphan_default_pointers`). Defaults apply to NEW module instances only — existing modules keep their current preset bindings (use diviops_preset_reassign for retroactive swaps). Use diviops_preset_audit's `is_default` and `orphan_default_pointers` fields to verify state before/after.",
|
|
973
980
|
inputSchema: {
|
|
974
981
|
preset_id: z
|
|
975
982
|
.string()
|
|
976
|
-
.
|
|
983
|
+
.optional()
|
|
984
|
+
.describe("Preset UUID. Bucket (module vs. group) and target module/group are auto-resolved from the registry — no need to specify them. Required unless using bucket-addressed clear (type + module + unset=true) to repair an orphan default pointer."),
|
|
985
|
+
type: z
|
|
986
|
+
.enum(["module", "group"])
|
|
987
|
+
.optional()
|
|
988
|
+
.describe("Bucket-addressed clear: bucket type. Required together with `module` and `unset=true` to clear an orphan default pointer (UUID gone from items[] but `default` still references it)."),
|
|
989
|
+
module: z
|
|
990
|
+
.string()
|
|
991
|
+
.optional()
|
|
992
|
+
.describe('Bucket-addressed clear: module slug or group key (e.g. "divi/blurb", "divi/font"). Required together with `type` and `unset=true`.'),
|
|
977
993
|
unset: z
|
|
978
994
|
.boolean()
|
|
979
995
|
.optional()
|
|
980
|
-
.describe("If true, clear the default pointer
|
|
996
|
+
.describe("If true, clear the default pointer. With preset_id, clears the bucket containing that preset. With type+module, clears that bucket directly (use this form for orphan-pointer repair). Defaults to false (set the preset as the default — preset_id required)."),
|
|
981
997
|
},
|
|
982
|
-
}, async ({ preset_id, unset }) => {
|
|
983
|
-
const body = {
|
|
998
|
+
}, async ({ preset_id, type, module, unset }) => {
|
|
999
|
+
const body = {};
|
|
1000
|
+
if (preset_id !== undefined)
|
|
1001
|
+
body.preset_id = preset_id;
|
|
1002
|
+
if (type !== undefined)
|
|
1003
|
+
body.type = type;
|
|
1004
|
+
if (module !== undefined)
|
|
1005
|
+
body.module = module;
|
|
984
1006
|
if (unset)
|
|
985
1007
|
body.unset = true;
|
|
986
1008
|
const result = await wp.request("/preset-set-default", {
|
|
@@ -1590,6 +1612,174 @@ server.registerTool("diviops_create_variable", {
|
|
|
1590
1612
|
],
|
|
1591
1613
|
};
|
|
1592
1614
|
});
|
|
1615
|
+
server.registerTool("diviops_create_fluid_system", {
|
|
1616
|
+
description: "Batch-emit a fluid typography + spacing + radius variable set in one call — mirrors Divi 5.4.0's Variable Generator Modal at the algorithm level (clamp() math is identical to diviops_create_variable's fluid mode) but layers profile-selectable anchors over it. Each category is independent and optional. Use for: (1) bootstrapping a design system in one call instead of 20+ individual diviops_create_variable invocations; (2) mirroring ET's variable layout so your tokens coexist with VB-generated ones in the Variable Manager; (3) deterministic preflight via dry_run before committing the registry change. By default, refuses to overwrite existing IDs (returns them in `skipped`) — pass overwrite=true to update in place. Persists in a single atomic write to the variable registry; mid-batch failures roll back cleanly.",
|
|
1617
|
+
inputSchema: {
|
|
1618
|
+
profile: z
|
|
1619
|
+
.enum(["divi-default", "wide", "custom"])
|
|
1620
|
+
.optional()
|
|
1621
|
+
.default("divi-default")
|
|
1622
|
+
.describe('Anchor preset for the underlying clamp() math. "divi-default" (360→1350) matches Divi 5.4.0\'s Variable Generator Modal defaults; "wide" (320→1920) covers a wider device span (the diviops convention); "custom" requires custom_anchors. Affects ALL three categories uniformly.'),
|
|
1623
|
+
custom_anchors: z
|
|
1624
|
+
.object({
|
|
1625
|
+
min_viewport_px: z.number().positive(),
|
|
1626
|
+
max_viewport_px: z.number().positive(),
|
|
1627
|
+
})
|
|
1628
|
+
.refine((a) => a.max_viewport_px > a.min_viewport_px, {
|
|
1629
|
+
message: "custom_anchors.max_viewport_px must be > min_viewport_px",
|
|
1630
|
+
})
|
|
1631
|
+
.optional()
|
|
1632
|
+
.describe('Required when profile="custom". Defines the (min_viewport_px, max_viewport_px) pair the clamp() formulas anchor to. max must be > min. (The profile/custom_anchors pairing is also enforced server-side, returning 400 invalid_profile if profile="custom" is sent without custom_anchors.)'),
|
|
1633
|
+
typography: z
|
|
1634
|
+
.object({
|
|
1635
|
+
base_px: z
|
|
1636
|
+
.number()
|
|
1637
|
+
.positive()
|
|
1638
|
+
.describe("Base body size in px. Step N's value = base_px × ratio^(steps-1). h1 = largest (top of chain), hN = base."),
|
|
1639
|
+
ratio: z
|
|
1640
|
+
.union([
|
|
1641
|
+
z.number().positive(),
|
|
1642
|
+
z.enum([
|
|
1643
|
+
"minor-second",
|
|
1644
|
+
"major-second",
|
|
1645
|
+
"minor-third",
|
|
1646
|
+
"major-third",
|
|
1647
|
+
"perfect-fourth",
|
|
1648
|
+
"augmented-fourth",
|
|
1649
|
+
"perfect-fifth",
|
|
1650
|
+
"golden",
|
|
1651
|
+
]),
|
|
1652
|
+
])
|
|
1653
|
+
.describe("Modular-scale ratio. Pass a named scale ('major-third'=1.25, 'perfect-fifth'=1.5, 'golden'=1.618, etc.) or a raw number. Step N is base × ratio^(steps-N), so h1 (step 1) is the largest size when steps>1."),
|
|
1654
|
+
steps: z
|
|
1655
|
+
.number()
|
|
1656
|
+
.int()
|
|
1657
|
+
.min(1)
|
|
1658
|
+
.max(20)
|
|
1659
|
+
.describe("Number of typography steps to emit (e.g. 6 = h1..h6). Cap is 20 to prevent runaway scale chains."),
|
|
1660
|
+
max_ratio: z
|
|
1661
|
+
.union([
|
|
1662
|
+
z.number().positive(),
|
|
1663
|
+
z.enum([
|
|
1664
|
+
"minor-second",
|
|
1665
|
+
"major-second",
|
|
1666
|
+
"minor-third",
|
|
1667
|
+
"major-third",
|
|
1668
|
+
"perfect-fourth",
|
|
1669
|
+
"augmented-fourth",
|
|
1670
|
+
"perfect-fifth",
|
|
1671
|
+
"golden",
|
|
1672
|
+
]),
|
|
1673
|
+
])
|
|
1674
|
+
.optional()
|
|
1675
|
+
.describe("Optional ratio at max viewport. Defaults to ratio (same chain at both anchors). Pass a larger value (e.g. ratio=1.2 + max_ratio=1.333) for a more dramatic scale on large screens."),
|
|
1676
|
+
fluid_growth: z
|
|
1677
|
+
.number()
|
|
1678
|
+
.positive()
|
|
1679
|
+
.optional()
|
|
1680
|
+
.describe("Multiplicative growth factor at max viewport. Default 1.0 = discrete (each step emits a fixed value, no clamp growth). Common values: 1.2-1.5 for moderate fluid scaling. Step N's clamp goes from `base × ratio^(steps-N)` at min_viewport to `base × max_ratio^(steps-N) × fluid_growth` at max_viewport."),
|
|
1681
|
+
name_prefix: z
|
|
1682
|
+
.string()
|
|
1683
|
+
.optional()
|
|
1684
|
+
.describe("ID prefix per step. Default 'h' → IDs become gvid-{namespace}-size-h1..hN. Pass 'display' for hero sizes ('gvid-{namespace}-size-display1..')."),
|
|
1685
|
+
})
|
|
1686
|
+
.optional(),
|
|
1687
|
+
spacing: z
|
|
1688
|
+
.object({
|
|
1689
|
+
min_px: z.number().min(0),
|
|
1690
|
+
max_px: z.number().positive(),
|
|
1691
|
+
steps: z.number().int().min(1).max(30),
|
|
1692
|
+
scale: z
|
|
1693
|
+
.enum(["linear", "geometric"])
|
|
1694
|
+
.optional()
|
|
1695
|
+
.default("linear")
|
|
1696
|
+
.describe("Distribution between min_px and max_px. 'linear' = equal arithmetic spacing (best for spacing scales). 'geometric' = equal multiplicative spacing (best for typography-like scales). geometric requires min_px > 0."),
|
|
1697
|
+
fluid_growth: z
|
|
1698
|
+
.number()
|
|
1699
|
+
.positive()
|
|
1700
|
+
.optional()
|
|
1701
|
+
.describe("Multiplicative growth factor at max viewport. Default 1.0 = discrete (each spacing token is constant across viewports — typical design-system behavior). > 1.0 = fluid (each token scales from `value` at min_viewport to `value × fluid_growth` at max_viewport)."),
|
|
1702
|
+
name_prefix: z
|
|
1703
|
+
.string()
|
|
1704
|
+
.optional()
|
|
1705
|
+
.describe("ID prefix. Default 'space' → gvid-{namespace}-space-1..N."),
|
|
1706
|
+
})
|
|
1707
|
+
.optional(),
|
|
1708
|
+
radius: z
|
|
1709
|
+
.object({
|
|
1710
|
+
min_px: z.number().min(0),
|
|
1711
|
+
max_px: z.number().positive(),
|
|
1712
|
+
steps: z.number().int().min(1).max(30),
|
|
1713
|
+
scale: z.enum(["linear", "geometric"]).optional().default("linear"),
|
|
1714
|
+
fluid_growth: z
|
|
1715
|
+
.number()
|
|
1716
|
+
.positive()
|
|
1717
|
+
.optional()
|
|
1718
|
+
.describe("Multiplicative growth factor at max viewport. Default 1.0 = discrete. Most radius tokens stay discrete; pass > 1.0 only when you want corners to grow with viewport."),
|
|
1719
|
+
name_prefix: z
|
|
1720
|
+
.string()
|
|
1721
|
+
.optional()
|
|
1722
|
+
.describe("ID prefix. Default 'rounded' → gvid-{namespace}-rounded-1..N."),
|
|
1723
|
+
})
|
|
1724
|
+
.optional(),
|
|
1725
|
+
namespace: z
|
|
1726
|
+
.string()
|
|
1727
|
+
.regex(/^[a-z0-9_-]+$/i, {
|
|
1728
|
+
message: "namespace must match [a-z0-9_-]+ (case-insensitive; lowercased server-side). Inputs outside this charset are rejected explicitly rather than silently rewritten — passing 'o a' or 'oa!' would alias onto the default 'oa' namespace and risk overwriting unrelated tokens.",
|
|
1729
|
+
})
|
|
1730
|
+
.optional()
|
|
1731
|
+
.default("oa")
|
|
1732
|
+
.describe("Namespace inserted into every generated ID (gvid-{namespace}-*). Default 'oa' matches existing diviops convention. Validated against [a-z0-9_-]+ on both client and server (rejects rather than sanitizes — see message for rationale)."),
|
|
1733
|
+
output_unit: z
|
|
1734
|
+
.enum(["rem", "px"])
|
|
1735
|
+
.optional()
|
|
1736
|
+
.describe('Unit for emitted clamp() formulas. Defaults to "px" (root-agnostic, safe). Pass "rem" to opt into rem emission (bakes the 1rem=16px assumption unless root_font_size_px is also passed).'),
|
|
1737
|
+
root_font_size_px: z
|
|
1738
|
+
.number()
|
|
1739
|
+
.positive()
|
|
1740
|
+
.optional()
|
|
1741
|
+
.describe("Site's actual root font-size in px. Pass for non-16px-root sites (e.g. 10 for `html { font-size: 62.5% }`). Passing this alone implies output_unit='rem'."),
|
|
1742
|
+
dry_run: z
|
|
1743
|
+
.boolean()
|
|
1744
|
+
.optional()
|
|
1745
|
+
.default(false)
|
|
1746
|
+
.describe("Preview the full plan without persisting. Returns identical `created`/`skipped` shape so callers can audit IDs and clamp() values before committing."),
|
|
1747
|
+
overwrite: z
|
|
1748
|
+
.boolean()
|
|
1749
|
+
.optional()
|
|
1750
|
+
.default(false)
|
|
1751
|
+
.describe("When false (default), existing IDs land in `skipped` with the existing value. When true, each existing ID is updated in place (label + value rewritten, order preserved)."),
|
|
1752
|
+
},
|
|
1753
|
+
}, async ({ profile, custom_anchors, typography, spacing, radius, namespace, output_unit, root_font_size_px, dry_run, overwrite, }) => {
|
|
1754
|
+
const body = { profile };
|
|
1755
|
+
if (custom_anchors !== undefined)
|
|
1756
|
+
body.custom_anchors = custom_anchors;
|
|
1757
|
+
if (typography !== undefined)
|
|
1758
|
+
body.typography = typography;
|
|
1759
|
+
if (spacing !== undefined)
|
|
1760
|
+
body.spacing = spacing;
|
|
1761
|
+
if (radius !== undefined)
|
|
1762
|
+
body.radius = radius;
|
|
1763
|
+
if (namespace !== undefined)
|
|
1764
|
+
body.namespace = namespace;
|
|
1765
|
+
if (output_unit !== undefined)
|
|
1766
|
+
body.output_unit = output_unit;
|
|
1767
|
+
if (root_font_size_px !== undefined)
|
|
1768
|
+
body.root_font_size_px = root_font_size_px;
|
|
1769
|
+
if (dry_run !== undefined)
|
|
1770
|
+
body.dry_run = dry_run;
|
|
1771
|
+
if (overwrite !== undefined)
|
|
1772
|
+
body.overwrite = overwrite;
|
|
1773
|
+
const result = await wp.request("/variables-create-fluid-system", {
|
|
1774
|
+
method: "POST",
|
|
1775
|
+
body,
|
|
1776
|
+
});
|
|
1777
|
+
return {
|
|
1778
|
+
content: [
|
|
1779
|
+
{ type: "text", text: JSON.stringify(result) },
|
|
1780
|
+
],
|
|
1781
|
+
};
|
|
1782
|
+
});
|
|
1593
1783
|
server.registerTool("diviops_delete_variable", {
|
|
1594
1784
|
description: "Delete a design token variable by ID. Auto-detects storage from ID prefix (gcid-* = colors, gvid-* = numbers/strings/etc). Returns HTTP 409 when live references exist unless force=true — run diviops_variables_scan_orphans to see where the references live. Returns HTTP 403 for Divi's customizer-bound defaults (gcid-primary-color, gcid-secondary-color, gcid-heading-color, gcid-body-color, gcid-link-color); those are managed via WP Customizer theme options and can't be deleted via this tool.",
|
|
1595
1785
|
inputSchema: {
|
|
@@ -1623,6 +1813,23 @@ server.registerTool("diviops_variables_scan_orphans", {
|
|
|
1623
1813
|
],
|
|
1624
1814
|
};
|
|
1625
1815
|
});
|
|
1816
|
+
server.registerTool("diviops_variables_used_on_page", {
|
|
1817
|
+
description: "Detect which numeric/font variable IDs a single page actually emits — the exact set Divi 5.4.0+ uses to scope selective `:root{--gvid-*}` CSS variable emission. Walks the same content stack the frontend assembles: post_content + active Theme Builder header/body/footer template content + appended canvas content (interaction targets etc.), plus presets referenced by that content. NOTE: this is `gvid-*` only — color variables (`gcid-*`) are emitted via a separate path (`GlobalData` color block) that is NOT scoped per-page in 5.4.0; this tool returns gvid IDs only. Use for per-page orphan validation (complements global diviops_variables_scan_orphans), preflight before bulk variable rename (know which pages are affected), or to debug why a numeric/font variable doesn't render on a specific page. Read-only. Returns variable_ids (sorted, deduped), count, and the tb_template_ids resolved for that post.",
|
|
1818
|
+
inputSchema: {
|
|
1819
|
+
post_id: z
|
|
1820
|
+
.number()
|
|
1821
|
+
.int()
|
|
1822
|
+
.positive()
|
|
1823
|
+
.describe("WordPress post/page ID. The page does not need to be Divi-built — TB templates and canvases attached to non-Divi posts are still scanned."),
|
|
1824
|
+
},
|
|
1825
|
+
}, async ({ post_id }) => {
|
|
1826
|
+
const result = await wp.request(`/variables-used-on-page/${post_id}`);
|
|
1827
|
+
return {
|
|
1828
|
+
content: [
|
|
1829
|
+
{ type: "text", text: JSON.stringify(result) },
|
|
1830
|
+
],
|
|
1831
|
+
};
|
|
1832
|
+
});
|
|
1626
1833
|
server.registerTool("diviops_flush_static_cache", {
|
|
1627
1834
|
description: "Flush Divi's compiled static CSS cache under wp-content/et-cache/. wp cache flush does NOT touch these files — the frontend can keep serving stale CSS after a preset/variable/module mutation until the cache is cleared. Delegates to Divi's native ET_Core_PageResource::remove_static_resources when available (response backend: \"divi_native\"), which additionally clears Theme Builder CSS scattered across other post dirs, archive/taxonomy/home/notfound CSS, the object cache, module features cache, post features cache, Google Fonts cache, dynamic assets cache, and post meta caches. Falls back to a targeted filesystem walk of numeric-named et-cache subdirs when the Divi class is absent (backend: \"fs_fallback\"). Provide exactly one selector — no site-wide default to prevent accidental full flush. Idempotent: missing cache root returns 200 with empty list.",
|
|
1628
1835
|
inputSchema: {
|