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: update_module_metadata // Edita la metadata de builder.json de un modulo (label, description, // onlyAdminModule, MJMLModule, cmsTables) delegando en // /api/modules/update-metadata. El id/carpeta del modulo NO se puede renombrar // y el endpoint rechaza los modulos generados del layout // (custom-header/footer[-twig]). // Claves editables del builder.json. Se envian solo las que llegan definidas, // de modo que el endpoint hace un merge parcial y no pisa el resto. const EDITABLE_KEYS = ["label", "description", "onlyAdminModule", "MJMLModule", "cmsTables"]; export function registerUpdateModuleMetadataTool(server) { server.tool( "update_module_metadata", `Edit a module's metadata in its builder.json: 'label' (display name shown in the visual builder), 'description' (short help text for editors), 'onlyAdminModule' (true = the module is only visible to admin users in the builder), 'MJMLModule' (true = the module is an email/MJML module), 'cmsTables' (CMS tables whose content this module displays). Use 'cmsTables' when the module renders records from a CMS table — a news list, a product grid, a blog carousel. Declare the tables it reads (e.g. ["noticias"]). The editor then shows a direct link to each of those tables from any page that includes the module, so whoever edits that page can reach the content without hunting for it. A module that only shows its own variables (a banner with a title and an image) needs no cmsTables. Do NOT confuse 'cmsTables' with the 'tables' key of builder.json: 'tables' is where the module's VARIABLE VALUES are stored (always builder_custom) and is managed by the compiler. 'cmsTables' is what content the module DISPLAYS, and is chosen by a human or by you. The module id (its folder name under template/estandar/modulos/) CANNOT be renamed with this tool — there is no rename option at all. Only the fields above change; everything else in builder.json is preserved. At least one of label, description, onlyAdminModule, MJMLModule or cmsTables is required. Fields you omit are left untouched. Passing cmsTables replaces the whole list, so include the tables you want to keep; pass [] to clear it. Not applicable to the generated layout modules (custom-header, custom-footer, custom-header-twig, custom-footer-twig): those are artifacts of the global layout and the request will be rejected — use set_layout_field for them.`, withAuthParams({ module: z.string().min(1).describe("Module id (the folder name under template/estandar/modulos/). Cannot be renamed."), label: z.string().optional().describe("Display name of the module in the visual builder"), description: z.string().optional().describe("Short description shown to editors in the builder"), onlyAdminModule: z.boolean().optional().describe("If true, the module is only visible to admin users in the builder"), MJMLModule: z.boolean().optional().describe("If true, the module is treated as an email (MJML) module"), cmsTables: z.array(z.string()).optional().describe("CMS tables whose records this module displays, e.g. [\"noticias\"]. Replaces the whole list; [] clears it. Only real tables of the project — they become direct links to the CMS."), }), { readOnlyHint: false, destructiveHint: false }, withAuth(async ({ module, label, description, onlyAdminModule, MJMLModule, cmsTables }, _extra) => { try { const provided = { label, description, onlyAdminModule, MJMLModule, cmsTables }; // Validacion temprana: sin ninguna clave editable no tiene // sentido llamar al endpoint. Ojo con los booleanos false — // se comprueba `undefined`, no truthiness. const changedKeys = EDITABLE_KEYS.filter((key) => provided[key] !== undefined); if (changedKeys.length === 0) { return handleToolError( `Nothing to update: provide at least one of ${EDITABLE_KEYS.join(", ")}. The module id cannot be renamed with this tool.`, "update_module_metadata", { module, editableFields: EDITABLE_KEYS } ); } const { projectSlug } = getCurrentProjectInfo(); const body = { project: projectSlug, module }; for (const key of changedKeys) body[key] = provided[key]; const result = await pythonPost("/api/modules/update-metadata", body); if (!result?.success) { return { content: [{ type: "text", text: JSON.stringify({ success: false, error: result?.error || "Could not update module metadata", }), }], isError: true, }; } return { content: [{ type: "text", text: JSON.stringify({ success: true, module: result.module || module, updatedFields: changedKeys, metadata: result.metadata || {}, }, null, 2), }], }; } catch (error) { return handleToolError(error, "update_module_metadata", { module }); } }) ); }