import { z } from "zod"; import { withAuth } from "../../auth/index.js"; import { withAuthParams } from "../helpers/authSchema.js"; import { handleToolError } from "../helpers/errorHandler.js"; import { pythonPost } from "../helpers/pythonServerClient.js"; import { getCurrentProjectInfo } from "../files/helpers.js"; // Tool: set_layout_field // Replaces the content of a global layout field (style or javascript) in the // project's layout.json. Destructive — overwrites the existing content. The // backend enforces a 500KB size limit and returns 400 if exceeded; that error // is propagated via handleToolError. export function registerSetLayoutFieldTool(server) { server.tool( "set_layout_field", `Replace the content of a global layout field. 'style'/'javascript' are simple string fields injected via CDN-like URLs (no regeneration needed). 'header'/'footer' are more complex: saving them triggers a server-side pipeline that regenerates the compiled PHP, Twig module files, and TWIG-compiled templates — changes are visible immediately. Destructive: overwrites existing content. Prefer reading with get_layout_field first.`, withAuthParams({ field: z.enum(["style", "javascript", "header", "footer"]).describe("Which layout field: 'style', 'javascript', 'header' or 'footer'"), content: z.string().describe("Full replacement content. Max 500KB."), }), { readOnlyHint: false, destructiveHint: true }, withAuth(async ({ field, content }, _extra) => { try { const { projectSlug } = getCurrentProjectInfo(); const result = await pythonPost("/api/project/layout-field/save", { project: projectSlug, field, content, }); if (!result?.success) { return { content: [{ type: "text", text: JSON.stringify({ success: false, error: result?.error || "Could not save layout field", }), }], isError: true, }; } return { content: [{ type: "text", text: JSON.stringify({ success: true, field: result.field || field, }, null, 2), }], }; } catch (error) { return handleToolError(error, "set_layout_field", { field, contentLength: typeof content === "string" ? content.length : 0, }); } }) ); }