@productmaker/mcp 12.11.0 → 12.12.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.
Files changed (3) hide show
  1. package/dist/http.js +193 -108
  2. package/dist/stdio.js +193 -108
  3. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -47,7 +47,11 @@ var NarrativeStyle = z.enum([
47
47
  "animated_storyteller",
48
48
  "animated_inner_journey",
49
49
  "animated_object_soul",
50
- "animated_timeline"
50
+ "animated_timeline",
51
+ // Voiceless story on the unified engine only: on-screen labels, before/after
52
+ // and a format the director picks from the Product Truth. Manual-only and
53
+ // admitted per user (`CREATIVE_VIRAL_NARRATIVE_USER_IDS`); never Auto.
54
+ "viral"
51
55
  ]);
52
56
  var BLOCKED_NARRATIVE_STYLES = [
53
57
  "animated_storyteller",
@@ -93,7 +97,8 @@ var VideoPreset = z.enum([
93
97
  "ugc_listicle_3",
94
98
  "ugc_skeptic_confession",
95
99
  "ugc_demo_review",
96
- "metaphor_product"
100
+ "metaphor_product",
101
+ "viral"
97
102
  ]);
98
103
  var VoiceId = z.string().refine((value) => !value.trim().toLowerCase().startsWith("bank:"), "El banco de voces fue retirado. Usa Auto o la voz privada de un actor.");
99
104
  var _VIDEO_MODEL_SET = new Set(VideoModel.options);
@@ -4531,6 +4536,37 @@ var TaskKind = z8.enum([
4531
4536
  // ../../packages/types/src/product.ts
4532
4537
  import { z as z10 } from "zod";
4533
4538
 
4539
+ // ../../packages/types/src/price-numeric.ts
4540
+ function parsePriceNumeric(raw) {
4541
+ if (!raw) return null;
4542
+ const cleaned = raw.replace(/[^\d.,-]/g, "").trim();
4543
+ if (!cleaned || cleaned === "-") return null;
4544
+ const hasDot = cleaned.includes(".");
4545
+ const hasComma = cleaned.includes(",");
4546
+ let normalized = cleaned;
4547
+ if (hasDot && hasComma) {
4548
+ const lastDot = cleaned.lastIndexOf(".");
4549
+ const lastComma = cleaned.lastIndexOf(",");
4550
+ const decimal = lastDot > lastComma ? "." : ",";
4551
+ const thousands = decimal === "." ? "," : ".";
4552
+ normalized = cleaned.split(thousands).join("");
4553
+ if (decimal === ",") normalized = normalized.replace(",", ".");
4554
+ } else if (hasDot) {
4555
+ const parts = cleaned.split(".");
4556
+ const lastGroup = parts[parts.length - 1] ?? "";
4557
+ const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
4558
+ if (isThousands) normalized = parts.join("");
4559
+ } else if (hasComma) {
4560
+ const parts = cleaned.split(",");
4561
+ const lastGroup = parts[parts.length - 1] ?? "";
4562
+ const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
4563
+ normalized = isThousands ? parts.join("") : cleaned.replace(",", ".");
4564
+ }
4565
+ const n = Number(normalized);
4566
+ return Number.isFinite(n) ? n : null;
4567
+ }
4568
+ __name(parsePriceNumeric, "parsePriceNumeric");
4569
+
4534
4570
  // ../../packages/types/src/product-reference-set.ts
4535
4571
  import { z as z9 } from "zod";
4536
4572
  var ProductReferenceScopeSchema = z9.enum([
@@ -4998,35 +5034,6 @@ var OfferSchema = z10.string().min(1).max(240);
4998
5034
  var CompareAtPriceSchema = z10.string().min(1).max(120);
4999
5035
  var PaymentMethodsSchema = z10.string().min(1).max(240);
5000
5036
  var LanguageCodeSchema = z10.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Invalid language code").max(10);
5001
- function parsePriceNumeric(raw) {
5002
- if (!raw) return null;
5003
- const cleaned = raw.replace(/[^\d.,-]/g, "").trim();
5004
- if (!cleaned || cleaned === "-") return null;
5005
- const hasDot = cleaned.includes(".");
5006
- const hasComma = cleaned.includes(",");
5007
- let normalized = cleaned;
5008
- if (hasDot && hasComma) {
5009
- const lastDot = cleaned.lastIndexOf(".");
5010
- const lastComma = cleaned.lastIndexOf(",");
5011
- const decimal = lastDot > lastComma ? "." : ",";
5012
- const thousands = decimal === "." ? "," : ".";
5013
- normalized = cleaned.split(thousands).join("");
5014
- if (decimal === ",") normalized = normalized.replace(",", ".");
5015
- } else if (hasDot) {
5016
- const parts = cleaned.split(".");
5017
- const lastGroup = parts[parts.length - 1] ?? "";
5018
- const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
5019
- if (isThousands) normalized = parts.join("");
5020
- } else if (hasComma) {
5021
- const parts = cleaned.split(",");
5022
- const lastGroup = parts[parts.length - 1] ?? "";
5023
- const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
5024
- normalized = isThousands ? parts.join("") : cleaned.replace(",", ".");
5025
- }
5026
- const n = Number(normalized);
5027
- return Number.isFinite(n) ? n : null;
5028
- }
5029
- __name(parsePriceNumeric, "parsePriceNumeric");
5030
5037
  var PRICE_SKIP_SENTINELS = /* @__PURE__ */ new Set([
5031
5038
  "skip",
5032
5039
  "none",
@@ -7861,11 +7868,16 @@ var PersistedBundleBindingSchema = z22.object({
7861
7868
  * the price comparison when it is absent.
7862
7869
  */
7863
7870
  priceAtPublish: z22.string().trim().min(1).max(MAX_MONEY_LENGTH).optional(),
7871
+ compareAtPriceAtPublish: z22.string().trim().min(1).max(MAX_MONEY_LENGTH).nullable().optional(),
7872
+ /** Seller's offer at publish time, independent of what Shopify charged. */
7873
+ offerAtPublish: z22.object({
7874
+ price: z22.string().trim().min(1).max(MAX_MONEY_LENGTH),
7875
+ compareAtPrice: z22.string().trim().min(1).max(MAX_MONEY_LENGTH).nullable()
7876
+ }).strict().optional(),
7864
7877
  /**
7865
7878
  * How the binding was produced: `mapped` = merchant-confirmed against an
7866
7879
  * existing catalog, `created` = ProductMaker-created "Oferta" variant,
7867
- * `implicit` = legacy exact-structure match (not persisted today; kept
7868
- * for forward compatibility).
7880
+ * `implicit` = exact-structure match.
7869
7881
  */
7870
7882
  mode: z22.enum([
7871
7883
  "mapped",
@@ -11465,6 +11477,28 @@ var CreativeEngineSceneSchema = z38.object({
11465
11477
  timeline: CreativeEngineTimelineSchema.optional(),
11466
11478
  factPaths: z38.array(id2)
11467
11479
  }).strict();
11480
+ var CreativeEngineViralFormatSchema = z38.enum([
11481
+ "pas",
11482
+ "before_after",
11483
+ "demo",
11484
+ "pov",
11485
+ "gift",
11486
+ "concept_vs_result"
11487
+ ]);
11488
+ var CreativeEngineViralPlanSchema = z38.object({
11489
+ format: CreativeEngineViralFormatSchema,
11490
+ /** The scene that shows the product's critical feature working. */
11491
+ mechanismSceneId: id2,
11492
+ /** Two stills of the same subject and framing: rigid surfaces wipe, soft ones (hair, skin, fabric) cut. */
11493
+ beforeAfter: z38.object({
11494
+ beforeSceneId: id2,
11495
+ afterSceneId: id2,
11496
+ surface: z38.enum([
11497
+ "rigid",
11498
+ "soft"
11499
+ ])
11500
+ }).strict().optional()
11501
+ }).strict();
11468
11502
  var CreativeEnginePlanSchema = z38.object({
11469
11503
  revision: z38.number().int().positive(),
11470
11504
  execution: CreativeEngineExecutionSchema.optional(),
@@ -11481,7 +11515,9 @@ var CreativeEnginePlanSchema = z38.object({
11481
11515
  music: z38.literal(false),
11482
11516
  scenes: z38.array(CreativeEngineSceneSchema).min(1).max(CREATIVE_ENGINE_MAX_PLAN_SCENES),
11483
11517
  /** The commercial binding actually applied; absent on guided/historical. */
11484
- commercialExecution: CreativeEngineCommercialExecutionSchema.optional()
11518
+ commercialExecution: CreativeEngineCommercialExecutionSchema.optional(),
11519
+ /** Voiceless «Viral» story; absent on every other narrative. */
11520
+ viral: CreativeEngineViralPlanSchema.optional()
11485
11521
  }).strict();
11486
11522
  var CreativeEngineSpeakerRegionSchema = z38.object({
11487
11523
  x: z38.number().finite().min(0).max(1),
@@ -12001,6 +12037,14 @@ var CreativeEngineStateSchema = z38.object({
12001
12037
  * seller-facing script equals the approved one (no second approval).
12002
12038
  */
12003
12039
  carriedPlanHash: hash.optional(),
12040
+ /**
12041
+ * Who approved without the seller: a «Viral» script has no editable
12042
+ * dialogue, so the system approves it on the seller's behalf.
12043
+ */
12044
+ approvedBy: z38.object({
12045
+ actor: z38.literal("system"),
12046
+ reason: z38.literal("viral_auto")
12047
+ }).strict().optional(),
12004
12048
  waitingStartedAtMs: z38.number().int().nonnegative().optional(),
12005
12049
  pausedMs: z38.number().int().nonnegative()
12006
12050
  }).strict().optional(),
@@ -12225,7 +12269,8 @@ var VideoGeneratorAiEdit = z39.object({
12225
12269
  error: z39.string().optional()
12226
12270
  });
12227
12271
  var VideoCreativeDirection = CreativeEnginePlanSchema.pick({
12228
- guide: true
12272
+ guide: true,
12273
+ viral: true
12229
12274
  });
12230
12275
  var VideoGenerator = z39.object({
12231
12276
  aiEdit: VideoGeneratorAiEdit.nullable().optional(),
@@ -12326,7 +12371,10 @@ var VideoScriptSceneForReview = z39.object({
12326
12371
  /** Objective visual observed in the winner source scene. */
12327
12372
  winnerVisual: z39.string().optional(),
12328
12373
  /** Localized target visual expected to accompany this spoken line. */
12329
- expectedVisual: z39.string().optional()
12374
+ expectedVisual: z39.string().optional(),
12375
+ /** «Viral» (voiceless) plans only: the label burned on screen over this
12376
+ * scene. Shown read-only in place of dialogue; the scene has no voice. */
12377
+ onScreenLabel: z39.string().optional()
12330
12378
  });
12331
12379
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES = 50;
12332
12380
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS = 2e3;
@@ -24226,7 +24274,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24226
24274
  // MCP 8.6.0: + storyteller narrative family and animationStyle axis.
24227
24275
  // MCP 8.10.0: storyteller family blocked (BLOCKED_NARRATIVE_STYLES).
24228
24276
  // MCP 9.1.0: combine current animated-video controls and initial GIF choice.
24229
- "5991b2e897aad7b10c4e38a93e8c58234741498393439cf0228ed9ffd966efef",
24277
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24278
+ "bfe5130b1941f5f0a690949411d83cdbd32c1ee65cc75f2c22568b87bfe90a42",
24230
24279
  "credit_consuming",
24231
24280
  "creative",
24232
24281
  [
@@ -24285,7 +24334,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24285
24334
  // MCP 9.1.0: combine current animated-video controls and initial GIF choice.
24286
24335
  // MCP 12.4.0: landingStrategy narrowed to classic + social_proof.
24287
24336
  // MCP 12.5.0: pain_solution restored to landingStrategy.
24288
- "68a740d97238e720000c16db56ae5748ceb560e342f8fbfe605c954e6284fda7",
24337
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24338
+ "bc90378e921718099faae3f6a11cac4f1fdd81727729d6df581f1f827f94a240",
24289
24339
  "credit_consuming",
24290
24340
  "creative",
24291
24341
  [
@@ -24491,28 +24541,38 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24491
24541
  ], [
24492
24542
  "task_draft"
24493
24543
  ]),
24494
- defineCapability("estimate_creative_variant", "468079ba24e5e0d3c5c707cd54fec64571be429e66cadc12019af4d6e9d10c4e", "none", "read_only", [
24495
- "read"
24496
- ], [
24497
- slot("source_task", true, [
24498
- "sourceTaskId"
24499
- ]),
24500
- slot("creative_kind", true, [
24501
- "kind"
24502
- ]),
24503
- slot("variant_options", false, [
24504
- "videoPreset",
24505
- "videoResolution",
24506
- "nVariants",
24507
- "sectionKey",
24508
- "instructions"
24509
- ])
24510
- ], [
24511
- "task",
24512
- "creative"
24513
- ], [
24514
- "cost_estimate"
24515
- ]),
24544
+ defineCapability(
24545
+ "estimate_creative_variant",
24546
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24547
+ "743d227d050dab27a8b385c9bc2c0c2d5b450e22abfed811c344b65faffb29ab",
24548
+ "none",
24549
+ "read_only",
24550
+ [
24551
+ "read"
24552
+ ],
24553
+ [
24554
+ slot("source_task", true, [
24555
+ "sourceTaskId"
24556
+ ]),
24557
+ slot("creative_kind", true, [
24558
+ "kind"
24559
+ ]),
24560
+ slot("variant_options", false, [
24561
+ "videoPreset",
24562
+ "videoResolution",
24563
+ "nVariants",
24564
+ "sectionKey",
24565
+ "instructions"
24566
+ ])
24567
+ ],
24568
+ [
24569
+ "task",
24570
+ "creative"
24571
+ ],
24572
+ [
24573
+ "cost_estimate"
24574
+ ]
24575
+ ),
24516
24576
  defineCapability("estimate_market_study_cost", "d1fbe8ead642d481258c419a1eed059f9c8188d1cd9f2d4eed12e202fc8800a4", "none", "read_only", [
24517
24577
  "read"
24518
24578
  ], [
@@ -24845,7 +24905,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24845
24905
  // MCP 8.6.0: + storyteller narrative family and animationStyle axis.
24846
24906
  // MCP 8.10.0: storyteller family blocked (BLOCKED_NARRATIVE_STYLES).
24847
24907
  // MCP 9.1.0: combine current animated-video controls and initial GIF choice.
24848
- "66dee35d59da0e88e72e24c503f3f1dc46c17c1162d98d48705e2bfe552f3f02",
24908
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24909
+ "0669339f0e89332c23588c9a91be31e4700a655367beaa5945569fe329cbf5b9",
24849
24910
  "credit_consuming",
24850
24911
  "creative",
24851
24912
  [
@@ -25624,42 +25685,52 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
25624
25685
  ], [
25625
25686
  "media_upload_session"
25626
25687
  ], MCP_ONLY_CHANNEL_EXPOSURE),
25627
- defineCapability("resolve_pending_action", "a7fef1e3299c2bfb387a16b3e1e243fba8df1db961ebc1f27d2119209124c293", "credit_consuming", "creative", [
25688
+ defineCapability(
25689
+ "resolve_pending_action",
25690
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
25691
+ "bba3af0b7022b79ba4859c7d6b880e835459cb23095d22147cb17127e8fb0dc9",
25628
25692
  "credit_consuming",
25629
- "state_change"
25630
- ], [
25631
- slot("task", true, [
25632
- "taskId"
25633
- ]),
25634
- slot("action", true, [
25635
- "action"
25636
- ], [
25637
- "actionKind"
25638
- ]),
25639
- slot("action_payload", false, [], [
25640
- "userChoice",
25641
- "selectedAngleIndex",
25642
- "confirmedProductNames",
25643
- "customAngle",
25644
- "painPoints",
25645
- "benefits",
25646
- "features",
25647
- "useMultiSceneShowcase",
25648
- "gapDurationSeconds",
25649
- "narrativeSelection",
25650
- "angleId",
25651
- "content",
25652
- "creativeDirection",
25653
- "actor",
25654
- "voiceovers",
25655
- "visualDirections"
25656
- ])
25657
- ], [
25658
- "task",
25659
- "pending_action"
25660
- ], [
25661
- "task"
25662
- ]),
25693
+ "creative",
25694
+ [
25695
+ "credit_consuming",
25696
+ "state_change"
25697
+ ],
25698
+ [
25699
+ slot("task", true, [
25700
+ "taskId"
25701
+ ]),
25702
+ slot("action", true, [
25703
+ "action"
25704
+ ], [
25705
+ "actionKind"
25706
+ ]),
25707
+ slot("action_payload", false, [], [
25708
+ "userChoice",
25709
+ "selectedAngleIndex",
25710
+ "confirmedProductNames",
25711
+ "customAngle",
25712
+ "painPoints",
25713
+ "benefits",
25714
+ "features",
25715
+ "useMultiSceneShowcase",
25716
+ "gapDurationSeconds",
25717
+ "narrativeSelection",
25718
+ "angleId",
25719
+ "content",
25720
+ "creativeDirection",
25721
+ "actor",
25722
+ "voiceovers",
25723
+ "visualDirections"
25724
+ ])
25725
+ ],
25726
+ [
25727
+ "task",
25728
+ "pending_action"
25729
+ ],
25730
+ [
25731
+ "task"
25732
+ ]
25733
+ ),
25663
25734
  defineCapability("start_dropshipping_project", "996385df905ed85a933c5726fbebf5a29a98f29364badd8256ff306aff38797c", "state_change", "business", [
25664
25735
  "state_change"
25665
25736
  ], [
@@ -26577,7 +26648,10 @@ var MCP_HIDDEN_NARRATIVE_STYLES = [
26577
26648
  "gap_replication",
26578
26649
  // The blocked storyteller family is not offered, not even when revising an
26579
26650
  // existing script.
26580
- ...BLOCKED_NARRATIVE_STYLES
26651
+ ...BLOCKED_NARRATIVE_STYLES,
26652
+ // «Viral» only renders on the unified engine, whose scripts are reviewed in
26653
+ // place: the previous engine's narrative regeneration cannot produce it.
26654
+ "viral"
26581
26655
  ];
26582
26656
  var McpNarrativeStyleSchema = NarrativeStyle.exclude(MCP_HIDDEN_NARRATIVE_STYLES);
26583
26657
  var MCP_ANGLE_NARRATIVE_STYLES = [
@@ -26591,6 +26665,9 @@ var MCP_ANGLE_NARRATIVE_STYLES = [
26591
26665
  "wild_card",
26592
26666
  "animated_problem_pixar",
26593
26667
  "sassy_product_pixar",
26668
+ // Manual-only, voiceless, unified engine only; the API admits it per user
26669
+ // (`CREATIVE_VIRAL_NARRATIVE_USER_IDS`).
26670
+ "viral",
26594
26671
  "market"
26595
26672
  ];
26596
26673
  var McpAngleNarrativeStyleSchema = NarrativeStyle.extract(MCP_ANGLE_NARRATIVE_STYLES);
@@ -27783,8 +27860,11 @@ var CreativeCompositionLocalManifestSchema = z111.object({
27783
27860
  scenes: z111.array(z111.object({
27784
27861
  id: id3,
27785
27862
  startSec: z111.number().nonnegative(),
27786
- durationSec: z111.number().positive()
27787
- }).strict()).min(1)
27863
+ durationSec: z111.number().positive(),
27864
+ /** «Viral» plans only: the one label the page burns over this scene. */
27865
+ copy: z111.array(z111.string()).optional()
27866
+ }).strict()).min(1),
27867
+ viral: CreativeEngineViralPlanSchema.optional()
27788
27868
  }).strict(),
27789
27869
  planHash: hash2,
27790
27870
  context: CreativeEngineContextBindingSchema,
@@ -32212,7 +32292,7 @@ var ApiClient = class {
32212
32292
  };
32213
32293
 
32214
32294
  // src/index.ts
32215
- var MCP_VERSION = "12.11.0";
32295
+ var MCP_VERSION = "12.12.0";
32216
32296
 
32217
32297
  // src/meta-upload-app.ts
32218
32298
  import { readFileSync } from "fs";
@@ -33219,7 +33299,8 @@ var VideoPresetEnum = VideoPreset.extract([
33219
33299
  "cinematic",
33220
33300
  "wild_card",
33221
33301
  "pixar_problem",
33222
- "pixar_sassy"
33302
+ "pixar_sassy",
33303
+ "viral"
33223
33304
  ]);
33224
33305
  var VideoStructureEnum = VideoStructure;
33225
33306
  var VideoQualityEnum = VideoQuality;
@@ -33251,6 +33332,10 @@ var VIDEO_PRESET_RESOLUTION = {
33251
33332
  videoStyle: "ai_dynamic",
33252
33333
  narrativeStyle: "sassy_product_pixar"
33253
33334
  },
33335
+ viral: {
33336
+ videoStyle: "ai_dynamic",
33337
+ narrativeStyle: "viral"
33338
+ },
33254
33339
  product_showcase: {
33255
33340
  videoStyle: "product_only",
33256
33341
  narrativeStyle: "product_showcase"
@@ -36133,7 +36218,7 @@ var CreateProductTaskInput = z141.object({
36133
36218
  paymentMethods: z141.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago que puede mostrar la landing. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
36134
36219
  productContext: z141.string().max(PRODUCT_CONTEXT_MAX_CHARS).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."),
36135
36220
  productLabel: z141.string().trim().max(80).optional().describe('Opcional. Qu\xE9 es el producto, en pocas palabras (ej. "quita pelusas para ropa"). Es AUTORITATIVO: si lo env\xEDas, la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA detecta el producto desde la imagen.'),
36136
- videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla. Default "auto" (la IA escoge tras analizar el producto). Todos los presets funcionan a 15s (single_call) y 30s (Multiescena); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
36221
+ videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla. Default "auto" (la IA escoge tras analizar el producto). Todos los presets salvo "viral" (solo Multiescena de 15 s) funcionan a 15s (single_call) y 30s (Multiescena); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla), "viral" (video sin voz con r\xF3tulos en pantalla y antes/despu\xE9s; solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
36137
36222
  animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
36138
36223
  durationSeconds: z141.union([
36139
36224
  z141.literal(15),
@@ -36146,7 +36231,7 @@ var CreateProductTaskInput = z141.object({
36146
36231
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
36147
36232
  videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render. En la web se pregunta "\xBFResoluci\xF3n del video?". "480p" = excelente calidad y m\xE1s econ\xF3mico (RECOMENDADO, default si se omite); "720p" = m\xE1xima nitidez, entre 3% y 15% m\xE1s caro seg\xFAn formato y tier. Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 480p).'),
36148
36233
  videoAngleCount: z141.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
36149
- angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
36234
+ angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "viral" (video sin voz: r\xF3tulos en pantalla y antes/despu\xE9s; solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones), "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
36150
36235
  outputs: z141.array(z141.enum([
36151
36236
  "landing",
36152
36237
  "video",
@@ -36256,7 +36341,7 @@ var PendingActionPayload = z141.discriminatedUnion("kind", [
36256
36341
  // an opaque HTTP 400 after the model already believed it had been saved.
36257
36342
  features: z141.array(z141.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
36258
36343
  buyerPersona: z141.string().min(1).max(360).optional(),
36259
- narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
36344
+ narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora. "viral" (sin voz, r\xF3tulos y antes/despu\xE9s; solo Multiescena de 15 s) solo est\xE1 disponible para cuentas habilitadas y tareas del motor nuevo.'),
36260
36345
  actor: z141.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
36261
36346
  actorId: z141.string().max(120).nullable().optional(),
36262
36347
  creativeDirection: z141.string().max(2e3).optional(),
@@ -36269,7 +36354,7 @@ var PendingActionPayload = z141.discriminatedUnion("kind", [
36269
36354
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
36270
36355
  angle: z141.string().min(1).max(480).optional(),
36271
36356
  buyerPersona: z141.string().min(1).max(360).optional(),
36272
- narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
36357
+ narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora. "viral" (sin voz, r\xF3tulos y antes/despu\xE9s; solo Multiescena de 15 s) solo est\xE1 disponible para cuentas habilitadas y tareas del motor nuevo.'),
36273
36358
  actor: z141.string().min(1).max(360).optional(),
36274
36359
  actorId: z141.string().max(120).nullable().optional(),
36275
36360
  creativeDirection: z141.string().max(2e3).optional()
@@ -38429,7 +38514,7 @@ var VideoCreativeSetup = z145.discriminatedUnion("mode", [
38429
38514
  }).strict(),
38430
38515
  z145.object({
38431
38516
  mode: z145.literal("guided"),
38432
- videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas funcionan en Un solo clip y Multiescena.'),
38517
+ videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas salvo "viral" funcionan en Un solo clip y Multiescena. "viral" es un video sin voz (r\xF3tulos en pantalla, antes/despu\xE9s), solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones.'),
38433
38518
  buyerPersona: z145.string().trim().min(1).max(360),
38434
38519
  animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
38435
38520
  presenter: VideoPresenter,
@@ -38451,7 +38536,7 @@ var VideoInput = z145.object({
38451
38536
  generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
38452
38537
  durationSeconds: z145.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
38453
38538
  videoAngleCount: z145.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
38454
- angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
38539
+ angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "viral" (video sin voz: r\xF3tulos en pantalla y antes/despu\xE9s; solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones), "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
38455
38540
  creativeSetup: VideoCreativeSetup.describe("Configuraci\xF3n creativa obligatoria. En guided pregunta narrativa, p\xFAblico, presentador y direcci\xF3n antes de confirmar. Usa automatic s\xF3lo si el usuario deleg\xF3 todo expl\xEDcitamente."),
38456
38541
  videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena (varias tomas concatenadas). Default: single_take.'),
38457
38542
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
@@ -39364,7 +39449,7 @@ var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
39364
39449
  });
39365
39450
  function registerScriptReviewTools(server, api) {
39366
39451
  server.registerTool("get_video_script", {
39367
- description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual? }], error? }. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192 consulta `get_task_status` antes de ofrecer recuperaci\xF3n. No regeneres autom\xE1ticamente una tarea terminal.\n\nANGLE KEY: usa las claves expl\xEDcitas de reviewNextAction.calls, incluso si s\xF3lo seleccionaste un candidato. Cuando uno est\xE9 ready, detente en ese \xE1ngulo y espera la decisi\xF3n antes de consultar otro.',
39452
+ description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual?, onScreenLabel? }], error? }. En videos \xABViral\xBB (sin voz) cada escena trae `onScreenLabel`: mu\xE9stralo como \xABTexto en pantalla\xBB; su `dialogue` viene vac\xEDo y no pidas di\xE1logo para esas escenas. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192 consulta `get_task_status` antes de ofrecer recuperaci\xF3n. No regeneres autom\xE1ticamente una tarea terminal.\n\nANGLE KEY: usa las claves expl\xEDcitas de reviewNextAction.calls, incluso si s\xF3lo seleccionaste un candidato. Cuando uno est\xE9 ready, detente en ese \xE1ngulo y espera la decisi\xF3n antes de consultar otro.',
39368
39453
  inputSchema: GetVideoScriptInput.shape,
39369
39454
  annotations: READS_INTERNAL
39370
39455
  }, async (input) => {
package/dist/stdio.js CHANGED
@@ -69,7 +69,11 @@ var NarrativeStyle = z.enum([
69
69
  "animated_storyteller",
70
70
  "animated_inner_journey",
71
71
  "animated_object_soul",
72
- "animated_timeline"
72
+ "animated_timeline",
73
+ // Voiceless story on the unified engine only: on-screen labels, before/after
74
+ // and a format the director picks from the Product Truth. Manual-only and
75
+ // admitted per user (`CREATIVE_VIRAL_NARRATIVE_USER_IDS`); never Auto.
76
+ "viral"
73
77
  ]);
74
78
  var BLOCKED_NARRATIVE_STYLES = [
75
79
  "animated_storyteller",
@@ -115,7 +119,8 @@ var VideoPreset = z.enum([
115
119
  "ugc_listicle_3",
116
120
  "ugc_skeptic_confession",
117
121
  "ugc_demo_review",
118
- "metaphor_product"
122
+ "metaphor_product",
123
+ "viral"
119
124
  ]);
120
125
  var VoiceId = z.string().refine((value) => !value.trim().toLowerCase().startsWith("bank:"), "El banco de voces fue retirado. Usa Auto o la voz privada de un actor.");
121
126
  var _VIDEO_MODEL_SET = new Set(VideoModel.options);
@@ -4306,6 +4311,37 @@ var TaskKind = z8.enum([
4306
4311
  // ../../packages/types/src/product.ts
4307
4312
  import { z as z10 } from "zod";
4308
4313
 
4314
+ // ../../packages/types/src/price-numeric.ts
4315
+ function parsePriceNumeric(raw) {
4316
+ if (!raw) return null;
4317
+ const cleaned = raw.replace(/[^\d.,-]/g, "").trim();
4318
+ if (!cleaned || cleaned === "-") return null;
4319
+ const hasDot = cleaned.includes(".");
4320
+ const hasComma = cleaned.includes(",");
4321
+ let normalized = cleaned;
4322
+ if (hasDot && hasComma) {
4323
+ const lastDot = cleaned.lastIndexOf(".");
4324
+ const lastComma = cleaned.lastIndexOf(",");
4325
+ const decimal = lastDot > lastComma ? "." : ",";
4326
+ const thousands = decimal === "." ? "," : ".";
4327
+ normalized = cleaned.split(thousands).join("");
4328
+ if (decimal === ",") normalized = normalized.replace(",", ".");
4329
+ } else if (hasDot) {
4330
+ const parts = cleaned.split(".");
4331
+ const lastGroup = parts[parts.length - 1] ?? "";
4332
+ const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
4333
+ if (isThousands) normalized = parts.join("");
4334
+ } else if (hasComma) {
4335
+ const parts = cleaned.split(",");
4336
+ const lastGroup = parts[parts.length - 1] ?? "";
4337
+ const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
4338
+ normalized = isThousands ? parts.join("") : cleaned.replace(",", ".");
4339
+ }
4340
+ const n = Number(normalized);
4341
+ return Number.isFinite(n) ? n : null;
4342
+ }
4343
+ __name(parsePriceNumeric, "parsePriceNumeric");
4344
+
4309
4345
  // ../../packages/types/src/product-reference-set.ts
4310
4346
  import { z as z9 } from "zod";
4311
4347
  var ProductReferenceScopeSchema = z9.enum([
@@ -4773,35 +4809,6 @@ var OfferSchema = z10.string().min(1).max(240);
4773
4809
  var CompareAtPriceSchema = z10.string().min(1).max(120);
4774
4810
  var PaymentMethodsSchema = z10.string().min(1).max(240);
4775
4811
  var LanguageCodeSchema = z10.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Invalid language code").max(10);
4776
- function parsePriceNumeric(raw) {
4777
- if (!raw) return null;
4778
- const cleaned = raw.replace(/[^\d.,-]/g, "").trim();
4779
- if (!cleaned || cleaned === "-") return null;
4780
- const hasDot = cleaned.includes(".");
4781
- const hasComma = cleaned.includes(",");
4782
- let normalized = cleaned;
4783
- if (hasDot && hasComma) {
4784
- const lastDot = cleaned.lastIndexOf(".");
4785
- const lastComma = cleaned.lastIndexOf(",");
4786
- const decimal = lastDot > lastComma ? "." : ",";
4787
- const thousands = decimal === "." ? "," : ".";
4788
- normalized = cleaned.split(thousands).join("");
4789
- if (decimal === ",") normalized = normalized.replace(",", ".");
4790
- } else if (hasDot) {
4791
- const parts = cleaned.split(".");
4792
- const lastGroup = parts[parts.length - 1] ?? "";
4793
- const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
4794
- if (isThousands) normalized = parts.join("");
4795
- } else if (hasComma) {
4796
- const parts = cleaned.split(",");
4797
- const lastGroup = parts[parts.length - 1] ?? "";
4798
- const isThousands = parts.length > 2 || parts.length === 2 && lastGroup.length === 3;
4799
- normalized = isThousands ? parts.join("") : cleaned.replace(",", ".");
4800
- }
4801
- const n = Number(normalized);
4802
- return Number.isFinite(n) ? n : null;
4803
- }
4804
- __name(parsePriceNumeric, "parsePriceNumeric");
4805
4812
  var PRICE_SKIP_SENTINELS = /* @__PURE__ */ new Set([
4806
4813
  "skip",
4807
4814
  "none",
@@ -7636,11 +7643,16 @@ var PersistedBundleBindingSchema = z22.object({
7636
7643
  * the price comparison when it is absent.
7637
7644
  */
7638
7645
  priceAtPublish: z22.string().trim().min(1).max(MAX_MONEY_LENGTH).optional(),
7646
+ compareAtPriceAtPublish: z22.string().trim().min(1).max(MAX_MONEY_LENGTH).nullable().optional(),
7647
+ /** Seller's offer at publish time, independent of what Shopify charged. */
7648
+ offerAtPublish: z22.object({
7649
+ price: z22.string().trim().min(1).max(MAX_MONEY_LENGTH),
7650
+ compareAtPrice: z22.string().trim().min(1).max(MAX_MONEY_LENGTH).nullable()
7651
+ }).strict().optional(),
7639
7652
  /**
7640
7653
  * How the binding was produced: `mapped` = merchant-confirmed against an
7641
7654
  * existing catalog, `created` = ProductMaker-created "Oferta" variant,
7642
- * `implicit` = legacy exact-structure match (not persisted today; kept
7643
- * for forward compatibility).
7655
+ * `implicit` = exact-structure match.
7644
7656
  */
7645
7657
  mode: z22.enum([
7646
7658
  "mapped",
@@ -11240,6 +11252,28 @@ var CreativeEngineSceneSchema = z38.object({
11240
11252
  timeline: CreativeEngineTimelineSchema.optional(),
11241
11253
  factPaths: z38.array(id2)
11242
11254
  }).strict();
11255
+ var CreativeEngineViralFormatSchema = z38.enum([
11256
+ "pas",
11257
+ "before_after",
11258
+ "demo",
11259
+ "pov",
11260
+ "gift",
11261
+ "concept_vs_result"
11262
+ ]);
11263
+ var CreativeEngineViralPlanSchema = z38.object({
11264
+ format: CreativeEngineViralFormatSchema,
11265
+ /** The scene that shows the product's critical feature working. */
11266
+ mechanismSceneId: id2,
11267
+ /** Two stills of the same subject and framing: rigid surfaces wipe, soft ones (hair, skin, fabric) cut. */
11268
+ beforeAfter: z38.object({
11269
+ beforeSceneId: id2,
11270
+ afterSceneId: id2,
11271
+ surface: z38.enum([
11272
+ "rigid",
11273
+ "soft"
11274
+ ])
11275
+ }).strict().optional()
11276
+ }).strict();
11243
11277
  var CreativeEnginePlanSchema = z38.object({
11244
11278
  revision: z38.number().int().positive(),
11245
11279
  execution: CreativeEngineExecutionSchema.optional(),
@@ -11256,7 +11290,9 @@ var CreativeEnginePlanSchema = z38.object({
11256
11290
  music: z38.literal(false),
11257
11291
  scenes: z38.array(CreativeEngineSceneSchema).min(1).max(CREATIVE_ENGINE_MAX_PLAN_SCENES),
11258
11292
  /** The commercial binding actually applied; absent on guided/historical. */
11259
- commercialExecution: CreativeEngineCommercialExecutionSchema.optional()
11293
+ commercialExecution: CreativeEngineCommercialExecutionSchema.optional(),
11294
+ /** Voiceless «Viral» story; absent on every other narrative. */
11295
+ viral: CreativeEngineViralPlanSchema.optional()
11260
11296
  }).strict();
11261
11297
  var CreativeEngineSpeakerRegionSchema = z38.object({
11262
11298
  x: z38.number().finite().min(0).max(1),
@@ -11776,6 +11812,14 @@ var CreativeEngineStateSchema = z38.object({
11776
11812
  * seller-facing script equals the approved one (no second approval).
11777
11813
  */
11778
11814
  carriedPlanHash: hash.optional(),
11815
+ /**
11816
+ * Who approved without the seller: a «Viral» script has no editable
11817
+ * dialogue, so the system approves it on the seller's behalf.
11818
+ */
11819
+ approvedBy: z38.object({
11820
+ actor: z38.literal("system"),
11821
+ reason: z38.literal("viral_auto")
11822
+ }).strict().optional(),
11779
11823
  waitingStartedAtMs: z38.number().int().nonnegative().optional(),
11780
11824
  pausedMs: z38.number().int().nonnegative()
11781
11825
  }).strict().optional(),
@@ -12000,7 +12044,8 @@ var VideoGeneratorAiEdit = z39.object({
12000
12044
  error: z39.string().optional()
12001
12045
  });
12002
12046
  var VideoCreativeDirection = CreativeEnginePlanSchema.pick({
12003
- guide: true
12047
+ guide: true,
12048
+ viral: true
12004
12049
  });
12005
12050
  var VideoGenerator = z39.object({
12006
12051
  aiEdit: VideoGeneratorAiEdit.nullable().optional(),
@@ -12101,7 +12146,10 @@ var VideoScriptSceneForReview = z39.object({
12101
12146
  /** Objective visual observed in the winner source scene. */
12102
12147
  winnerVisual: z39.string().optional(),
12103
12148
  /** Localized target visual expected to accompany this spoken line. */
12104
- expectedVisual: z39.string().optional()
12149
+ expectedVisual: z39.string().optional(),
12150
+ /** «Viral» (voiceless) plans only: the label burned on screen over this
12151
+ * scene. Shown read-only in place of dialogue; the scene has no voice. */
12152
+ onScreenLabel: z39.string().optional()
12105
12153
  });
12106
12154
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES = 50;
12107
12155
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS = 2e3;
@@ -24001,7 +24049,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24001
24049
  // MCP 8.6.0: + storyteller narrative family and animationStyle axis.
24002
24050
  // MCP 8.10.0: storyteller family blocked (BLOCKED_NARRATIVE_STYLES).
24003
24051
  // MCP 9.1.0: combine current animated-video controls and initial GIF choice.
24004
- "5991b2e897aad7b10c4e38a93e8c58234741498393439cf0228ed9ffd966efef",
24052
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24053
+ "bfe5130b1941f5f0a690949411d83cdbd32c1ee65cc75f2c22568b87bfe90a42",
24005
24054
  "credit_consuming",
24006
24055
  "creative",
24007
24056
  [
@@ -24060,7 +24109,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24060
24109
  // MCP 9.1.0: combine current animated-video controls and initial GIF choice.
24061
24110
  // MCP 12.4.0: landingStrategy narrowed to classic + social_proof.
24062
24111
  // MCP 12.5.0: pain_solution restored to landingStrategy.
24063
- "68a740d97238e720000c16db56ae5748ceb560e342f8fbfe605c954e6284fda7",
24112
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24113
+ "bc90378e921718099faae3f6a11cac4f1fdd81727729d6df581f1f827f94a240",
24064
24114
  "credit_consuming",
24065
24115
  "creative",
24066
24116
  [
@@ -24266,28 +24316,38 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24266
24316
  ], [
24267
24317
  "task_draft"
24268
24318
  ]),
24269
- defineCapability("estimate_creative_variant", "468079ba24e5e0d3c5c707cd54fec64571be429e66cadc12019af4d6e9d10c4e", "none", "read_only", [
24270
- "read"
24271
- ], [
24272
- slot("source_task", true, [
24273
- "sourceTaskId"
24274
- ]),
24275
- slot("creative_kind", true, [
24276
- "kind"
24277
- ]),
24278
- slot("variant_options", false, [
24279
- "videoPreset",
24280
- "videoResolution",
24281
- "nVariants",
24282
- "sectionKey",
24283
- "instructions"
24284
- ])
24285
- ], [
24286
- "task",
24287
- "creative"
24288
- ], [
24289
- "cost_estimate"
24290
- ]),
24319
+ defineCapability(
24320
+ "estimate_creative_variant",
24321
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24322
+ "743d227d050dab27a8b385c9bc2c0c2d5b450e22abfed811c344b65faffb29ab",
24323
+ "none",
24324
+ "read_only",
24325
+ [
24326
+ "read"
24327
+ ],
24328
+ [
24329
+ slot("source_task", true, [
24330
+ "sourceTaskId"
24331
+ ]),
24332
+ slot("creative_kind", true, [
24333
+ "kind"
24334
+ ]),
24335
+ slot("variant_options", false, [
24336
+ "videoPreset",
24337
+ "videoResolution",
24338
+ "nVariants",
24339
+ "sectionKey",
24340
+ "instructions"
24341
+ ])
24342
+ ],
24343
+ [
24344
+ "task",
24345
+ "creative"
24346
+ ],
24347
+ [
24348
+ "cost_estimate"
24349
+ ]
24350
+ ),
24291
24351
  defineCapability("estimate_market_study_cost", "d1fbe8ead642d481258c419a1eed059f9c8188d1cd9f2d4eed12e202fc8800a4", "none", "read_only", [
24292
24352
  "read"
24293
24353
  ], [
@@ -24620,7 +24680,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24620
24680
  // MCP 8.6.0: + storyteller narrative family and animationStyle axis.
24621
24681
  // MCP 8.10.0: storyteller family blocked (BLOCKED_NARRATIVE_STYLES).
24622
24682
  // MCP 9.1.0: combine current animated-video controls and initial GIF choice.
24623
- "66dee35d59da0e88e72e24c503f3f1dc46c17c1162d98d48705e2bfe552f3f02",
24683
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
24684
+ "0669339f0e89332c23588c9a91be31e4700a655367beaa5945569fe329cbf5b9",
24624
24685
  "credit_consuming",
24625
24686
  "creative",
24626
24687
  [
@@ -25399,42 +25460,52 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
25399
25460
  ], [
25400
25461
  "media_upload_session"
25401
25462
  ], MCP_ONLY_CHANNEL_EXPOSURE),
25402
- defineCapability("resolve_pending_action", "a7fef1e3299c2bfb387a16b3e1e243fba8df1db961ebc1f27d2119209124c293", "credit_consuming", "creative", [
25463
+ defineCapability(
25464
+ "resolve_pending_action",
25465
+ // MCP 12.8.0: + manual-only, cohort-gated «viral» preset/angle narrative.
25466
+ "bba3af0b7022b79ba4859c7d6b880e835459cb23095d22147cb17127e8fb0dc9",
25403
25467
  "credit_consuming",
25404
- "state_change"
25405
- ], [
25406
- slot("task", true, [
25407
- "taskId"
25408
- ]),
25409
- slot("action", true, [
25410
- "action"
25411
- ], [
25412
- "actionKind"
25413
- ]),
25414
- slot("action_payload", false, [], [
25415
- "userChoice",
25416
- "selectedAngleIndex",
25417
- "confirmedProductNames",
25418
- "customAngle",
25419
- "painPoints",
25420
- "benefits",
25421
- "features",
25422
- "useMultiSceneShowcase",
25423
- "gapDurationSeconds",
25424
- "narrativeSelection",
25425
- "angleId",
25426
- "content",
25427
- "creativeDirection",
25428
- "actor",
25429
- "voiceovers",
25430
- "visualDirections"
25431
- ])
25432
- ], [
25433
- "task",
25434
- "pending_action"
25435
- ], [
25436
- "task"
25437
- ]),
25468
+ "creative",
25469
+ [
25470
+ "credit_consuming",
25471
+ "state_change"
25472
+ ],
25473
+ [
25474
+ slot("task", true, [
25475
+ "taskId"
25476
+ ]),
25477
+ slot("action", true, [
25478
+ "action"
25479
+ ], [
25480
+ "actionKind"
25481
+ ]),
25482
+ slot("action_payload", false, [], [
25483
+ "userChoice",
25484
+ "selectedAngleIndex",
25485
+ "confirmedProductNames",
25486
+ "customAngle",
25487
+ "painPoints",
25488
+ "benefits",
25489
+ "features",
25490
+ "useMultiSceneShowcase",
25491
+ "gapDurationSeconds",
25492
+ "narrativeSelection",
25493
+ "angleId",
25494
+ "content",
25495
+ "creativeDirection",
25496
+ "actor",
25497
+ "voiceovers",
25498
+ "visualDirections"
25499
+ ])
25500
+ ],
25501
+ [
25502
+ "task",
25503
+ "pending_action"
25504
+ ],
25505
+ [
25506
+ "task"
25507
+ ]
25508
+ ),
25438
25509
  defineCapability("start_dropshipping_project", "996385df905ed85a933c5726fbebf5a29a98f29364badd8256ff306aff38797c", "state_change", "business", [
25439
25510
  "state_change"
25440
25511
  ], [
@@ -26345,7 +26416,10 @@ var MCP_HIDDEN_NARRATIVE_STYLES = [
26345
26416
  "gap_replication",
26346
26417
  // The blocked storyteller family is not offered, not even when revising an
26347
26418
  // existing script.
26348
- ...BLOCKED_NARRATIVE_STYLES
26419
+ ...BLOCKED_NARRATIVE_STYLES,
26420
+ // «Viral» only renders on the unified engine, whose scripts are reviewed in
26421
+ // place: the previous engine's narrative regeneration cannot produce it.
26422
+ "viral"
26349
26423
  ];
26350
26424
  var McpNarrativeStyleSchema = NarrativeStyle.exclude(MCP_HIDDEN_NARRATIVE_STYLES);
26351
26425
  var MCP_ANGLE_NARRATIVE_STYLES = [
@@ -26359,6 +26433,9 @@ var MCP_ANGLE_NARRATIVE_STYLES = [
26359
26433
  "wild_card",
26360
26434
  "animated_problem_pixar",
26361
26435
  "sassy_product_pixar",
26436
+ // Manual-only, voiceless, unified engine only; the API admits it per user
26437
+ // (`CREATIVE_VIRAL_NARRATIVE_USER_IDS`).
26438
+ "viral",
26362
26439
  "market"
26363
26440
  ];
26364
26441
  var McpAngleNarrativeStyleSchema = NarrativeStyle.extract(MCP_ANGLE_NARRATIVE_STYLES);
@@ -27551,8 +27628,11 @@ var CreativeCompositionLocalManifestSchema = z111.object({
27551
27628
  scenes: z111.array(z111.object({
27552
27629
  id: id3,
27553
27630
  startSec: z111.number().nonnegative(),
27554
- durationSec: z111.number().positive()
27555
- }).strict()).min(1)
27631
+ durationSec: z111.number().positive(),
27632
+ /** «Viral» plans only: the one label the page burns over this scene. */
27633
+ copy: z111.array(z111.string()).optional()
27634
+ }).strict()).min(1),
27635
+ viral: CreativeEngineViralPlanSchema.optional()
27556
27636
  }).strict(),
27557
27637
  planHash: hash2,
27558
27638
  context: CreativeEngineContextBindingSchema,
@@ -30539,7 +30619,7 @@ var ApiClient = class {
30539
30619
  };
30540
30620
 
30541
30621
  // src/index.ts
30542
- var MCP_VERSION = "12.11.0";
30622
+ var MCP_VERSION = "12.12.0";
30543
30623
 
30544
30624
  // src/meta-upload-app.ts
30545
30625
  import { readFileSync } from "fs";
@@ -31550,7 +31630,8 @@ var VideoPresetEnum = VideoPreset.extract([
31550
31630
  "cinematic",
31551
31631
  "wild_card",
31552
31632
  "pixar_problem",
31553
- "pixar_sassy"
31633
+ "pixar_sassy",
31634
+ "viral"
31554
31635
  ]);
31555
31636
  var VideoStructureEnum = VideoStructure;
31556
31637
  var VideoQualityEnum = VideoQuality;
@@ -31582,6 +31663,10 @@ var VIDEO_PRESET_RESOLUTION = {
31582
31663
  videoStyle: "ai_dynamic",
31583
31664
  narrativeStyle: "sassy_product_pixar"
31584
31665
  },
31666
+ viral: {
31667
+ videoStyle: "ai_dynamic",
31668
+ narrativeStyle: "viral"
31669
+ },
31585
31670
  product_showcase: {
31586
31671
  videoStyle: "product_only",
31587
31672
  narrativeStyle: "product_showcase"
@@ -34618,7 +34703,7 @@ var CreateProductTaskInput = z140.object({
34618
34703
  paymentMethods: z140.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago que puede mostrar la landing. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
34619
34704
  productContext: z140.string().max(PRODUCT_CONTEXT_MAX_CHARS).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."),
34620
34705
  productLabel: z140.string().trim().max(80).optional().describe('Opcional. Qu\xE9 es el producto, en pocas palabras (ej. "quita pelusas para ropa"). Es AUTORITATIVO: si lo env\xEDas, la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA detecta el producto desde la imagen.'),
34621
- videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla. Default "auto" (la IA escoge tras analizar el producto). Todos los presets funcionan a 15s (single_call) y 30s (Multiescena); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
34706
+ videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla. Default "auto" (la IA escoge tras analizar el producto). Todos los presets salvo "viral" (solo Multiescena de 15 s) funcionan a 15s (single_call) y 30s (Multiescena); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla), "viral" (video sin voz con r\xF3tulos en pantalla y antes/despu\xE9s; solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
34622
34707
  animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
34623
34708
  durationSeconds: z140.union([
34624
34709
  z140.literal(15),
@@ -34631,7 +34716,7 @@ var CreateProductTaskInput = z140.object({
34631
34716
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
34632
34717
  videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render. En la web se pregunta "\xBFResoluci\xF3n del video?". "480p" = excelente calidad y m\xE1s econ\xF3mico (RECOMENDADO, default si se omite); "720p" = m\xE1xima nitidez, entre 3% y 15% m\xE1s caro seg\xFAn formato y tier. Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 480p).'),
34633
34718
  videoAngleCount: z140.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
34634
- angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
34719
+ angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "viral" (video sin voz: r\xF3tulos en pantalla y antes/despu\xE9s; solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones), "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
34635
34720
  outputs: z140.array(z140.enum([
34636
34721
  "landing",
34637
34722
  "video",
@@ -34741,7 +34826,7 @@ var PendingActionPayload = z140.discriminatedUnion("kind", [
34741
34826
  // an opaque HTTP 400 after the model already believed it had been saved.
34742
34827
  features: z140.array(z140.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
34743
34828
  buyerPersona: z140.string().min(1).max(360).optional(),
34744
- narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
34829
+ narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora. "viral" (sin voz, r\xF3tulos y antes/despu\xE9s; solo Multiescena de 15 s) solo est\xE1 disponible para cuentas habilitadas y tareas del motor nuevo.'),
34745
34830
  actor: z140.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
34746
34831
  actorId: z140.string().max(120).nullable().optional(),
34747
34832
  creativeDirection: z140.string().max(2e3).optional(),
@@ -34754,7 +34839,7 @@ var PendingActionPayload = z140.discriminatedUnion("kind", [
34754
34839
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
34755
34840
  angle: z140.string().min(1).max(480).optional(),
34756
34841
  buyerPersona: z140.string().min(1).max(360).optional(),
34757
- narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
34842
+ narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora. "viral" (sin voz, r\xF3tulos y antes/despu\xE9s; solo Multiescena de 15 s) solo est\xE1 disponible para cuentas habilitadas y tareas del motor nuevo.'),
34758
34843
  actor: z140.string().min(1).max(360).optional(),
34759
34844
  actorId: z140.string().max(120).nullable().optional(),
34760
34845
  creativeDirection: z140.string().max(2e3).optional()
@@ -36914,7 +36999,7 @@ var VideoCreativeSetup = z144.discriminatedUnion("mode", [
36914
36999
  }).strict(),
36915
37000
  z144.object({
36916
37001
  mode: z144.literal("guided"),
36917
- videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas funcionan en Un solo clip y Multiescena.'),
37002
+ videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas salvo "viral" funcionan en Un solo clip y Multiescena. "viral" es un video sin voz (r\xF3tulos en pantalla, antes/despu\xE9s), solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones.'),
36918
37003
  buyerPersona: z144.string().trim().min(1).max(360),
36919
37004
  animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
36920
37005
  presenter: VideoPresenter,
@@ -36936,7 +37021,7 @@ var VideoInput = z144.object({
36936
37021
  generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
36937
37022
  durationSeconds: z144.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
36938
37023
  videoAngleCount: z144.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
36939
- angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
37024
+ angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "viral" (video sin voz: r\xF3tulos en pantalla y antes/despu\xE9s; solo Multiescena de 15 s y solo para cuentas habilitadas; la API rechaza otras combinaciones), "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
36940
37025
  creativeSetup: VideoCreativeSetup.describe("Configuraci\xF3n creativa obligatoria. En guided pregunta narrativa, p\xFAblico, presentador y direcci\xF3n antes de confirmar. Usa automatic s\xF3lo si el usuario deleg\xF3 todo expl\xEDcitamente."),
36941
37026
  videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena (varias tomas concatenadas). Default: single_take.'),
36942
37027
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
@@ -37849,7 +37934,7 @@ var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
37849
37934
  });
37850
37935
  function registerScriptReviewTools(server, api) {
37851
37936
  server.registerTool("get_video_script", {
37852
- description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual? }], error? }. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192 consulta `get_task_status` antes de ofrecer recuperaci\xF3n. No regeneres autom\xE1ticamente una tarea terminal.\n\nANGLE KEY: usa las claves expl\xEDcitas de reviewNextAction.calls, incluso si s\xF3lo seleccionaste un candidato. Cuando uno est\xE9 ready, detente en ese \xE1ngulo y espera la decisi\xF3n antes de consultar otro.',
37937
+ description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual?, onScreenLabel? }], error? }. En videos \xABViral\xBB (sin voz) cada escena trae `onScreenLabel`: mu\xE9stralo como \xABTexto en pantalla\xBB; su `dialogue` viene vac\xEDo y no pidas di\xE1logo para esas escenas. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192 consulta `get_task_status` antes de ofrecer recuperaci\xF3n. No regeneres autom\xE1ticamente una tarea terminal.\n\nANGLE KEY: usa las claves expl\xEDcitas de reviewNextAction.calls, incluso si s\xF3lo seleccionaste un candidato. Cuando uno est\xE9 ready, detente en ese \xE1ngulo y espera la decisi\xF3n antes de consultar otro.',
37853
37938
  inputSchema: GetVideoScriptInput.shape,
37854
37939
  annotations: READS_INTERNAL
37855
37940
  }, async (input) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "12.11.0",
3
+ "version": "12.12.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "ProductMaker MCP server — cost products, generate landing pages, UGC videos, and ad creatives, and publish to Shopify, Meta Ads, and TikTok Ads.",