PluginProbe
Extendify / 3.1.5
Extendify v3.1.5
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / workflows / block-selector / tools / block-patching.js

block-patching.js in Extendify 3.1.5, at src/Agent/workflows/block-selector/tools/block-patching.js

87 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { fetchBlockCodeById } from '@agent/lib/block-code';
2 import { applyBlockPatch } from '@agent/lib/block-patch';
3 import { buildNewBlock } from '@agent/lib/insertable-blocks';
4 import { ensureCoreBlocksRegistered } from '@agent/lib/register-blocks';
5 import { swapBlockImage } from '@agent/lib/replace-image';
6 import { useQuickEditStore } from '@quick-edit/state/store';
7 import apiFetch from '@wordpress/api-fetch';
8
9 // clear lists attributes to reset — null in a patch means "no change", not "remove".
10 const buildEdit = async ({ blockId, patch, clear }, source, postId) => {
11 const previousContent = await fetchBlockCodeById(blockId, source, postId);
12 if (!previousContent) return null;
13 const presetSlugs = window.extAgentData?.context?.presetSlugs ?? {};
14 const blockCode = applyBlockPatch(
15 previousContent,
16 patch,
17 clear ?? [],
18 presetSlugs,
19 );
20 if (blockCode === previousContent) return null;
21 return { op: 'edit', blockId, block: blockCode };
22 };
23
24 const buildAdd = ({ anchorId, position, blockType, patch, clear }) => {
25 const presetSlugs = window.extAgentData?.context?.presetSlugs ?? {};
26 const block = buildNewBlock(blockType, patch, clear ?? [], presetSlugs);
27 if (!block) return null;
28 return { op: 'add', anchorId, position, block };
29 };
30
31 // The backend op has no image — the confirm UI attaches it before the tool runs.
32 const buildReplaceImage = async ({ blockId, image }, source, postId) => {
33 if (!image) return null;
34 const previousContent = await fetchBlockCodeById(blockId, source, postId);
35 if (!previousContent) return null;
36 const blockCode = swapBlockImage(previousContent, image);
37 if (!blockCode || blockCode === previousContent) return null;
38 return { op: 'edit', blockId, block: blockCode };
39 };
40
41 const BUILDERS = {
42 edit: buildEdit,
43 'replace-image': buildReplaceImage,
44 delete: ({ blockId }) => ({ op: 'delete', blockId }),
45 move: ({ blockId, targetId, position }) => ({
46 op: 'move',
47 blockId,
48 targetId,
49 position,
50 }),
51 wrap: ({ blockId, container }) => ({ op: 'wrap', blockId, container }),
52 add: buildAdd,
53 };
54
55 export default async (input) => {
56 await ensureCoreBlocksRegistered();
57 const operations = Array.isArray(input?.operations) ? input.operations : [];
58 if (!operations.length) return { refused: true, reason: 'no-block' };
59
60 const { agentBlock } = useQuickEditStore.getState();
61 // Template parts have a separate id space; refusing beats a silent no-op.
62 if (agentBlock?.source?.kind === 'template-part')
63 return { refused: true, reason: 'template-part' };
64
65 const { postId } = window.extAgentData?.context ?? {};
66 const results = await Promise.all(
67 operations.map((operation) =>
68 BUILDERS[operation?.op]?.(operation, agentBlock?.source, postId),
69 ),
70 );
71 const built = results.filter(Boolean);
72 // A no-op build must surface, or the reply claims a change that never happened.
73 const dropped = operations
74 .filter((operation, index) => operation && !results[index])
75 .map(({ blockId }) => ({ blockId, reason: 'no-change' }));
76 if (!built.length) return { refused: true, reason: 'no-op' };
77
78 const { applied = [], refused = [] } = await apiFetch({
79 path: '/extendify/v1/agent/update-blocks',
80 method: 'POST',
81 data: { postId, operations: built },
82 });
83 if (!applied.length) return { refused: true, reason: 'not-applied' };
84 // Not `refused`: Agent.jsx reads any truthy `refused` — even [] — as a refusal.
85 return { ok: true, applied, refusedOperations: [...refused, ...dropped] };
86 };
87