@diviops/mcp-server 1.5.9 → 1.5.11
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 +22 -1
- package/data/verified-attrs-backlog.json +197 -0
- package/data/verified-attrs.json +663 -0
- package/dist/index.js +38 -2
- package/dist/preset-cli/__tests__/button-emitter.test.d.ts +8 -0
- package/dist/preset-cli/__tests__/button-emitter.test.js +188 -0
- package/dist/preset-cli/__tests__/cli.test.d.ts +9 -0
- package/dist/preset-cli/__tests__/cli.test.js +149 -0
- package/dist/preset-cli/__tests__/preset-create-unchanged.test.d.ts +13 -0
- package/dist/preset-cli/__tests__/preset-create-unchanged.test.js +64 -0
- package/dist/preset-cli/__tests__/registry.test.d.ts +5 -0
- package/dist/preset-cli/__tests__/registry.test.js +134 -0
- package/dist/preset-cli/__tests__/write-path.test.d.ts +8 -0
- package/dist/preset-cli/__tests__/write-path.test.js +120 -0
- package/dist/preset-cli/bin.d.ts +8 -0
- package/dist/preset-cli/bin.js +32 -0
- package/dist/preset-cli/button-emitter.d.ts +117 -0
- package/dist/preset-cli/button-emitter.js +218 -0
- package/dist/preset-cli/cli.d.ts +59 -0
- package/dist/preset-cli/cli.js +326 -0
- package/dist/preset-cli/registry.d.ts +107 -0
- package/dist/preset-cli/registry.js +168 -0
- package/dist/preset-cli/variable-token.d.ts +42 -0
- package/dist/preset-cli/variable-token.js +70 -0
- package/dist/preset-cli/write-path.d.ts +59 -0
- package/dist/preset-cli/write-path.js +89 -0
- package/package.json +6 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `$variable()` color-token helpers for the preset-emitter CLI.
|
|
3
|
+
*
|
|
4
|
+
* Divi 5.5.x color bindings use the token grammar:
|
|
5
|
+
*
|
|
6
|
+
* $variable({"type":"color","value":{"name":"gcid-heading-color","settings":{}}})$
|
|
7
|
+
*
|
|
8
|
+
* Two load-bearing rules (both from VB-verified memory):
|
|
9
|
+
* - The token MUST end with `)$` — a missing trailing `$` causes silent
|
|
10
|
+
* render failure (`feedback_variable_trailing_dollar`).
|
|
11
|
+
* - The `value` payload MUST be an object `{name, settings}`, not a flat
|
|
12
|
+
* `gcid-*` string — a flat string crashes PHP 8 in Divi's DynamicData
|
|
13
|
+
* resolver (`feedback_variable_color_value_object_shape`).
|
|
14
|
+
*
|
|
15
|
+
* The CLI accepts a color param that is EITHER a literal (a hex string,
|
|
16
|
+
* or an already-formed `$variable(...)$` token) OR a bare `gcid-*` /
|
|
17
|
+
* `gvid-*` token name, which this module wraps into the canonical shape.
|
|
18
|
+
*/
|
|
19
|
+
/** An already-formed `$variable(...)$` token. */
|
|
20
|
+
export declare function isVariableToken(value: string): boolean;
|
|
21
|
+
/** A bare token name like `gcid-primary-color`. */
|
|
22
|
+
export declare function isBareTokenName(value: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Build a canonical `$variable()` color token from a bare token name.
|
|
25
|
+
*
|
|
26
|
+
* The inner JSON uses single-escape `\"` when the whole preset is later
|
|
27
|
+
* `JSON.stringify`-d — that is handled by JSON.stringify itself; here we
|
|
28
|
+
* return the raw string value (un-stringified), which is what belongs in
|
|
29
|
+
* the in-memory preset object.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildColorVariableToken(tokenName: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Normalize a CLI color param to the value that belongs in the preset.
|
|
34
|
+
*
|
|
35
|
+
* - An already-formed `$variable(...)$` token → returned verbatim (the
|
|
36
|
+
* caller is responsible for its correctness; the trailing `)$` is
|
|
37
|
+
* asserted).
|
|
38
|
+
* - A bare `gcid-*`/`gvid-*` name → wrapped into the canonical token.
|
|
39
|
+
* - Anything else (a hex string, `rgba(...)`, etc.) → returned verbatim
|
|
40
|
+
* as a literal color value.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizeColorValue(value: string): string;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `$variable()` color-token helpers for the preset-emitter CLI.
|
|
3
|
+
*
|
|
4
|
+
* Divi 5.5.x color bindings use the token grammar:
|
|
5
|
+
*
|
|
6
|
+
* $variable({"type":"color","value":{"name":"gcid-heading-color","settings":{}}})$
|
|
7
|
+
*
|
|
8
|
+
* Two load-bearing rules (both from VB-verified memory):
|
|
9
|
+
* - The token MUST end with `)$` — a missing trailing `$` causes silent
|
|
10
|
+
* render failure (`feedback_variable_trailing_dollar`).
|
|
11
|
+
* - The `value` payload MUST be an object `{name, settings}`, not a flat
|
|
12
|
+
* `gcid-*` string — a flat string crashes PHP 8 in Divi's DynamicData
|
|
13
|
+
* resolver (`feedback_variable_color_value_object_shape`).
|
|
14
|
+
*
|
|
15
|
+
* The CLI accepts a color param that is EITHER a literal (a hex string,
|
|
16
|
+
* or an already-formed `$variable(...)$` token) OR a bare `gcid-*` /
|
|
17
|
+
* `gvid-*` token name, which this module wraps into the canonical shape.
|
|
18
|
+
*/
|
|
19
|
+
/** A bare Divi variable token name (gcid-* or gvid-*). */
|
|
20
|
+
const BARE_TOKEN_RE = /^(gcid|gvid)-[A-Za-z0-9_-]+$/;
|
|
21
|
+
/** An already-formed `$variable(...)$` token. */
|
|
22
|
+
export function isVariableToken(value) {
|
|
23
|
+
return value.startsWith("$variable(") && value.endsWith(")$");
|
|
24
|
+
}
|
|
25
|
+
/** A bare token name like `gcid-primary-color`. */
|
|
26
|
+
export function isBareTokenName(value) {
|
|
27
|
+
return BARE_TOKEN_RE.test(value);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a canonical `$variable()` color token from a bare token name.
|
|
31
|
+
*
|
|
32
|
+
* The inner JSON uses single-escape `\"` when the whole preset is later
|
|
33
|
+
* `JSON.stringify`-d — that is handled by JSON.stringify itself; here we
|
|
34
|
+
* return the raw string value (un-stringified), which is what belongs in
|
|
35
|
+
* the in-memory preset object.
|
|
36
|
+
*/
|
|
37
|
+
export function buildColorVariableToken(tokenName) {
|
|
38
|
+
if (!isBareTokenName(tokenName)) {
|
|
39
|
+
throw new Error(`Invalid variable token name "${tokenName}". Expected a bare gcid-*/gvid-* name ` +
|
|
40
|
+
`(e.g. "gcid-primary-color"), a hex literal, or an already-formed $variable(...)$ token.`);
|
|
41
|
+
}
|
|
42
|
+
const payload = JSON.stringify({
|
|
43
|
+
type: "color",
|
|
44
|
+
value: { name: tokenName, settings: {} },
|
|
45
|
+
});
|
|
46
|
+
return `$variable(${payload})$`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Normalize a CLI color param to the value that belongs in the preset.
|
|
50
|
+
*
|
|
51
|
+
* - An already-formed `$variable(...)$` token → returned verbatim (the
|
|
52
|
+
* caller is responsible for its correctness; the trailing `)$` is
|
|
53
|
+
* asserted).
|
|
54
|
+
* - A bare `gcid-*`/`gvid-*` name → wrapped into the canonical token.
|
|
55
|
+
* - Anything else (a hex string, `rgba(...)`, etc.) → returned verbatim
|
|
56
|
+
* as a literal color value.
|
|
57
|
+
*/
|
|
58
|
+
export function normalizeColorValue(value) {
|
|
59
|
+
if (isVariableToken(value)) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
if (value.startsWith("$variable(") && !value.endsWith(")$")) {
|
|
63
|
+
throw new Error(`Malformed $variable() token "${value}" — must end with ")$" ` +
|
|
64
|
+
`(missing trailing "$" causes silent render failure).`);
|
|
65
|
+
}
|
|
66
|
+
if (isBareTokenName(value)) {
|
|
67
|
+
return buildColorVariableToken(value);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply-mode write path for the preset-emitter CLI.
|
|
3
|
+
*
|
|
4
|
+
* Reuses the existing server WP-client conventions:
|
|
5
|
+
* - `WP_URL` / `WP_USER` / `WP_APP_PASSWORD` env vars.
|
|
6
|
+
* - `WPClient` from `wp-client.ts` for the HTTP + Basic-Auth machinery.
|
|
7
|
+
* - `WPClient.handshake()` for the plugin capability map.
|
|
8
|
+
*
|
|
9
|
+
* Before any write the CLI verifies the plugin handshake reports the
|
|
10
|
+
* `storage_multipath_probe_v1` capability (the storage-path capability
|
|
11
|
+
* contract, shipped in plugin 1.4.9). Absent → fail fast, before composing
|
|
12
|
+
* a write.
|
|
13
|
+
*
|
|
14
|
+
* `--dry-run` never reaches this module: it requires no credentials, no
|
|
15
|
+
* handshake, and no network.
|
|
16
|
+
*/
|
|
17
|
+
import { WPClient } from "../wp-client.js";
|
|
18
|
+
import type { HandshakeResult } from "../compatibility.js";
|
|
19
|
+
import type { DiviopsResponse } from "../envelope.js";
|
|
20
|
+
import type { ButtonPresetEntry } from "./button-emitter.js";
|
|
21
|
+
/** The plugin capability the storage-path capability contract ships. */
|
|
22
|
+
export declare const STORAGE_CAPABILITY = "storage_multipath_probe_v1";
|
|
23
|
+
/** The REST route the CLI posts to — same route `diviops_preset_create` uses. */
|
|
24
|
+
export declare const PRESET_CREATE_ROUTE = "/preset/create";
|
|
25
|
+
/** Minimal client surface the write path needs — eased for mocking in tests. */
|
|
26
|
+
export interface PresetWriteClient {
|
|
27
|
+
handshake(serverVersion: string): Promise<HandshakeResult>;
|
|
28
|
+
requestEnveloped<T = unknown>(endpoint: string, options?: {
|
|
29
|
+
method?: string;
|
|
30
|
+
body?: Record<string, unknown>;
|
|
31
|
+
params?: Record<string, string>;
|
|
32
|
+
}): Promise<DiviopsResponse<T>>;
|
|
33
|
+
}
|
|
34
|
+
export declare class CredentialsMissingError extends Error {
|
|
35
|
+
constructor(missing: string[]);
|
|
36
|
+
}
|
|
37
|
+
export declare class CapabilityMissingError extends Error {
|
|
38
|
+
readonly capability: string;
|
|
39
|
+
readonly pluginVersion: string;
|
|
40
|
+
constructor(capability: string, pluginVersion: string);
|
|
41
|
+
}
|
|
42
|
+
/** Build a `WPClient` from the standard env vars, or throw if any are absent. */
|
|
43
|
+
export declare function buildClientFromEnv(env?: NodeJS.ProcessEnv): WPClient;
|
|
44
|
+
/**
|
|
45
|
+
* Verify the plugin handshake reports `storage_multipath_probe_v1`.
|
|
46
|
+
* Throws `CapabilityMissingError` if absent. Returns the handshake result
|
|
47
|
+
* so callers can surface the plugin version.
|
|
48
|
+
*/
|
|
49
|
+
export declare function assertStorageCapability(client: PresetWriteClient, serverVersion: string): Promise<HandshakeResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Apply a button preset: capability-gate, then POST to `/preset/create`.
|
|
52
|
+
*
|
|
53
|
+
* The capability check runs BEFORE the write. The write goes through the
|
|
54
|
+
* existing storage-routed route — no plugin route is added here.
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyButtonPreset(client: PresetWriteClient, entry: ButtonPresetEntry, opts: {
|
|
57
|
+
serverVersion: string;
|
|
58
|
+
dry_run?: boolean;
|
|
59
|
+
}): Promise<DiviopsResponse<unknown>>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply-mode write path for the preset-emitter CLI.
|
|
3
|
+
*
|
|
4
|
+
* Reuses the existing server WP-client conventions:
|
|
5
|
+
* - `WP_URL` / `WP_USER` / `WP_APP_PASSWORD` env vars.
|
|
6
|
+
* - `WPClient` from `wp-client.ts` for the HTTP + Basic-Auth machinery.
|
|
7
|
+
* - `WPClient.handshake()` for the plugin capability map.
|
|
8
|
+
*
|
|
9
|
+
* Before any write the CLI verifies the plugin handshake reports the
|
|
10
|
+
* `storage_multipath_probe_v1` capability (the storage-path capability
|
|
11
|
+
* contract, shipped in plugin 1.4.9). Absent → fail fast, before composing
|
|
12
|
+
* a write.
|
|
13
|
+
*
|
|
14
|
+
* `--dry-run` never reaches this module: it requires no credentials, no
|
|
15
|
+
* handshake, and no network.
|
|
16
|
+
*/
|
|
17
|
+
import { WPClient } from "../wp-client.js";
|
|
18
|
+
import { buildPresetCreateBody } from "./button-emitter.js";
|
|
19
|
+
/** The plugin capability the storage-path capability contract ships. */
|
|
20
|
+
export const STORAGE_CAPABILITY = "storage_multipath_probe_v1";
|
|
21
|
+
/** The REST route the CLI posts to — same route `diviops_preset_create` uses. */
|
|
22
|
+
export const PRESET_CREATE_ROUTE = "/preset/create";
|
|
23
|
+
export class CredentialsMissingError extends Error {
|
|
24
|
+
constructor(missing) {
|
|
25
|
+
super(`Apply mode requires WordPress credentials. Missing: ${missing.join(", ")}. ` +
|
|
26
|
+
`Set WP_URL / WP_USER / WP_APP_PASSWORD (the same env vars the MCP server uses). ` +
|
|
27
|
+
`Use --dry-run to compose preset JSON without credentials.`);
|
|
28
|
+
this.name = "CredentialsMissingError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class CapabilityMissingError extends Error {
|
|
32
|
+
capability;
|
|
33
|
+
pluginVersion;
|
|
34
|
+
constructor(capability, pluginVersion) {
|
|
35
|
+
super(`The active diviops-agent plugin (version ${pluginVersion}) does not report ` +
|
|
36
|
+
`the "${capability}" capability required for storage-routed preset writes. ` +
|
|
37
|
+
`Upgrade diviops-agent to a version that ships the "${capability}" capability ` +
|
|
38
|
+
`(plugin 1.4.9 or later).`);
|
|
39
|
+
this.capability = capability;
|
|
40
|
+
this.pluginVersion = pluginVersion;
|
|
41
|
+
this.name = "CapabilityMissingError";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Build a `WPClient` from the standard env vars, or throw if any are absent. */
|
|
45
|
+
export function buildClientFromEnv(env = process.env) {
|
|
46
|
+
const url = env.WP_URL ?? "";
|
|
47
|
+
const user = env.WP_USER ?? "";
|
|
48
|
+
const pass = env.WP_APP_PASSWORD ?? "";
|
|
49
|
+
const missing = [];
|
|
50
|
+
if (!url)
|
|
51
|
+
missing.push("WP_URL");
|
|
52
|
+
if (!user)
|
|
53
|
+
missing.push("WP_USER");
|
|
54
|
+
if (!pass)
|
|
55
|
+
missing.push("WP_APP_PASSWORD");
|
|
56
|
+
if (missing.length > 0)
|
|
57
|
+
throw new CredentialsMissingError(missing);
|
|
58
|
+
return new WPClient({
|
|
59
|
+
siteUrl: url,
|
|
60
|
+
username: user,
|
|
61
|
+
applicationPassword: pass,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Verify the plugin handshake reports `storage_multipath_probe_v1`.
|
|
66
|
+
* Throws `CapabilityMissingError` if absent. Returns the handshake result
|
|
67
|
+
* so callers can surface the plugin version.
|
|
68
|
+
*/
|
|
69
|
+
export async function assertStorageCapability(client, serverVersion) {
|
|
70
|
+
const hs = await client.handshake(serverVersion);
|
|
71
|
+
if (!hs.capabilities || hs.capabilities[STORAGE_CAPABILITY] !== true) {
|
|
72
|
+
throw new CapabilityMissingError(STORAGE_CAPABILITY, hs.plugin_version ?? "unknown");
|
|
73
|
+
}
|
|
74
|
+
return hs;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Apply a button preset: capability-gate, then POST to `/preset/create`.
|
|
78
|
+
*
|
|
79
|
+
* The capability check runs BEFORE the write. The write goes through the
|
|
80
|
+
* existing storage-routed route — no plugin route is added here.
|
|
81
|
+
*/
|
|
82
|
+
export async function applyButtonPreset(client, entry, opts) {
|
|
83
|
+
await assertStorageCapability(client, opts.serverVersion);
|
|
84
|
+
const body = buildPresetCreateBody(entry, { dry_run: opts.dry_run });
|
|
85
|
+
return client.requestEnveloped(PRESET_CREATE_ROUTE, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
body,
|
|
88
|
+
});
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diviops/mcp-server",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.11",
|
|
4
4
|
"description": "MCP server exposing Divi 5 Visual Builder as tools for Claude",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"diviops-mcp": "dist/index.js"
|
|
8
|
+
"diviops-mcp": "dist/index.js",
|
|
9
|
+
"diviops-preset": "dist/preset-cli/bin.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dist",
|
|
12
13
|
"templates",
|
|
14
|
+
"data/verified-attrs.json",
|
|
15
|
+
"data/verified-attrs-backlog.json",
|
|
13
16
|
"README.md"
|
|
14
17
|
],
|
|
15
18
|
"scripts": {
|
|
16
19
|
"build": "tsc",
|
|
17
20
|
"start": "node dist/index.js",
|
|
18
21
|
"dev": "tsc --watch",
|
|
22
|
+
"test": "npm run build && node --test \"dist/preset-cli/__tests__/*.test.js\"",
|
|
19
23
|
"prepublishOnly": "npm run build",
|
|
20
24
|
"regen:skill": "node scripts/regen-module-formats.mjs"
|
|
21
25
|
},
|