Initial commit
This commit is contained in:
85
mcp-server/tools/orchestrator/workflows/createModule.js
Normal file
85
mcp-server/tools/orchestrator/workflows/createModule.js
Normal file
@@ -0,0 +1,85 @@
|
||||
export const createModuleWorkflow = {
|
||||
id: "create_module",
|
||||
name: "Create Module",
|
||||
description: "Design and create an HTML module by writing project files directly, then compile it in the CMS.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Understand the design",
|
||||
description: "Clarify with user: what does the module show? Is it a hero, grid, list, slider, CTA, form?",
|
||||
tool: null,
|
||||
critical: "Get clear requirements before writing code. Ask about: layout, colors, responsive behavior, editable fields."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Review project styling and patterns",
|
||||
description: "Use the saved project styles and nearby modules as reference before writing code.",
|
||||
tool: "save_project_styles",
|
||||
critical: "Align typography, spacing, colors, and component patterns with the existing project."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "Create the module files",
|
||||
description: "Write index-base.tpl, style.css, script.js, and optional hook.php directly in the module folder.",
|
||||
tool: "acai-write",
|
||||
critical: "Use project-relative paths. Create complete files. Keep variable names lowercase, descriptive, and stable."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Refine targeted blocks if needed",
|
||||
description: "Use incremental replacements for small fixes instead of rewriting whole files.",
|
||||
tool: "acai-line-replace",
|
||||
critical: "Prefer block edits for existing files to reduce token usage and avoid accidental rewrites."
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
action: "Compile the module",
|
||||
description: "Compile after editing index-base.tpl so the CMS syncs index.tpl and builder metadata.",
|
||||
tool: "compile_module",
|
||||
critical: "This is mandatory after every index-base.tpl change."
|
||||
},
|
||||
{
|
||||
step: 6,
|
||||
action: "Set example data",
|
||||
description: "Set example/static data for module preview. MUST call get_module first to discover the variable schema.",
|
||||
tool: "set_module_example_data",
|
||||
critical: "Call get_module first to get ALL variable names. Then fill EVERY variable with realistic example data. Missing variables = blank preview."
|
||||
},
|
||||
{
|
||||
step: 7,
|
||||
action: "Check module rendering",
|
||||
description: "Test the module with specific variable values to verify it renders correctly.",
|
||||
tool: "check_module",
|
||||
critical: "Test with realistic values. Check for Twig syntax errors, broken images, layout issues."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
builder_vars: "data-field-type attribute on elements creates editable fields. Types: textfield (single line text), headfield (heading), textbox (multiline), wysiwyg (rich HTML), link (URL), upload (single image), uploadBackground (background image), uploadMulti (gallery), list (dropdown options), multiv2 (repeatable block).",
|
||||
component_syntax: "c-if='varname' shows/hides element based on variable. c-for='item in items' loops over array. c-hidden='true' makes element invisible (for config vars). c-else after c-if for alternative content.",
|
||||
module_structure: "Create index-base.tpl, style.css, script.js, and optional hook.php in the module directory. Compile to generate builder.json and the public templates.",
|
||||
css_conventions: "Use TailwindCSS by default. For custom CSS: BEM naming with kebab-case. Root class should match module name. Avoid !important.",
|
||||
upload_in_modules: "Upload fields are arrays. Single image: {{ varname[0].urlPath | imagec(WIDTH) }}. Background: style=\"background-image: url('{{ varname[0].urlPath | imagec(1920) }}')\". Gallery: {% for img in varname %}{{ img.urlPath }}{% endfor %}."
|
||||
},
|
||||
rules: [
|
||||
"Variable names: lowercase, no spaces, no accents, no special characters",
|
||||
"Labels must be UNIQUE — duplicate labels create shared fields",
|
||||
"Upload fields are ALWAYS arrays — access with [0].urlPath",
|
||||
"Use ONLY Twig FILTERS (pipe syntax), not Twig functions",
|
||||
"c-if='varname' for conditional rendering of optional fields",
|
||||
"c-hidden='true' for configuration variables not shown to end user",
|
||||
"data-field-width on upload elements to set image optimization width",
|
||||
"For multiv2 (repeatable): parent element needs data-field-type='multiv2', children are the repeated fields"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT use duplicate labels — they create shared/linked fields",
|
||||
"DO NOT forget to set example data — the module will appear blank in the editor",
|
||||
"DO NOT use Twig functions (range, random, etc.) — only filters work",
|
||||
"DO NOT access upload vars as strings — always use varname[0].urlPath (array)",
|
||||
"DO NOT mix React/Vue syntax — use Twig for templating, vanilla JS for interactivity"
|
||||
],
|
||||
resources: [
|
||||
"acai://resources/guia-builder-vars",
|
||||
"acai://resources/guia-atributos-acai",
|
||||
"acai://resources/guia-programacion-acai"
|
||||
]
|
||||
};
|
||||
110
mcp-server/tools/orchestrator/workflows/createSection.js
Normal file
110
mcp-server/tools/orchestrator/workflows/createSection.js
Normal file
@@ -0,0 +1,110 @@
|
||||
export const createSectionWorkflow = {
|
||||
id: "create_section",
|
||||
name: "Create New Section",
|
||||
description: "Full workflow for creating a new website section: table + fields + module + template + content.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Understand requirements",
|
||||
description: "Clarify with user: section name, type (multi/single/category), fields needed, whether it needs URL (enlace), SEO meta tags.",
|
||||
tool: null,
|
||||
critical: "Ask before acting. Multi = multiple records (blog, products). Single = one record (about page). Category = grouping for other sections."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Check existing tables",
|
||||
description: "List current tables to avoid naming conflicts and understand existing structure.",
|
||||
tool: "list_tables",
|
||||
critical: "Table names must be unique. Check if a similar section already exists."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "Create the table",
|
||||
description: "Create the database table with correct type and configuration.",
|
||||
tool: "create_table",
|
||||
critical: "type must be: 'multi' (multiple records), 'single' (one record), 'category' (grouping), or 'separador' (menu separator). Set enlace=true if records need their own URL page."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Add fields to the table",
|
||||
description: "Create all necessary fields with correct types and configuration.",
|
||||
tool: "edit_table_field",
|
||||
critical: "Can batch multiple fields in one call. Field types: textfield, textbox, wysiwyg, date, checkbox, list, upload, multitext, codigo, separator."
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
action: "Verify table schema",
|
||||
description: "Get the complete schema to confirm all fields were created correctly.",
|
||||
tool: "get_table_schema",
|
||||
critical: "Verify all fields exist with correct types before proceeding to module creation."
|
||||
},
|
||||
{
|
||||
step: 6,
|
||||
action: "Design and create the listing module",
|
||||
description: "Create an HTML module that displays a list/grid of records from this section.",
|
||||
tool: "save_module",
|
||||
critical: "Use Twig syntax. Access records with the 'get' filter. Primary key is 'num' not 'id'. Upload fields are ALWAYS arrays: use record.field[0].urlPath | imagec(width)."
|
||||
},
|
||||
{
|
||||
step: 7,
|
||||
action: "Set module example data",
|
||||
description: "Set example/static data for module preview. MUST call get_module first to discover ALL variables.",
|
||||
tool: "set_module_example_data",
|
||||
critical: "Every builder variable must have example data. Missing variables cause blank previews."
|
||||
},
|
||||
{
|
||||
step: 8,
|
||||
action: "Add sample content",
|
||||
description: "Create 2-3 sample records with realistic content and images. If table has enlace=true, include the 'enlace' field with a URL slug.",
|
||||
tool: "create_or_update_record",
|
||||
critical: "Date format: YYYY-MM-DD HH:mm:ss. Checkbox: 1 or 0. Upload fields: use upload_record_image separately. For sections with enlace, creating records first ensures directory structure is ready."
|
||||
},
|
||||
{
|
||||
step: 9,
|
||||
action: "Create detail template (if enlace=true)",
|
||||
description: "If the section has enlace enabled, create the detail page template that shows when navigating to a record's URL.",
|
||||
tool: "save_general_section",
|
||||
critical: "Use 'thisrecord' variable to access the current record. Same Twig rules apply. Note: save_general_section will auto-initialize the directory if needed."
|
||||
},
|
||||
{
|
||||
step: 10,
|
||||
action: "Verify the result",
|
||||
description: "Check module rendering with actual variable values.",
|
||||
tool: "check_module",
|
||||
critical: "Test with actual variable values to ensure no rendering errors."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
twig_filters: "Use 'get' filter for DB queries: {% set items = 'tablename' | get('WHERE active=1', 'ORDER BY num DESC', 10) %}. Use 'imagec' for image resize: {{ path | imagec(400) }}. Use 'module' to include other modules: {{ 'modulename' | module(vars) }}.",
|
||||
field_types: "textfield (single line), textbox (multiline), wysiwyg (rich HTML), date (YYYY-MM-DD), checkbox (0/1), list (dropdown/radio/checkbox), upload (files/images), multitext (key-value pairs), codigo (code editor), separator (visual divider).",
|
||||
list_field_config: "Static options: optionsType='text', optionsText='value1|Label 1\\nvalue2|Label 2'. Table relation: optionsType='table', optionsTablename='tablename', optionsValueField='num', optionsLabelField='name'. SQL: optionsType='query', optionsText='SELECT num,name FROM cms_tablename'.",
|
||||
builder_vars: "data-field-type attribute on HTML elements creates editable fields. Types: textfield, headfield, textbox, wysiwyg, link, upload, uploadBackground, uploadMulti, list, multiv2. Variable names derived from labels (lowercase, no spaces/accents).",
|
||||
upload_rules: "Upload fields ALWAYS return arrays. Single image: {{ record.imagen[0].urlPath | imagec(WIDTH) }}. Gallery loop: {% for img in record.galeria %}{{ img.urlPath }}{% endfor %}. Check existence: {% if record.imagen and record.imagen|length > 0 %}."
|
||||
},
|
||||
rules: [
|
||||
"Table names WITHOUT 'cms_' prefix in all tool calls",
|
||||
"Primary key is ALWAYS 'num', never 'id'",
|
||||
"Upload fields are ALWAYS arrays of objects with urlPath property",
|
||||
"Use ONLY Twig FILTERS (pipe syntax), not Twig functions",
|
||||
"Date format: YYYY-MM-DD HH:mm:ss",
|
||||
"Checkbox values: 1 or 0 (number, not boolean)",
|
||||
"Enlace (URL slug): auto-formatted to /path/ with slashes",
|
||||
"Variable names in modules: lowercase, no spaces, no accents, no special chars",
|
||||
"c-if='varname' for conditional rendering, c-hidden='true' for invisible config vars",
|
||||
"When using 'get' filter: SQL string syntax, NOT objects. Example: 'WHERE num > 5'"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT use record.imagen.urlPath — it's record.imagen[0].urlPath (array!)",
|
||||
"DO NOT use 'id' as primary key — Acai uses 'num'",
|
||||
"DO NOT forget to set example data after creating a module — it will look blank",
|
||||
"DO NOT create a detail template if enlace is false — there's no URL to navigate to",
|
||||
"DO NOT use Twig functions like range() — only filters (pipe syntax) are available",
|
||||
"For best results with new enlace sections, create records BEFORE calling save_general_section to ensure directory structure exists"
|
||||
],
|
||||
resources: [
|
||||
"acai://resources/guia-builder-vars",
|
||||
"acai://resources/guia-twig-filters",
|
||||
"acai://resources/guia-atributos-acai",
|
||||
"acai://resources/guia-registros"
|
||||
]
|
||||
};
|
||||
64
mcp-server/tools/orchestrator/workflows/editModule.js
Normal file
64
mcp-server/tools/orchestrator/workflows/editModule.js
Normal file
@@ -0,0 +1,64 @@
|
||||
export const editModuleWorkflow = {
|
||||
id: "edit_module",
|
||||
name: "Edit Module",
|
||||
description: "Modify an existing HTML module: update code, styles, variables, or structure.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Get current module code",
|
||||
description: "Read the current HTML, CSS, JS, and PHP of the module.",
|
||||
tool: "get_module",
|
||||
critical: "ALWAYS read the current code before modifying. Understand existing variables, structure, and styling."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Check where it's used",
|
||||
description: "Find all pages and records using this module to understand impact.",
|
||||
tool: "check_module_usage",
|
||||
critical: "Know the blast radius of your changes — how many live pages will be affected."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "Make changes",
|
||||
description: "Update the module code with the required modifications.",
|
||||
tool: "save_module",
|
||||
critical: "Pass the module 'id' parameter to update (not create). save_module REPLACES the entire module — include ALL html/css/js, not just the changed parts."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Update example data if needed",
|
||||
description: "If you added or renamed variables, update the example data to match.",
|
||||
tool: "set_module_example_data",
|
||||
critical: "Call get_module first to discover new variable names. Fill ALL variables, including new ones."
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
action: "Verify rendering",
|
||||
description: "Test the modified module with variable values to confirm changes work.",
|
||||
tool: "check_module",
|
||||
critical: "Test with realistic values. Compare rendering before and after changes."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
builder_vars: "data-field-type attribute on elements creates editable fields. Types: textfield, headfield, textbox, wysiwyg, link, upload, uploadBackground, uploadMulti, list, multiv2.",
|
||||
component_syntax: "c-if='varname' shows/hides element. c-for='item in items' loops. c-hidden='true' invisible config. c-else after c-if.",
|
||||
save_behavior: "save_module with 'id' parameter = UPDATE. Without 'id' = CREATE new. The tool replaces the ENTIRE module code, not a diff."
|
||||
},
|
||||
rules: [
|
||||
"ALWAYS include the full html/css/js when saving — save_module replaces everything",
|
||||
"Pass the 'id' parameter to update an existing module",
|
||||
"Variable names: lowercase, no spaces, no accents",
|
||||
"Labels must be UNIQUE across the module",
|
||||
"Upload fields are ALWAYS arrays — access with [0].urlPath"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT remove existing variables without checking usage — they may have data on live pages",
|
||||
"DO NOT rename variables — it breaks existing data bindings. Add new ones instead if needed",
|
||||
"DO NOT save partial code (just HTML without CSS) — save_module replaces ALL sections",
|
||||
"DO NOT forget to update example data when adding new variables"
|
||||
],
|
||||
resources: [
|
||||
"acai://resources/guia-builder-vars",
|
||||
"acai://resources/guia-atributos-acai"
|
||||
]
|
||||
};
|
||||
48
mcp-server/tools/orchestrator/workflows/exploreSite.js
Normal file
48
mcp-server/tools/orchestrator/workflows/exploreSite.js
Normal file
@@ -0,0 +1,48 @@
|
||||
export const exploreSiteWorkflow = {
|
||||
id: "explore_site",
|
||||
name: "Explore Site",
|
||||
description: "Get an overview of the current Acai site: sections, modules, content.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "List all tables/sections",
|
||||
description: "Get the complete site structure with all sections, their types, and menu order.",
|
||||
tool: "list_tables",
|
||||
critical: "This returns the site's skeleton: all sections with type (multi/single/category/separador), menu name, and order."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Inspect sections of interest",
|
||||
description: "Get the full schema of specific sections to understand their fields and configuration.",
|
||||
tool: "get_table_schema",
|
||||
critical: "Look at field types, required fields, list configurations, and upload fields."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "List all modules",
|
||||
description: "See all available design components/modules.",
|
||||
tool: "list_modules",
|
||||
critical: "Modules are the visual building blocks. Each has HTML, CSS, JS, and builder variables."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Sample content",
|
||||
description: "Preview records in key sections to understand what content exists.",
|
||||
tool: "list_table_records",
|
||||
critical: "Use limit=5 to get a representative sample without overwhelming the response."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
orientation: "list_tables returns all sections with their type: 'multi' (multiple records like blog/products), 'single' (one record like about page), 'category' (grouping for other sections), 'separador' (menu separator). This is the site's architecture.",
|
||||
modules_overview: "list_modules shows all components. Use get_module on specific ones to see their HTML/CSS/JS code and builder variables."
|
||||
},
|
||||
rules: [
|
||||
"Table names WITHOUT 'cms_' prefix",
|
||||
"Primary key is 'num', never 'id'"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT modify anything during exploration — this workflow is read-only",
|
||||
"DO NOT assume field names — always check the schema first"
|
||||
],
|
||||
resources: []
|
||||
};
|
||||
44
mcp-server/tools/orchestrator/workflows/index.js
Normal file
44
mcp-server/tools/orchestrator/workflows/index.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { createSectionWorkflow } from "./createSection.js";
|
||||
import { populateContentWorkflow } from "./populateContent.js";
|
||||
import { createModuleWorkflow } from "./createModule.js";
|
||||
import { editModuleWorkflow } from "./editModule.js";
|
||||
import { manageRecordsWorkflow } from "./manageRecords.js";
|
||||
import { manageMediaWorkflow } from "./manageMedia.js";
|
||||
import { seoSetupWorkflow } from "./seoSetup.js";
|
||||
import { exploreSiteWorkflow } from "./exploreSite.js";
|
||||
|
||||
/**
|
||||
* Registry of all available workflows.
|
||||
* Keyed by workflow ID for fast lookup.
|
||||
*/
|
||||
export const WORKFLOWS = {
|
||||
create_section: createSectionWorkflow,
|
||||
populate_content: populateContentWorkflow,
|
||||
create_module: createModuleWorkflow,
|
||||
edit_module: editModuleWorkflow,
|
||||
manage_records: manageRecordsWorkflow,
|
||||
manage_media: manageMediaWorkflow,
|
||||
seo_setup: seoSetupWorkflow,
|
||||
explore_site: exploreSiteWorkflow,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a workflow by ID.
|
||||
* @param {string} id - Workflow identifier
|
||||
* @returns {object|null} The workflow definition or null
|
||||
*/
|
||||
export function getWorkflow(id) {
|
||||
return WORKFLOWS[id] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a summary list of all available workflows (for help/listing).
|
||||
*/
|
||||
export function listWorkflows() {
|
||||
return Object.values(WORKFLOWS).map((w) => ({
|
||||
id: w.id,
|
||||
name: w.name,
|
||||
description: w.description,
|
||||
totalSteps: w.steps.length,
|
||||
}));
|
||||
}
|
||||
53
mcp-server/tools/orchestrator/workflows/manageMedia.js
Normal file
53
mcp-server/tools/orchestrator/workflows/manageMedia.js
Normal file
@@ -0,0 +1,53 @@
|
||||
export const manageMediaWorkflow = {
|
||||
id: "manage_media",
|
||||
name: "Manage Media",
|
||||
description: "Image upload, generation, replacement, and management.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Prepare or generate images",
|
||||
description: "Use an existing image URL/asset or generate an AI image for the content.",
|
||||
tool: "generate_image",
|
||||
critical: "generate_image uses Nano Banana AI. Existing remote image URLs can also be passed directly to upload tools."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Upload to record",
|
||||
description: "Attach images to a record's upload field.",
|
||||
tool: "upload_record_image",
|
||||
critical: "Requires: tableName, recordId, fieldName, imageUrl. The image is downloaded server-side and attached to the record."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "List current uploads",
|
||||
description: "Check what's already uploaded in a field to know if replacing or adding.",
|
||||
tool: "list_record_uploads",
|
||||
critical: "Returns array of upload objects with uploadId needed for replace/delete operations."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Replace or delete if needed",
|
||||
description: "Replace an existing image or delete an upload.",
|
||||
tool: "replace_record_image OR delete_record_upload",
|
||||
critical: "Both require the uploadId from list_record_uploads. replace_record_image downloads new image and swaps it."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
upload_structure: "Upload fields store arrays of objects: [{urlPath, fileName, fileSize, mimeType, uploadDate}]. Access in Twig templates: record.field[0].urlPath | imagec(width).",
|
||||
image_sources: "Use existing remote image URLs, project assets, or Nano Banana AI image generation.",
|
||||
assets_upload: "upload_image_to_assets: uploads to website /images/ folder (not tied to a record). Accepts base64, data URI, or URL. Can resize and compress.",
|
||||
s3_upload: "upload_image_to_s3: uploads to Amazon S3. Returns public S3 URL. Accepts URL, local path, base64, or data URI."
|
||||
},
|
||||
rules: [
|
||||
"Table names WITHOUT 'cms_' prefix",
|
||||
"Primary key is 'num', never 'id'",
|
||||
"Upload fields are ALWAYS arrays of objects with urlPath property",
|
||||
"Use imagec filter for resizing: {{ path | imagec(width_in_pixels) }}"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT try to upload before creating the record — the record must exist first",
|
||||
"DO NOT confuse upload_record_image (attaches to record) with upload_image_to_assets (saves to /images/ folder)",
|
||||
"DO NOT delete uploads without confirming — the image will be removed from the live page"
|
||||
],
|
||||
resources: []
|
||||
};
|
||||
64
mcp-server/tools/orchestrator/workflows/manageRecords.js
Normal file
64
mcp-server/tools/orchestrator/workflows/manageRecords.js
Normal file
@@ -0,0 +1,64 @@
|
||||
export const manageRecordsWorkflow = {
|
||||
id: "manage_records",
|
||||
name: "Manage Records",
|
||||
description: "CRUD operations on existing records: query, create, update, and delete data.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Get table schema",
|
||||
description: "Understand field names, types, and constraints before querying or modifying.",
|
||||
tool: "get_table_schema",
|
||||
critical: "Know the exact field names and types. Upload fields require special handling."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Query records",
|
||||
description: "List or search records to find the ones to work with.",
|
||||
tool: "list_table_records",
|
||||
critical: "Use 'where' param for SQL WHERE filtering. Use 'limit' for pagination. Use 'page' for page navigation."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "Create or update records",
|
||||
description: "Create new records or update existing ones with correct field values.",
|
||||
tool: "create_or_update_record",
|
||||
critical: "Pass 'recordId' for update, omit for create. Only included fields are modified on update. Field values must match field types."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Handle uploads if needed",
|
||||
description: "Upload images or files to record fields.",
|
||||
tool: "upload_record_image",
|
||||
critical: "Separate call per image per field per record. Cannot set upload fields via create_or_update_record."
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
action: "Verify changes",
|
||||
description: "Query the records again to confirm changes were applied correctly.",
|
||||
tool: "list_table_records",
|
||||
critical: "Confirm all fields have the expected values, including upload fields."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
querying: "list_table_records supports: where='campo = \"valor\"' (SQL WHERE), page=1 (pagination), limit=20 (records per page). WHERE clause uses SQL string syntax.",
|
||||
updating: "Pass recordId + fields object to update. Only the fields included in the object are modified — other fields are left unchanged.",
|
||||
creating: "Omit recordId to create. Can batch insert by passing fields as an array of objects.",
|
||||
deleting: "delete_table_records requires tableName and recordIds (array of IDs). Use deleteAll=true to delete everything (DANGEROUS)."
|
||||
},
|
||||
rules: [
|
||||
"Table names WITHOUT 'cms_' prefix in all tool calls",
|
||||
"Primary key is ALWAYS 'num', never 'id'",
|
||||
"Upload fields CANNOT be set via create_or_update_record — use upload_record_image",
|
||||
"Date format: YYYY-MM-DD HH:mm:ss",
|
||||
"Checkbox values: 1 or 0 (number, not boolean)",
|
||||
"WHERE clauses use SQL string syntax: where='nombre = \"valor\"'"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT use 'id' to reference records — use 'num'",
|
||||
"DO NOT set upload fields via create_or_update_record — it will not work",
|
||||
"DO NOT delete records without confirming with the user first"
|
||||
],
|
||||
resources: [
|
||||
"acai://resources/guia-registros"
|
||||
]
|
||||
};
|
||||
70
mcp-server/tools/orchestrator/workflows/populateContent.js
Normal file
70
mcp-server/tools/orchestrator/workflows/populateContent.js
Normal file
@@ -0,0 +1,70 @@
|
||||
export const populateContentWorkflow = {
|
||||
id: "populate_content",
|
||||
name: "Populate Content",
|
||||
description: "Bulk record creation with images for an existing section.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Get table schema",
|
||||
description: "Understand all fields and their types before creating records.",
|
||||
tool: "get_table_schema",
|
||||
critical: "Know the exact field names and types. Upload fields cannot be set via create_or_update_record."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "List existing records",
|
||||
description: "Check what already exists to avoid duplicates.",
|
||||
tool: "list_table_records",
|
||||
critical: "Review existing content before adding new records."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "Generate images if needed",
|
||||
description: "Create AI images for the content being created when existing assets are not available.",
|
||||
tool: "generate_image",
|
||||
critical: "Generate the image first and use the returned URL for upload later."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Create records",
|
||||
description: "Create all records with text content. Can batch insert multiple records in one call.",
|
||||
tool: "create_or_update_record",
|
||||
critical: "Batch insert: pass an array of objects in 'fields' parameter. Date format: YYYY-MM-DD HH:mm:ss. Checkbox: 1 or 0."
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
action: "Upload images to records",
|
||||
description: "Attach images to each record's upload fields.",
|
||||
tool: "upload_record_image",
|
||||
critical: "Must call SEPARATELY for each record+field combination. Cannot batch image uploads. Need the record's num/ID from step 4."
|
||||
},
|
||||
{
|
||||
step: 6,
|
||||
action: "Verify records",
|
||||
description: "Confirm all records were created with correct data.",
|
||||
tool: "list_table_records",
|
||||
critical: "Check that all fields are populated correctly including upload fields."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
batch_insert: "create_or_update_record supports batch: pass fields as an array of objects instead of a single object. Each object is one record. Returns an array of created record IDs.",
|
||||
image_sources: "Use existing project/client assets when available, or generate_image for AI-generated images via Nano Banana.",
|
||||
upload_flow: "1. Create record first (get its num/ID). 2. Then call upload_record_image with tableName, recordId, fieldName, imageUrl. 3. The image is downloaded server-side and attached to the record."
|
||||
},
|
||||
rules: [
|
||||
"Table names WITHOUT 'cms_' prefix in all tool calls",
|
||||
"Primary key is ALWAYS 'num', never 'id'",
|
||||
"Upload fields CANNOT be set via create_or_update_record — use upload_record_image",
|
||||
"Date format: YYYY-MM-DD HH:mm:ss",
|
||||
"Checkbox values: 1 or 0 (number, not boolean)",
|
||||
"Enlace field: auto-formatted to /path/ with slashes if not provided"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT try to set upload field values in create_or_update_record — use upload_record_image after creation",
|
||||
"DO NOT forget that batch insert returns an array of created record IDs — you need these for image uploads",
|
||||
"DO NOT upload images before creating the record — the record must exist first"
|
||||
],
|
||||
resources: [
|
||||
"acai://resources/guia-registros"
|
||||
]
|
||||
};
|
||||
58
mcp-server/tools/orchestrator/workflows/seoSetup.js
Normal file
58
mcp-server/tools/orchestrator/workflows/seoSetup.js
Normal file
@@ -0,0 +1,58 @@
|
||||
export const seoSetupWorkflow = {
|
||||
id: "seo_setup",
|
||||
name: "SEO Setup",
|
||||
description: "Configure SEO for a section: meta tags, URL slugs, and structured data.",
|
||||
steps: [
|
||||
{
|
||||
step: 1,
|
||||
action: "Get current table schema",
|
||||
description: "Check if seo_metas is already enabled and if enlace (URL slug) exists.",
|
||||
tool: "get_table_schema",
|
||||
critical: "Look for seo_metas flag and enlace configuration in the schema response."
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
action: "Enable SEO meta tags",
|
||||
description: "Turn on seo_metas in the table schema to add meta title/description fields.",
|
||||
tool: "update_table_schema",
|
||||
critical: "Set seo_metas=true in the schema. This adds SEO fields to each record."
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
action: "Enable enlace for URL slugs",
|
||||
description: "Enable enlace so records get their own URL-friendly pages.",
|
||||
tool: "update_table_schema",
|
||||
critical: "Set enlace=true. This auto-generates /section/record-name/ URLs for each record."
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
action: "Update records with SEO data",
|
||||
description: "Fill in SEO fields for each record: meta title, meta description.",
|
||||
tool: "create_or_update_record",
|
||||
critical: "SEO fields are typically: seo_title, seo_description. Check the schema for exact field names."
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
action: "Create or update detail template",
|
||||
description: "Ensure the detail page template includes proper meta tags and structured data.",
|
||||
tool: "save_general_section",
|
||||
critical: "The template uses 'thisrecord' variable. Include meta tags in the template for SEO."
|
||||
}
|
||||
],
|
||||
context: {
|
||||
enlace_behavior: "When enlace is enabled, Acai auto-generates URL slugs in /section/record-name/ format. The enlace field value is auto-formatted with slashes.",
|
||||
seo_fields: "Enabling seo_metas adds meta title and description fields to the record editor. These are used in the <head> of the detail page.",
|
||||
detail_template: "The general section template (save_general_section) defines what renders when a user visits a record's URL. Uses 'thisrecord' to access the current record's data."
|
||||
},
|
||||
rules: [
|
||||
"Table names WITHOUT 'cms_' prefix",
|
||||
"update_table_schema requires both tableName and the schema object",
|
||||
"Enlace values are auto-formatted to /path/ format",
|
||||
"SEO meta fields are only available after enabling seo_metas on the table"
|
||||
],
|
||||
warnings: [
|
||||
"DO NOT enable enlace on a 'single' type table — single tables have only one record and usually don't need individual URLs",
|
||||
"DO NOT forget to create a detail template after enabling enlace — without it, record URLs show blank pages"
|
||||
],
|
||||
resources: []
|
||||
};
|
||||
Reference in New Issue
Block a user