@respira/wordpress-mcp-server 7.2.0 → 7.2.2

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 CHANGED
@@ -7,14 +7,14 @@
7
7
  <h1 align="center">Respira WordPress MCP Server</h1>
8
8
 
9
9
  <p align="center">
10
- <strong>180+ MCP tools. 16 page builders. Context-aware tool filtering. The AI infrastructure layer for WordPress.</strong><br>
10
+ <strong>200+ MCP tools (275+ with add-ons). 16 page builders. Context-aware tool filtering. The AI infrastructure layer for WordPress.</strong><br>
11
11
  Element-level editing, full page creation, HTML-to-builder conversion with rendering fidelity validation, per-site tool governance, storefront design intelligence, stock images, bulk operations — all through one MCP server.
12
12
  </p>
13
13
 
14
14
  <p align="center">
15
15
  <a href="https://www.npmjs.com/package/@respira/wordpress-mcp-server"><img src="https://img.shields.io/npm/v/@respira/wordpress-mcp-server.svg?style=flat-square&color=10b981" alt="npm version"></a>
16
16
  <a href="https://www.npmjs.com/package/@respira/wordpress-mcp-server"><img src="https://img.shields.io/npm/dm/@respira/wordpress-mcp-server.svg?style=flat-square" alt="npm downloads"></a>
17
- <img src="https://img.shields.io/badge/tools-172+-10b981?style=flat-square" alt="172+ Tools">
17
+ <img src="https://img.shields.io/badge/tools-200+-10b981?style=flat-square" alt="200+ Tools">
18
18
  <img src="https://img.shields.io/badge/builders-16-10b981?style=flat-square" alt="16 Page Builders">
19
19
  <img src="https://img.shields.io/badge/TypeScript-100%25-blue?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript">
20
20
  </p>
@@ -40,12 +40,12 @@ Respira includes a WordPress plugin that gives AI **native access** to 16 page b
40
40
  The biggest release since launch.
41
41
 
42
42
  - **Four new page builders.** Spectra, Kadence Blocks, and GenerateBlocks join with full read + write; SeedProd ships read + audit. Supported builders go from 12 to 16.
43
- - **Make any builder responsive in one call** across Bricks, Elementor, Divi 4, Beaver Builder, and WPBakery.
43
+ - **Make a page responsive in one call** on Bricks, Elementor, Divi 4, Beaver Builder, and WPBakery.
44
44
  - **Playbooks.** Teach an agent a multi-step workflow once and rerun it as a single callable WordPress Ability. Five tools (create / list / get / update / delete), with static cycle detection and a runtime depth cap.
45
45
  - **Agent-creatable Custom Post Types, taxonomies, and ACF field groups** (twelve tools), stored in options and registered on `init`. No PHP files, server-side slug allowlist, conservative deletes that report orphans.
46
46
  - **Native in-WP MCP endpoint.** Point a client straight at `your-site/?respira=mcp` (Streamable HTTP, JSON-RPC) with an API key, no npx process required. One-click connect-by-link mints and installs the key for you.
47
47
  - **System certificate-store trust.** The connector trusts the OS certificate store at startup (verification stays on) with a bundled Mozilla CA fallback, so valid public certs stop being rejected on Claude Desktop's bundled Node.
48
- - **Bricks design-token import + section presets**, the **Elementor 4 atomic write path**, and **`respira_generate_activity_report`** for client-ready reports.
48
+ - **Bricks design-token import + section presets**, the **Elementor 4 atomic write path** (partial: 20 atomic element types with `$$type` envelopes, per-breakpoint + per-state styling, and a clear 422 on unsupported types instead of a silent drop), and **`respira_generate_activity_report`** for client-ready reports.
49
49
 
50
50
  ### New in v6.17.0: an MCP that knows how to behave
51
51
 
@@ -71,20 +71,20 @@ Every successful tool response includes `structuredContent`, the raw JSON object
71
71
 
72
72
  The MCP server automatically filters the tool list based on your site's detected builder and active plugins. A Divi site without WooCommerce sees ~130 tools instead of ~170. Less noise, faster AI responses, lower token usage. Fail-open: if detection fails, the full list is returned.
73
73
 
74
- | Capability | Respira | Other MCP Servers |
74
+ | Capability | Respira | Typical WordPress MCP servers |
75
75
  |---|---|---|
76
- | Page builder support | **16 builders** (incl. Spectra, Kadence, GenerateBlocks) | None |
76
+ | Page builder support | **16 builders** (incl. Spectra, Kadence, GenerateBlocks) | None, or a single builder |
77
77
  | Element-level find/update/move/remove | **Yes** | No |
78
78
  | Build full pages from structure | **Yes** | No |
79
79
  | Convert HTML to native builder | **Yes** | No |
80
- | Stock image search + sideload | **Yes** | No |
80
+ | Stock image search + sideload | **Yes** | Rare |
81
81
  | Bulk operations (100 pages/call) | **Yes** | No |
82
82
  | 27 widget shortcuts (add_heading, etc.) | **Yes** | No |
