@productmaker/mcp 0.15.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/http.js CHANGED
@@ -1171,6 +1171,7 @@ var CreateProductTaskInput = z2.object({
1171
1171
  country: Country.describe('C\xF3digo ISO del pa\xEDs objetivo. Ejemplos: "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago locales y tono. REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat.'),
1172
1172
  price: z2.string().optional().describe('Precio que se mostrar\xE1 en la landing y video. Formato libre \u2014 ej. "$89.900", "USD 29.99", "MXN 599". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si te dice "t\xFA elige", om\xEDtelo y el backend sugiere uno.'),
1173
1173
  offer: z2.string().optional().describe('Oferta o promoci\xF3n a destacar. Ej. "2x1", "Env\xEDo gratis hoy", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si te dice "t\xFA elige", om\xEDtelo.'),
1174
+ productContext: z2.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
1174
1175
  videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla (en la web es el \xFAnico dropdown). Default "auto" (la IA escoge tras analizar el producto). Opciones: "auto", "ugc_dynamic" (UGC testimonial), "ugc_unboxing_chaos" (unboxing agresivo), "ugc_curiosity_reveal" (hook con producto oculto), "ugc_listicle_3" (3 razones, ideal 30s), "ugc_skeptic_confession" (esc\xE9ptico\u2192conversi\xF3n, ideal 30s), "ugc_demo_review" (demo en uso), "problem_solution" (problema\u2192producto\u2192CTA), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla), "product_showcase" (solo producto, sin actor), "wearable_showcase" (ropa/accesorios puestos). Si el usuario pide algo fuera de esta lista (ej. "estilo anime"), p\xEDdele una opci\xF3n v\xE1lida.'),
1175
1176
  videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video (en la web la etiqueta es "\xBFCalidad de video?", 2 opciones \u2014 sin escalera de calidad, son ESTILOS distintos). "basic" = "Realista" (RECOMENDADO por la web): render de 15s con audio nativo, el m\xE1s natural \u2014 S\xD3LO v\xE1lido si la duraci\xF3n del video es 15s. "standard" = "Multiescena": m\xFAltiples tomas, hasta 30s. Si el usuario no menciona estilo, OMITE este campo y el backend usa su default. Para duraci\xF3n 30s s\xF3lo aplica "standard" (Realista est\xE1 vetada).'),
1176
1177
  videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render \u2014 aplica S\xD3LO al tier "basic" (Realista); "standard" la deriva solo. En la web se pregunta "\xBFResoluci\xF3n del video?" tras elegir "basic". "480p" = excelente calidad y m\xE1s econ\xF3mico (RECOMENDADO, default si se omite); "720p" = m\xE1xima nitidez (~el doble de precio). Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 480p para basic).'),
@@ -1240,8 +1241,25 @@ var StatusForResolveSchema = z2.object({
1240
1241
  featuresDraft: z2.array(z2.string()).optional()
1241
1242
  }).optional()
1242
1243
  }).passthrough();
1244
+ var DEFAULT_PRODUCT_TASK_OUTPUTS = [
1245
+ "landing",
1246
+ "video",
1247
+ "image"
1248
+ ];
1249
+ var PRODUCT_TASK_OUTPUT_LABELS = {
1250
+ landing: "landing",
1251
+ video: "video",
1252
+ image: "im\xE1genes creativas"
1253
+ };
1254
+ function formatOutputList(outputs) {
1255
+ const labels = outputs.map((output) => PRODUCT_TASK_OUTPUT_LABELS[output]);
1256
+ if (labels.length <= 1) return labels[0] ?? "";
1257
+ if (labels.length === 2) return `${labels[0]} + ${labels[1]}`;
1258
+ return `${labels.slice(0, -1).join(" + ")} + ${labels[labels.length - 1]}`;
1259
+ }
1260
+ __name(formatOutputList, "formatOutputList");
1243
1261
  function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
