@diviops/mcp-server 1.5.10 → 1.5.12

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.
Files changed (28) hide show
  1. package/README.md +34 -0
  2. package/dist/preset-cli/__tests__/button-emitter.test.d.ts +8 -0
  3. package/dist/preset-cli/__tests__/button-emitter.test.js +188 -0
  4. package/dist/preset-cli/__tests__/cli.test.d.ts +9 -0
  5. package/dist/preset-cli/__tests__/cli.test.js +330 -0
  6. package/dist/preset-cli/__tests__/heading-font-emitter.test.d.ts +12 -0
  7. package/dist/preset-cli/__tests__/heading-font-emitter.test.js +249 -0
  8. package/dist/preset-cli/__tests__/preset-create-unchanged.test.d.ts +13 -0
  9. package/dist/preset-cli/__tests__/preset-create-unchanged.test.js +64 -0
  10. package/dist/preset-cli/__tests__/registry.test.d.ts +5 -0
  11. package/dist/preset-cli/__tests__/registry.test.js +149 -0
  12. package/dist/preset-cli/__tests__/write-path.test.d.ts +8 -0
  13. package/dist/preset-cli/__tests__/write-path.test.js +174 -0
  14. package/dist/preset-cli/bin.d.ts +8 -0
  15. package/dist/preset-cli/bin.js +32 -0
  16. package/dist/preset-cli/button-emitter.d.ts +117 -0
  17. package/dist/preset-cli/button-emitter.js +218 -0
  18. package/dist/preset-cli/cli.d.ts +62 -0
  19. package/dist/preset-cli/cli.js +429 -0
  20. package/dist/preset-cli/heading-font-emitter.d.ts +128 -0
  21. package/dist/preset-cli/heading-font-emitter.js +166 -0
  22. package/dist/preset-cli/registry.d.ts +121 -0
  23. package/dist/preset-cli/registry.js +192 -0
  24. package/dist/preset-cli/variable-token.d.ts +42 -0
  25. package/dist/preset-cli/variable-token.js +70 -0
  26. package/dist/preset-cli/write-path.d.ts +74 -0
  27. package/dist/preset-cli/write-path.js +110 -0
  28. package/package.json +4 -2
@@ -0,0 +1,110 @@
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
+ import { buildHeadingFontPresetCreateBody } from "./heading-font-emitter.js";
20
+ /** The plugin capability the storage-path capability contract ships. */
21
+ export const STORAGE_CAPABILITY = "storage_multipath_probe_v1";
22
+ /** The REST route the CLI posts to — same route `diviops_preset_create` uses. */
23
+ export const PRESET_CREATE_ROUTE = "/preset/create";
24
+ export class CredentialsMissingError extends Error {
25
+ constructor(missing) {
26
+ super(`Apply mode requires WordPress credentials. Missing: ${missing.join(", ")}. ` +
27
+ `Set WP_URL / WP_USER / WP_APP_PASSWORD (the same env vars the MCP server uses). ` +
28
+ `Use --dry-run to compose preset JSON without credentials.`);
29
+ this.name = "CredentialsMissingError";
30
+ }
31
+ }
32
+ export class CapabilityMissingError extends Error {
33
+ capability;
34
+ pluginVersion;
35
+ constructor(capability, pluginVersion) {
36
+ super(`The active diviops-agent plugin (version ${pluginVersion}) does not report ` +
37
+ `the "${capability}" capability required for storage-routed preset writes. ` +
38
+ `Upgrade diviops-agent to a version that ships the "${capability}" capability ` +
39
+ `(plugin 1.4.9 or later).`);
40
+ this.capability = capability;
41
+ this.pluginVersion = pluginVersion;
42
+ this.name = "CapabilityMissingError";
43
+ }
44
+ }
45
+ /** Build a `WPClient` from the standard env vars, or throw if any are absent. */
46
+ export function buildClientFromEnv(env = process.env) {
47
+ const url = env.WP_URL ?? "";
48
+ const user = env.WP_USER ?? "";
49
+ const pass = env.WP_APP_PASSWORD ?? "";
50
+ const missing = [];
51
+ if (!url)
52
+ missing.push("WP_URL");
53
+ if (!user)
54
+ missing.push("WP_USER");
55
+ if (!pass)
56
+ missing.push("WP_APP_PASSWORD");
57
+ if (missing.length > 0)
58
+ throw new CredentialsMissingError(missing);
59
+ return new WPClient({
60
+ siteUrl: url,
61
+ username: user,
62
+ applicationPassword: pass,
63
+ });
64
+ }
65
+ /**
66
+ * Verify the plugin handshake reports `storage_multipath_probe_v1`.
67
+ * Throws `CapabilityMissingError` if absent. Returns the handshake result
68
+ * so callers can surface the plugin version.
69
+ */
70
+ export async function assertStorageCapability(client, serverVersion) {
71
+ const hs = await client.handshake(serverVersion);
72
+ if (!hs.capabilities || hs.capabilities[STORAGE_CAPABILITY] !== true) {
73
+ throw new CapabilityMissingError(STORAGE_CAPABILITY, hs.plugin_version ?? "unknown");
74
+ }
75
+ return hs;
76
+ }
77
+ /**
78
+ * Apply a button preset: capability-gate, then POST to `/preset/create`.
79
+ *
80
+ * The capability check runs BEFORE the write. The write goes through the
81
+ * existing storage-routed route — no plugin route is added here.
82
+ */
83
+ export async function applyButtonPreset(client, entry, opts) {
84
+ await assertStorageCapability(client, opts.serverVersion);
85
+ const body = buildPresetCreateBody(entry, { dry_run: opts.dry_run });
86
+ return client.requestEnveloped(PRESET_CREATE_ROUTE, {
87
+ method: "POST",
88
+ body,
89
+ });
90
+ }
91
+ /**
92
+ * Apply a `divi/font` heading group preset: capability-gate, then POST
93
+ * to `/preset/create`. Mirrors `applyButtonPreset`'s sequence — the
94
+ * capability check runs BEFORE the write, and the write reuses the
95
+ * existing storage-routed route (no plugin route is added).
96
+ *
97
+ * The `pattern_variant` metadata is intentionally NOT in the wire body —
98
+ * variant selection is a client-side registry-gate decision and the
99
+ * server route accepts only the standard preset-create fields.
100
+ */
101
+ export async function applyHeadingFontPreset(client, entry, opts) {
102
+ await assertStorageCapability(client, opts.serverVersion);
103
+ const body = buildHeadingFontPresetCreateBody(entry, {
104
+ dry_run: opts.dry_run,
105
+ });
106
+ return client.requestEnveloped(PRESET_CREATE_ROUTE, {
107
+ method: "POST",
108
+ body,
109
+ });
110
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@diviops/mcp-server",
3
- "version": "1.5.10",
3
+ "version": "1.5.12",
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",
@@ -18,6 +19,7 @@
18
19
  "build": "tsc",
19
20
  "start": "node dist/index.js",
20
21
  "dev": "tsc --watch",
22
+ "test": "npm run build && node --test \"dist/preset-cli/__tests__/*.test.js\"",
21
23
  "prepublishOnly": "npm run build",
22
24
  "regen:skill": "node scripts/regen-module-formats.mjs"
23
25
  },