83
- | Duplicate-before-edit safety | **Yes** | No |
84
- | Snapshot rollback | **Yes** | No |
85
- | SEO / Core Web Vitals / AEO analysis | **Yes** | No |
86
- | WooCommerce (products, orders, inventory) | **Yes** (add-on) | No |
87
- | Tool governance (per-tool enable/disable) | **Yes** | No |
83
+ | Duplicate-before-edit safety | **Yes** | Rare |
84
+ | Snapshot rollback | **Yes**, builder-aware | Rare, post content only |
85
+ | SEO / Core Web Vitals / AEO analysis | **Yes** | Rare |
86
+ | WooCommerce (products, orders, inventory) | **Yes** (add-on) | Rare |
87
+ | Tool governance (per-tool enable/disable) | **Yes** | Rare |
88
88
 
89
89
  ---
90
90
 
@@ -450,7 +450,7 @@ Add any widget to a page in one call:
450
450
  | `respira_switch_site` | Switch active site |
451
451
  | `respira_get_active_site` | Get current site info |
452
452
 
453
- ### WooCommerce Add-on (36 tools)
453
+ ### WooCommerce Add-on (21 tools)
454
454
  Available when the [WooCommerce add-on](https://respira.press/addons/woocommerce) is installed. Included free with Studio and Founder plans.
455
455
 
456
456
  | Category | Tools |
@@ -475,7 +475,7 @@ Every mutation creates a snapshot. Roll back anytime.
475
475
  1. **Snapshot captured** before every edit
476
476
  2. **Duplicate-before-edit** — original stays untouched
477
477
  3. **Approval workflow** — review changes in WordPress admin
478
- 4. **Rollback** — restore any snapshot with `respira_restore_snapshot`
478
+ 4. **Rollback** — restore snapshots (90-day retention, pinnable) with `respira_restore_snapshot`
479
479
 
480
480
  ### Tool Governance
481
481
 
@@ -735,6 +735,6 @@ MIT © [Respira](https://respira.press)
735
735
  ---
736
736
 
737
737
  <p align="center">
738
- <strong>172 tools. 12 builders. The AI infrastructure layer for WordPress.</strong><br>
738
+ <strong>200+ tools. 16 builders. The AI infrastructure layer for WordPress.</strong><br>
739
739
  <a href="https://respira.press">respira.press</a>
740
740
  </p>
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides comprehensive Divi documentation for AI assistants.
5
5
  */
6
- export declare const diviContext = "\nYou are editing a Divi Builder page. Divi has two storage formats you must handle safely:\n- Divi 5: block-based layout using `divi/*` blocks in post content\n- Divi 4: legacy shortcode layout using `et_pb_*`\n\n## Divi 5 Structure (Primary)\n\n- **Sections (`divi/section`)**: Top-level containers\n- **Rows (`divi/row`)**: Layout containers inside sections\n- **Columns/Groups (`divi/column`, `divi/group`)**: Nested containers\n- **Modules (`divi/*`)**: Text, button, image, CTA, and other content blocks\n\n## Divi 4 Structure (Legacy)\n\n- **Sections (`et_pb_section`)**\n- **Rows (`et_pb_row`)**\n- **Modules (`et_pb_text`, `et_pb_image`, `et_pb_button`, etc.)**\n\n## Editing Contract\n\n- Use structured nodes: `{ type, attributes, children, content }`\n- Preserve unknown attributes exactly\n- Do not rewrite entire trees for small edits\n- Keep non-Divi blocks and legacy shortcode wrapper blocks unless explicitly asked to remove\n- Treat legacy wrappers as opaque: move/delete allowed, deep edits discouraged\n\n## Important Rules\n\n1. Prefer Divi 5 block edits (`divi/*`) when present\n2. Keep Divi 4 shortcode edits only for legacy pages\n3. Preserve parent/child nesting and ordering\n4. Preserve all existing attributes unless explicitly changed\n5. Use hex colors and full URLs where relevant\n6. Avoid lossy conversion between Divi 4 and Divi 5 formats\n7. For every Divi inject operation, ask for explicit confirmation: Divi 4 or Divi 5\n8. For code modules, preserve extracted content encoding; do not blindly base64-encode content\n";
6
+ export declare const diviContext = "\nYou are editing a Divi Builder page. Divi has two storage formats you must handle safely:\n- Divi 5: block-based layout using `divi/*` blocks in post content\n- Divi 4: legacy shortcode layout using `et_pb_*`\n\n## Divi 5 Structure (Primary)\n\n- **Sections (`divi/section`)**: Top-level containers\n- **Rows (`divi/row`)**: Layout containers inside sections\n- **Columns/Groups (`divi/column`, `divi/group`)**: Nested containers\n- **Modules (`divi/*`)**: Text, button, image, CTA, and other content blocks\n\n## Divi 4 Structure (Legacy)\n\n- **Sections (`et_pb_section`)**\n- **Rows (`et_pb_row`)**\n- **Modules (`et_pb_text`, `et_pb_image`, `et_pb_button`, etc.)**\n\n## Editing Contract\n\n- Use structured nodes: `{ type, attributes, children, content }`\n- Preserve unknown attributes exactly\n- Do not rewrite entire trees for small edits\n- Keep non-Divi blocks and legacy shortcode wrapper blocks unless explicitly asked to remove\n- Treat legacy wrappers as opaque: move/delete allowed, deep edits discouraged\n\n## Important Rules\n\n1. Prefer Divi 5 block edits (`divi/*`) when present\n2. Keep Divi 4 shortcode edits only for legacy pages\n3. Preserve parent/child nesting and ordering\n4. Preserve all existing attributes unless explicitly changed\n5. Use hex colors and full URLs where relevant\n6. Avoid lossy conversion between Divi 4 and Divi 5 formats\n7. Auto-detect Divi 4 vs Divi 5 from the page. respira_get_builder_info and respira_read_page reveal the mode, and the plugin already detects Divi 5 and flips into block format on its own. Only ask the human when it is genuinely ambiguous, like a brand new page with no builder set yet\n8. For code modules, preserve extracted content encoding; do not blindly base64-encode content\n";
7
7
  export declare const diviAttributeHelp: {
8
8
  colors: string;
9
9
  spacing: string;
@@ -11,5 +11,5 @@ export declare const diviAttributeHelp: {
11
11
  fonts: string;
12
12
  urls: string;
13
13
  };
14
- export declare const diviValidationRules = "\nCRITICAL Divi Rules:\n1. If Divi 5 blocks exist, keep output in block format (`divi/*`)\n2. Preserve `attributes` and `children` unless explicitly changed\n3. Keep legacy shortcode-wrapper blocks opaque\n4. Never overwrite a Divi 5 page with Divi 4 shortcodes\n5. Preserve module structure and ordering\n6. Always use proper attribute formats\n7. Ask user to confirm Divi 4 vs Divi 5 before every Divi inject\n";
14
+ export declare const diviValidationRules = "\nCRITICAL Divi Rules:\n1. If Divi 5 blocks exist, keep output in block format (`divi/*`)\n2. Preserve `attributes` and `children` unless explicitly changed\n3. Keep legacy shortcode-wrapper blocks opaque\n4. Never overwrite a Divi 5 page with Divi 4 shortcodes\n5. Preserve module structure and ordering\n6. Always use proper attribute formats\n7. Auto-detect Divi 4 vs Divi 5 from the page (respira_get_builder_info / respira_read_page); only ask the human on a genuinely ambiguous page with no builder set\n";
15
15
  //# sourceMappingURL=divi-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"divi-context.d.ts","sourceRoot":"","sources":["../src/divi-context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,WAAW,yhDAoCvB,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;CAM7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,iaAS/B,CAAC"}
1
+ {"version":3,"file":"divi-context.d.ts","sourceRoot":"","sources":["../src/divi-context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,WAAW,muDAoCvB,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;CAM7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,mgBAS/B,CAAC"}
@@ -37,7 +37,7 @@ You are editing a Divi Builder page. Divi has two storage formats you must handl
37
37
  4. Preserve all existing attributes unless explicitly changed
38
38
  5. Use hex colors and full URLs where relevant
39
39
  6. Avoid lossy conversion between Divi 4 and Divi 5 formats
40
- 7. For every Divi inject operation, ask for explicit confirmation: Divi 4 or Divi 5
40
+ 7. Auto-detect Divi 4 vs Divi 5 from the page. respira_get_builder_info and respira_read_page reveal the mode, and the plugin already detects Divi 5 and flips into block format on its own. Only ask the human when it is genuinely ambiguous, like a brand new page with no builder set yet
41
41
  8. For code modules, preserve extracted content encoding; do not blindly base64-encode content
42
42
  `;
43
43
  export const diviAttributeHelp = {
@@ -55,6 +55,6 @@ CRITICAL Divi Rules:
55
55
  4. Never overwrite a Divi 5 page with Divi 4 shortcodes
56
56
  5. Preserve module structure and ordering
57
57
  6. Always use proper attribute formats
58
- 7. Ask user to confirm Divi 4 vs Divi 5 before every Divi inject
58
+ 7. Auto-detect Divi 4 vs Divi 5 from the page (respira_get_builder_info / respira_read_page); only ask the human on a genuinely ambiguous page with no builder set
59
59
  `;
60
60
  //# sourceMappingURL=divi-context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"divi-prompts.d.ts","sourceRoot":"","sources":["../src/divi-prompts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,wLAI5B,CAAC;AAEF,eAAO,MAAM,8BAA8B,oHACmE,CAAC;AAE/G,eAAO,MAAM,2BAA2B;;;;GA0BvC,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAmFlD,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAShC,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAElE;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAYR"}
1
+ {"version":3,"file":"divi-prompts.d.ts","sourceRoot":"","sources":["../src/divi-prompts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,wLAI5B,CAAC;AAEF,eAAO,MAAM,8BAA8B,oHACmE,CAAC;AAE/G,eAAO,MAAM,2BAA2B;;;;GA0BvC,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAoNlD,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAShC,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAElE;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAYR"}
@@ -39,22 +39,148 @@ export const diviMigrationCopilotPrompts = [
39
39
  export const diviPrompts = {
40
40
  createHeroSection: {
41
41
  name: 'create_divi_hero',
42
- description: 'Create a Divi hero section using structured nodes',
43
- template: `Create a Divi 5 hero structure (or Divi 4 equivalent on legacy pages) using node format:
42
+ description: 'Build a Divi 5 hero section with native heading, text, and button modules',
43
+ template: `Build a Divi 5 hero with native modules (heading, text, button). Use node format { type, attributes, children, content }. The plugin auto-detects Divi 4 vs Divi 5, so write Divi 5 unless the page is on legacy Divi 4.
44
44
  {
45
45
  type: "divi/section",
46
- attributes: { background_color: "{bg_color}", background_image: "{bg_url}" },
46
+ attributes: { background_color: "{bg_color}" },
47
47
  children: [
48
48
  {
49
49
  type: "divi/row",
50
50
  attributes: {},
51
51
  children: [
52
- { type: "divi/text", attributes: { text_orientation: "center" }, content: "<h1>{heading}</h1><p>{subheading}</p>" },
53
- { type: "divi/button", attributes: { button_url: "{url}", button_text: "{text}", button_alignment: "center" }, content: "" }
52
+ {
53
+ type: "divi/column",
54
+ attributes: {},
55
+ children: [
56
+ { type: "divi/heading", attributes: { title: "{heading}", text_orientation: "center" }, content: "" },
57
+ { type: "divi/text", attributes: { text_orientation: "center" }, content: "<p>{subheading}</p>" },
58
+ { type: "divi/button", attributes: { linkUrl: "{url}", button_text: "{text}", button_alignment: "center" }, content: "" }
59
+ ]
60
+ }
54
61
  ]
55
62
  }
56
63
  ]
57
64
  }`,
65
+ },
66
+ createFeaturesSection: {
67
+ name: 'create_divi_features',
68
+ description: 'Build a Divi 5 features row of three blurb columns',
69
+ template: `Build a Divi 5 features section: one row, three columns, each with a native divi/blurb. Use node format { type, attributes, children, content }. divi/blurb title is an object: { "text": "..." }.
70
+ {
71
+ type: "divi/section",
72
+ attributes: {},
73
+ children: [
74
+ {
75
+ type: "divi/row",
76
+ attributes: { flexColumnStructure: "8_24,8_24,8_24" },
77
+ children: [
78
+ {
79
+ type: "divi/column",
80
+ attributes: {},
81
+ children: [
82
+ { type: "divi/blurb", attributes: { title: { text: "{feature_1_title}" }, image: "{feature_1_icon}" }, content: "<p>{feature_1_text}</p>" }
83
+ ]
84
+ },
85
+ {
86
+ type: "divi/column",
87
+ attributes: {},
88
+ children: [
89
+ { type: "divi/blurb", attributes: { title: { text: "{feature_2_title}" }, image: "{feature_2_icon}" }, content: "<p>{feature_2_text}</p>" }
90
+ ]
91
+ },
92
+ {
93
+ type: "divi/column",
94
+ attributes: {},
95
+ children: [
96
+ { type: "divi/blurb", attributes: { title: { text: "{feature_3_title}" }, image: "{feature_3_icon}" }, content: "<p>{feature_3_text}</p>" }
97
+ ]
98
+ }
99
+ ]
100
+ }
101
+ ]
102
+ }`,
103
+ },
104
+ createCtaSection: {
105
+ name: 'create_divi_cta',
106
+ description: 'Build a centered Divi 5 call-to-action section',
107
+ template: `Build a centered Divi 5 call-to-action: heading, text, and button in one column. Use node format { type, attributes, children, content }.
108
+ {
109
+ type: "divi/section",
110
+ attributes: { background_color: "{bg_color}" },
111
+ children: [
112
+ {
113
+ type: "divi/row",
114
+ attributes: {},
115
+ children: [
116
+ {
117
+ type: "divi/column",
118
+ attributes: {},
119
+ children: [
120
+ { type: "divi/heading", attributes: { title: "{heading}", text_orientation: "center" }, content: "" },
121
+ { type: "divi/text", attributes: { text_orientation: "center" }, content: "<p>{subheading}</p>" },
122
+ { type: "divi/button", attributes: { linkUrl: "{url}", button_text: "{text}", button_alignment: "center" }, content: "" }
123
+ ]
124
+ }
125
+ ]
126
+ }
127
+ ]
128
+ }`,
129
+ },
130
+ createLandingPage: {
131
+ name: 'create_divi_landing',
132
+ description: 'Build a basic Divi 5 landing page: hero, features, image, and CTA sections',
133
+ template: `Build a basic Divi 5 landing page by composing native-module sections in order: hero, features, image, then CTA. Use node format { type, attributes, children, content }. Pass this whole array as the page content.
134
+ [
135
+ {
136
+ type: "divi/section",
137
+ attributes: { background_color: "{hero_bg}" },
138
+ children: [
139
+ { type: "divi/row", attributes: {}, children: [
140
+ { type: "divi/column", attributes: {}, children: [
141
+ { type: "divi/heading", attributes: { title: "{hero_heading}", text_orientation: "center" }, content: "" },
142
+ { type: "divi/text", attributes: { text_orientation: "center" }, content: "<p>{hero_subheading}</p>" },
143
+ { type: "divi/button", attributes: { linkUrl: "{hero_url}", button_text: "{hero_cta}", button_alignment: "center" }, content: "" }
144
+ ] }
145
+ ] }
146
+ ]
147
+ },
148
+ {
149
+ type: "divi/section",
150
+ attributes: {},
151
+ children: [
152
+ { type: "divi/row", attributes: { flexColumnStructure: "8_24,8_24,8_24" }, children: [
153
+ { type: "divi/column", attributes: {}, children: [ { type: "divi/blurb", attributes: { title: { text: "{feature_1_title}" } }, content: "<p>{feature_1_text}</p>" } ] },
154
+ { type: "divi/column", attributes: {}, children: [ { type: "divi/blurb", attributes: { title: { text: "{feature_2_title}" } }, content: "<p>{feature_2_text}</p>" } ] },
155
+ { type: "divi/column", attributes: {}, children: [ { type: "divi/blurb", attributes: { title: { text: "{feature_3_title}" } }, content: "<p>{feature_3_text}</p>" } ] }
156
+ ] }
157
+ ]
158
+ },
159
+ {
160
+ type: "divi/section",
161
+ attributes: {},
162
+ children: [
163
+ { type: "divi/row", attributes: {}, children: [
164
+ { type: "divi/column", attributes: {}, children: [
165
+ { type: "divi/image", attributes: { src: "{image_url}", alt: "{image_alt}", align: "center" }, content: "" }
166
+ ] }
167
+ ] }
168
+ ]
169
+ },
170
+ {
171
+ type: "divi/section",
172
+ attributes: { background_color: "{cta_bg}" },
173
+ children: [
174
+ { type: "divi/row", attributes: {}, children: [
175
+ { type: "divi/column", attributes: {}, children: [
176
+ { type: "divi/heading", attributes: { title: "{cta_heading}", text_orientation: "center" }, content: "" },
177
+ { type: "divi/text", attributes: { text_orientation: "center" }, content: "<p>{cta_subheading}</p>" },
178
+ { type: "divi/button", attributes: { linkUrl: "{cta_url}", button_text: "{cta_text}", button_alignment: "center" }, content: "" }
179
+ ] }
180
+ ] }
181
+ ]
182
+ }
183
+ ]`,
58
184
  },
59
185
  updateModuleStyle: {
60
186
  name: 'update_divi_style',
@@ -1 +1 @@
1
- {"version":3,"file":"divi-prompts.js","sourceRoot":"","sources":["../src/divi-prompts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;CAI/B,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GACzC,4GAA4G,CAAC;AAE/G,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC;QACE,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,2BAA2B;QAClC,MAAM,EAAE,wOAAwO;KACjP;IACD;QACE,EAAE,EAAE,qBAAqB;QACzB,KAAK,EAAE,uBAAuB;QAC9B,MAAM,EAAE,2MAA2M;KACpN;IACD;QACE,EAAE,EAAE,uBAAuB;QAC3B,KAAK,EAAE,4BAA4B;QACnC,MAAM,EAAE,gNAAgN;KACzN;IACD;QACE,EAAE,EAAE,mBAAmB;QACvB,KAAK,EAAE,mBAAmB;QAC1B,MAAM,EAAE,yMAAyM;KAClN;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,KAAK,EAAE,uBAAuB;QAC9B,MAAM,EAAE,8OAA8O;KACvP;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAA+B;IACrD,iBAAiB,EAAE;QACjB,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,mDAAmD;QAChE,QAAQ,EAAE;;;;;;;;;;;;;;EAcZ;KACC;IAED,iBAAiB,EAAE;QACjB,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,wCAAwC;QACrD,QAAQ,EAAE;;;;;;;qDAOuC;KAClD;IAED,iBAAiB,EAAE;QACjB,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,yCAAyC;QACtD,QAAQ,EAAE;;;;;gCAKkB;KAC7B;IAED,SAAS,EAAE;QACT,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,kCAAkC;QAC/C,QAAQ,EAAE;;;;;;;;yMAQ2L;KACtM;IAED,WAAW,EAAE;QACX,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,wCAAwC;QACrD,QAAQ,EAAE;;;;;CAKb;KACE;IAED,YAAY,EAAE;QACZ,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,+BAA+B;QAC5C,QAAQ,EAAE;;;;;;;;wDAQ0C;KACrD;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB;IAClB,YAAY;IACZ,eAAe;IACf,SAAS;IACT,QAAQ;IACR,aAAa;IACb,WAAW;IACX,cAAc;CACf,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,SAAiC;IAEjC,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC/B,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACjD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"divi-prompts.js","sourceRoot":"","sources":["../src/divi-prompts.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAiLzE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IAEhE;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;gBA4Bb,WAAW,EAAE,mBAAmB,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;IAmUvE,OAAO,CAAC,cAAc;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IA4BrB,gEAAgE;IAChE,OAAO,CAAC,aAAa;IAUrB;;;;;;OAMG;YACW,UAAU;IA2CxB;;;;;;;;;;;;;;OAcG;YACW,WAAW;IAiJzB;;;;;;;;;OASG;YACW,kBAAkB;IA0GhC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,6BAA6B;IA0BrC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,aAAa;YAuPP,kBAAkB;YA6BlB,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YAyBd,QAAQ;IAmvFtB;;;;;;OAMG;IACH,yEAAyE;IACzE,OAAO,CAAC,mBAAmB,CAAoD;IAC/E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;YAEpC,oBAAoB;YAqDpB,2BAA2B;IAazC;;;;OAIG;YACW,cAAc;IAY5B,OAAO,CAAC,mBAAmB;IAwT3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAe3C;IAEF;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;YAmCpB,cAAc;IAqG5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,eAAe;YAuCT,gBAAgB;IAu2B9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoUzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6UxB,GAAG;CAyCV"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAkQzE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IAEhE;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;gBA4Bb,WAAW,EAAE,mBAAmB,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;IAqUvE,OAAO,CAAC,cAAc;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IA4BrB,gEAAgE;IAChE,OAAO,CAAC,aAAa;IAUrB;;;;;;OAMG;YACW,UAAU;IA2CxB;;;;;;;;;;;;;;OAcG;YACW,WAAW;IAiJzB;;;;;;;;;OASG;YACW,kBAAkB;IAiHhC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,6BAA6B;IA0BrC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,aAAa;YAmQP,kBAAkB;YA6BlB,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YAyBd,QAAQ;IA+vFtB;;;;;;OAMG;IACH,yEAAyE;IACzE,OAAO,CAAC,mBAAmB,CAAoD;IAC/E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;YAEpC,oBAAoB;YAqDpB,2BAA2B;IAazC;;;;OAIG;YACW,cAAc;IAY5B,OAAO,CAAC,mBAAmB;IAwT3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAe3C;IAEF;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;YAmCpB,cAAc;IAqG5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,eAAe;YAuCT,gBAAgB;IAy2B9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwUzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6UxB,GAAG;CAyCV"}
package/dist/server.js CHANGED
@@ -123,6 +123,81 @@ class ToolTimeoutError extends Error {
123
123
  function getMaxToolTimeoutMs() {
124
124
  return Math.max(5000, parseInt(process.env.RESPIRA_MAX_TOOL_TIMEOUT_MS || '120000', 10));
125
125
  }
126
+ /**
127
+ * v7.2.1: hoist plugin-side dropped-styling warnings to the TOP of a build
128
+ * write result so the agent sees them before it inspects anything else.
129
+ *
130
+ * The Divi 5 build path (and any builder write) can drop style settings the
131
+ * builder does not recognise. The plugin reports these under the tool result's
132
+ * `warnings` array (objects shaped { reason: 'unknown_setting', key, type }) or
133
+ * a top-level `dropped_settings` array. This mirrors the existing
134
+ * write_was_noop hoist on update_element: the dashboard shows agents retry the
135
+ * same write blindly when the signal sits deep in the payload. Front-loading a
136
+ * plain-English hint stops the retry loop and tells the agent to pick a
137
+ * supported attribute or drop into a divi/code block instead.
138
+ *
139
+ * Defensive about the exact key shape: handles both the `warnings` array and a
140
+ * possible top-level `dropped_settings` array, and a pre-summarised
141
+ * `styling_dropped` count/string if the plugin sends one.
142
+ */
143
+ function hoistDroppedStylingWarnings(result) {
144
+ if (!result || typeof result !== 'object') {
145
+ return result;
146
+ }
147
+ const dropped = [];
148
+ // Shape 1: a `warnings` array of objects with reason: 'unknown_setting'.
149
+ if (Array.isArray(result.warnings)) {
150
+ for (const w of result.warnings) {
151
+ if (w && typeof w === 'object' && w.reason === 'unknown_setting') {
152
+ dropped.push({ key: w.key, type: w.type, reason: w.reason });
153
+ }
154
+ }
155
+ }
156
+ // Shape 2: a top-level `dropped_settings` array. Entries may be plain strings
157
+ // (the setting key) or objects with key/type.
158
+ if (Array.isArray(result.dropped_settings)) {
159
+ for (const d of result.dropped_settings) {
160
+ if (typeof d === 'string') {
161
+ dropped.push({ key: d });
162
+ }
163
+ else if (d && typeof d === 'object') {
164
+ dropped.push({ key: d.key, type: d.type, reason: d.reason });
165
+ }
166
+ }
167
+ }
168
+ if (dropped.length === 0) {
169
+ // Shape 3: a pre-summarised count/string with no per-setting detail.
170
+ const summary = result.styling_dropped;
171
+ if (typeof summary === 'number' && summary > 0) {
172
+ const hint = `${summary} style settings did not apply. use a supported attribute or a divi/code block. do not retry the same write.`;
173
+ result.dropped_styling_hint = hint;
174
+ const original = typeof result.message === 'string' ? result.message : '';
175
+ result.message = `STYLING DROPPED — ${hint}\n\n${original}`.trim();
176
+ result.agent_must_not_retry = true;
177
+ }
178
+ else if (typeof summary === 'string' && summary.trim() !== '') {
179
+ const hint = `${summary} use a supported attribute or a divi/code block. do not retry the same write.`;
180
+ result.dropped_styling_hint = hint;
181
+ const original = typeof result.message === 'string' ? result.message : '';
182
+ result.message = `STYLING DROPPED — ${hint}\n\n${original}`.trim();
183
+ result.agent_must_not_retry = true;
184
+ }
185
+ return result;
186
+ }
187
+ // Build a compact, readable list grouped by module type where known.
188
+ const parts = dropped.map((d) => {
189
+ const where = d.type ? ` on ${d.type}` : '';
190
+ return d.key ? `${d.key}${where}` : `unknown setting${where}`;
191
+ });
192
+ const list = parts.join(', ');
193
+ const hint = `${dropped.length} style setting${dropped.length === 1 ? '' : 's'} did not apply on these modules: ${list}. use a supported attribute or a divi/code block. do not retry the same write.`;
194
+ const original = typeof result.message === 'string' ? result.message : '';
195
+ result.message = `STYLING DROPPED — ${hint}\n\n${original}`.trim();
196
+ result.dropped_styling_hint = hint;
197
+ result.dropped_styling = dropped;
198
+ result.agent_must_not_retry = true;
199
+ return result;
200
+ }
126
201
  /**
127
202
  * v6.12.0: Tool names that do NOT receive the optional site_id input parameter.
128
203
  * These tools operate on global Respira config or pre-site setup state, so a
@@ -340,6 +415,7 @@ Use respira_get_builder_info first to detect which builder is active. Then use t
340
415
  - HTML-to-Elementor conversion creates native widgets with mapped CSS styles, responsive breakpoints, and optional global color/font creation
341
416
 
342
417
  ### Divi 5 (Full Intelligence)
418
+ - Build real pages with the native modules. divi/heading, divi/text, divi/image, divi/button, and divi/blurb are advertised by default and safe to use. Prefer them over divi/code raw HTML for real content. Reach for divi/code only for genuinely custom markup the native modules cannot express.
343
419
  - Content format: Block comments wrapping JSON module definitions inside <!-- wp:divi/placeholder -->
344
420
  - Every module needs "builderVersion": "5.0.1"
345
421
  - Hierarchy is strict: Section → Row → Column → Module (never skip levels)
@@ -352,6 +428,7 @@ Use respira_get_builder_info first to detect which builder is active. Then use t
352
428
  - Blurb title must be {"text": "..."} object format, not a plain string
353
429
  - 40+ module definitions and 7 page patterns available
354
430
  - 13-point payload validation with 16 actionable error messages
431
+ - If a write comes back with dropped styling (dropped_styling_hint, or a STYLING DROPPED message at the top of the result), the builder did not recognise those settings. Do not retry the same write. Pick a supported attribute or move that bit into a divi/code block, then write again.
355
432
 
356
433
  ### Divi 4 Legacy (Smart Defaults)
357
434
  - Content format: Shortcode-based — [et_pb_section][et_pb_row][et_pb_column][et_pb_text]content[/et_pb_text][/et_pb_column][/et_pb_row][/et_pb_section]
@@ -941,12 +1018,18 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
941
1018
  name: s.name || s.id || 'site',
942
1019
  url: s.url,
943
1020
  }));
1021
+ const hasConfigB64 = Boolean(process.env.RESPIRA_CONFIG_B64);
1022
+ const baseMessage = `Connected ${sites.length} site${sites.length === 1 ? '' : 's'} via the Respira Cowork token. The config was written to ~/.respira/config.json. Restart this Cowork chat (or open a new one) so the MCP server picks up the new sites.`;
1023
+ const message = hasConfigB64
1024
+ ? `${baseMessage} IMPORTANT: your MCP server is currently configured via the RESPIRA_CONFIG_B64 environment variable, which takes precedence over the file on disk. To activate the new site, update RESPIRA_CONFIG_B64 in your agent's MCP server config with the base64-encoded contents of the new ~/.respira/config.json file, then restart the agent.`
1025
+ : baseMessage;
944
1026
  return {
945
1027
  success: true,
946
1028
  sites_count: sites.length,
947
1029
  sites,
948
1030
  config_path: configPath,
949
- message: `Connected ${sites.length} site${sites.length === 1 ? '' : 's'} via the Respira Cowork token. The config was written to ~/.respira/config.json. Restart this Cowork chat (or open a new one) so the MCP server picks up the new sites.`,
1031
+ config_b64_active: hasConfigB64,
1032
+ message,
950
1033
  };
951
1034
  }
952
1035
  /**
@@ -1059,7 +1142,16 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
1059
1142
  // respira_* alias to wordpress_* before dispatch.
1060
1143
  const canonical = this.normalizeToolName(name).canonical;
1061
1144
  if (canonical === 'wordpress_redeem_token') {
1062
- return this.withSiteContext(await this.redeemInstallToken(String(args?.token || '')), args);
1145
+ // redeemInstallToken returns a plain object. Wrap it in the standard
1146
+ // MCP content envelope — the early-exit path bypasses the normal
1147
+ // handleToolCall wrapper, so non-Claude clients (Antigravity, etc.)
1148
+ // would receive a bare object instead of {content:[{type:"text",...}]}
1149
+ // and render it as an empty response.
1150
+ const redeemResult = this.withSiteContext(await this.redeemInstallToken(String(args?.token || '')), args);
1151
+ return {
1152
+ content: [{ type: 'text', text: JSON.stringify(redeemResult) }],
1153
+ structuredContent: redeemResult,
1154
+ };
1063
1155
  }
1064
1156
  if (!this.currentSite) {
1065
1157
  throw new Error('No WordPress site configured');
@@ -1493,7 +1585,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
1493
1585
  },
1494
1586
  {
1495
1587
  name: 'wordpress_create_page_duplicate',
1496
- description: 'Create a duplicate of an existing page for safe editing. IMPORTANT: Always use this before making changes to an original page. After creating a duplicate, edit the duplicate using wordpress_update_page. The user must then approve the duplicate in WordPress admin (Respira → Page Approvals) to replace the original page.',
1588
+ description: 'Create an approval-gated duplicate of a page for staged editing. Optional, NOT required before edits: every write already auto-captures a snapshot, and the write response returns a snapshot_uuid for one-call rollback via respira_restore_snapshot. Use a duplicate only when you want a separate copy the user reviews and approves in WordPress admin (Respira → Page Approvals) before it replaces the original. After creating it, edit the duplicate with wordpress_update_page.',
1497
1589
  inputSchema: {
1498
1590
  type: 'object',
1499
1591
  properties: {
@@ -1543,6 +1635,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
1543
1635
  type: 'object',
1544
1636
  description: 'Post meta data',
1545
1637
  },
1638
+ post_parent: {
1639
+ type: 'number',
1640
+ description: 'Parent page ID. Pass 0 to detach from any parent (make a root page). Accepts parent, parent_id, or post_parent.',
1641
+ },
1546
1642
  edit_target: {
1547
1643
  type: 'string',
1548
1644
  description: 'Choose ask, live, or duplicate when the target is an original page.',
@@ -1639,7 +1735,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
1639
1735
  },
1640
1736
  {
1641
1737
  name: 'wordpress_create_post_duplicate',
1642
- description: 'Create a duplicate of an existing post for safe editing. IMPORTANT: Always use this before making changes to an original post. After creating a duplicate, edit the duplicate using wordpress_update_post. The user must then approve the duplicate in WordPress admin (Respira → Page Approvals) to replace the original post.',
1738
+ description: 'Create an approval-gated duplicate of a post for staged editing. Optional, NOT required before edits: every write already auto-captures a snapshot, and the write response returns a snapshot_uuid for one-call rollback via respira_restore_snapshot. Use a duplicate only when you want a separate copy the user reviews and approves in WordPress admin (Respira → Page Approvals) before it replaces the original. After creating it, edit the duplicate with wordpress_update_post.',
1643
1739
  inputSchema: {
1644
1740
  type: 'object',
1645
1741
  properties: {
@@ -3537,6 +3633,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
3537
3633
  type: 'boolean',
3538
3634
  description: 'When true, auto-create taxonomy terms that do not exist by name. Default false (strict: unknown slug returns 400 and the post is rolled back).',
3539
3635
  },
3636
+ post_parent: {
3637
+ type: 'number',
3638
+ description: 'Parent post ID. Pass 0 for no parent. Useful when creating sub-pages or nested custom post types.',
3639
+ },
3540
3640
  meta: {
3541
3641
  type: 'object',
3542
3642
  description: 'Post meta data (map of meta key to value).',
@@ -3618,6 +3718,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
3618
3718
  type: 'boolean',
3619
3719
  description: 'When true, append to existing taxonomy terms instead of replacing. Default false (replace).',
3620
3720
  },
3721
+ post_parent: {
3722
+ type: 'number',
3723
+ description: 'Parent post ID. Pass 0 to detach. Accepts parent, parent_id, or post_parent.',
3724
+ },
3621
3725
  meta: {
3622
3726
  type: 'object',
3623
3727
  description: 'Post meta data (e.g., { "_et_pb_custom_css": "/* CSS */" })',
@@ -4899,17 +5003,17 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
4899
5003
  case 'wordpress_get_builder_inline_schemas':
4900
5004
  return await client.getBuilderInlineSchemas(args.builder, args.types);
4901
5005
  case 'wordpress_inject_builder_content':
4902
- return {
5006
+ return hoistDroppedStylingWarnings({
4903
5007
  ...(await client.injectBuilderContent(args.builder, args.page_id, args.content, args.divi_version, args.edit_target, args.mode, args.confirm_replace)),
4904
5008
  respira_approvals_url: client.getApprovalsUrl(),
4905
- };
5009
+ });
4906
5010
  case 'wordpress_make_responsive':
4907
5011
  return await client.makeResponsive(args.page_id, args.dry_run || false);
4908
5012
  case 'wordpress_update_module':
4909
- return {
5013
+ return hoistDroppedStylingWarnings({
4910
5014
  ...(await client.updateModule(args.builder, args.page_id, args.module_identifier, args.updates, args.edit_target)),
4911
5015
  respira_approvals_url: client.getApprovalsUrl(),
4912
- };
5016
+ });
4913
5017
  case 'wordpress_validate_security':
4914
5018
  return await client.validateSecurity(args.content);
4915
5019
  case 'wordpress_read_theme_file':
@@ -5337,7 +5441,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
5337
5441
  return await client.callRestV2('POST', `/builder/elements/reorder/${post_id}`, rest);
5338
5442
  }
5339
5443
  case 'wordpress_build_page':
5340
- return await client.callRestV2('POST', '/builder/build', args);
5444
+ return hoistDroppedStylingWarnings(await client.callRestV2('POST', '/builder/build', args));
5341
5445
  case 'wordpress_convert_html_to_builder':
5342
5446
  return await client.callRestV2('POST', '/builder/convert', args);
5343
5447
  case 'wordpress_bulk_pages_operation':
@@ -5596,6 +5700,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
5596
5700
  type: 'string',
5597
5701
  description: 'Target builder (auto-detected if omitted)',
5598
5702
  },
5703
+ post_parent: {
5704
+ type: 'number',
5705
+ description: 'Parent page ID. Pass 0 for no parent (root page). The created page will appear nested under the given parent in Page Attributes.',
5706
+ },
5599
5707
  },
5600
5708
  required: ['title', 'structure'],
5601
5709
  },