1244
- server.tool("create_product_task", 'Crea una tarea de producto desde una o varias fotos. Por defecto genera los 3 outputs (landing + video + image creatives). Devuelve un taskId.\n\nINPUTS REQUERIDOS: images (1-5 fotos del MISMO producto; la primera es la hero), language, country.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto del chat: preg\xFAntale expl\xEDcitamente, incluso si el usuario est\xE1 en LATAM. Si te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nSi el usuario tiene varias fotos del MISMO producto (frente, lateral, detalle, uso), incl\xFAyelas todas en images[] hasta 5. Si tiene fotos de productos DIFERENTES, son llamadas separadas (una tarea por producto).\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos):\n- videoPreset (tipo/narrativa del video \u2014 \xFAnico campo de estilo)\n- videoTier (estilo: basic="Realista"/standard="Multiescena")\n- multiAngleVideos (booleano)\n- angleNarratives (override per-angle de la narrativa, avanzado)\n- outputs (subconjunto de {landing,video,image})\n- productUrl\n\nGUION: para revisar/editar el guion del video antes de renderizar, usa `generate_video_creative` con `pauseForVideoScriptReview: true` en vez de este tool. Despu\xE9s de la pausa: get_video_script para leer, approve_video_script para aprobar con ediciones.\n\nUsa SOLO valores declarados en los enums. Si el usuario pide algo no soportado (ej. "estilo anime", "modelo X"), p\xEDdele una opci\xF3n v\xE1lida del enum correspondiente.', CreateProductTaskInput.shape, async (input) => {
1262
+ server.tool("create_product_task", 'Crea una tarea de producto desde una o varias fotos. Por defecto genera los 3 outputs (landing + video + image creatives) EN UN MISMO TASK. Devuelve un taskId.\n\nINPUTS REQUERIDOS: images (1-5 fotos del MISMO producto; la primera es la hero), language, country.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto del chat: preg\xFAntale expl\xEDcitamente, incluso si el usuario est\xE1 en LATAM. Si te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nANTES de invocar, DILE CLARAMENTE al usuario qu\xE9 outputs vas a generar y que `create_product_task` los genera juntos en un mismo task. Ejemplo: "Voy a generar landing + video en un mismo task; esto consume cr\xE9ditos de ambos outputs". Si el usuario s\xF3lo quiere un output, usa generate_landing / generate_video_creative / generate_image_creatives en vez de este tool.\n\nSi el usuario tiene varias fotos del MISMO producto (frente, lateral, detalle, uso), incl\xFAyelas todas en images[] hasta 5. Si tiene fotos de productos DIFERENTES, son llamadas separadas (una tarea por producto).\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos):\n- videoPreset (tipo/narrativa del video \u2014 \xFAnico campo de estilo)\n- videoTier (estilo: basic="Realista"/standard="Multiescena")\n- multiAngleVideos (booleano)\n- angleNarratives (override per-angle de la narrativa, avanzado)\n- outputs (subconjunto de {landing,video,image}); omitido = ["landing","video","image"] en un mismo task\n- productUrl\n\nGUION: para revisar/editar el guion del video antes de renderizar, usa `generate_video_creative` con `pauseForVideoScriptReview: true` en vez de este tool. Despu\xE9s de la pausa: get_video_script para leer, approve_video_script para aprobar con ediciones.\n\nUsa SOLO valores declarados en los enums. Si el usuario pide algo no soportado (ej. "estilo anime", "modelo X"), p\xEDdele una opci\xF3n v\xE1lida del enum correspondiente.', CreateProductTaskInput.shape, async (input) => {
1245
1263
  try {
1246
1264
  const imgs = await resolveImages(input.images, {
1247
1265
  transport
@@ -1250,6 +1268,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1250
1268
  ...img,
1251
1269
  filename: `image-${i}.png`
1252
1270
  }));
1271
+ const selectedOutputs = input.outputs ?? DEFAULT_PRODUCT_TASK_OUTPUTS;
1253
1272
  const resolved = resolveVideoPreset(input.videoPreset);
1254
1273
  const wireTier = resolveVideoTier(input.videoTier);
1255
1274
  const fields = flatten({
@@ -1257,6 +1276,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1257
1276
  "options.country": input.country,
1258
1277
  "options.price": input.price,
1259
1278
  "options.offer": input.offer,
1279
+ "options.productContext": input.productContext,
1260
1280
  "options.videoPreset": input.videoPreset,
1261
1281
  "options.videoStyle": resolved?.videoStyle,
1262
1282
  "options.narrativeStyle": resolved?.narrativeStyle,
@@ -1278,7 +1298,10 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1278
1298
  return asText({
1279
1299
  taskId: r.taskId,
1280
1300
  status: "queued",
1281
- estimatedSeconds: 300
1301
+ estimatedSeconds: 300,
1302
+ outputs: selectedOutputs,
1303
+ outputMode: "single_task",
1304
+ message: `Se est\xE1 generando ${formatOutputList(selectedOutputs)} en un mismo task.`
1282
1305
  });
1283
1306
  } catch (e) {
1284
1307
  throw translateError(e);
@@ -1411,6 +1434,7 @@ var CreativeRefs = {
1411
1434
  country: Country.describe('Pa\xEDs objetivo ISO. Ej. "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago y tono. REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
1412
1435
  price: z3.string().optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
1413
1436
  offer: z3.string().optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
1437
+ productContext: z3.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
1414
1438
  buyerPersona: z3.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
1415
1439
  isCombo: z3.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
1416
1440
  competitorScanEnabled: z3.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true.")
@@ -1433,6 +1457,7 @@ var VideoInput = z3.object({
1433
1457
  features: z3.array(z3.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
1434
1458
  price: CreativeRefs.price,
1435
1459
  offer: CreativeRefs.offer,
1460
+ productContext: CreativeRefs.productContext,
1436
1461
  cta: z3.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
1437
1462
  scriptNotes: z3.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
1438
1463
  pauseForVideoScriptReview: z3.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
@@ -1463,6 +1488,7 @@ var ImageInput = z3.object({
1463
1488
  price: CreativeRefs.price,
1464
1489
  compareAtPrice: z3.string().optional().describe('Opcional. Precio "antes" de la oferta \u2014 solo para im\xE1genes con descuento. Ej. "$129.000" cuando price="$89.900". \xDAtil con creativeArchetype="offer_value_prop".'),
1465
1490
  offer: CreativeRefs.offer,
1491
+ productContext: CreativeRefs.productContext,
1466
1492
  isCombo: CreativeRefs.isCombo,
1467
1493
  competitorScanEnabled: CreativeRefs.competitorScanEnabled
1468
1494
  });
@@ -1474,6 +1500,7 @@ var LandingInput = z3.object({
1474
1500
  buyerPersona: CreativeRefs.buyerPersona,
1475
1501
  price: CreativeRefs.price,
1476
1502
  offer: CreativeRefs.offer,
1503
+ productContext: CreativeRefs.productContext,
1477
1504
  paymentMethods: z3.string().optional().describe('Opcional. M\xE9todos de pago a mostrar (lista libre). Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la IA usa los m\xE1s comunes del pa\xEDs.'),
1478
1505
  isCombo: CreativeRefs.isCombo,
1479
1506
  competitorScanEnabled: CreativeRefs.competitorScanEnabled
package/dist/stdio.js CHANGED
@@ -1127,6 +1127,7 @@ var CreateProductTaskInput = z2.object({
1127
1127
  country: Country.describe('C\xF3digo ISO del pa\xEDs objetivo. Ejemplos: "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago locales y tono. REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat.'),
1128
1128
  price: z2.string().optional().describe('Precio que se mostrar\xE1 en la landing y video. Formato libre \u2014 ej. "$89.900", "USD 29.99", "MXN 599". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si te dice "t\xFA elige", om\xEDtelo y el backend sugiere uno.'),
1129
1129
  offer: z2.string().optional().describe('Oferta o promoci\xF3n a destacar. Ej. "2x1", "Env\xEDo gratis hoy", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si te dice "t\xFA elige", om\xEDtelo.'),
1130
+ productContext: z2.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
1130
1131
  videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla (en la web es el \xFAnico dropdown). Default "auto" (la IA escoge tras analizar el producto). Opciones: "auto", "ugc_dynamic" (UGC testimonial), "ugc_unboxing_chaos" (unboxing agresivo), "ugc_curiosity_reveal" (hook con producto oculto), "ugc_listicle_3" (3 razones, ideal 30s), "ugc_skeptic_confession" (esc\xE9ptico\u2192conversi\xF3n, ideal 30s), "ugc_demo_review" (demo en uso), "problem_solution" (problema\u2192producto\u2192CTA), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla), "product_showcase" (solo producto, sin actor), "wearable_showcase" (ropa/accesorios puestos). Si el usuario pide algo fuera de esta lista (ej. "estilo anime"), p\xEDdele una opci\xF3n v\xE1lida.'),
1131
1132
  videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video (en la web la etiqueta es "\xBFCalidad de video?", 2 opciones \u2014 sin escalera de calidad, son ESTILOS distintos). "basic" = "Realista" (RECOMENDADO por la web): render de 15s con audio nativo, el m\xE1s natural \u2014 S\xD3LO v\xE1lido si la duraci\xF3n del video es 15s. "standard" = "Multiescena": m\xFAltiples tomas, hasta 30s. Si el usuario no menciona estilo, OMITE este campo y el backend usa su default. Para duraci\xF3n 30s s\xF3lo aplica "standard" (Realista est\xE1 vetada).'),
1132
1133
  videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render \u2014 aplica S\xD3LO al tier "basic" (Realista); "standard" la deriva solo. En la web se pregunta "\xBFResoluci\xF3n del video?" tras elegir "basic". "480p" = excelente calidad y m\xE1s econ\xF3mico (RECOMENDADO, default si se omite); "720p" = m\xE1xima nitidez (~el doble de precio). Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 480p para basic).'),
@@ -1196,8 +1197,25 @@ var StatusForResolveSchema = z2.object({
1196
1197
  featuresDraft: z2.array(z2.string()).optional()
1197
1198
  }).optional()
1198
1199
  }).passthrough();
1200
+ var DEFAULT_PRODUCT_TASK_OUTPUTS = [
1201
+ "landing",
1202
+ "video",
1203
+ "image"
1204
+ ];
1205
+ var PRODUCT_TASK_OUTPUT_LABELS = {
1206
+ landing: "landing",
1207
+ video: "video",
1208
+ image: "im\xE1genes creativas"
1209
+ };
1210
+ function formatOutputList(outputs) {
1211
+ const labels = outputs.map((output) => PRODUCT_TASK_OUTPUT_LABELS[output]);
1212
+ if (labels.length <= 1) return labels[0] ?? "";
1213
+ if (labels.length === 2) return `${labels[0]} + ${labels[1]}`;
1214
+ return `${labels.slice(0, -1).join(" + ")} + ${labels[labels.length - 1]}`;
1215
+ }
1216
+ __name(formatOutputList, "formatOutputList");
1199
1217
  function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
1200
- server.tool("create_product_task", 'Crea una tarea de producto desde una o varias fotos. Por defecto genera los 3 outputs (landing + video + image creatives). Devuelve un taskId.\n\nINPUTS REQUERIDOS: images (1-5 fotos del MISMO producto; la primera es la hero), language, country.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto del chat: preg\xFAntale expl\xEDcitamente, incluso si el usuario est\xE1 en LATAM. Si te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nSi el usuario tiene varias fotos del MISMO producto (frente, lateral, detalle, uso), incl\xFAyelas todas en images[] hasta 5. Si tiene fotos de productos DIFERENTES, son llamadas separadas (una tarea por producto).\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos):\n- videoPreset (tipo/narrativa del video \u2014 \xFAnico campo de estilo)\n- videoTier (estilo: basic="Realista"/standard="Multiescena")\n- multiAngleVideos (booleano)\n- angleNarratives (override per-angle de la narrativa, avanzado)\n- outputs (subconjunto de {landing,video,image})\n- productUrl\n\nGUION: para revisar/editar el guion del video antes de renderizar, usa `generate_video_creative` con `pauseForVideoScriptReview: true` en vez de este tool. Despu\xE9s de la pausa: get_video_script para leer, approve_video_script para aprobar con ediciones.\n\nUsa SOLO valores declarados en los enums. Si el usuario pide algo no soportado (ej. "estilo anime", "modelo X"), p\xEDdele una opci\xF3n v\xE1lida del enum correspondiente.', CreateProductTaskInput.shape, async (input) => {
1218
+ server.tool("create_product_task", 'Crea una tarea de producto desde una o varias fotos. Por defecto genera los 3 outputs (landing + video + image creatives) EN UN MISMO TASK. Devuelve un taskId.\n\nINPUTS REQUERIDOS: images (1-5 fotos del MISMO producto; la primera es la hero), language, country.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto del chat: preg\xFAntale expl\xEDcitamente, incluso si el usuario est\xE1 en LATAM. Si te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nANTES de invocar, DILE CLARAMENTE al usuario qu\xE9 outputs vas a generar y que `create_product_task` los genera juntos en un mismo task. Ejemplo: "Voy a generar landing + video en un mismo task; esto consume cr\xE9ditos de ambos outputs". Si el usuario s\xF3lo quiere un output, usa generate_landing / generate_video_creative / generate_image_creatives en vez de este tool.\n\nSi el usuario tiene varias fotos del MISMO producto (frente, lateral, detalle, uso), incl\xFAyelas todas en images[] hasta 5. Si tiene fotos de productos DIFERENTES, son llamadas separadas (una tarea por producto).\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos):\n- videoPreset (tipo/narrativa del video \u2014 \xFAnico campo de estilo)\n- videoTier (estilo: basic="Realista"/standard="Multiescena")\n- multiAngleVideos (booleano)\n- angleNarratives (override per-angle de la narrativa, avanzado)\n- outputs (subconjunto de {landing,video,image}); omitido = ["landing","video","image"] en un mismo task\n- productUrl\n\nGUION: para revisar/editar el guion del video antes de renderizar, usa `generate_video_creative` con `pauseForVideoScriptReview: true` en vez de este tool. Despu\xE9s de la pausa: get_video_script para leer, approve_video_script para aprobar con ediciones.\n\nUsa SOLO valores declarados en los enums. Si el usuario pide algo no soportado (ej. "estilo anime", "modelo X"), p\xEDdele una opci\xF3n v\xE1lida del enum correspondiente.', CreateProductTaskInput.shape, async (input) => {
1201
1219
  try {
1202
1220
  const imgs = await resolveImages(input.images, {
1203
1221
  transport
@@ -1206,6 +1224,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1206
1224
  ...img,
1207
1225
  filename: `image-${i}.png`
1208
1226
  }));
1227
+ const selectedOutputs = input.outputs ?? DEFAULT_PRODUCT_TASK_OUTPUTS;
1209
1228
  const resolved = resolveVideoPreset(input.videoPreset);
1210
1229
  const wireTier = resolveVideoTier(input.videoTier);
1211
1230
  const fields = flatten({
@@ -1213,6 +1232,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1213
1232
  "options.country": input.country,
1214
1233
  "options.price": input.price,
1215
1234
  "options.offer": input.offer,
1235
+ "options.productContext": input.productContext,
1216
1236
  "options.videoPreset": input.videoPreset,
1217
1237
  "options.videoStyle": resolved?.videoStyle,
1218
1238
  "options.narrativeStyle": resolved?.narrativeStyle,
@@ -1234,7 +1254,10 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1234
1254
  return asText({
1235
1255
  taskId: r.taskId,
1236
1256
  status: "queued",
1237
- estimatedSeconds: 300
1257
+ estimatedSeconds: 300,
1258
+ outputs: selectedOutputs,
1259
+ outputMode: "single_task",
1260
+ message: `Se est\xE1 generando ${formatOutputList(selectedOutputs)} en un mismo task.`
1238
1261
  });
1239
1262
  } catch (e) {
1240
1263
  throw translateError(e);
@@ -1367,6 +1390,7 @@ var CreativeRefs = {
1367
1390
  country: Country.describe('Pa\xEDs objetivo ISO. Ej. "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago y tono. REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
1368
1391
  price: z3.string().optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
1369
1392
  offer: z3.string().optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
1393
+ productContext: z3.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
1370
1394
  buyerPersona: z3.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
1371
1395
  isCombo: z3.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
1372
1396
  competitorScanEnabled: z3.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true.")
@@ -1389,6 +1413,7 @@ var VideoInput = z3.object({
1389
1413
  features: z3.array(z3.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
1390
1414
  price: CreativeRefs.price,
1391
1415
  offer: CreativeRefs.offer,
1416
+ productContext: CreativeRefs.productContext,
1392
1417
  cta: z3.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
1393
1418
  scriptNotes: z3.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
1394
1419
  pauseForVideoScriptReview: z3.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
@@ -1419,6 +1444,7 @@ var ImageInput = z3.object({
1419
1444
  price: CreativeRefs.price,
1420
1445
  compareAtPrice: z3.string().optional().describe('Opcional. Precio "antes" de la oferta \u2014 solo para im\xE1genes con descuento. Ej. "$129.000" cuando price="$89.900". \xDAtil con creativeArchetype="offer_value_prop".'),
1421
1446
  offer: CreativeRefs.offer,
1447
+ productContext: CreativeRefs.productContext,
1422
1448
  isCombo: CreativeRefs.isCombo,
1423
1449
  competitorScanEnabled: CreativeRefs.competitorScanEnabled
1424
1450
  });
@@ -1430,6 +1456,7 @@ var LandingInput = z3.object({
1430
1456
  buyerPersona: CreativeRefs.buyerPersona,
1431
1457
  price: CreativeRefs.price,
1432
1458
  offer: CreativeRefs.offer,
1459
+ productContext: CreativeRefs.productContext,
1433
1460
  paymentMethods: z3.string().optional().describe('Opcional. M\xE9todos de pago a mostrar (lista libre). Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la IA usa los m\xE1s comunes del pa\xEDs.'),
1434
1461
  isCombo: CreativeRefs.isCombo,
1435
1462
  competitorScanEnabled: CreativeRefs.competitorScanEnabled
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "0.15.3",
3
+ "version": "0.16.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Product Maker MCP server — connect Claude Desktop, Claude Code, ChatGPT, or Gemini to Product Maker AI to generate dropshipping landing pages, UGC videos, and ad creatives, and publish to Shopify and Meta Ads from your AI assistant.",