@respira/wordpress-mcp-server 8.3.5 → 8.3.7
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/CHANGELOG.md +18 -0
- package/README.md +4 -4
- package/dist/__tests__/429299b5-delete-post-empty-envelope.test.d.ts +46 -0
- package/dist/__tests__/429299b5-delete-post-empty-envelope.test.d.ts.map +1 -0
- package/dist/__tests__/429299b5-delete-post-empty-envelope.test.js +360 -0
- package/dist/__tests__/429299b5-delete-post-empty-envelope.test.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +48 -19
- package/dist/server.js.map +1 -1
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/wordpress-client.d.ts +52 -6
- package/dist/wordpress-client.d.ts.map +1 -1
- package/dist/wordpress-client.js +107 -7
- package/dist/wordpress-client.js.map +1 -1
- package/package.json +2 -2
- package/skills/html-to-breakdance/README.md +66 -0
- package/skills/html-to-breakdance/SKILL.md +268 -0
- package/skills/html-to-breakdance/metadata.json +51 -0
package/dist/server.js
CHANGED
|
@@ -2350,7 +2350,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2350
2350
|
},
|
|
2351
2351
|
{
|
|
2352
2352
|
name: 'wordpress_create_theme_builder_template',
|
|
2353
|
-
description: 'Create a Divi global header, footer, or body Theme Builder template,
|
|
2353
|
+
description: 'Create a Divi global header, footer, or body Theme Builder template. WHERE IT APPLIES IS NEVER GUESSED: omit `assignments` and the template is created UNASSIGNED, so nothing on the site renders it until someone assigns it (in Divi > Theme Builder, or by re-sending with assignments). Site-wide happens only when you pass {"all_pages": true}, and if that would fill an empty slot on the site\'s existing default Theme Builder template the first call is refused with respira_tb_default_slot_confirmation_required until you re-send with confirm_live_edit=true. The response states `scope` (unassigned / conditional / site_wide) and returns rollback.snapshot_uuid for restore_snapshot. Pass structure as a Divi 4 shortcode string, or a Divi 5 block/node array. Works on Divi 4 and Divi 5.',
|
|
2354
2354
|
inputSchema: {
|
|
2355
2355
|
type: 'object',
|
|
2356
2356
|
properties: {
|
|
@@ -2358,9 +2358,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2358
2358
|
name: { type: 'string', description: 'Template name.' },
|
|
2359
2359
|
assignments: {
|
|
2360
2360
|
type: 'object',
|
|
2361
|
-
description: 'Where it applies. {"all_pages": true} for site-wide
|
|
2361
|
+
description: 'Where it applies. Omit for unassigned (safe: renders nowhere). {"all_pages": true} for site-wide. {"post_types": ["page"], "excluded_ids": [12, 34]} for conditional. Those three keys are the whole vocabulary; anything else is refused by name. Divi\'s Theme Builder UI also supports taxonomy and post-type archive conditions, author/date/search archives and singular ids, which this tool cannot express yet: set those by hand in Divi > Theme Builder, then fill the layout with wordpress_update_theme_builder_template using the layout_id from wordpress_list_theme_builder_templates.',
|
|
2362
2362
|
},
|
|
2363
2363
|
structure: { description: 'Divi 4 shortcode string, or a Divi 5 block/node array.' },
|
|
2364
|
+
confirm_live_edit: {
|
|
2365
|
+
type: 'boolean',
|
|
2366
|
+
description: 'Only needed for a site-wide assignment that fills an empty slot on the site\'s existing default Theme Builder template. Set true to acknowledge that every page on the site starts rendering this layout immediately (for kind "body", instead of its own content). Tell the user what is about to change before setting it.',
|
|
2367
|
+
},
|
|
2364
2368
|
},
|
|
2365
2369
|
required: ['kind', 'name'],
|
|
2366
2370
|
},
|
|
@@ -2521,7 +2525,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2521
2525
|
},
|
|
2522
2526
|
{
|
|
2523
2527
|
name: 'wordpress_delete_post',
|
|
2524
|
-
description: 'Delete a post. IMPORTANT: By default, this only works on Respira-created duplicates.
|
|
2528
|
+
description: 'Delete a post. IMPORTANT: By default, this only works on Respira-created duplicates. To delete an original: pass `force=true` AND `confirm_live_edit=true`. The "Allow Direct Editing" setting in Respira must also be enabled (disabled by default for safety).\n\nApproval flow: destructive — the FIRST call returns `code: respira_approval_required` with `data.approval_request.approval_token`, and deletes nothing. Pass that exact token back via the `approval_token` param on the next call to complete the delete. Deleting a Respira-created duplicate still takes both calls; the approval gate runs before the duplicate check.\n\nFixed in 8.3.7 (ticket 429299b5): this tool used to discard the response body, so the approval token, the refusal reason and the success flag were all invisible and every call looked like an empty response. It now always returns the site\'s answer.',
|
|
2525
2529
|
inputSchema: {
|
|
2526
2530
|
type: 'object',
|
|
2527
2531
|
properties: {
|
|
@@ -2531,11 +2535,15 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2531
2535
|
},
|
|
2532
2536
|
force: {
|
|
2533
2537
|
type: 'boolean',
|
|
2534
|
-
description: 'Force delete even if not a duplicate',
|
|
2538
|
+
description: 'Force delete even if not a duplicate. Requires confirm_live_edit=true.',
|
|
2539
|
+
},
|
|
2540
|
+
confirm_live_edit: {
|
|
2541
|
+
type: 'boolean',
|
|
2542
|
+
description: 'Operator confirmation that a force-delete of an original post is intended. The plugin has always required this alongside force=true; before 8.3.7 the delete_post schema did not expose it, and the error asking for it was thrown away with the rest of the response body.',
|
|
2535
2543
|
},
|
|
2536
2544
|
approval_token: {
|
|
2537
2545
|
type: 'string',
|
|
2538
|
-
description: '
|
|
2546
|
+
description: 'Approval token from a prior respira_approval_required response (data.approval_request.approval_token). Omit on the first call; re-call with this parameter set to that exact token to confirm and execute. The token is bound to this tool and expires after 10 minutes.',
|
|
2539
2547
|
},
|
|
2540
2548
|
},
|
|
2541
2549
|
required: ['id'],
|
|
@@ -3514,7 +3522,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
3514
3522
|
properties: {
|
|
3515
3523
|
identifier: {
|
|
3516
3524
|
type: 'object',
|
|
3517
|
-
description: 'Element identifier. Provide exactly one of id / admin_label / path / type. match_content disambiguates duplicates of the same type.',
|
|
3525
|
+
description: 'Element identifier. Provide exactly one of id / admin_label / path / type. match_content disambiguates duplicates of the same type. `path` accepts both dialects: the index form respira_find_element emits ("1.0.1") and the key-interleaved form ("1.children.0.children.1"). They name the same element.',
|
|
3518
3526
|
properties: {
|
|
3519
3527
|
id: { type: 'string', description: 'Builder element ID (Divi 5 _nodeId, Elementor element id, Bricks id, etc).' },
|
|
3520
3528
|
admin_label: { type: 'string', description: 'Admin label / navigator label.' },
|
|
@@ -7576,6 +7584,8 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
7576
7584
|
name: args.name,
|
|
7577
7585
|
assignments: args.assignments ?? null,
|
|
7578
7586
|
structure: args.structure ?? null,
|
|
7587
|
+
// Same three spellings the plugin normalises for the update tool.
|
|
7588
|
+
confirm_live_edit: args.confirm_live_edit ?? args.confirmLiveEdit ?? args.confirmed,
|
|
7579
7589
|
});
|
|
7580
7590
|
case 'wordpress_update_theme_builder_template':
|
|
7581
7591
|
return await client.updateThemeBuilderTemplate({
|
|
@@ -7616,7 +7626,11 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
7616
7626
|
};
|
|
7617
7627
|
}
|
|
7618
7628
|
case 'wordpress_delete_post':
|
|
7619
|
-
|
|
7629
|
+
// Ticket 429299b5: `deletePost` used to be `Promise<void>`, so this
|
|
7630
|
+
// `return` handed `undefined` to withSiteContext and the agent got a
|
|
7631
|
+
// bare `{"site":{...}}` — approval token, refusal reason and success
|
|
7632
|
+
// flag all thrown away. The client now returns the plugin body.
|
|
7633
|
+
return await client.deletePost(args.id, args.force, args.approval_token, args.confirm_live_edit);
|
|
7620
7634
|
case 'wordpress_list_media':
|
|
7621
7635
|
return await client.listMedia(args);
|
|
7622
7636
|
case 'wordpress_upload_media': {
|
|
@@ -7996,7 +8010,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
7996
8010
|
case 'wordpress_update_media_batch':
|
|
7997
8011
|
return await client.updateMediaBatch(args.items);
|
|
7998
8012
|
case 'wordpress_delete_media':
|
|
7999
|
-
|
|
8013
|
+
// Ticket 429299b5 (second defect): this line used to be
|
|
8014
|
+
// `client.deleteMedia(args.id)`. The schema advertises `force` and
|
|
8015
|
+
// `approval_token`, the client method forwards both, but the token
|
|
8016
|
+
// died here — so the plugin saw a fresh first call every time and
|
|
8017
|
+
// minted a new token forever. Ticket 927aa7ed fixed the client method
|
|
8018
|
+
// and tested the client method; the dispatcher was the broken link.
|
|
8019
|
+
return await client.deleteMedia(args.id, args.force, args.approval_token);
|
|
8000
8020
|
// Menu Management
|
|
8001
8021
|
case 'wordpress_list_menus':
|
|
8002
8022
|
return await client.listMenus();
|
|
@@ -8580,13 +8600,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8580
8600
|
post_id: { type: 'number', description: 'Page/post ID' },
|
|
8581
8601
|
identifier_type: {
|
|
8582
8602
|
type: 'string',
|
|
8583
|
-
description: 'How to find the element',
|
|
8584
|
-
enum: ['id', 'type', 'class', 'content', 'uncode_shortcode_id'],
|
|
8603
|
+
description: 'How to find the element. "path" takes an index path such as "1.0.1" (the `path_string` this tool returns) and names exactly one element.',
|
|
8604
|
+
enum: ['id', 'type', 'admin_label', 'class', 'content', 'text', 'path', 'uncode_shortcode_id'],
|
|
8585
8605
|
},
|
|
8586
8606
|
identifier_value: { type: 'string', description: 'Value to search for' },
|
|
8587
8607
|
match_content: {
|
|
8588
8608
|
type: 'string',
|
|
8589
|
-
description: 'Optional text
|
|
8609
|
+
description: 'Optional text to narrow the result set to elements whose own text or attribute values contain it. Works for every identifier_type. It separates siblings; it cannot separate an element from an ancestor that contains it, so use identifier_type "path" when you need certainty.',
|
|
8590
8610
|
},
|
|
8591
8611
|
},
|
|
8592
8612
|
required: ['post_id', 'identifier_type', 'identifier_value'],
|
|
@@ -8602,7 +8622,8 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8602
8622
|
post_id: { type: 'number', description: 'Page/post ID' },
|
|
8603
8623
|
identifier_type: {
|
|
8604
8624
|
type: 'string',
|
|
8605
|
-
enum: ['id', 'type', 'class', 'content', 'uncode_shortcode_id'],
|
|
8625
|
+
enum: ['id', 'type', 'admin_label', 'class', 'content', 'text', 'path', 'uncode_shortcode_id'],
|
|
8626
|
+
description: 'How to locate the element. Accepts everything respira_find_element accepts, so any identifier it returns works here as-is. "path" takes a find_element `path_string` (e.g. "1.0.1"), names exactly one element, and is the reliable answer to a 422 respira_ambiguous_target.',
|
|
8606
8627
|
},
|
|
8607
8628
|
identifier_value: { type: 'string', description: 'Value to match' },
|
|
8608
8629
|
updates: {
|
|
@@ -8616,6 +8637,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8616
8637
|
},
|
|
8617
8638
|
},
|
|
8618
8639
|
},
|
|
8640
|
+
match_content: {
|
|
8641
|
+
type: 'string',
|
|
8642
|
+
description: 'Narrows a set of elements sharing identifier_type/identifier_value down to the ones whose own text or attribute values contain this string (e.g. two buttons of the same type, one saying "Buy"). It separates siblings; it cannot separate an element from an ancestor, since an ancestor contains its children\'s text. For that case use identifier_type "path".',
|
|
8643
|
+
},
|
|
8619
8644
|
edit_target: {
|
|
8620
8645
|
type: 'string',
|
|
8621
8646
|
enum: ['live', 'duplicate'],
|
|
@@ -8633,7 +8658,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8633
8658
|
on_ambiguous_match: {
|
|
8634
8659
|
type: 'string',
|
|
8635
8660
|
enum: ['reject', 'first'],
|
|
8636
|
-
description: 'What to do when identifier_type/identifier_value match more than one element and match_content does not narrow it to exactly one. Default "reject" refuses the write with a 422 respira_ambiguous_target error and a candidate list, because guessing has silently edited the wrong element before.
|
|
8661
|
+
description: 'What to do when identifier_type/identifier_value match more than one element and match_content does not narrow it to exactly one. Default "reject" refuses the write with a 422 respira_ambiguous_target error and a candidate list, because guessing has silently edited the wrong element before. "first" accepts whichever element respira_find_element resolves for this identifier. It does NOT mean the outermost match: for content and text lookups the resolver deliberately returns the DEEPEST (innermost) match, so the edit lands on the leaf module, not the section wrapping it; for other identifier types it is the first in document order. The 422 also returns `candidate_paths` — re-sending with identifier_type "path" and one of those values picks an exact element instead of accepting a default.',
|
|
8637
8662
|
},
|
|
8638
8663
|
},
|
|
8639
8664
|
required: ['post_id', 'identifier_type', 'identifier_value', 'updates'],
|
|
@@ -8728,13 +8753,17 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8728
8753
|
post_id: { type: 'number', description: 'Page/post ID' },
|
|
8729
8754
|
identifier_type: {
|
|
8730
8755
|
type: 'string',
|
|
8731
|
-
enum: ['id', 'css_class', 'text', 'widget_type', 'global_id'],
|
|
8732
|
-
description: 'How to locate the element: "id" (element ID), "css_class" (CSS class name), "text" (visible text content), "widget_type" (widget/module type),
|
|
8756
|
+
enum: ['id', 'css_class', 'text', 'widget_type', 'global_id', 'type', 'admin_label', 'content', 'class', 'path'],
|
|
8757
|
+
description: 'How to locate the element: "id" (element ID), "css_class"/"class" (CSS class name), "text"/"content" (visible text content), "widget_type"/"type" (widget/module type), "admin_label", "global_id" (cross-page global element ID), or "path" (the `path_string` respira_find_element returns, e.g. "1.0.1", which names exactly one element and is the reliable answer to a 422 respira_ambiguous_target).',
|
|
8733
8758
|
},
|
|
8734
8759
|
identifier_value: {
|
|
8735
8760
|
type: 'string',
|
|
8736
8761
|
description: 'Value matching the chosen identifier_type (e.g. the element ID, the class name, the text to match).',
|
|
8737
8762
|
},
|
|
8763
|
+
match_content: {
|
|
8764
|
+
type: 'string',
|
|
8765
|
+
description: 'Narrows a set of elements sharing identifier_type/identifier_value down to the ones whose own text or attribute values contain this string. It separates siblings; it cannot separate an element from an ancestor that contains it. For that case use identifier_type "path".',
|
|
8766
|
+
},
|
|
8738
8767
|
edit_target: {
|
|
8739
8768
|
type: 'string',
|
|
8740
8769
|
enum: ['live', 'duplicate'],
|
|
@@ -8752,7 +8781,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8752
8781
|
on_ambiguous_match: {
|
|
8753
8782
|
type: 'string',
|
|
8754
8783
|
enum: ['reject', 'first'],
|
|
8755
|
-
description: 'What to do when identifier_type/identifier_value match more than one element and match_content does not narrow it to exactly one. Default "reject" refuses the removal with a 422 respira_ambiguous_target error and a candidate list, because guessing has silently deleted the wrong element before.
|
|
8784
|
+
description: 'What to do when identifier_type/identifier_value match more than one element and match_content does not narrow it to exactly one. Default "reject" refuses the removal with a 422 respira_ambiguous_target error and a candidate list, because guessing has silently deleted the wrong element before. "first" removes whichever element respira_find_element resolves for this identifier. It does NOT mean the outermost match: for content and text lookups the resolver deliberately returns the DEEPEST (innermost) match, so the removal takes the leaf module, not the section wrapping it; for other identifier types it is the first in document order. The 422 also returns `candidate_paths` — re-sending with identifier_type "path" and one of those values picks an exact element instead of accepting a default.',
|
|
8756
8785
|
},
|
|
8757
8786
|
},
|
|
8758
8787
|
required: ['post_id', 'identifier_type', 'identifier_value'],
|
|
@@ -8886,7 +8915,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8886
8915
|
},
|
|
8887
8916
|
{
|
|
8888
8917
|
name: 'wordpress_bulk_pages_operation',
|
|
8889
|
-
description: 'Apply an operation across up to 100 pages. Supports strip_inline_styles, find_and_replace, and custom operations. Each page gets a snapshot for rollback.
|
|
8918
|
+
description: 'Apply an operation across up to 100 pages. Supports strip_inline_styles, find_and_replace, and custom operations. Each page gets a snapshot for rollback.\n\nRate limit: 20 write runs per hour per API key. Dry runs (`options.dry_run: true`) are NOT counted, so preview freely. find_and_replace also accepts an ARRAY of needles in one call — `find: ["a","b"], replace: ["x","y"]` (paired) or `find: ["a","b"], replace: "x"` (one replacement for all) — so a batch of rewrites costs one run instead of one each.\n\nApproval flow: destructive — the first call may return `code: respira_approval_required` with `data.approval_request.approval_token`. Pass that token back via the `approval_token` param on the next call to complete the operation.',
|
|
8890
8919
|
inputSchema: {
|
|
8891
8920
|
type: 'object',
|
|
8892
8921
|
properties: {
|
|
@@ -8897,11 +8926,11 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
8897
8926
|
},
|
|
8898
8927
|
operation: {
|
|
8899
8928
|
type: 'object',
|
|
8900
|
-
description: 'Operation to apply: {type: "strip_inline_styles"|"find_and_replace"|"custom", options: {...}}',
|
|
8929
|
+
description: 'Operation to apply: {type: "strip_inline_styles"|"find_and_replace"|"custom", options: {...}}. For find_and_replace: options.find is a string OR an array of strings; options.replace is a string (applied to every needle) OR an array of the same length as find; options.regex treats every find entry as a pattern. A mismatched pair, an object, or a non-string entry is refused with a 400 before any page is touched.',
|
|
8901
8930
|
},
|
|
8902
8931
|
options: {
|
|
8903
8932
|
type: 'object',
|
|
8904
|
-
description: 'Execution options: {dry_run: boolean}',
|
|
8933
|
+
description: 'Execution options: {dry_run: boolean}. dry_run previews every page without writing, without taking a snapshot, and without spending a rate-limited run.',
|
|
8905
8934
|
},
|
|
8906
8935
|
approval_token: {
|
|
8907
8936
|
type: 'string',
|