@diviops/mcp-server 0.2.17 → 0.2.19
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 +4 -1
- package/dist/compatibility.d.ts +1 -1
- package/dist/compatibility.js +1 -1
- package/dist/index.js +2 -2
- package/dist/wp-client.js +43 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,8 @@ Claude Code <-> MCP Server (stdio) <-> WordPress REST API <-> Divi MCP Plugin
|
|
|
9
9
|
## Requirements
|
|
10
10
|
|
|
11
11
|
- **Node.js** >= 18.0.0
|
|
12
|
-
- **
|
|
12
|
+
- **PHP** >= 7.4
|
|
13
|
+
- **WordPress** >= 6.5
|
|
13
14
|
- **Divi 5** theme active
|
|
14
15
|
- **DiviOps Agent** WordPress plugin installed and active
|
|
15
16
|
|
|
@@ -175,6 +176,8 @@ Read-only commands plus non-destructive writes needed for core MCP functionality
|
|
|
175
176
|
| Cache | `cache flush`, `transient delete`, `rewrite flush` |
|
|
176
177
|
| Export | `export` (WXR data export to file) |
|
|
177
178
|
| Info | `cron event list`, `plugin list`, `theme list`, `menu list`, `site url` |
|
|
179
|
+
| Core (read-only) | `core version`, `core check-update`, `core is-installed`, `core verify-checksums`, `core language list` |
|
|
180
|
+
| DB (introspection) | `db columns`, `db size`, `db tables`, `db check`, `db search` |
|
|
178
181
|
|
|
179
182
|
### Extended commands (opt-in)
|
|
180
183
|
|
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.36";
|
|
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.36';
|
|
6
6
|
/**
|
|
7
7
|
* Compare two semver-like version strings (supports pre-release tags).
|
|
8
8
|
*
|
package/dist/index.js
CHANGED
|
@@ -726,7 +726,7 @@ server.registerTool("diviops_preset_create", {
|
|
|
726
726
|
};
|
|
727
727
|
});
|
|
728
728
|
server.registerTool("diviops_preset_reassign", {
|
|
729
|
-
description: 'Reassign a preset UUID across page content. Covers both module-level refs (`attrs.modulePreset[...]`) and attribute-level group-preset refs (`attrs.groupPreset.<slot>.presetId`), plus — for group presets — registry chain refs: module-bucket presets via top-level `groupPresets.<slot>.presetId`, group-bucket presets via `attrs.groupPreset.<slot>.presetId`. The `scope` param controls which ref types are walked (default "both", auto-selects based on new_uuid\'s bucket). Cross-bucket swaps (module ↔ group) are rejected.
|
|
729
|
+
description: 'Reassign a preset UUID across page content. Covers both module-level refs (`attrs.modulePreset[...]`) and attribute-level group-preset refs (`attrs.groupPreset.<slot>.presetId`), plus — for group presets — registry chain refs: module-bucket presets via top-level `groupPresets.<slot>.presetId`, group-bucket presets via `attrs.groupPreset.<slot>.presetId`. The `scope` param controls which ref types are walked (default "both", auto-selects based on new_uuid\'s bucket). Cross-bucket swaps (module ↔ group) are rejected. When `strip_inline=true` (default), strips inline attrs that duplicate the new preset\'s attrs (otherwise inline wins over preset): for module scope, strips from block root; for group scope, strips per-slot using Divi\'s own slot→target-path resolver (handles composite button groups, `-id-classes` suffix, FormField/checkbox/radio `attrName` mappings, cross-module translation). Both scopes enforce a singular-stack guard (skip strip when slot holds multiple presets). Unmappable group slots skip strip and emit a per-slot advisory at `summary.strip_advisory_per_slot[<module>::<slot>]`; neighbor slots are unaffected. Defaults to dry-run — set mode="apply" to actually rewrite. Use this to consolidate repeated inline styling into a reusable preset after creating one with diviops_preset_create.',
|
|
730
730
|
inputSchema: {
|
|
731
731
|
old_uuid: z
|
|
732
732
|
.string()
|
|
@@ -747,7 +747,7 @@ server.registerTool("diviops_preset_reassign", {
|
|
|
747
747
|
.boolean()
|
|
748
748
|
.optional()
|
|
749
749
|
.default(true)
|
|
750
|
-
.describe("If true (default), strip inline attrs that deep-equal the new preset's attrs so the preset actually takes effect. Applies to module-scope
|
|
750
|
+
.describe("If true (default), strip inline attrs that deep-equal the new preset's attrs so the preset actually takes effect. Applies to both module-scope (block-root strip) and group-scope (per-slot strip via Divi's target-path resolver). Singular-stack guard enforced at both scopes — strip is skipped when the modulePreset stack or a groupPreset slot holds multiple presets. Unmappable group slots skip strip with a per-slot advisory. Set false to swap UUIDs only."),
|
|
751
751
|
scope: z
|
|
752
752
|
.enum(["module", "group", "both"])
|
|
753
753
|
.optional()
|
package/dist/wp-client.js
CHANGED
|
@@ -5,6 +5,48 @@
|
|
|
5
5
|
* Generate one at: WP Admin → Users → Your Profile → Application Passwords.
|
|
6
6
|
*/
|
|
7
7
|
import { MIN_PLUGIN_VERSION, compareVersions, } from './compatibility.js';
|
|
8
|
+
/**
|
|
9
|
+
* Normalize over-escaped variable-token quote sequences inside `$variable(...)$`
|
|
10
|
+
* token regions only.
|
|
11
|
+
*
|
|
12
|
+
* Divi block-attrs JSON uses `\"` (2-byte) for inner quotes inside Divi variable
|
|
13
|
+
* tokens. Two over-escaped forms can leak in via callers that round-trip
|
|
14
|
+
* pre-existing broken bytes:
|
|
15
|
+
* - `\u0022` (11 bytes literal) — the mass-corruption form (backslash
|
|
16
|
+
* itself unicode-escaped, observed in the wild on Divi 5.3.x sites)
|
|
17
|
+
* - `\\u0022` (7 bytes literal) — produced when a caller passes the
|
|
18
|
+
* 6-byte `"` form through an extra JSON-encoding layer
|
|
19
|
+
*
|
|
20
|
+
* Both decode to the same value after Divi's resolver, but cause render asymmetry
|
|
21
|
+
* across attr paths (`background.color`, `spacing.margin`, `border.color`,
|
|
22
|
+
* `layout.columnGap` silently fail to resolve). We normalize defensively so any
|
|
23
|
+
* write — clean or pre-broken — settles on canonical bytes.
|
|
24
|
+
*
|
|
25
|
+
* Scope is intentionally narrow: rewrites only happen inside `$variable(...)$`
|
|
26
|
+
* regions (Divi's actual resolver boundary). Bytes outside those regions —
|
|
27
|
+
* arbitrary user text, code samples, string-variable values that happen to
|
|
28
|
+
* contain `\u0022` — are left untouched.
|
|
29
|
+
*/
|
|
30
|
+
function normalizeQuoteEscapes(s) {
|
|
31
|
+
return s.replace(/\$variable\([^$]*?\)\$/g, (token) => token.replace(/(?:\\u005cu0022|\\\\u0022)/g, '\\"'));
|
|
32
|
+
}
|
|
33
|
+
function normalizeBody(value) {
|
|
34
|
+
if (typeof value === 'string')
|
|
35
|
+
return normalizeQuoteEscapes(value);
|
|
36
|
+
if (Array.isArray(value))
|
|
37
|
+
return value.map(normalizeBody);
|
|
38
|
+
// Restrict recursion to plain objects so Date / RegExp / class instances
|
|
39
|
+
// with custom `toJSON` keep their canonical serialization.
|
|
40
|
+
if (value &&
|
|
41
|
+
typeof value === 'object' &&
|
|
42
|
+
Object.getPrototypeOf(value) === Object.prototype) {
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [k, v] of Object.entries(value))
|
|
45
|
+
out[k] = normalizeBody(v);
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
8
50
|
export class WPClient {
|
|
9
51
|
baseUrl;
|
|
10
52
|
authHeader;
|
|
@@ -34,7 +76,7 @@ export class WPClient {
|
|
|
34
76
|
},
|
|
35
77
|
};
|
|
36
78
|
if (body && method !== 'GET') {
|
|
37
|
-
fetchOptions.body = JSON.stringify(body);
|
|
79
|
+
fetchOptions.body = JSON.stringify(normalizeBody(body));
|
|
38
80
|
}
|
|
39
81
|
const response = await fetch(url, fetchOptions);
|
|
40
82
|
if (!response.ok) {
|