import { z } from "zod"; import { withAuth } from "../../auth/index.js"; import { withAuthParams } from "../helpers/authSchema.js"; import { handleToolError } from "../helpers/errorHandler.js"; import { callSchemaEndpoint } from "./_schemaEndpoint.js"; // Tool: update_field // Actualiza props de un campo. Puede renombrar la columna MySQL (newFieldName). // Cambios de 'type' pueden truncar datos; el backend devuelve warnings que // propagamos intactos — son info critica para el LLM. export function registerUpdateFieldTool(server) { server.tool( "update_field", `Update properties of an existing field. Common 'props' keys (not exhaustive; passthrough accepted): label, type, description, isRequired, isUnique, defaultValue, minLength, maxLength, listType, optionsType, optionsText, optionsTablename, optionsValueField, optionsLabelField, optionsQuery, filterField, allowedExtensions, maxUploads, createThumbnails, maxThumbnailWidth, maxThumbnailHeight, fieldWidth, fieldHeight, adminOnly, charsetRule, charset, tipoTags, tipoAtributo. Destructive cases: - 'newFieldName' renames the MySQL column (data preserved, but any hardcoded reference breaks). - Changing 'type' may coerce/truncate existing data (e.g. wysiwyg -> textfield drops HTML). The backend returns 'warnings' in the response — surface them to the user. Table names WITHOUT 'cms_' prefix. MULTITEXT FIELDS — when 'props' touches multitext config: - descriptionjson: JSON STRING (not object) with the array of sub-fields. Each: {id_campo, nombre_campo, tipo} where tipo is '0'(texto)|'1'(tabla)| '3'(fecha)|'4'(color)|'5'(icono). For tipo='1' also include tabla, campo_valor, campo_muestra. ⚠ MUST be JSON-encoded string. Backend rejects objects directly. Example: "descriptionjson":"[{\\"id_campo\\":\\"pregunta\\",\\"nombre_campo\\":\\"Pregunta\\",\\"tipo\\":\\"0\\"}]" LIST FIELDS — when 'props' touches list config: - listType: 'pulldown' | 'radios' | 'pulldownMulti' | 'checkboxes' (NOT 'select'). - optionsType: 'text' | 'table' | 'query'. - optionsText (for optionsType='text'): one option per LINE, separated by '\\n' (real newline). Each line is 'value|Label' or just 'label'. ⚠ Do NOT use commas as the option separator — commas are valid inside a label. Example (correct): "indef|Indefinido\\ntemp|Temporal". - optionsTablename / optionsValueField / optionsLabelField / filterField for optionsType='table'. - optionsQuery for optionsType='query' — column 0 is the value, column 1 the label (positional, 'AS value/label' aliases are ignored).`, withAuthParams({ tableName: z.string().describe("Table name without 'cms_' prefix"), fieldName: z.string().describe("Current field name"), newFieldName: z.string().optional().describe("If set, rename the column. Data is preserved but hardcoded references break."), props: z.object({}).passthrough().describe("Partial props object with the keys to update"), }), { readOnlyHint: false, destructiveHint: true }, withAuth(async ({ tableName, fieldName, newFieldName, props }, _extra) => { try { const body = { tableName, fieldName, props }; if (newFieldName) body.newFieldName = newFieldName; const { mcp } = await callSchemaEndpoint("/api/schema/update-field", body); return mcp; } catch (error) { return handleToolError(error, "update_field", { tableName, fieldName, newFieldName }); } }) ); }