@productmaker/mcp 7.2.0 → 8.0.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/stdio.js CHANGED
@@ -3631,11 +3631,12 @@ var FreeformLandingConfigSchema = z21.object({
3631
3631
  showVariantPicker: z21.boolean().optional(),
3632
3632
  /**
3633
3633
  * Suppress the native Shopify buy form (the `BUY_FORM_MARKER` block). The page
3634
- * CTAs already carry `data-cl-buy-trigger` → they open the ReleaseIt COD popup,
3635
- * so on ReleaseIt-only stores the native add-to-cart form is a redundant second
3636
- * buy path (it rendered as a bare "price + Comprar" block). When true the
3637
- * assembler omits the marker entirely. Undefined/false = keep the native form
3638
- * (backward compatible with already-assembled configs).
3634
+ * CTAs already carry `data-cl-buy-trigger` → they open the installed COD
3635
+ * provider's popup (Releasit or EasySell), so on COD-provider stores the
3636
+ * native add-to-cart form is a redundant second buy path (it rendered as a
3637
+ * bare "price + Comprar" block). When true the assembler omits the marker
3638
+ * entirely. Undefined/false = keep the native form (backward compatible with
3639
+ * already-assembled configs).
3639
3640
  */
3640
3641
  hideNativeBuyForm: z21.boolean().optional()
3641
3642
  });
@@ -5423,6 +5424,17 @@ var CodeLandingThemeSetupResponse = z28.discriminatedUnion("status", [
5423
5424
  themeEditorDeepLink: z28.string().url(),
5424
5425
  shopDomain: z28.string()
5425
5426
  }),
5427
+ z28.object({
5428
+ /**
5429
+ * The block is missing and the store has NO products yet. Shopify's theme
5430
+ * editor cannot add an app block to a product template with nothing to
5431
+ * preview (it answers "there is a problem with the app block"), so there
5432
+ * is deliberately no deep link: the seller publishes first, and the
5433
+ * publish response carries the link aimed at the product it created.
5434
+ */
5435
+ status: z28.literal("setup_after_publish"),
5436
+ shopDomain: z28.string()
5437
+ }),
5426
5438
  z28.object({
5427
5439
  /** Not a code-landing task — the gate does not apply. */
5428
5440
  status: z28.literal("not_applicable"),
@@ -6925,7 +6937,10 @@ var ChatParseEstimationOptions = z34.object({}).strict();
6925
6937
  var CodeLandingEditEstimationOptions = z34.object({}).strict();
6926
6938
  var ServiceCreativeEstimationOptions = z34.object({
6927
6939
  mediaAssetCount: z34.number().int().min(0).max(8).optional(),
6928
- uploadedVideoDurationSeconds: z34.number().min(0).max(240).optional()
6940
+ uploadedVideoDurationSeconds: z34.number().min(0).max(240).optional(),
6941
+ /** Quality the panels render at (its registry model sets the per-second
6942
+ * price). Absent = economy, the pre-quality service default. */
6943
+ videoQuality: VideoQuality.optional()
6929
6944
  });
6930
6945
  var ActorGridEstimationOptions = z34.object({}).strict();
6931
6946
  var CostEstimationRequest = z34.discriminatedUnion("type", [
@@ -7695,7 +7710,18 @@ var KIE_SUBMIT_IMAGE_TASK_TARGETS = [
7695
7710
  "rapid_master_anchor",
7696
7711
  "clean_product_image",
7697
7712
  "single_call_anchor",
7698
- "product_view_reference"
7713
+ "product_view_reference",
7714
+ // Generated service-video presenter (text-to-image portrait). Task-owned, so
7715
+ // it lives here and not beside `actor_candidate`; it mirrors that target's
7716
+ // model, resolution and recovery policy. The fan-in resumes the service init
7717
+ // (`dispatchServiceActor`, refKey prefix `service_actor:`).
7718
+ "service_actor",
7719
+ // First frame of a generated service B-roll panel: image-to-image from the
7720
+ // service photo the planner cited, cleaned of overlaid text/graphics and
7721
+ // fitted to the shot. Mirrors `rapid_panel`'s model tier and recovery
7722
+ // policy. The same fan-in waits for the whole expected image set
7723
+ // (`dispatchServiceActor`, refKey prefix `service_broll_anchor:`).
7724
+ "service_broll_anchor"
7699
7725
  ];
7700
7726
  var ACTOR_CANDIDATE_TARGET = "actor_candidate";
7701
7727
  var ANY_KIE_SUBMIT_IMAGE_TARGETS = [
@@ -9617,6 +9643,12 @@ var DEFAULT_PRICING = {
9617
9643
  ourCostCents: 0.01,
9618
9644
  userPriceCents: 0.02
9619
9645
  },
9646
+ // Service reels harvested from the business's own public profile (per second,
9647
+ // same Whisper-1 rate). Separate action so the ledger names the source.
9648
+ "openai:service-social-transcribe": {
9649
+ ourCostCents: 0.01,
9650
+ userPriceCents: 0.02
9651
+ },
9620
9652
  // User-uploaded service reference/competitor analysis (per second, same Whisper-1 rate).
9621
9653
  // This is a separate action because its ledger entries identify the analysis source.
9622
9654
  "openai:service-reference-transcribe": {
@@ -10756,6 +10788,11 @@ var DECLARATION = DELIVERY_FAMILIES.map((family) => [
10756
10788
  ])
10757
10789
  ]);
10758
10790
 
10791
+ // ../../packages/types/src/seller-prohibitions.ts
10792
+ var MARKER = String.raw`(?:no|nunca|jam[aá]s|prohibido|evita[r]?)(?:\s*:)?\s`;
10793
+ var PROHIBITION_AT_START = new RegExp(String.raw`^(?:[-•*]\s*)?(${MARKER}[\s\S]*)$`, "iu");
10794
+ var PROHIBITION_AFTER_LABEL = new RegExp(String.raw`^(?:[-•*]\s*)?[^:.!?\n]{1,40}:\s*(${MARKER}[\s\S]*)$`, "iu");
10795
+
10759
10796
  // ../../packages/types/src/task-type.ts
10760
10797
  import { z as z50 } from "zod";
10761
10798
  var TaskTypeSchema = z50.enum([
@@ -13337,7 +13374,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13337
13374
  "task",
13338
13375
  "product"
13339
13376
  ]),
13340
- defineCapability("create_service_video", "40551b8c5d430a494e94bc40a91f265327a2ff5f68e97160559f5219d74d8786", "credit_consuming", "creative", [
13377
+ defineCapability("create_service_video", "863884c1af5de3e168cbbe825ea3961901c84dae1899ca400f8f7fa01df91c0a", "credit_consuming", "creative", [
13341
13378
  "credit_consuming",
13342
13379
  "state_change"
13343
13380
  ], [
@@ -13361,7 +13398,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13361
13398
  ]),
13362
13399
  slot("video_preset", false, [
13363
13400
  "videoPreset"
13364
- ])
13401
+ ]),
13402
+ // MCP-only for now: WhatsApp's service flow keeps the economy default.
13403
+ slot("video_quality", false, [
13404
+ "videoQuality"
13405
+ ], [])
13365
13406
  ], [
13366
13407
  "service_context"
13367
13408
  ], [
@@ -14155,7 +14196,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
14155
14196
  ], [
14156
14197
  "meta_upload_session"
14157
14198
  ], WHATSAPP_ONLY_CHANNEL_EXPOSURE),
14158
- defineCapability("request_media_upload", "e91cda1b2d9e44cecf28990b8018ce535ae4e9e6594fa80f503a1bf69d7146ee", "none", "creative", [
14199
+ defineCapability("request_media_upload", "9a50a4647c61f97fb12bbb9b25f7660f392e3cd9825151735cd66292058882ea", "none", "creative", [
14159
14200
  "state_change"
14160
14201
  ], [
14161
14202
  slot("media_kind", true, [
@@ -14900,6 +14941,81 @@ var WhatsAppPresentationManifestSchema = z67.object({
14900
14941
  }
14901
14942
  });
14902
14943
 
14944
+ // ../../packages/types/src/flight-recorder.ts
14945
+ import { z as z68 } from "zod";
14946
+ var FlightRecorderGenerationTypeSchema = z68.enum([
14947
+ "initial",
14948
+ "regeneration",
14949
+ "edit",
14950
+ "retry"
14951
+ ]);
14952
+ var FlightRecorderProviderSchema = z68.enum([
14953
+ "kie",
14954
+ "fal"
14955
+ ]);
14956
+ var FlightRecorderElementSchema = z68.object({
14957
+ name: z68.string().optional(),
14958
+ description: z68.string().optional(),
14959
+ frontalImageUrl: z68.string().optional(),
14960
+ referenceImageUrls: z68.array(z68.string()).optional(),
14961
+ videoUrl: z68.string().optional()
14962
+ });
14963
+ var FlightRecorderDistillationSchema = z68.object({
14964
+ actorGender: z68.enum([
14965
+ "female",
14966
+ "male",
14967
+ "mixed"
14968
+ ]).or(z68.string()).optional(),
14969
+ voiceId: z68.string().optional(),
14970
+ cameraMotion: z68.string().optional()
14971
+ }).catchall(z68.unknown());
14972
+ var FlightRecorderEntrySchema = z68.object({
14973
+ schemaVersion: z68.literal(1).optional(),
14974
+ id: z68.string().min(1),
14975
+ taskId: z68.string().min(1),
14976
+ runId: z68.string().min(1),
14977
+ sequence: z68.number().int().nonnegative(),
14978
+ timestamp: z68.string().min(1),
14979
+ provider: FlightRecorderProviderSchema.or(z68.string()),
14980
+ model: z68.string().min(1),
14981
+ prompt: z68.string(),
14982
+ durationSeconds: z68.number().nonnegative(),
14983
+ aspectRatio: z68.string().optional(),
14984
+ resolution: z68.string().optional(),
14985
+ startImageUrl: z68.string().optional(),
14986
+ endImageUrl: z68.string().optional(),
14987
+ generateAudio: z68.boolean().optional(),
14988
+ // Correlation & pipeline metadata
14989
+ angleKey: z68.string().optional(),
14990
+ sceneIndex: z68.number().int().nonnegative().optional(),
14991
+ generationType: FlightRecorderGenerationTypeSchema,
14992
+ operationId: z68.string().min(1).optional(),
14993
+ revisionId: z68.string().min(1).optional(),
14994
+ attemptNumber: z68.number().int().nonnegative().default(1),
14995
+ // Elements & Distillation
14996
+ elements: z68.array(FlightRecorderElementSchema).optional(),
14997
+ distillation: FlightRecorderDistillationSchema.optional(),
14998
+ // Raw payload (sanitized of secrets)
14999
+ rawPayload: z68.record(z68.unknown())
15000
+ });
15001
+ var FlightRecorderQuerySchema = z68.object({
15002
+ taskId: z68.string().min(1),
15003
+ runId: z68.string().optional(),
15004
+ sceneIndex: z68.number().int().nonnegative().optional(),
15005
+ angleKey: z68.string().optional(),
15006
+ generationType: FlightRecorderGenerationTypeSchema.optional(),
15007
+ cursor: z68.number().int().nonnegative().optional(),
15008
+ limit: z68.number().int().positive().optional()
15009
+ });
15010
+ var FlightRecorderResponseSchema = z68.object({
15011
+ taskId: z68.string().min(1),
15012
+ runId: z68.string().min(1),
15013
+ entries: z68.array(FlightRecorderEntrySchema),
15014
+ lastCall: FlightRecorderEntrySchema.nullable(),
15015
+ count: z68.number().int().nonnegative(),
15016
+ nextCursor: z68.number().int().nonnegative().nullable()
15017
+ });
15018
+
14903
15019
  // src/response-body.ts
14904
15020
  var ResponseBodyTooLargeError = class extends Error {
14905
15021
  static {
@@ -15139,7 +15255,7 @@ var ApiClient = class {
15139
15255
  };
15140
15256
 
15141
15257
  // src/index.ts
15142
- var MCP_VERSION = "7.2.0";
15258
+ var MCP_VERSION = "8.0.0";
15143
15259
 
15144
15260
  // src/meta-upload-app.ts
15145
15261
  import { readFileSync } from "fs";
@@ -15211,7 +15327,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
15211
15327
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
15212
15328
 
15213
15329
  // src/tools/tasks.ts
15214
- import { z as z71 } from "zod";
15330
+ import { z as z72 } from "zod";
15215
15331
 
15216
15332
  // src/resolve-image.ts
15217
15333
  import { lookup as dnsLookup } from "dns/promises";
@@ -15772,10 +15888,10 @@ async function resolveMediaRef(ref, opts) {
15772
15888
  __name(resolveMediaRef, "resolveMediaRef");
15773
15889
 
15774
15890
  // src/tools/shared.ts
15775
- import { z as z68 } from "zod";
15776
- var Lang = z68.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
15777
- var Country = z68.string().min(2).max(3);
15778
- var LandingStrategyEnum = z68.enum([
15891
+ import { z as z69 } from "zod";
15892
+ var Lang = z69.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
15893
+ var Country = z69.string().min(2).max(3);
15894
+ var LandingStrategyEnum = z69.enum([
15779
15895
  "auto",
15780
15896
  "classic",
15781
15897
  "pain_solution",
@@ -15784,12 +15900,12 @@ var LandingStrategyEnum = z68.enum([
15784
15900
  "offer_value",
15785
15901
  "lifestyle_identity"
15786
15902
  ]);
15787
- var LandingImageFormatEnum = z68.enum([
15903
+ var LandingImageFormatEnum = z69.enum([
15788
15904
  "9:16",
15789
15905
  "4:5",
15790
15906
  "1:1"
15791
15907
  ]);
15792
- var VideoPresetEnum = z68.enum([
15908
+ var VideoPresetEnum = z69.enum([
15793
15909
  "auto",
15794
15910
  "ugc_dynamic",
15795
15911
  "ugc_how_to",
@@ -15802,21 +15918,21 @@ var VideoPresetEnum = z68.enum([
15802
15918
  "pixar_problem",
15803
15919
  "pixar_sassy"
15804
15920
  ]);
15805
- var VideoStructureEnum = z68.enum([
15921
+ var VideoStructureEnum = z69.enum([
15806
15922
  "single_take",
15807
15923
  "multi_scene"
15808
15924
  ]);
15809
- var VideoQualityEnum = z68.enum([
15925
+ var VideoQualityEnum = z69.enum([
15810
15926
  "economy",
15811
15927
  "medium",
15812
15928
  "pro"
15813
15929
  ]);
15814
- var VideoRouteIdEnum = z68.enum([
15930
+ var VideoRouteIdEnum = z69.enum([
15815
15931
  "single_take",
15816
15932
  "multi_scene",
15817
15933
  "free"
15818
15934
  ]);
15819
- var TaskCreativeVariantVideoPresetEnum = z68.enum([
15935
+ var TaskCreativeVariantVideoPresetEnum = z69.enum([
15820
15936
  "auto",
15821
15937
  "ugc_dynamic",
15822
15938
  "ugc_how_to",
@@ -15887,7 +16003,7 @@ function resolveVideoPreset(preset) {
15887
16003
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
15888
16004
  }
15889
16005
  __name(resolveVideoPreset, "resolveVideoPreset");
15890
- var VideoTierEnum = z68.enum([
16006
+ var VideoTierEnum = z69.enum([
15891
16007
  "basic"
15892
16008
  ]);
15893
16009
  function resolveVideoTier(_tier) {
@@ -15927,22 +16043,22 @@ function assertSemanticVideoDurationCompatibility(structure, quality, durationSe
15927
16043
  }
15928
16044
  }
15929
16045
  __name(assertSemanticVideoDurationCompatibility, "assertSemanticVideoDurationCompatibility");
15930
- var VideoResolutionEnum = z68.enum([
16046
+ var VideoResolutionEnum = z69.enum([
15931
16047
  "480p",
15932
16048
  "720p"
15933
16049
  ]);
15934
- var CreativeGenderEnum = z68.enum([
16050
+ var CreativeGenderEnum = z69.enum([
15935
16051
  "female",
15936
16052
  "male",
15937
16053
  "mixed"
15938
16054
  ]);
15939
- var VideoStyleEnum = z68.enum([
16055
+ var VideoStyleEnum = z69.enum([
15940
16056
  "ugc",
15941
16057
  "cartoon_3d",
15942
16058
  "product_only",
15943
16059
  "ai_dynamic"
15944
16060
  ]);
15945
- var NarrativeStyleEnum = z68.enum([
16061
+ var NarrativeStyleEnum = z69.enum([
15946
16062
  "review",
15947
16063
  "ugc_how_to",
15948
16064
  "problem_product_cta",
@@ -15960,7 +16076,7 @@ var NarrativeStyleEnum = z68.enum([
15960
16076
  "ugc_demo_review",
15961
16077
  "market"
15962
16078
  ]);
15963
- var PublicNarrativeStyleEnum = z68.enum([
16079
+ var PublicNarrativeStyleEnum = z69.enum([
15964
16080
  "review",
15965
16081
  "ugc_how_to",
15966
16082
  "ugc_unboxing_chaos",
@@ -15973,7 +16089,7 @@ var PublicNarrativeStyleEnum = z68.enum([
15973
16089
  "sassy_product_pixar",
15974
16090
  "market"
15975
16091
  ]);
15976
- var VideoModelEnum = z68.enum([
16092
+ var VideoModelEnum = z69.enum([
15977
16093
  "veo",
15978
16094
  "wan",
15979
16095
  "bytedance",
@@ -15981,29 +16097,29 @@ var VideoModelEnum = z68.enum([
15981
16097
  "grok",
15982
16098
  "kling"
15983
16099
  ]);
15984
- var ProductReferenceUserChoiceEnum = z68.enum([
16100
+ var ProductReferenceUserChoiceEnum = z69.enum([
15985
16101
  "same_product",
15986
16102
  "variants",
15987
16103
  "different_products",
15988
16104
  "combo_distinct"
15989
16105
  ]);
15990
- var ProductReferenceCandidateGroupingEnum = z68.enum([
16106
+ var ProductReferenceCandidateGroupingEnum = z69.enum([
15991
16107
  "same_product_same_variant",
15992
16108
  "same_product_different_variants",
15993
16109
  "different_products",
15994
16110
  "unclear"
15995
16111
  ]);
15996
- var ProductReferenceScopeEnum = z68.enum([
16112
+ var ProductReferenceScopeEnum = z69.enum([
15997
16113
  "base",
15998
16114
  "video_view_pack"
15999
16115
  ]);
16000
- var ProductReferenceResolutionDecisionEnum = z68.enum([
16116
+ var ProductReferenceResolutionDecisionEnum = z69.enum([
16001
16117
  "approve",
16002
16118
  "reject",
16003
16119
  "observed_only",
16004
16120
  "correct_view"
16005
16121
  ]);
16006
- var ProductReferenceRejectionReasonEnum = z68.enum([
16122
+ var ProductReferenceRejectionReasonEnum = z69.enum([
16007
16123
  "replacement_requested",
16008
16124
  "wrong_product_identity",
16009
16125
  "wrong_variant",
@@ -16014,13 +16130,13 @@ var ProductReferenceRejectionReasonEnum = z68.enum([
16014
16130
  "not_a_product_photo",
16015
16131
  "other"
16016
16132
  ]);
16017
- var GapDurationChoiceMirror = z68.object({
16018
- angleIndex: z68.number().int().nonnegative(),
16019
- recommendedSec: z68.union([
16020
- z68.literal(15),
16021
- z68.literal(30)
16133
+ var GapDurationChoiceMirror = z69.object({
16134
+ angleIndex: z69.number().int().nonnegative(),
16135
+ recommendedSec: z69.union([
16136
+ z69.literal(15),
16137
+ z69.literal(30)
16022
16138
  ]),
16023
- estimatedDeltaCredits: z68.number().int().nonnegative().optional()
16139
+ estimatedDeltaCredits: z69.number().int().nonnegative().optional()
16024
16140
  });
16025
16141
  function buildSelectedImageUrlsHash(urls) {
16026
16142
  const input = [
@@ -16030,13 +16146,13 @@ function buildSelectedImageUrlsHash(urls) {
16030
16146
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
16031
16147
  }
16032
16148
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
16033
- var ImageCreativeStyleEnum = z68.enum([
16149
+ var ImageCreativeStyleEnum = z69.enum([
16034
16150
  "studio",
16035
16151
  "floating",
16036
16152
  "ingredients",
16037
16153
  "in_use"
16038
16154
  ]);
16039
- var ImageCreativeArchetypeEnum = z68.enum([
16155
+ var ImageCreativeArchetypeEnum = z69.enum([
16040
16156
  "direct_response_product_ad",
16041
16157
  "hero_outcome",
16042
16158
  "offer_value_prop",
@@ -16045,20 +16161,20 @@ var ImageCreativeArchetypeEnum = z68.enum([
16045
16161
  "problem_solution",
16046
16162
  "lifestyle_identity"
16047
16163
  ]);
16048
- var ImageCreativeVisualTreatmentEnum = z68.enum([
16164
+ var ImageCreativeVisualTreatmentEnum = z69.enum([
16049
16165
  "performance_product_ad",
16050
16166
  "premium_dtc_carousel"
16051
16167
  ]);
16052
- var ImageCreativeAspectRatioEnum = z68.enum([
16168
+ var ImageCreativeAspectRatioEnum = z69.enum([
16053
16169
  "1:1",
16054
16170
  "4:5",
16055
16171
  "9:16",
16056
16172
  "16:9"
16057
16173
  ]);
16058
- var ImageRefSchema = z68.object({
16059
- url: z68.string().url().optional().describe('URL p\xFAblica HTTPS de la foto. Ej: una URL de Shopify CDN, Cloudinary, Imgur. \xDAsala cuando el usuario te diga "est\xE1 en X.com/foto.jpg" o cuando la foto ya est\xE9 hospedada.'),
16060
- path: z68.string().min(1).optional().describe('Ruta del archivo en el computador del usuario. Ej: "/Users/maria/Desktop/foto.jpg", "~/Pictures/camiseta.png", "C:\\Users\\Maria\\Desktop\\foto.jpg". El MCP local la lee del disco y la sube. SOLO funciona cuando el MCP corre local (stdio). NO funciona en mcp.productmaker.app (HTTP) \u2014 ah\xED usa `url`.'),
16061
- assetId: z68.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
16174
+ var ImageRefSchema = z69.object({
16175
+ url: z69.string().url().optional().describe('URL p\xFAblica HTTPS de la foto. Ej: una URL de Shopify CDN, Cloudinary, Imgur. \xDAsala cuando el usuario te diga "est\xE1 en X.com/foto.jpg" o cuando la foto ya est\xE9 hospedada.'),
16176
+ path: z69.string().min(1).optional().describe('Ruta del archivo en el computador del usuario. Ej: "/Users/maria/Desktop/foto.jpg", "~/Pictures/camiseta.png", "C:\\Users\\Maria\\Desktop\\foto.jpg". El MCP local la lee del disco y la sube. SOLO funciona cuando el MCP corre local (stdio). NO funciona en mcp.productmaker.app (HTTP) \u2014 ah\xED usa `url`.'),
16177
+ assetId: z69.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
16062
16178
  }).refine((v) => [
16063
16179
  v.url,
16064
16180
  v.path,
@@ -16066,11 +16182,11 @@ var ImageRefSchema = z68.object({
16066
16182
  ].filter(Boolean).length === 1, {
16067
16183
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
16068
16184
  });
16069
- var ImagesInput = z68.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
16185
+ var ImagesInput = z69.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
16070
16186
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
16071
16187
  if (assetCount > 0 && assetCount !== images.length) {
16072
16188
  ctx.addIssue({
16073
- code: z68.ZodIssueCode.custom,
16189
+ code: z69.ZodIssueCode.custom,
16074
16190
  message: "all image entries must use assetId, or all must use URL/path sources"
16075
16191
  });
16076
16192
  }
@@ -16138,14 +16254,14 @@ async function submitCreative(api, opts) {
16138
16254
  });
16139
16255
  }
16140
16256
  __name(submitCreative, "submitCreative");
16141
- var ResearchTargetCountryEnum = z68.enum([
16257
+ var ResearchTargetCountryEnum = z69.enum([
16142
16258
  "CO",
16143
16259
  "MX",
16144
16260
  "PE",
16145
16261
  "EC",
16146
16262
  "CL"
16147
16263
  ]);
16148
- var ResearchCategoryEnum = z68.enum([
16264
+ var ResearchCategoryEnum = z69.enum([
16149
16265
  "auto",
16150
16266
  "automotive",
16151
16267
  "kitchen",
@@ -16170,7 +16286,7 @@ var READS_EXTERNAL = {
16170
16286
  readOnlyHint: true,
16171
16287
  destructiveHint: false,
16172
16288
  idempotentHint: true,
16173
- openWorldHint: true
16289
+ openWorldHint: false
16174
16290
  };
16175
16291
  var CREATES_INTERNAL = {
16176
16292
  readOnlyHint: false,
@@ -16179,6 +16295,24 @@ var CREATES_INTERNAL = {
16179
16295
  openWorldHint: false
16180
16296
  };
16181
16297
  var CREATES_EXTERNAL = {
16298
+ readOnlyHint: false,
16299
+ destructiveHint: false,
16300
+ idempotentHint: false,
16301
+ openWorldHint: false
16302
+ };
16303
+ var CREATES_PAID = {
16304
+ readOnlyHint: false,
16305
+ destructiveHint: true,
16306
+ idempotentHint: false,
16307
+ openWorldHint: false
16308
+ };
16309
+ var CREATES_PAID_OPEN_WORLD = {
16310
+ readOnlyHint: false,
16311
+ destructiveHint: true,
16312
+ idempotentHint: false,
16313
+ openWorldHint: true
16314
+ };
16315
+ var CREATES_OPEN_WORLD = {
16182
16316
  readOnlyHint: false,
16183
16317
  destructiveHint: false,
16184
16318
  idempotentHint: false,
@@ -16194,9 +16328,9 @@ var OVERWRITES_EXTERNAL = {
16194
16328
  readOnlyHint: false,
16195
16329
  destructiveHint: true,
16196
16330
  idempotentHint: false,
16197
- openWorldHint: true
16331
+ openWorldHint: false
16198
16332
  };
16199
- var DailyControlStatusEnum = z68.enum([
16333
+ var DailyControlStatusEnum = z69.enum([
16200
16334
  "ok",
16201
16335
  "sales_unavailable",
16202
16336
  "timezone_unavailable",
@@ -16209,19 +16343,19 @@ var DailyControlStatusEnum = z68.enum([
16209
16343
  "product_missing",
16210
16344
  "store_unreachable"
16211
16345
  ]);
16212
- var DailyControlLightEnum = z68.enum([
16346
+ var DailyControlLightEnum = z69.enum([
16213
16347
  "green",
16214
16348
  "amber",
16215
16349
  "red",
16216
16350
  "none"
16217
16351
  ]);
16218
- var DailyControlVerdictEnum = z68.enum([
16352
+ var DailyControlVerdictEnum = z69.enum([
16219
16353
  "scale",
16220
16354
  "hold",
16221
16355
  "kill",
16222
16356
  "insufficient_sample"
16223
16357
  ]);
16224
- var DailyControlSourceEnum = z68.enum([
16358
+ var DailyControlSourceEnum = z69.enum([
16225
16359
  "shopify",
16226
16360
  "shopify_settling",
16227
16361
  "user",
@@ -17362,29 +17496,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
17362
17496
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
17363
17497
 
17364
17498
  // src/tools/media-presentation.ts
17365
- import { z as z69 } from "zod";
17366
- var HttpsPresentationUrlSchema = z69.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
17499
+ import { z as z70 } from "zod";
17500
+ var HttpsPresentationUrlSchema = z70.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
17367
17501
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
17368
17502
  const hostname = new URL(value).hostname.toLowerCase();
17369
17503
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
17370
17504
  }, "preview URL must be owned by ProductMaker");
17371
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z69.number().int().positive().max(maximum), "positiveIntAtMost");
17372
- var PresentationImageSchema = z69.object({
17373
- kind: z69.literal("image"),
17505
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z70.number().int().positive().max(maximum), "positiveIntAtMost");
17506
+ var PresentationImageSchema = z70.object({
17507
+ kind: z70.literal("image"),
17374
17508
  url: HttpsPresentationUrlSchema,
17375
- mimeType: z69.enum([
17509
+ mimeType: z70.enum([
17376
17510
  "image/jpeg",
17377
17511
  "image/png"
17378
17512
  ]),
17379
17513
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
17380
17514
  width: positiveIntAtMost(16384),
17381
17515
  height: positiveIntAtMost(16384),
17382
- alt: z69.string().trim().min(1).max(240)
17516
+ alt: z70.string().trim().min(1).max(240)
17383
17517
  }).strict();
17384
17518
  var McpMediaPresentationSchema = PresentationImageSchema;
17385
- var GalleryImageSchema = z69.object({
17519
+ var GalleryImageSchema = z70.object({
17386
17520
  url: ProductMakerPreviewUrlSchema,
17387
- alt: z69.string().trim().min(1).max(240)
17521
+ alt: z70.string().trim().min(1).max(240)
17388
17522
  });
17389
17523
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
17390
17524
  async function imageBlocks(image, transport) {
@@ -17534,10 +17668,10 @@ ${summary}`,
17534
17668
  __name(requirePaidCreativeConfirmation, "requirePaidCreativeConfirmation");
17535
17669
 
17536
17670
  // src/tools/winning-product-image.ts
17537
- import { z as z70 } from "zod";
17538
- var WinnerReferenceInput = z70.object({
17539
- runId: z70.string().uuid(),
17540
- candidateSourceId: z70.string().trim().min(1).max(160)
17671
+ import { z as z71 } from "zod";
17672
+ var WinnerReferenceInput = z71.object({
17673
+ runId: z71.string().uuid(),
17674
+ candidateSourceId: z71.string().trim().min(1).max(160)
17541
17675
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
17542
17676
  async function resolveWinnerImages(api, winnerReference, images) {
17543
17677
  if (!winnerReference) return images;
@@ -17574,188 +17708,189 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
17574
17708
  var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
17575
17709
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
17576
17710
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
17577
- var CreateProductTaskInput = z71.object({
17711
+ var CreateProductTaskInput = z72.object({
17578
17712
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
17579
17713
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
17580
- projectId: z71.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
17581
- productUrl: z71.string().url().optional().describe("Opcional. URL de la p\xE1gina del producto (Shopify, AliExpress, Amazon, etc.) para enriquecer el contexto. Si se omite, la IA infiere todo desde la imagen."),
17714
+ projectId: z72.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
17715
+ productUrl: z72.string().url().optional().describe("Opcional. URL de la p\xE1gina del producto (Shopify, AliExpress, Amazon, etc.) para enriquecer el contexto. Si se omite, la IA infiere todo desde la imagen."),
17582
17716
  language: Lang.describe('C\xF3digo de idioma para el contenido generado. Ejemplos: "es", "en", "pt". REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas "es" por default.'),
17583
17717
  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.'),
17584
- price: z71.string().min(1).max(120).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.'),
17585
- compareAtPrice: z71.string().min(1).max(120).optional().describe('Opcional. Precio anterior para comunicar un descuento real en landing e im\xE1genes. Ej. "$129.000" cuando price="$89.900".'),
17586
- offer: z71.string().min(1).max(240).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.'),
17587
- paymentMethods: z71.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.'),
17588
- productContext: z71.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."),
17589
- productLabel: z71.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.'),
17718
+ price: z72.string().min(1).max(120).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.'),
17719
+ compareAtPrice: z72.string().min(1).max(120).optional().describe('Opcional. Precio anterior para comunicar un descuento real en landing e im\xE1genes. Ej. "$129.000" cuando price="$89.900".'),
17720
+ offer: z72.string().min(1).max(240).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.'),
17721
+ paymentMethods: z72.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.'),
17722
+ productContext: z72.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."),
17723
+ productLabel: z72.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.'),
17590
17724
  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), excepto "problem_solution", que requiere 30s Multiescena. 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.'),
17591
- durationSeconds: z71.union([
17592
- z71.literal(15),
17593
- z71.literal(30)
17725
+ durationSeconds: z72.union([
17726
+ z72.literal(15),
17727
+ z72.literal(30)
17594
17728
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
17595
- pauseForAngleReview: z71.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
17596
- aiDecidesAll: z71.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
17729
+ pauseForAngleReview: z72.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
17730
+ aiDecidesAll: z72.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
17597
17731
  videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video. "basic" = "Realista" para 15s; al pedir durationSeconds=30 el sistema selecciona internamente Multiescena. No se expone el tier interno directamente.'),
17598
17732
  videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena. Default: single_take.'),
17599
17733
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
17600
17734
  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).'),
17601
- videoAngleCount: z71.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."),
17735
+ videoAngleCount: z72.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."),
17602
17736
  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.'),
17603
- outputs: z71.array(z71.enum([
17737
+ outputs: z72.array(z72.enum([
17604
17738
  "landing",
17605
17739
  "video",
17606
17740
  "image"
17607
17741
  ])).min(2).max(3).optional().describe(`Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). ${createProductTaskSingleOutputDescription}`),
17608
- competitorScanEnabled: z71.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico. Omitir no autoriza el estudio profundo."),
17609
- replicateWinnerWhenFound: z71.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
17610
- brandId: z71.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer los outputs generados."),
17611
- actorId: z71.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
17742
+ competitorScanEnabled: z72.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico. Omitir no autoriza el estudio profundo."),
17743
+ replicateWinnerWhenFound: z72.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
17744
+ brandId: z72.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer los outputs generados."),
17745
+ actorId: z72.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
17612
17746
  creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en todos los creativos de la task: el presentador del video, las personas fotografiadas en la landing y la persona del anuncio. NO es la voz. M\xE1ndalo en cuanto el usuario lo diga en cualquier momento de la conversaci\xF3n y con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "esto es para hombres"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario recibe lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. "mixed" solo cuando pida expl\xEDcitamente ambos. Si adem\xE1s mandas actorId, el personaje guardado manda sobre este campo.'),
17613
- creativeDirection: z71.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo) que aplica a los outputs de IMAGEN y LANDING (no al video \u2014 el estilo/ambiente del video se dirige con scriptNotes). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Ej. "amarillo y azul, minimalista". M\xE1x 500 caracteres.'),
17614
- headline: z71.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar. Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. Se aplica a las IM\xC1GENES y a la portada de la landing de esta task (el video no lo usa; para el video usa scriptNotes). \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
17615
- subheadline: z71.string().max(160).optional().describe("Opcional. Subt\xEDtulo EXACTO a renderizar, misma regla que headline. Independiente: puedes fijar solo el subt\xEDtulo. M\xE1x 160 caracteres."),
17747
+ creativeDirection: z72.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo) que aplica a los outputs de IMAGEN y LANDING (no al video \u2014 el estilo/ambiente del video se dirige con scriptNotes). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Ej. "amarillo y azul, minimalista". M\xE1x 500 caracteres.'),
17748
+ headline: z72.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar. Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. Se aplica a las IM\xC1GENES y a la portada de la landing de esta task (el video no lo usa; para el video usa scriptNotes). \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
17749
+ subheadline: z72.string().max(160).optional().describe("Opcional. Subt\xEDtulo EXACTO a renderizar, misma regla que headline. Independiente: puedes fijar solo el subt\xEDtulo. M\xE1x 160 caracteres."),
17616
17750
  landingStrategy: LandingStrategyEnum.default("classic").describe('Opcional. Estructura de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "classic" (estructura original probada y recomendada; default del primer rollout), "auto" (la IA decide; experimental), "pain_solution", "social_proof" (Landing Viral: UGC, WhatsApp, Instagram y evidencia social), "benefits_clarity", "offer_value" o "lifestyle_identity". Default "classic".'),
17617
17751
  landingImageFormat: LandingImageFormatEnum.default("9:16").describe('Opcional. Formato/relaci\xF3n de aspecto de las im\xE1genes de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "9:16" (vertical, por defecto), "4:5" (vertical compacto para feed) o "1:1" (cuadrado). Default "9:16".')
17618
17752
  }).strict();
17619
- var CreateServiceVideoInput = z71.object({
17620
- landingUrl: z71.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
17621
- additionalContext: z71.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
17753
+ var CreateServiceVideoInput = z72.object({
17754
+ landingUrl: z72.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
17755
+ additionalContext: z72.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
17622
17756
  language: Lang.describe("Idioma del video: es, en o pt."),
17623
- voiceId: z71.string().trim().min(1).optional().describe('Opcional. Voz de ElevenLabs para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador o env\xEDa un ID concreto de la lista de voces de la web.'),
17624
- brandId: z71.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
17625
- reviewMode: z71.enum([
17757
+ voiceId: z72.string().trim().min(1).optional().describe('Opcional. Voz de ElevenLabs para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador o env\xEDa un ID concreto de la lista de voces de la web.'),
17758
+ brandId: z72.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
17759
+ reviewMode: z72.enum([
17626
17760
  "automatic",
17627
17761
  "guided"
17628
17762
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
17629
- videoPreset: z71.enum([
17763
+ videoPreset: z72.enum([
17630
17764
  "auto",
17631
17765
  "ugc_dynamic",
17632
17766
  "ugc_how_to",
17633
17767
  "cinematic",
17634
17768
  "wild_card"
17635
- ]).default("auto")
17769
+ ]).default("auto"),
17770
+ videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.')
17636
17771
  }).strict();
17637
- var GetTaskStatusInput = z71.object({
17638
- taskId: z71.string().min(1),
17639
- waitSeconds: z71.number().int().min(0).max(120).optional()
17772
+ var GetTaskStatusInput = z72.object({
17773
+ taskId: z72.string().min(1),
17774
+ waitSeconds: z72.number().int().min(0).max(120).optional()
17640
17775
  });
17641
- var ListTasksInput = z71.object({
17642
- limit: z71.number().int().min(1).max(50).optional(),
17643
- offset: z71.number().int().min(0).optional(),
17644
- search: z71.string().optional()
17776
+ var ListTasksInput = z72.object({
17777
+ limit: z72.number().int().min(1).max(50).optional(),
17778
+ offset: z72.number().int().min(0).optional(),
17779
+ search: z72.string().optional()
17645
17780
  });
17646
17781
  var MCP_REVIEW_LIST_FIELD_MAX = 1500;
17647
17782
  var MCP_REVIEW_FEATURE_ITEM_MAX = 240;
17648
- var EditTaskDraftInput = z71.object({
17649
- taskId: z71.string().min(1),
17650
- angleIndex: z71.number().int().min(0),
17651
- angle: z71.object({
17652
- angle: z71.string().min(1).max(480),
17653
- buyerPersona: z71.string().min(1).max(360),
17654
- actor: z71.string().min(1).max(360).optional(),
17655
- actorId: z71.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
17656
- gender: z71.enum([
17783
+ var EditTaskDraftInput = z72.object({
17784
+ taskId: z72.string().min(1),
17785
+ angleIndex: z72.number().int().min(0),
17786
+ angle: z72.object({
17787
+ angle: z72.string().min(1).max(480),
17788
+ buyerPersona: z72.string().min(1).max(360),
17789
+ actor: z72.string().min(1).max(360).optional(),
17790
+ actorId: z72.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
17791
+ gender: z72.enum([
17657
17792
  "female",
17658
17793
  "male"
17659
17794
  ]).optional(),
17660
- scriptNotes: z71.string().max(2e3).optional()
17795
+ scriptNotes: z72.string().max(2e3).optional()
17661
17796
  })
17662
17797
  });
17663
- var PendingActionPayload = z71.discriminatedUnion("kind", [
17664
- z71.object({
17665
- kind: z71.literal("product_reference_set_approval"),
17798
+ var PendingActionPayload = z72.discriminatedUnion("kind", [
17799
+ z72.object({
17800
+ kind: z72.literal("product_reference_set_approval"),
17666
17801
  scope: ProductReferenceScopeEnum.optional(),
17667
- scopeKey: z71.string().min(1).max(120).optional(),
17668
- scopeSnapshotId: z71.string().uuid().optional(),
17669
- expectedScopeHash: z71.string().min(1).max(128).optional(),
17802
+ scopeKey: z72.string().min(1).max(120).optional(),
17803
+ scopeSnapshotId: z72.string().uuid().optional(),
17804
+ expectedScopeHash: z72.string().min(1).max(128).optional(),
17670
17805
  decision: ProductReferenceResolutionDecisionEnum,
17671
17806
  reason: ProductReferenceRejectionReasonEnum.optional(),
17672
- affectedRefKeys: z71.array(z71.string().min(1).max(200)).min(1).optional(),
17673
- affectedPhotoNumbers: z71.array(z71.number().int().positive()).min(1).optional(),
17674
- recoveryAction: z71.enum([
17807
+ affectedRefKeys: z72.array(z72.string().min(1).max(200)).min(1).optional(),
17808
+ affectedPhotoNumbers: z72.array(z72.number().int().positive()).min(1).optional(),
17809
+ recoveryAction: z72.enum([
17675
17810
  "remove",
17676
17811
  "replace",
17677
17812
  "upload",
17678
17813
  "return_to_selection"
17679
17814
  ]).optional()
17680
17815
  }),
17681
- z71.object({
17682
- kind: z71.literal("product_reference_confirmation"),
17683
- selectedPhotoNumbers: z71.array(z71.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
17816
+ z72.object({
17817
+ kind: z72.literal("product_reference_confirmation"),
17818
+ selectedPhotoNumbers: z72.array(z72.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
17684
17819
  userChoice: ProductReferenceUserChoiceEnum.optional(),
17685
- confirmedProductNames: z71.array(z71.string().min(1).max(120)).min(2).max(8).optional(),
17820
+ confirmedProductNames: z72.array(z72.string().min(1).max(120)).min(2).max(8).optional(),
17686
17821
  videoStructure: VideoStructureEnum.optional().describe("Opcional. Formato para reanudar el video: single_take (Un solo clip, generado completo; puede incluir cambios de plano) o multi_scene (Multiescena). El backend vuelve a validar que sea compatible con el agrupamiento confirmado."),
17687
17822
  videoQuality: VideoQualityEnum.optional().describe("Opcional. Calidad para reanudar el video: economy (Econ\xF3mico), medium (Medio) o pro. El proveedor se elige internamente y el backend vuelve a cotizar la ruta."),
17688
- useMultiSceneShowcase: z71.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
17823
+ useMultiSceneShowcase: z72.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
17689
17824
  }),
17690
- z71.object({
17691
- kind: z71.literal("angle_review_approval"),
17825
+ z72.object({
17826
+ kind: z72.literal("angle_review_approval"),
17692
17827
  // All edits are optional — empty action body just approves the
17693
17828
  // backend-generated draft as-is. Field shapes mirror the angle-review
17694
17829
  // request contracts in @packages/types/wizard.ts; the handler routes to
17695
17830
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
17696
- customAngle: z71.string().min(1).max(480).optional(),
17831
+ customAngle: z72.string().min(1).max(480).optional(),
17697
17832
  // Keep the shared MCP action within the strictest downstream contract:
17698
17833
  // autopilot/image resume endpoints cap these fields at 1500 characters.
17699
- painPoints: z71.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
17700
- benefits: z71.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
17834
+ painPoints: z72.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
17835
+ benefits: z72.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
17701
17836
  // Same policy as the two fields above: the strictest downstream contract
17702
17837
  // wins. The image endpoint caps each feature at 240 while landing/video
17703
17838
  // accept 300, and this single action routes to whichever the task is — so
17704
17839
  // accepting 300 here turns a 250-character feature on an image task into
17705
17840
  // an opaque HTTP 400 after the model already believed it had been saved.
17706
- features: z71.array(z71.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
17707
- buyerPersona: z71.string().min(1).max(360).optional(),
17841
+ features: z72.array(z72.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
17842
+ buyerPersona: z72.string().min(1).max(360).optional(),
17708
17843
  narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) requiere Multiescena de 30s: en un video de 15s en formato Un solo clip el servidor la rechaza.'),
17709
- actor: z71.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."),
17710
- actorId: z71.string().max(120).nullable().optional(),
17711
- creativeDirection: z71.string().max(2e3).optional(),
17712
- selectedAngleNumbers: z71.array(z71.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
17713
- angleEdits: z71.array(z71.object({
17714
- angleNumber: z71.number().int().positive(),
17715
- narrativeSelection: z71.enum([
17844
+ actor: z72.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."),
17845
+ actorId: z72.string().max(120).nullable().optional(),
17846
+ creativeDirection: z72.string().max(2e3).optional(),
17847
+ selectedAngleNumbers: z72.array(z72.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
17848
+ angleEdits: z72.array(z72.object({
17849
+ angleNumber: z72.number().int().positive(),
17850
+ narrativeSelection: z72.enum([
17716
17851
  "market",
17717
17852
  "guided"
17718
17853
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
17719
- angle: z71.string().min(1).max(480).optional(),
17720
- buyerPersona: z71.string().min(1).max(360).optional(),
17854
+ angle: z72.string().min(1).max(480).optional(),
17855
+ buyerPersona: z72.string().min(1).max(360).optional(),
17721
17856
  narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) requiere Multiescena de 30s: en un video de 15s en formato Un solo clip el servidor la rechaza.'),
17722
- actor: z71.string().min(1).max(360).optional(),
17723
- actorId: z71.string().max(120).nullable().optional(),
17724
- creativeDirection: z71.string().max(2e3).optional()
17857
+ actor: z72.string().min(1).max(360).optional(),
17858
+ actorId: z72.string().max(120).nullable().optional(),
17859
+ creativeDirection: z72.string().max(2e3).optional()
17725
17860
  }).strict()).max(3).optional().describe("Ediciones independientes por n\xFAmero visible de \xE1ngulo. S\xF3lo se aceptan para \xE1ngulos incluidos en selectedAngleNumbers (o en la selecci\xF3n por defecto)."),
17726
- gapDurationSeconds: z71.union([
17727
- z71.literal(15),
17728
- z71.literal(30)
17861
+ gapDurationSeconds: z72.union([
17862
+ z72.literal(15),
17863
+ z72.literal(30)
17729
17864
  ]).optional().describe("Opcional. Solo para aceptar expl\xEDcitamente la recomendaci\xF3n gapDurationChoice del status. 30 env\xEDa el override double_30s para el \xE1ngulo recomendado; 15 u omitido conserva la duraci\xF3n cotizada.")
17730
17865
  }),
17731
- z71.object({
17732
- kind: z71.literal("service_angle_approval"),
17733
- angleId: z71.string().uuid().optional(),
17734
- angleNumber: z71.number().int().positive().optional(),
17735
- content: z71.string().min(1).max(480).optional(),
17736
- creativeDirection: z71.string().min(1).max(1500).optional(),
17737
- actor: z71.string().min(1).max(360).optional()
17866
+ z72.object({
17867
+ kind: z72.literal("service_angle_approval"),
17868
+ angleId: z72.string().uuid().optional(),
17869
+ angleNumber: z72.number().int().positive().optional(),
17870
+ content: z72.string().min(1).max(480).optional(),
17871
+ creativeDirection: z72.string().min(1).max(1500).optional(),
17872
+ actor: z72.string().min(1).max(360).optional()
17738
17873
  }),
17739
- z71.object({
17740
- kind: z71.literal("service_script_approval"),
17741
- voiceovers: z71.record(z71.string(), z71.string().min(1).max(600)).optional(),
17742
- visualDirections: z71.record(z71.string(), z71.string().min(1).max(1200)).optional(),
17743
- voiceoversByScene: z71.record(z71.string(), z71.string().min(1).max(600)).optional(),
17744
- visualDirectionsByScene: z71.record(z71.string(), z71.string().min(1).max(1200)).optional()
17874
+ z72.object({
17875
+ kind: z72.literal("service_script_approval"),
17876
+ voiceovers: z72.record(z72.string(), z72.string().min(1).max(600)).optional(),
17877
+ visualDirections: z72.record(z72.string(), z72.string().min(1).max(1200)).optional(),
17878
+ voiceoversByScene: z72.record(z72.string(), z72.string().min(1).max(600)).optional(),
17879
+ visualDirectionsByScene: z72.record(z72.string(), z72.string().min(1).max(1200)).optional()
17745
17880
  })
17746
17881
  ]);
17747
- var ResolvePendingActionInput = z71.object({
17748
- taskId: z71.string().min(1),
17882
+ var ResolvePendingActionInput = z72.object({
17883
+ taskId: z72.string().min(1),
17749
17884
  action: PendingActionPayload
17750
17885
  }).strict();
17751
17886
  function resolveVariantConfirmVideoTier(action) {
17752
17887
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
17753
17888
  }
17754
17889
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
17755
- var StatusForResolveSchema = z71.object({
17890
+ var StatusForResolveSchema = z72.object({
17756
17891
  // Metadata used to select the backend resume contract. Older API responses
17757
17892
  // may omit these fields, so the resolver keeps the generic fallback.
17758
- kind: z71.enum([
17893
+ kind: z72.enum([
17759
17894
  "autopilot",
17760
17895
  "video",
17761
17896
  "image",
@@ -17763,18 +17898,18 @@ var StatusForResolveSchema = z71.object({
17763
17898
  "mix",
17764
17899
  "service"
17765
17900
  ]).optional(),
17766
- selectedOutputs: z71.array(z71.enum([
17901
+ selectedOutputs: z72.array(z72.enum([
17767
17902
  "landing",
17768
17903
  "video",
17769
17904
  "image"
17770
17905
  ])).optional(),
17771
- videoAngleCount: z71.number().int().min(1).max(3).optional(),
17772
- ugcFormat: z71.enum([
17906
+ videoAngleCount: z72.number().int().min(1).max(3).optional(),
17907
+ ugcFormat: z72.enum([
17773
17908
  "single_8s",
17774
17909
  "single_15s",
17775
17910
  "double_30s"
17776
17911
  ]).optional(),
17777
- videoStyle: z71.enum([
17912
+ videoStyle: z72.enum([
17778
17913
  "ugc",
17779
17914
  "cartoon_3d",
17780
17915
  "product_only",
@@ -17783,7 +17918,7 @@ var StatusForResolveSchema = z71.object({
17783
17918
  videoStructure: VideoStructureEnum.optional(),
17784
17919
  videoQuality: VideoQualityEnum.optional(),
17785
17920
  videoRouteId: VideoRouteIdEnum.optional(),
17786
- videoModel: z71.enum([
17921
+ videoModel: z72.enum([
17787
17922
  "veo",
17788
17923
  "wan",
17789
17924
  "bytedance",
@@ -17791,71 +17926,71 @@ var StatusForResolveSchema = z71.object({
17791
17926
  "grok",
17792
17927
  "kling"
17793
17928
  ]).optional(),
17794
- videoTier: z71.enum([
17929
+ videoTier: z72.enum([
17795
17930
  "legacy",
17796
17931
  "standard",
17797
17932
  "pro",
17798
17933
  "single_call"
17799
17934
  ]).optional(),
17800
- videoResolution: z71.enum([
17935
+ videoResolution: z72.enum([
17801
17936
  "480p",
17802
17937
  "720p"
17803
17938
  ]).optional(),
17804
17939
  narrativeStyle: NarrativeStyleEnum.optional(),
17805
- pauseForVideoScriptReview: z71.boolean().optional(),
17806
- pendingUserAction: z71.object({
17807
- kind: z71.string(),
17808
- candidateGrouping: z71.string().optional(),
17809
- selectedImageUrls: z71.array(z71.string()).optional(),
17810
- proposedProductNames: z71.array(z71.string()).optional(),
17940
+ pauseForVideoScriptReview: z72.boolean().optional(),
17941
+ pendingUserAction: z72.object({
17942
+ kind: z72.string(),
17943
+ candidateGrouping: z72.string().optional(),
17944
+ selectedImageUrls: z72.array(z72.string()).optional(),
17945
+ proposedProductNames: z72.array(z72.string()).optional(),
17811
17946
  // Adaptive reference questions are server-owned. Echo only the evidence
17812
17947
  // identity and the choices shown by the current snapshot; never accept a
17813
17948
  // client-supplied reference set as authorization.
17814
- options: z71.array(ProductReferenceUserChoiceEnum).max(4).optional(),
17815
- mode: z71.enum([
17949
+ options: z72.array(ProductReferenceUserChoiceEnum).max(4).optional(),
17950
+ mode: z72.enum([
17816
17951
  "question",
17817
17952
  "visual_recovery"
17818
17953
  ]).optional(),
17819
17954
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
17820
- canKeepSelection: z71.boolean().optional(),
17821
- decisionKey: z71.string().optional(),
17822
- questionOrdinal: z71.number().int().min(1).max(5).optional(),
17823
- questionCeiling: z71.union([
17824
- z71.literal(3),
17825
- z71.literal(5)
17955
+ canKeepSelection: z72.boolean().optional(),
17956
+ decisionKey: z72.string().optional(),
17957
+ questionOrdinal: z72.number().int().min(1).max(5).optional(),
17958
+ questionCeiling: z72.union([
17959
+ z72.literal(3),
17960
+ z72.literal(5)
17826
17961
  ]).optional(),
17827
- referenceEvidenceVersion: z71.number().int().positive().optional(),
17828
- expectedEvidenceHash: z71.string().optional(),
17829
- question: z71.object({
17830
- prompt: z71.string().min(1).max(240),
17831
- helpText: z71.string().min(1).max(300).optional(),
17832
- options: z71.array(z71.object({
17962
+ referenceEvidenceVersion: z72.number().int().positive().optional(),
17963
+ expectedEvidenceHash: z72.string().optional(),
17964
+ question: z72.object({
17965
+ prompt: z72.string().min(1).max(240),
17966
+ helpText: z72.string().min(1).max(300).optional(),
17967
+ options: z72.array(z72.object({
17833
17968
  value: ProductReferenceUserChoiceEnum,
17834
- label: z71.string().min(1).max(120),
17835
- description: z71.string().min(1).max(240).optional()
17969
+ label: z72.string().min(1).max(120),
17970
+ description: z72.string().min(1).max(240).optional()
17836
17971
  })).min(2).max(4)
17837
17972
  }).optional(),
17838
17973
  scope: ProductReferenceScopeEnum.optional(),
17839
- scopeKey: z71.string().optional(),
17840
- scopeSnapshotId: z71.string().uuid().optional(),
17841
- scopeHash: z71.string().optional(),
17842
- baseReferenceSetHash: z71.string().optional(),
17843
- phase: z71.enum([
17974
+ scopeKey: z72.string().optional(),
17975
+ scopeSnapshotId: z72.string().uuid().optional(),
17976
+ scopeHash: z72.string().optional(),
17977
+ baseReferenceSetHash: z72.string().optional(),
17978
+ phase: z72.enum([
17844
17979
  "preparation",
17845
17980
  "final"
17846
17981
  ]).optional(),
17847
- selectedRefKeys: z71.array(z71.string().min(1).max(200)).optional(),
17848
- allowedDecisions: z71.array(ProductReferenceResolutionDecisionEnum).optional(),
17849
- previews: z71.array(z71.object({
17850
- refKey: z71.string().min(1).max(200)
17982
+ selectedRefKeys: z72.array(z72.string().min(1).max(200)).optional(),
17983
+ allowedDecisions: z72.array(ProductReferenceResolutionDecisionEnum).optional(),
17984
+ previews: z72.array(z72.object({
17985
+ refKey: z72.string().min(1).max(200)
17851
17986
  }).passthrough()).optional(),
17852
- customAngleDraft: z71.string().optional(),
17853
- painPointsDraft: z71.string().optional(),
17854
- benefitsDraft: z71.string().optional(),
17855
- featuresDraft: z71.array(z71.string()).optional(),
17856
- angleOptions: z71.array(z71.object({
17857
- index: z71.number().int().nonnegative(),
17858
- angle: z71.string().min(1)
17987
+ customAngleDraft: z72.string().optional(),
17988
+ painPointsDraft: z72.string().optional(),
17989
+ benefitsDraft: z72.string().optional(),
17990
+ featuresDraft: z72.array(z72.string()).optional(),
17991
+ angleOptions: z72.array(z72.object({
17992
+ index: z72.number().int().nonnegative(),
17993
+ angle: z72.string().min(1)
17859
17994
  }).passthrough()).min(1).max(5).optional(),
17860
17995
  // Recommendation consumed only when the caller explicitly sends
17861
17996
  // gapDurationSeconds: 30 in the angle approval action.
@@ -17865,17 +18000,17 @@ var StatusForResolveSchema = z71.object({
17865
18000
  // keys. `actorId` (the saved custom actor the picker stored) was silently
17866
18001
  // dropped here, so the approval handler below could not echo it back on the
17867
18002
  // PATCH — the selection looked accepted and reached no render.
17868
- angles: z71.array(z71.object({
17869
- id: z71.string().uuid(),
17870
- content: z71.string(),
17871
- creativeDirection: z71.string(),
17872
- actor: z71.string(),
17873
- actorId: z71.string().nullable().optional()
18003
+ angles: z72.array(z72.object({
18004
+ id: z72.string().uuid(),
18005
+ content: z72.string(),
18006
+ creativeDirection: z72.string(),
18007
+ actor: z72.string(),
18008
+ actorId: z72.string().nullable().optional()
17874
18009
  }).passthrough()).optional(),
17875
- panels: z71.array(z71.object({
17876
- beatId: z71.string(),
17877
- voiceover: z71.string(),
17878
- visualDirection: z71.string()
18010
+ panels: z72.array(z72.object({
18011
+ beatId: z72.string(),
18012
+ voiceover: z72.string(),
18013
+ visualDirection: z72.string()
17879
18014
  }).passthrough()).optional()
17880
18015
  }).optional()
17881
18016
  }).passthrough();
@@ -17996,7 +18131,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
17996
18131
 
17997
18132
  REQUERIDOS: images o projectId expl\xEDcito, language y country. Cuando los outputs incluyen video (tambi\xE9n por default), pregunta SIEMPRE videoAngleCount: 1, 2 o 3; es una decisi\xF3n de costo incluso con aiDecidesAll. Si falta una foto local, llama primero \`request_media_upload\`. Pregunta price, offer, paymentMethods y compareAtPrice cuando aplique; nunca asumas country/language.
17998
18133
 
17999
- ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explica que inicia trabajo pagado y espera confirmaci\xF3n expl\xEDcita. aiDecidesAll omitido/false pausa para reviews conversacionales; muestra todos los \xE1ngulos candidatos y permite escoger/editar hasta el m\xE1ximo autorizado. Usa aiDecidesAll=true s\xF3lo si el usuario pidi\xF3 \u201Cdecide todo\u201D o \u201Cno me preguntes\u201D.`, CreateProductTaskInput.shape, CREATES_EXTERNAL, async (input) => {
18134
+ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explica que inicia trabajo pagado y espera confirmaci\xF3n expl\xEDcita. aiDecidesAll omitido/false pausa para reviews conversacionales; muestra todos los \xE1ngulos candidatos y permite escoger/editar hasta el m\xE1ximo autorizado. Usa aiDecidesAll=true s\xF3lo si el usuario pidi\xF3 \u201Cdecide todo\u201D o \u201Cno me preguntes\u201D.`, CreateProductTaskInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
18000
18135
  try {
18001
18136
  const selectedOutputs = input.outputs ?? DEFAULT_PRODUCT_TASK_OUTPUTS;
18002
18137
  const videoPreset = selectedOutputs.includes("video") && input.competitorScanEnabled === true ? "auto" : input.videoPreset;
@@ -18087,7 +18222,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
18087
18222
  throw translateError(e);
18088
18223
  }
18089
18224
  });
18090
- server.tool("create_service_video", createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.", CreateServiceVideoInput.shape, CREATES_EXTERNAL, async (input) => {
18225
+ server.tool("create_service_video", createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.", CreateServiceVideoInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
18091
18226
  try {
18092
18227
  await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
18093
18228
  const created = await api.postJson("/v2/ingest", {
@@ -18101,6 +18236,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
18101
18236
  voiceId: input.voiceId
18102
18237
  } : {},
18103
18238
  videoPreset: input.videoPreset,
18239
+ videoQuality: input.videoQuality,
18104
18240
  reviewMode: input.reviewMode,
18105
18241
  ...input.brandId ? {
18106
18242
  brandId: input.brandId
@@ -18705,7 +18841,7 @@ __name(registerTaskTools, "registerTaskTools");
18705
18841
 
18706
18842
  // src/tools/creatives.ts
18707
18843
  import { randomUUID } from "crypto";
18708
- import { z as z72 } from "zod";
18844
+ import { z as z73 } from "zod";
18709
18845
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
18710
18846
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
18711
18847
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -18715,70 +18851,70 @@ var CreativeRefs = {
18715
18851
  images: ImagesInput,
18716
18852
  language: Lang.describe('Idioma del contenido. Ej. "es", "en", "pt". REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
18717
18853
  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.'),
18718
- price: z72.string().min(1).max(120).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.'),
18719
- offer: z72.string().min(1).max(240).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.'),
18720
- compareAtPrice: z72.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
18721
- productContext: z72.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."),
18722
- productLabel: z72.string().trim().max(80).optional().describe('Opcional. Nombre o tipo del producto en pocas palabras (ej. "collar de oro", "quita pelusas para ropa"). Es AUTORITATIVO: la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA lo detecta desde la imagen. NO salta la extracci\xF3n.'),
18723
- buyerPersona: z72.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.'),
18724
- isCombo: z72.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
18725
- competitorScanEnabled: z72.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico. Omitir no autoriza el estudio profundo."),
18726
- brandId: z72.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer el creativo.")
18854
+ price: z73.string().min(1).max(120).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.'),
18855
+ offer: z73.string().min(1).max(240).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.'),
18856
+ compareAtPrice: z73.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
18857
+ productContext: z73.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."),
18858
+ productLabel: z73.string().trim().max(80).optional().describe('Opcional. Nombre o tipo del producto en pocas palabras (ej. "collar de oro", "quita pelusas para ropa"). Es AUTORITATIVO: la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA lo detecta desde la imagen. NO salta la extracci\xF3n.'),
18859
+ buyerPersona: z73.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.'),
18860
+ isCombo: z73.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
18861
+ competitorScanEnabled: z73.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico. Omitir no autoriza el estudio profundo."),
18862
+ brandId: z73.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer el creativo.")
18727
18863
  };
18728
- var VideoPresenter = z72.discriminatedUnion("mode", [
18729
- z72.object({
18730
- mode: z72.literal("none")
18864
+ var VideoPresenter = z73.discriminatedUnion("mode", [
18865
+ z73.object({
18866
+ mode: z73.literal("none")
18731
18867
  }).strict(),
18732
- z72.object({
18733
- mode: z72.literal("saved_actor"),
18734
- actorId: z72.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
18868
+ z73.object({
18869
+ mode: z73.literal("saved_actor"),
18870
+ actorId: z73.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
18735
18871
  }).strict(),
18736
- z72.object({
18737
- mode: z72.literal("described"),
18738
- description: z72.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
18872
+ z73.object({
18873
+ mode: z73.literal("described"),
18874
+ description: z73.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
18739
18875
  }).strict()
18740
18876
  ]);
18741
- var VideoCreativeSetup = z72.discriminatedUnion("mode", [
18742
- z72.object({
18743
- mode: z72.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
18877
+ var VideoCreativeSetup = z73.discriminatedUnion("mode", [
18878
+ z73.object({
18879
+ mode: z73.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
18744
18880
  }).strict(),
18745
- z72.object({
18746
- mode: z72.literal("guided"),
18881
+ z73.object({
18882
+ mode: z73.literal("guided"),
18747
18883
  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. "problem_solution" requiere 30s.'),
18748
- buyerPersona: z72.string().trim().min(1).max(360),
18884
+ buyerPersona: z73.string().trim().min(1).max(360),
18749
18885
  presenter: VideoPresenter,
18750
- creativeDirection: z72.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
18886
+ creativeDirection: z73.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
18751
18887
  }).strict()
18752
18888
  ]);
18753
- var VideoInput = z72.object({
18889
+ var VideoInput = z73.object({
18754
18890
  images: CreativeRefs.images.optional(),
18755
18891
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
18756
- title: z72.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
18757
- primaryAngle: z72.string().min(1).describe('\xC1ngulo de venta principal (frase del beneficio). Ej. "Reduce arrugas en 14 d\xEDas" o "Para quienes odian las cremas grasosas".'),
18892
+ title: z73.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
18893
+ primaryAngle: z73.string().min(1).describe('\xC1ngulo de venta principal (frase del beneficio). Ej. "Reduce arrugas en 14 d\xEDas" o "Para quienes odian las cremas grasosas".'),
18758
18894
  language: CreativeRefs.language,
18759
18895
  country: CreativeRefs.country,
18760
- aspectRatio: z72.enum([
18896
+ aspectRatio: z73.enum([
18761
18897
  "9:16",
18762
18898
  "16:9",
18763
18899
  "Auto"
18764
18900
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
18765
- durationSeconds: z72.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."),
18766
- videoAngleCount: z72.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."),
18901
+ durationSeconds: z73.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."),
18902
+ videoAngleCount: z73.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."),
18767
18903
  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.'),
18768
18904
  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."),
18769
18905
  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.'),
18770
18906
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
18771
18907
  videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render: "480p" o "720p". Si se omite, se usa 480p; elige 720p expl\xEDcitamente si necesitas m\xE1s nitidez.'),
18772
- features: z72.array(z72.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
18908
+ features: z73.array(z73.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
18773
18909
  price: CreativeRefs.price,
18774
18910
  offer: CreativeRefs.offer,
18775
18911
  productContext: CreativeRefs.productContext,
18776
18912
  productLabel: CreativeRefs.productLabel,
18777
- cta: z72.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.'),
18778
- scriptNotes: z72.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: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
18913
+ cta: z73.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.'),
18914
+ scriptNotes: z73.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: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
18779
18915
  creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en el video: mujer ("female"), hombre ("male") o ambos ("mixed"). NO es la voz; cuando se fija, la voz se alinea sola con el personaje. M\xE1ndalo en cuanto el usuario diga qui\xE9n debe SALIR en el video, con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "protagonista femenina"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario puede recibir lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. NO lo mandes cuando hable del P\xDABLICO COMPRADOR ("esto es para hombres", "mi p\xFAblico son mujeres", "va dirigido a mam\xE1s"): eso es a qui\xE9n se le vende, no qui\xE9n act\xFAa, y fijarlo ah\xED pinea un protagonista que nadie pidi\xF3. "mixed" solo cuando pida expl\xEDcitamente ambos, y ten en cuenta que no garantiza una mezcla: no fija ning\xFAn g\xE9nero y cada creativo elige su protagonista. No lo preguntes como paso obligatorio. Si creativeSetup.presenter.mode="saved_actor", el personaje guardado manda sobre este campo.'),
18780
18916
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
18781
- replicateWinnerWhenFound: z72.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
18917
+ replicateWinnerWhenFound: z73.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
18782
18918
  brandId: CreativeRefs.brandId
18783
18919
  }).strict();
18784
18920
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -18796,7 +18932,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
18796
18932
  length: 29
18797
18933
  }, (_, index) => index + 2)
18798
18934
  };
18799
- var FreeVideoModelIdEnum = z72.enum([
18935
+ var FreeVideoModelIdEnum = z73.enum([
18800
18936
  "grok-imagine-video-1-5-preview",
18801
18937
  "minimax-h3/reference-to-video",
18802
18938
  "wan/3-0-video",
@@ -18807,70 +18943,70 @@ var FREE_SELECTABLE_MODEL_IDS = [
18807
18943
  "minimax-h3/reference-to-video",
18808
18944
  "wan/3-0-video"
18809
18945
  ];
18810
- var FreeVideoInput = z72.object({
18946
+ var FreeVideoInput = z73.object({
18811
18947
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
18812
- rawPrompt: z72.string().trim().min(1).max(2e3).describe("Prompt o guion exacto del video. Si activas subt\xEDtulos, este mismo texto se usa como guion de subt\xEDtulos."),
18948
+ rawPrompt: z73.string().trim().min(1).max(2e3).describe("Prompt o guion exacto del video. Si activas subt\xEDtulos, este mismo texto se usa como guion de subt\xEDtulos."),
18813
18949
  language: CreativeRefs.language,
18814
18950
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
18815
18951
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
18816
18952
  // parsed ONLY so the handler can reject it with a message naming its
18817
18953
  // replacement — dropping it silently would turn a caller's explicit
18818
18954
  // Pro++ pick into a quiet fallback to Wan.
18819
- freeProModel: z72.enum([
18955
+ freeProModel: z73.enum([
18820
18956
  "wan",
18821
18957
  "seedance"
18822
18958
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
18823
18959
  modelId: FreeVideoModelIdEnum.optional().describe('Opcional. Elige expl\xEDcitamente el modelo del registro en vez del default de la calidad: "grok-imagine-video-1-5-preview" (Grok 1.5), "minimax-h3/reference-to-video" (H3 Max) o "wan/3-0-video" (Wan 3.0). Om\xEDtelo para usar el modelo por defecto de la calidad elegida. El modelo determina la duraci\xF3n permitida (Grok 6/8/10/15s, H3 Max 4-15s, Wan 2-30s) y el precio. "bytedance/seedance-2-5" est\xE1 inactivo y se rechaza con un error claro, nunca un 500.'),
18824
- durationSeconds: z72.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
18960
+ durationSeconds: z73.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
18825
18961
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
18826
- generateAiMusic: z72.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
18827
- addSubtitles: z72.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
18828
- idempotencyKey: z72.string().uuid().optional().describe("Opcional. UUID para reintentar exactamente esta misma solicitud sin crear ni cobrar otro video. Reutiliza el mismo valor si el cliente no recibi\xF3 la respuesta.")
18962
+ generateAiMusic: z73.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
18963
+ addSubtitles: z73.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
18964
+ idempotencyKey: z73.string().uuid().optional().describe("Opcional. UUID para reintentar exactamente esta misma solicitud sin crear ni cobrar otro video. Reutiliza el mismo valor si el cliente no recibi\xF3 la respuesta.")
18829
18965
  }).strict();
18830
18966
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
18831
- var ImageCreativeSetup = z72.discriminatedUnion("mode", [
18832
- z72.object({
18833
- mode: z72.literal("automatic")
18967
+ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
18968
+ z73.object({
18969
+ mode: z73.literal("automatic")
18834
18970
  }).strict(),
18835
- z72.object({
18836
- mode: z72.literal("guided"),
18837
- creativeArchetype: z72.union([
18971
+ z73.object({
18972
+ mode: z73.literal("guided"),
18973
+ creativeArchetype: z73.union([
18838
18974
  ImageCreativeArchetypeEnum,
18839
- z72.literal("ai_decides")
18975
+ z73.literal("ai_decides")
18840
18976
  ]),
18841
- visualTreatment: z72.union([
18977
+ visualTreatment: z73.union([
18842
18978
  ImageCreativeVisualTreatmentEnum,
18843
- z72.literal("ai_decides")
18979
+ z73.literal("ai_decides")
18844
18980
  ]),
18845
18981
  aspectRatio: ImageCreativeAspectRatioEnum,
18846
- nVariants: z72.union([
18847
- z72.literal(1),
18848
- z72.literal(2),
18849
- z72.literal(3),
18850
- z72.literal(4),
18851
- z72.literal(6)
18982
+ nVariants: z73.union([
18983
+ z73.literal(1),
18984
+ z73.literal(2),
18985
+ z73.literal(3),
18986
+ z73.literal(4),
18987
+ z73.literal(6)
18852
18988
  ]),
18853
- imageModel: z72.enum([
18989
+ imageModel: z73.enum([
18854
18990
  "gpt-image-2-5:1k",
18855
18991
  "gpt-image-2-5:2k",
18856
18992
  "gpt-image-2:1k",
18857
18993
  "gpt-image-2:2k"
18858
18994
  ]),
18859
- styleMix: z72.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
18860
- generateAdCopy: z72.boolean(),
18861
- competitorScanEnabled: z72.boolean(),
18862
- productContext: z72.string().trim().min(1).max(3e3).nullable(),
18863
- creativeDirection: z72.string().trim().min(1).max(500).nullable(),
18864
- brandColors: z72.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
18865
- headline: z72.string().trim().min(1).max(120).nullable(),
18866
- subheadline: z72.string().trim().min(1).max(160).nullable()
18995
+ styleMix: z73.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
18996
+ generateAdCopy: z73.boolean(),
18997
+ competitorScanEnabled: z73.boolean(),
18998
+ productContext: z73.string().trim().min(1).max(3e3).nullable(),
18999
+ creativeDirection: z73.string().trim().min(1).max(500).nullable(),
19000
+ brandColors: z73.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
19001
+ headline: z73.string().trim().min(1).max(120).nullable(),
19002
+ subheadline: z73.string().trim().min(1).max(160).nullable()
18867
19003
  }).strict()
18868
19004
  ]).superRefine((setup, context) => {
18869
19005
  if (setup.mode !== "guided") return;
18870
19006
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
18871
19007
  if (needsStyleMix && setup.styleMix === null) {
18872
19008
  context.addIssue({
18873
- code: z72.ZodIssueCode.custom,
19009
+ code: z73.ZodIssueCode.custom,
18874
19010
  path: [
18875
19011
  "styleMix"
18876
19012
  ],
@@ -18879,7 +19015,7 @@ var ImageCreativeSetup = z72.discriminatedUnion("mode", [
18879
19015
  }
18880
19016
  if (!needsStyleMix && setup.styleMix !== null) {
18881
19017
  context.addIssue({
18882
- code: z72.ZodIssueCode.custom,
19018
+ code: z73.ZodIssueCode.custom,
18883
19019
  path: [
18884
19020
  "styleMix"
18885
19021
  ],
@@ -18888,7 +19024,7 @@ var ImageCreativeSetup = z72.discriminatedUnion("mode", [
18888
19024
  }
18889
19025
  if ((setup.imageModel === "gpt-image-2:2k" || setup.imageModel === "gpt-image-2-5:2k") && setup.aspectRatio === "4:5") {
18890
19026
  context.addIssue({
18891
- code: z72.ZodIssueCode.custom,
19027
+ code: z73.ZodIssueCode.custom,
18892
19028
  path: [
18893
19029
  "aspectRatio"
18894
19030
  ],
@@ -18896,53 +19032,53 @@ var ImageCreativeSetup = z72.discriminatedUnion("mode", [
18896
19032
  });
18897
19033
  }
18898
19034
  });
18899
- var LandingCreativeSetup = z72.discriminatedUnion("mode", [
18900
- z72.object({
18901
- mode: z72.literal("automatic")
19035
+ var LandingCreativeSetup = z73.discriminatedUnion("mode", [
19036
+ z73.object({
19037
+ mode: z73.literal("automatic")
18902
19038
  }).strict(),
18903
- z72.object({
18904
- mode: z72.literal("guided"),
19039
+ z73.object({
19040
+ mode: z73.literal("guided"),
18905
19041
  landingStrategy: LandingStrategyEnum,
18906
19042
  landingImageFormat: LandingImageFormatEnum,
18907
- competitorScanEnabled: z72.boolean(),
18908
- paymentMethods: z72.string().trim().min(1).max(240).nullable(),
18909
- productContext: z72.string().trim().min(1).max(3e3).nullable(),
18910
- creativeDirection: z72.string().trim().min(1).max(500).nullable(),
18911
- headline: z72.string().trim().min(1).max(120).nullable(),
18912
- subheadline: z72.string().trim().min(1).max(160).nullable()
19043
+ competitorScanEnabled: z73.boolean(),
19044
+ paymentMethods: z73.string().trim().min(1).max(240).nullable(),
19045
+ productContext: z73.string().trim().min(1).max(3e3).nullable(),
19046
+ creativeDirection: z73.string().trim().min(1).max(500).nullable(),
19047
+ headline: z73.string().trim().min(1).max(120).nullable(),
19048
+ subheadline: z73.string().trim().min(1).max(160).nullable()
18913
19049
  }).strict()
18914
19050
  ]);
18915
- var ImageInput = z72.object({
19051
+ var ImageInput = z73.object({
18916
19052
  images: CreativeRefs.images.optional(),
18917
19053
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
18918
- productTitle: z72.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
18919
- primaryAngle: z72.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
19054
+ productTitle: z73.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
19055
+ primaryAngle: z73.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
18920
19056
  buyerPersona: CreativeRefs.buyerPersona,
18921
19057
  language: CreativeRefs.language,
18922
19058
  country: CreativeRefs.country,
18923
19059
  creativeSetup: ImageCreativeSetup.describe("Configuraci\xF3n obligatoria equivalente al wizard web. Usa guided salvo que el usuario delegue expl\xEDcitamente todo; presenta las decisiones guiadas en un \xFAnico checklist compacto."),
18924
19060
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
18925
- features: z72.array(z72.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
19061
+ features: z73.array(z73.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
18926
19062
  price: CreativeRefs.price,
18927
- omitPrice: z72.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
19063
+ omitPrice: z73.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
18928
19064
  compareAtPrice: CreativeRefs.compareAtPrice,
18929
19065
  offer: CreativeRefs.offer,
18930
19066
  productLabel: CreativeRefs.productLabel,
18931
19067
  isCombo: CreativeRefs.isCombo,
18932
19068
  brandId: CreativeRefs.brandId
18933
19069
  });
18934
- var EditImageCreativeInput = z72.object({
18935
- taskId: z72.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
18936
- variantIndex: z72.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
18937
- instruction: z72.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
19070
+ var EditImageCreativeInput = z73.object({
19071
+ taskId: z73.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
19072
+ variantIndex: z73.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
19073
+ instruction: z73.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
18938
19074
  });
18939
- var LandingInput = z72.object({
19075
+ var LandingInput = z73.object({
18940
19076
  images: CreativeRefs.images.optional(),
18941
19077
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
18942
19078
  language: CreativeRefs.language,
18943
19079
  country: CreativeRefs.country,
18944
19080
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
18945
- salesAngle: z72.string().optional().describe('Opcional. \xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas". Si se omite, la IA lo deduce de la imagen.'),
19081
+ salesAngle: z73.string().optional().describe('Opcional. \xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas". Si se omite, la IA lo deduce de la imagen.'),
18946
19082
  buyerPersona: CreativeRefs.buyerPersona,
18947
19083
  price: CreativeRefs.price,
18948
19084
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -19011,7 +19147,7 @@ function resolveLandingSetup(setup) {
19011
19147
  }
19012
19148
  __name(resolveLandingSetup, "resolveLandingSetup");
19013
19149
  function registerCreativeTools(server, api, { transport = "http" } = {}) {
19014
- server.tool("generate_free_video", generateFreeVideoGuidance.summary + ' Si el usuario adjunta o menciona una imagen local, llama primero request_media_upload con mediaKind=image y usa el assetId devuelto; no pidas path ni URL. Devuelve un taskId y procesa el job de forma as\xEDncrona.\n\nREQUERIDOS: rawPrompt, quality, durationSeconds y videoResolution.\n\nCALIDAD: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan). Economy admite 6/8/10/15s; Medium admite cualquier duraci\xF3n entera de 4 a 15s; Pro admite enteros de 2 a 30s y audio natural. `freeProModel` se elimin\xF3 \u2014 usa `modelId` (ver su descripci\xF3n); Seedance 2.5 est\xE1 inactivo y se rechaza con un error claro.\n\nSUBT\xCDTULOS: si addSubtitles=true, el rawPrompt completo se usa como texto exacto de subt\xEDtulos y debe tener m\xE1ximo 500 caracteres; no existe una pregunta adicional de transcripci\xF3n.\n\nPara videos normales con narrativa/\xE1ngulo usa generate_video_creative. Para tareas combinadas de producto usa create_product_task.', FreeVideoInput.shape, CREATES_EXTERNAL, async (input) => {
19150
+ server.tool("generate_free_video", generateFreeVideoGuidance.summary + ' Si el usuario adjunta o menciona una imagen local, llama primero request_media_upload con mediaKind=image y usa el assetId devuelto; no pidas path ni URL. Devuelve un taskId y procesa el job de forma as\xEDncrona.\n\nREQUERIDOS: rawPrompt, quality, durationSeconds y videoResolution.\n\nCALIDAD: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan). Economy admite 6/8/10/15s; Medium admite cualquier duraci\xF3n entera de 4 a 15s; Pro admite enteros de 2 a 30s y audio natural. `freeProModel` se elimin\xF3 \u2014 usa `modelId` (ver su descripci\xF3n); Seedance 2.5 est\xE1 inactivo y se rechaza con un error claro.\n\nSUBT\xCDTULOS: si addSubtitles=true, el rawPrompt completo se usa como texto exacto de subt\xEDtulos y debe tener m\xE1ximo 500 caracteres; no existe una pregunta adicional de transcripci\xF3n.\n\nPara videos normales con narrativa/\xE1ngulo usa generate_video_creative. Para tareas combinadas de producto usa create_product_task.', FreeVideoInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
19015
19151
  try {
19016
19152
  if (input.freeProModel) {
19017
19153
  throw new Error("freeProModel se elimin\xF3 en MCP 7.0.0. Usa `modelId` para elegir el modelo expl\xEDcitamente (ver la descripci\xF3n del par\xE1metro).");
@@ -19059,7 +19195,7 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
19059
19195
  throw translateError(e);
19060
19196
  }
19061
19197
  });
19062
- server.tool("generate_video_creative", generateVideoCreativeGuidance.summary + " Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), title, primaryAngle, language, country, aspectRatio, videoAngleCount y creativeSetup. Pregunta SIEMPRE cu\xE1ntos videos quiere (1, 2 o 3): la cantidad cambia el costo y no forma parte de \u2018la IA decide todo\u2019. Si falta una foto local, llama primero `request_media_upload` y usa los assetId; no pidas path ni URL. PREGUNTA price y offer si faltan; no asumas country/language.\n\nFORMATO Y CALIDAD: pregunta videoStructure (Un solo clip o Multiescena) y videoQuality (Econ\xF3mico, Medio o Pro). Un solo clip se genera completo y puede incluir cambios de plano. El sistema elige el proveedor internamente.\n\nCONFIGURACI\xD3N: salvo que el usuario diga expl\xEDcitamente que la IA decida todo, usa creativeSetup.mode=guided y pregunta narrativa solo si no hay estudio de mercado; recoge p\xFAblico comprador, presentador (actor guardado, descripci\xF3n o ninguno) y direcci\xF3n creativa. Si el usuario dice qui\xE9n debe aparecer (mujer, hombre o ambos), env\xEDa creativeGender; no lo preguntes si no lo menciona. creativeDirection=null s\xF3lo despu\xE9s de que el usuario delegue esa decisi\xF3n concreta. No inventes valores de setup.\n\nANTES de invocar, muestra un resumen compacto que incluya cantidad, planificaci\xF3n (estudio de mercado o narrativa), p\xFAblico, presentador y direcci\xF3n y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. Multiescena se factura por escena, as\xED que avisa ese mayor costo. Advierte tambi\xE9n que, si luego el usuario confirma que las fotos son de varios productos (combo), el pipeline r\xE1pido actualmente omite la pausa de guion aunque mantiene las dem\xE1s revisiones.\n\nREVIEWS: guided muestra los \xE1ngulos candidatos y permite escoger hasta videoAngleCount, editar cada \xE1ngulo y revisar sus guiones. automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite ambas reviews. scriptNotes agrega restricciones al guion; get_video_script y approve_video_script manejan la review palabra por palabra.", VideoInput.shape, CREATES_EXTERNAL, async (input) => {
19198
+ server.tool("generate_video_creative", generateVideoCreativeGuidance.summary + " Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), title, primaryAngle, language, country, aspectRatio, videoAngleCount y creativeSetup. Pregunta SIEMPRE cu\xE1ntos videos quiere (1, 2 o 3): la cantidad cambia el costo y no forma parte de \u2018la IA decide todo\u2019. Si falta una foto local, llama primero `request_media_upload` y usa los assetId; no pidas path ni URL. PREGUNTA price y offer si faltan; no asumas country/language.\n\nFORMATO Y CALIDAD: pregunta videoStructure (Un solo clip o Multiescena) y videoQuality (Econ\xF3mico, Medio o Pro). Un solo clip se genera completo y puede incluir cambios de plano. El sistema elige el proveedor internamente.\n\nCONFIGURACI\xD3N: salvo que el usuario diga expl\xEDcitamente que la IA decida todo, usa creativeSetup.mode=guided y pregunta narrativa solo si no hay estudio de mercado; recoge p\xFAblico comprador, presentador (actor guardado, descripci\xF3n o ninguno) y direcci\xF3n creativa. Si el usuario dice qui\xE9n debe aparecer (mujer, hombre o ambos), env\xEDa creativeGender; no lo preguntes si no lo menciona. creativeDirection=null s\xF3lo despu\xE9s de que el usuario delegue esa decisi\xF3n concreta. No inventes valores de setup.\n\nANTES de invocar, muestra un resumen compacto que incluya cantidad, planificaci\xF3n (estudio de mercado o narrativa), p\xFAblico, presentador y direcci\xF3n y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. Multiescena se factura por escena, as\xED que avisa ese mayor costo. Advierte tambi\xE9n que, si luego el usuario confirma que las fotos son de varios productos (combo), el pipeline r\xE1pido actualmente omite la pausa de guion aunque mantiene las dem\xE1s revisiones.\n\nREVIEWS: guided muestra los \xE1ngulos candidatos y permite escoger hasta videoAngleCount, editar cada \xE1ngulo y revisar sus guiones. automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite ambas reviews. scriptNotes agrega restricciones al guion; get_video_script y approve_video_script manejan la review palabra por palabra.", VideoInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
19063
19199
  try {
19064
19200
  if (!input.images && !input.winnerReference) {
19065
19201
  throw new Error("images o winnerReference es requerido.");
@@ -19123,7 +19259,7 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
19123
19259
  throw translateError(e);
19124
19260
  }
19125
19261
  });
19126
- server.tool("generate_image_creatives", generateImageCreativesGuidance.summary + " Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), productTitle, language, country y creativeSetup. Si falta una foto local, llama primero `request_media_upload` y usa los assetId. Pregunta price, offer y compareAtPrice cuando aplique; no asumas country/language. primaryAngle es opcional: si falta, ProductMaker lo genera y guided lo muestra para revisi\xF3n.\n\nCONFIGURACI\xD3N: usa guided salvo delegaci\xF3n total expl\xEDcita. No hagas un interrogatorio campo por campo: presenta UN checklist compacto con arquetipo, tratamiento visual, formato, cantidad, calidad, mezcla condicional, copy, competencia, contexto, direcci\xF3n, colores y copy exacto; propone los defaults recomendados y permite que el usuario delegue los campos con ai_decides o null donde el schema lo admite. La UI ofrece 1, 2, 3, 4 o 6 variantes: para 2\u20134 pregunta styleMix; para 1 o 6 usa null, y 6 activa autom\xE1ticamente una imagen de cada estilo. Premium 2K no admite 4:5.\n\nANTES de invocar, muestra el resumen de esas decisiones y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. guided pausa para revisar el \xE1ngulo; automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite la review.", ImageInput.shape, CREATES_EXTERNAL, async (input) => {
19262
+ server.tool("generate_image_creatives", generateImageCreativesGuidance.summary + " Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), productTitle, language, country y creativeSetup. Si falta una foto local, llama primero `request_media_upload` y usa los assetId. Pregunta price, offer y compareAtPrice cuando aplique; no asumas country/language. primaryAngle es opcional: si falta, ProductMaker lo genera y guided lo muestra para revisi\xF3n.\n\nCONFIGURACI\xD3N: usa guided salvo delegaci\xF3n total expl\xEDcita. No hagas un interrogatorio campo por campo: presenta UN checklist compacto con arquetipo, tratamiento visual, formato, cantidad, calidad, mezcla condicional, copy, competencia, contexto, direcci\xF3n, colores y copy exacto; propone los defaults recomendados y permite que el usuario delegue los campos con ai_decides o null donde el schema lo admite. La UI ofrece 1, 2, 3, 4 o 6 variantes: para 2\u20134 pregunta styleMix; para 1 o 6 usa null, y 6 activa autom\xE1ticamente una imagen de cada estilo. Premium 2K no admite 4:5.\n\nANTES de invocar, muestra el resumen de esas decisiones y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. guided pausa para revisar el \xE1ngulo; automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite la review.", ImageInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
19127
19263
  try {
19128
19264
  if (!input.images && !input.winnerReference) {
19129
19265
  throw new Error("images o winnerReference es requerido.");
@@ -19169,7 +19305,7 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
19169
19305
  throw translateError(e);
19170
19306
  }
19171
19307
  });
19172
- server.tool("generate_landing", generateLandingGuidance.summary + " No expone landing editable/code mientras siga siendo admin-only. Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), language, country y creativeSetup. Ante \u201Ccrea una landing con este producto\u201D y una foto local, llama primero `request_media_upload` y usa los assetId. Pregunta price, offer y compareAtPrice cuando aplique; no asumas country/language.\n\nCONFIGURACI\xD3N: usa guided salvo delegaci\xF3n total expl\xEDcita. Presenta UN checklist compacto \u2014no preguntas seriales\u2014 con estrategia, formato, competencia, m\xE9todos de pago, contexto, direcci\xF3n creativa y headline/subheadline exactos opcionales. Prop\xF3n defaults recomendados; null significa que el usuario deleg\xF3 esa decisi\xF3n concreta, nunca que el agente la olvid\xF3.\n\nANTES de invocar, muestra el resumen y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. guided pausa para revisar el \xE1ngulo; automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite la review.", LandingInput.shape, CREATES_EXTERNAL, async (input) => {
19308
+ server.tool("generate_landing", generateLandingGuidance.summary + " No expone landing editable/code mientras siga siendo admin-only. Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), language, country y creativeSetup. Ante \u201Ccrea una landing con este producto\u201D y una foto local, llama primero `request_media_upload` y usa los assetId. Pregunta price, offer y compareAtPrice cuando aplique; no asumas country/language.\n\nCONFIGURACI\xD3N: usa guided salvo delegaci\xF3n total expl\xEDcita. Presenta UN checklist compacto \u2014no preguntas seriales\u2014 con estrategia, formato, competencia, m\xE9todos de pago, contexto, direcci\xF3n creativa y headline/subheadline exactos opcionales. Prop\xF3n defaults recomendados; null significa que el usuario deleg\xF3 esa decisi\xF3n concreta, nunca que el agente la olvid\xF3.\n\nANTES de invocar, muestra el resumen y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. guided pausa para revisar el \xE1ngulo; automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite la review.", LandingInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
19173
19309
  try {
19174
19310
  if (!input.images && !input.winnerReference) {
19175
19311
  throw new Error("images o winnerReference es requerido.");
@@ -19204,10 +19340,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
19204
19340
  __name(registerCreativeTools, "registerCreativeTools");
19205
19341
 
19206
19342
  // src/tools/creative-variants.ts
19207
- import { z as z73 } from "zod";
19343
+ import { z as z74 } from "zod";
19208
19344
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
19209
19345
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
19210
- var LandingSectionKeyEnum = z73.enum([
19346
+ var LandingSectionKeyEnum = z74.enum([
19211
19347
  "problem_hook",
19212
19348
  "problem_cost",
19213
19349
  "solution_mechanism",
@@ -19247,24 +19383,24 @@ var LandingSectionKeyEnum = z73.enum([
19247
19383
  "lifestyle_fit",
19248
19384
  "join_lifestyle"
19249
19385
  ]);
19250
- var CreativeVariantKindEnum = z73.enum([
19386
+ var CreativeVariantKindEnum = z74.enum([
19251
19387
  "video",
19252
19388
  "image",
19253
19389
  "landing"
19254
19390
  ]);
19255
- var EstimateCreativeVariantInputBase = z73.object({
19256
- sourceTaskId: z73.string().uuid().describe("ID de la tarea original completada."),
19391
+ var EstimateCreativeVariantInputBase = z74.object({
19392
+ sourceTaskId: z74.string().uuid().describe("ID de la tarea original completada."),
19257
19393
  kind: CreativeVariantKindEnum,
19258
19394
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
19259
19395
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
19260
- nVariants: z73.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
19396
+ nVariants: z74.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
19261
19397
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
19262
- instructions: z73.string().trim().min(1).max(2e3).optional().describe("Opcional para landing. Si se env\xEDa sin sectionKey, el estimado suma la clasificaci\xF3n pagada con IA.")
19398
+ instructions: z74.string().trim().min(1).max(2e3).optional().describe("Opcional para landing. Si se env\xEDa sin sectionKey, el estimado suma la clasificaci\xF3n pagada con IA.")
19263
19399
  }).strict();
19264
19400
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
19265
19401
  if (input.kind === "video" && input.nVariants !== void 0) {
19266
19402
  ctx.addIssue({
19267
- code: z73.ZodIssueCode.custom,
19403
+ code: z74.ZodIssueCode.custom,
19268
19404
  path: [
19269
19405
  "nVariants"
19270
19406
  ],
@@ -19274,7 +19410,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19274
19410
  if (input.kind !== "video") {
19275
19411
  if (input.videoPreset !== void 0) {
19276
19412
  ctx.addIssue({
19277
- code: z73.ZodIssueCode.custom,
19413
+ code: z74.ZodIssueCode.custom,
19278
19414
  path: [
19279
19415
  "videoPreset"
19280
19416
  ],
@@ -19283,7 +19419,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19283
19419
  }
19284
19420
  if (input.videoResolution !== void 0) {
19285
19421
  ctx.addIssue({
19286
- code: z73.ZodIssueCode.custom,
19422
+ code: z74.ZodIssueCode.custom,
19287
19423
  path: [
19288
19424
  "videoResolution"
19289
19425
  ],
@@ -19293,7 +19429,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19293
19429
  }
19294
19430
  if (input.kind !== "image" && input.nVariants !== void 0) {
19295
19431
  ctx.addIssue({
19296
- code: z73.ZodIssueCode.custom,
19432
+ code: z74.ZodIssueCode.custom,
19297
19433
  path: [
19298
19434
  "nVariants"
19299
19435
  ],
@@ -19303,7 +19439,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19303
19439
  if (input.kind !== "landing") {
19304
19440
  if (input.sectionKey !== void 0) {
19305
19441
  ctx.addIssue({
19306
- code: z73.ZodIssueCode.custom,
19442
+ code: z74.ZodIssueCode.custom,
19307
19443
  path: [
19308
19444
  "sectionKey"
19309
19445
  ],
@@ -19312,7 +19448,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19312
19448
  }
19313
19449
  if (input.instructions !== void 0) {
19314
19450
  ctx.addIssue({
19315
- code: z73.ZodIssueCode.custom,
19451
+ code: z74.ZodIssueCode.custom,
19316
19452
  path: [
19317
19453
  "instructions"
19318
19454
  ],
@@ -19321,31 +19457,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19321
19457
  }
19322
19458
  }
19323
19459
  });
19324
- var CreateCreativeVariantInputBase = z73.object({
19325
- sourceTaskId: z73.string().uuid().describe("ID de la tarea original completada."),
19460
+ var CreateCreativeVariantInputBase = z74.object({
19461
+ sourceTaskId: z74.string().uuid().describe("ID de la tarea original completada."),
19326
19462
  kind: CreativeVariantKindEnum,
19327
- confirm: z73.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
19328
- clientRequestId: z73.string().uuid().describe("UUID estable y obligatorio para esta intenci\xF3n. Reutil\xEDzalo ante timeouts o transporte ambiguo. Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n y un UUID nuevo."),
19329
- angle: z73.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
19330
- buyerPersona: z73.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
19331
- scriptNotes: z73.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
19332
- creativeDirection: z73.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
19463
+ confirm: z74.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
19464
+ clientRequestId: z74.string().uuid().describe("UUID estable y obligatorio para esta intenci\xF3n. Reutil\xEDzalo ante timeouts o transporte ambiguo. Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n y un UUID nuevo."),
19465
+ angle: z74.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
19466
+ buyerPersona: z74.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
19467
+ scriptNotes: z74.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
19468
+ creativeDirection: z74.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
19333
19469
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
19334
19470
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
19335
- generateAiMusic: z73.boolean().optional().describe("Opcional para video."),
19336
- nVariants: z73.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
19471
+ generateAiMusic: z74.boolean().optional().describe("Opcional para video."),
19472
+ nVariants: z74.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
19337
19473
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
19338
19474
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
19339
19475
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
19340
19476
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
19341
- styleMix: z73.boolean().optional().describe("Opcional para imagen."),
19477
+ styleMix: z74.boolean().optional().describe("Opcional para imagen."),
19342
19478
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
19343
- instructions: z73.string().trim().min(1).max(2e3).optional().describe("Solicitud libre para una nueva secci\xF3n de landing. La IA la clasifica si no env\xEDas sectionKey.")
19479
+ instructions: z74.string().trim().min(1).max(2e3).optional().describe("Solicitud libre para una nueva secci\xF3n de landing. La IA la clasifica si no env\xEDas sectionKey.")
19344
19480
  }).strict();
19345
19481
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
19346
19482
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
19347
19483
  ctx.addIssue({
19348
- code: z73.ZodIssueCode.custom,
19484
+ code: z74.ZodIssueCode.custom,
19349
19485
  path: [
19350
19486
  "angle"
19351
19487
  ],
@@ -19354,7 +19490,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
19354
19490
  }
19355
19491
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
19356
19492
  ctx.addIssue({
19357
- code: z73.ZodIssueCode.custom,
19493
+ code: z74.ZodIssueCode.custom,
19358
19494
  path: [
19359
19495
  "instructions"
19360
19496
  ],
@@ -19400,7 +19536,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
19400
19536
  for (const field of fieldsByKind[input.kind]) {
19401
19537
  if (input[field] !== void 0) {
19402
19538
  ctx.addIssue({
19403
- code: z73.ZodIssueCode.custom,
19539
+ code: z74.ZodIssueCode.custom,
19404
19540
  path: [
19405
19541
  field
19406
19542
  ],
@@ -19447,7 +19583,7 @@ function registerCreativeVariantTools(server, api) {
19447
19583
  throw translateError(error);
19448
19584
  }
19449
19585
  });
19450
- server.tool("create_creative_variant", createCreativeVariantGuidance.summary + " ES UNA ACCI\xD3N DE PAGO: primero llama estimate_creative_variant, muestra el rango de cr\xE9ditos al usuario y solo despu\xE9s invoca este tool con confirm=true. Las recomendaciones IA tambi\xE9n son acciones pagas a 2x del costo real. clientRequestId es obligatorio: genera un UUID por intenci\xF3n y reutiliza el mismo ante timeouts o transporte ambiguo. Si recibes status=error, pide confirmaci\xF3n para un intento nuevo y usa otro UUID. Reutiliza el producto y referencias del task origen; crea un child task independiente y devuelve variantTaskId. Para landing puedes enviar instructions en texto libre y omitir sectionKey: el backend lo clasifica con IA. No expone ni permite cambiar videoModel, videoTier, videoStyle o narrativeStyle; esos valores se heredan del task origen.", CreateCreativeVariantInputBase.shape, CREATES_EXTERNAL, async (input) => {
19586
+ server.tool("create_creative_variant", createCreativeVariantGuidance.summary + " ES UNA ACCI\xD3N DE PAGO: primero llama estimate_creative_variant, muestra el rango de cr\xE9ditos al usuario y solo despu\xE9s invoca este tool con confirm=true. Las recomendaciones IA tambi\xE9n son acciones pagas a 2x del costo real. clientRequestId es obligatorio: genera un UUID por intenci\xF3n y reutiliza el mismo ante timeouts o transporte ambiguo. Si recibes status=error, pide confirmaci\xF3n para un intento nuevo y usa otro UUID. Reutiliza el producto y referencias del task origen; crea un child task independiente y devuelve variantTaskId. Para landing puedes enviar instructions en texto libre y omitir sectionKey: el backend lo clasifica con IA. No expone ni permite cambiar videoModel, videoTier, videoStyle o narrativeStyle; esos valores se heredan del task origen.", CreateCreativeVariantInputBase.shape, CREATES_PAID, async (input) => {
19451
19587
  try {
19452
19588
  const validatedInput = parseVariantInput(CreateCreativeVariantInput, input);
19453
19589
  const estimateInput = EstimateCreativeVariantInput.parse({
@@ -19517,32 +19653,32 @@ function registerCreativeVariantTools(server, api) {
19517
19653
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
19518
19654
 
19519
19655
  // src/tools/script-review.ts
19520
- import { z as z74 } from "zod";
19656
+ import { z as z75 } from "zod";
19521
19657
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
19522
19658
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
19523
19659
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
19524
- var GetVideoScriptInput = z74.object({
19525
- taskId: z74.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
19526
- angleKey: z74.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
19660
+ var GetVideoScriptInput = z75.object({
19661
+ taskId: z75.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
19662
+ angleKey: z75.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
19527
19663
  }).strict();
19528
19664
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
19529
19665
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
19530
- var ApproveSceneEdit = z74.object({
19531
- index: z74.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
19532
- dialogue: z74.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
19666
+ var ApproveSceneEdit = z75.object({
19667
+ index: z75.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
19668
+ dialogue: z75.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
19533
19669
  message: "dialogue no puede ser s\xF3lo espacios"
19534
19670
  }).describe("Di\xE1logo final de la escena. NO puede estar vac\xEDo ni ser s\xF3lo espacios. Puede ser el original sin cambios o la edici\xF3n del usuario.")
19535
19671
  }).strict();
19536
- var ApproveVideoScriptInput = z74.object({
19537
- taskId: z74.string().min(1).describe("ID de la tarea."),
19538
- angleKey: z74.string().trim().min(1).max(120).optional().describe('Mismo angleKey usado en get_video_script. REQUERIDO en multi-angle (si se omite el backend resuelve a "angle_0" literal). En single-angle puede omitirse.'),
19539
- scenes: z74.array(ApproveSceneEdit).min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_SCENES2).describe("Escenas con los di\xE1logos finales. El backend mergea por `index` \u2014 las escenas NO incluidas conservan el di\xE1logo original. Debe haber entre 1 y 50 entradas. Para cada entrada que mandes con un dialogue distinto del original, el backend valida minWords \u2264 words \u2264 maxWords y rechaza con 400 si te sales del rango.")
19672
+ var ApproveVideoScriptInput = z75.object({
19673
+ taskId: z75.string().min(1).describe("ID de la tarea."),
19674
+ angleKey: z75.string().trim().min(1).max(120).optional().describe('Mismo angleKey usado en get_video_script. REQUERIDO en multi-angle (si se omite el backend resuelve a "angle_0" literal). En single-angle puede omitirse.'),
19675
+ scenes: z75.array(ApproveSceneEdit).min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_SCENES2).describe("Escenas con los di\xE1logos finales. El backend mergea por `index` \u2014 las escenas NO incluidas conservan el di\xE1logo original. Debe haber entre 1 y 50 entradas. Para cada entrada que mandes con un dialogue distinto del original, el backend valida minWords \u2264 words \u2264 maxWords y rechaza con 400 si te sales del rango.")
19540
19676
  }).strict();
19541
- var RegenerateVideoScriptInput = z74.object({
19542
- taskId: z74.string().min(1).describe("ID de la tarea."),
19543
- angleKey: z74.string().min(1).describe('Clave del \xE1ngulo a regenerar. Single-angle: pasa "angle_0". Multi-angle: el mismo que devuelve get_video_script. NO se puede omitir \u2014 el backend lo exige siempre.'),
19677
+ var RegenerateVideoScriptInput = z75.object({
19678
+ taskId: z75.string().min(1).describe("ID de la tarea."),
19679
+ angleKey: z75.string().min(1).describe('Clave del \xE1ngulo a regenerar. Single-angle: pasa "angle_0". Multi-angle: el mismo que devuelve get_video_script. NO se puede omitir \u2014 el backend lo exige siempre.'),
19544
19680
  narrativeStyle: NarrativeStyleEnum.describe('Narrativa para el nuevo guion. Incluye valores hist\xF3ricos porque esta herramienta tambi\xE9n regenera tareas antiguas. REQUERIDO \u2014 el backend NO acepta "mantener la actual"; siempre tienes que elegir una. Si el usuario quiere re-rolear con la misma narrativa, pasa la que ya tiene el \xE1ngulo (la ves en get_video_script o en get_task_status).'),
19545
- narrativeSelection: z74.enum([
19681
+ narrativeSelection: z75.enum([
19546
19682
  "market",
19547
19683
  "guided"
19548
19684
  ]).optional().describe("Elecci\xF3n expl\xEDcita del usuario: market usa el estudio de mercado disponible; guided usa la narrativa elegida. Omitir conserva el comportamiento existente.")
@@ -19602,9 +19738,9 @@ function registerScriptReviewTools(server, api) {
19602
19738
  // Not CREATES_INTERNAL: approving the script is what STARTS the render, so
19603
19739
  // this call dispatches jobs to the video providers and burns credits. Its own
19604
19740
  // description says so ("Tras llamarlo, el render arranca y consume créditos").
19605
- // A host that decides when to interrupt the user by `destructiveHint ||
19606
- // openWorldHint` would otherwise auto-invoke the one call that spends money.
19607
- CREATES_EXTERNAL,
19741
+ // `destructiveHint` keeps a host from treating the credit charge as a
19742
+ // reversible bookkeeping update.
19743
+ CREATES_PAID,
19608
19744
  async (input) => {
19609
19745
  try {
19610
19746
  await requirePaidCreativeConfirmation(server, `Aprobar ${input.scenes.length} escena(s) y comenzar el render pagado del video.`);
@@ -19623,14 +19759,14 @@ function registerScriptReviewTools(server, api) {
19623
19759
  __name(registerScriptReviewTools, "registerScriptReviewTools");
19624
19760
 
19625
19761
  // src/tools/connections.ts
19626
- import { z as z75 } from "zod";
19762
+ import { z as z76 } from "zod";
19627
19763
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
19628
19764
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
19629
19765
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
19630
19766
  var listMetaDestinationsGuidance = getProductMakerCapabilityModelGuidance("list_meta_destinations");
19631
19767
  var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list_tiktok_advertisers");
19632
19768
  function registerConnectionTools(server, api) {
19633
- server.tool("list_shopify_shops", listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z75.object({}).shape, READS_INTERNAL, async () => {
19769
+ server.tool("list_shopify_shops", listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z76.object({}).shape, READS_INTERNAL, async () => {
19634
19770
  try {
19635
19771
  const r = await api.getJson("/v1/shopify/shops");
19636
19772
  return asText(r);
@@ -19638,10 +19774,10 @@ function registerConnectionTools(server, api) {
19638
19774
  throw translateError(e);
19639
19775
  }
19640
19776
  });
19641
- server.tool("list_shopify_products", listShopifyProductsGuidance.summary + ' Usa el `id` devuelto junto con `publicationMode="existing"` en `publish_to_shopify`. Si `taskId` se proporciona, la respuesta tambi\xE9n indica el producto publicado actualmente para esa tarea y tienda. No modifica Shopify.', z75.object({
19642
- shopDomain: z75.string().min(3).max(120),
19643
- query: z75.string().trim().max(120).optional(),
19644
- taskId: z75.string().uuid().optional()
19777
+ server.tool("list_shopify_products", listShopifyProductsGuidance.summary + ' Usa el `id` devuelto junto con `publicationMode="existing"` en `publish_to_shopify`. Si `taskId` se proporciona, la respuesta tambi\xE9n indica el producto publicado actualmente para esa tarea y tienda. No modifica Shopify.', z76.object({
19778
+ shopDomain: z76.string().min(3).max(120),
19779
+ query: z76.string().trim().max(120).optional(),
19780
+ taskId: z76.string().uuid().optional()
19645
19781
  }).shape, READS_EXTERNAL, async ({ shopDomain, query, taskId }) => {
19646
19782
  try {
19647
19783
  const params = new URLSearchParams({
@@ -19655,7 +19791,7 @@ function registerConnectionTools(server, api) {
19655
19791
  throw translateError(e);
19656
19792
  }
19657
19793
  });
19658
- server.tool("list_meta_ad_accounts", listMetaAdAccountsGuidance.summary + " Para publicar, prefiere `list_meta_destinations`, que tambi\xE9n devuelve el portfolio y las p\xE1ginas disponibles. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.", z75.object({}).shape, READS_EXTERNAL, async () => {
19794
+ server.tool("list_meta_ad_accounts", listMetaAdAccountsGuidance.summary + " Para publicar, prefiere `list_meta_destinations`, que tambi\xE9n devuelve el portfolio y las p\xE1ginas disponibles. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.", z76.object({}).shape, READS_EXTERNAL, async () => {
19659
19795
  try {
19660
19796
  const r = await api.getJson("/v1/facebook/ad-accounts");
19661
19797
  return asText(r);
@@ -19665,7 +19801,7 @@ function registerConnectionTools(server, api) {
19665
19801
  });
19666
19802
  server.registerTool("list_meta_destinations", {
19667
19803
  description: listMetaDestinationsGuidance.summary + " Es obligatorio llamar esta herramienta antes de publicar, mostrar las opciones y enviar al publicador el `portfolioId`, `adAccountId` y `pageId` elegidos; nunca elijas silenciosamente la primera p\xE1gina o cuenta. No modifica Meta.",
19668
- inputSchema: z75.object({}).shape,
19804
+ inputSchema: z76.object({}).shape,
19669
19805
  annotations: READS_EXTERNAL,
19670
19806
  _meta: {
19671
19807
  "openai/widgetAccessible": true
@@ -19678,7 +19814,7 @@ function registerConnectionTools(server, api) {
19678
19814
  throw translateError(e);
19679
19815
  }
19680
19816
  });
19681
- server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z75.object({}).shape, READS_EXTERNAL, async () => {
19817
+ server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z76.object({}).shape, READS_EXTERNAL, async () => {
19682
19818
  try {
19683
19819
  const r = await api.getJson("/v1/tiktok/advertisers");
19684
19820
  return asText(r);
@@ -19690,10 +19826,10 @@ function registerConnectionTools(server, api) {
19690
19826
  __name(registerConnectionTools, "registerConnectionTools");
19691
19827
 
19692
19828
  // src/tools/actors.ts
19693
- import { z as z76 } from "zod";
19829
+ import { z as z77 } from "zod";
19694
19830
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
19695
19831
  function registerActorTools(server, api) {
19696
- server.tool("list_actors", listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.", z76.object({}).shape, READS_INTERNAL, async () => {
19832
+ server.tool("list_actors", listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.", z77.object({}).shape, READS_INTERNAL, async () => {
19697
19833
  try {
19698
19834
  const rows = await api.getJson("/v1/actors");
19699
19835
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -19714,7 +19850,7 @@ function registerActorTools(server, api) {
19714
19850
  __name(registerActorTools, "registerActorTools");
19715
19851
 
19716
19852
  // src/tools/publish.ts
19717
- import { z as z77 } from "zod";
19853
+ import { z as z78 } from "zod";
19718
19854
 
19719
19855
  // src/tools/stable-uuid.ts
19720
19856
  import { createHash as createHash2 } from "crypto";
@@ -19786,40 +19922,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
19786
19922
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
19787
19923
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
19788
19924
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
19789
- var ShopifyInput = z77.object({
19790
- taskId: z77.string().min(1),
19791
- shopDomain: z77.string().min(1),
19925
+ var ShopifyInput = z78.object({
19926
+ taskId: z78.string().min(1),
19927
+ shopDomain: z78.string().min(1),
19792
19928
  /** Override: number of landing images to include. Default = ALL images the
19793
19929
  * task generated (the MCP fetches /v1/results first to count). Bounded
19794
19930
  * generously here; the backend validates each index against
19795
19931
  * landing.images.length and rejects out-of-range. */
19796
- numLandingImages: z77.number().int().min(1).max(20).optional(),
19797
- variantIndex: z77.number().int().min(0).optional(),
19932
+ numLandingImages: z78.number().int().min(1).max(20).optional(),
19933
+ variantIndex: z78.number().int().min(0).optional(),
19798
19934
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
19799
19935
  * When true, the landing renders variant-picker pills; when false, it ships
19800
19936
  * a single-option product page. Defaults to false. */
19801
- showVariantPicker: z77.boolean().optional(),
19937
+ showVariantPicker: z78.boolean().optional(),
19802
19938
  /** Default `auto` updates the product previously published for this task and
19803
19939
  * shop. Use `existing` with targetProductId to choose another product, or
19804
19940
  * `new` only when the user explicitly wants a duplicate/new listing. */
19805
- publicationMode: z77.enum([
19941
+ publicationMode: z78.enum([
19806
19942
  "auto",
19807
19943
  "existing",
19808
19944
  "new"
19809
19945
  ]).optional(),
19810
19946
  /** Shopify product GID, numeric id, or admin product URL. Required when
19811
19947
  * publicationMode is `existing`. */
19812
- targetProductId: z77.string().trim().min(1).max(300).optional(),
19948
+ targetProductId: z78.string().trim().min(1).max(300).optional(),
19813
19949
  /** Add an announcement bar text above add-to-cart (optional). */
19814
- announcementBarEnabled: z77.boolean().optional(),
19815
- announcementBarText: z77.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
19950
+ announcementBarEnabled: z78.boolean().optional(),
19951
+ announcementBarText: z78.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
19816
19952
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
19817
- confirmed: z77.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
19953
+ confirmed: z78.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
19818
19954
  });
19819
19955
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
19820
19956
  if (value.commerceCorrection && value.confirmed !== true) {
19821
19957
  ctx.addIssue({
19822
- code: z77.ZodIssueCode.custom,
19958
+ code: z78.ZodIssueCode.custom,
19823
19959
  path: [
19824
19960
  "confirmed"
19825
19961
  ],
@@ -19828,7 +19964,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
19828
19964
  }
19829
19965
  if (value.announcementBarEnabled && !value.announcementBarText) {
19830
19966
  ctx.addIssue({
19831
- code: z77.ZodIssueCode.custom,
19967
+ code: z78.ZodIssueCode.custom,
19832
19968
  path: [
19833
19969
  "announcementBarText"
19834
19970
  ],
@@ -19837,7 +19973,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
19837
19973
  }
19838
19974
  if (!value.announcementBarEnabled && value.announcementBarText) {
19839
19975
  ctx.addIssue({
19840
- code: z77.ZodIssueCode.custom,
19976
+ code: z78.ZodIssueCode.custom,
19841
19977
  path: [
19842
19978
  "announcementBarText"
19843
19979
  ],
@@ -19851,91 +19987,91 @@ function parseShopifyInput(rawInput) {
19851
19987
  return parsed.data;
19852
19988
  }
19853
19989
  __name(parseShopifyInput, "parseShopifyInput");
19854
- var McpCampaignConfig = z77.object({
19990
+ var McpCampaignConfig = z78.object({
19855
19991
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
19856
19992
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
19857
19993
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
19858
- dailyBudgetUsd: z77.number().positive().optional(),
19994
+ dailyBudgetUsd: z78.number().positive().optional(),
19859
19995
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
19860
19996
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
19861
19997
  * TikTok takes only the first entry. */
19862
- targetCountries: z77.array(CountryIso2Schema).max(1).optional(),
19863
- campaignName: z77.string().trim().min(1).max(100).optional()
19998
+ targetCountries: z78.array(CountryIso2Schema).max(1).optional(),
19999
+ campaignName: z78.string().trim().min(1).max(100).optional()
19864
20000
  });
19865
20001
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
19866
- var MetaInput = z77.object({
19867
- taskId: z77.string().min(1),
20002
+ var MetaInput = z78.object({
20003
+ taskId: z78.string().min(1),
19868
20004
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
19869
- portfolioId: z77.string().trim().min(1),
20005
+ portfolioId: z78.string().trim().min(1),
19870
20006
  /** Exact Facebook Page selected from `list_meta_destinations`. */
19871
- pageId: z77.string().trim().min(1),
20007
+ pageId: z78.string().trim().min(1),
19872
20008
  adAccountId: McpAdAccountId,
19873
- pixelId: z77.string().min(1).optional(),
19874
- landingUrl: z77.string().url().optional(),
20009
+ pixelId: z78.string().min(1).optional(),
20010
+ landingUrl: z78.string().url().optional(),
19875
20011
  /** Select which angles to publish by 0-based index. Omit to publish all
19876
20012
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
19877
- angleIndexes: z77.array(z77.number().int().nonnegative()).optional(),
20013
+ angleIndexes: z78.array(z78.number().int().nonnegative()).optional(),
19878
20014
  campaignConfig: McpCampaignConfig.optional(),
19879
20015
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
19880
20016
  * uses the auto-generated copy attached to the task. Capped at 500 chars
19881
20017
  * (Meta's primary-text limit). */
19882
- primaryText: z77.string().trim().min(1).max(500).optional(),
20018
+ primaryText: z78.string().trim().min(1).max(500).optional(),
19883
20019
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
19884
20020
  * (wa.me) instead of a landing page. */
19885
- phoneNumber: z77.string().min(8).max(32).optional()
20021
+ phoneNumber: z78.string().min(8).max(32).optional()
19886
20022
  });
19887
- var GroupedTaskSource = z77.object({
19888
- type: z77.literal("task"),
19889
- taskId: z77.string().min(1),
19890
- angleIndex: z77.number().int().min(0).optional(),
19891
- videoVariant: z77.enum([
20023
+ var GroupedTaskSource = z78.object({
20024
+ type: z78.literal("task"),
20025
+ taskId: z78.string().min(1),
20026
+ angleIndex: z78.number().int().min(0).optional(),
20027
+ videoVariant: z78.enum([
19892
20028
  "with_subtitles",
19893
20029
  "without_subtitles"
19894
20030
  ]).optional(),
19895
- imageVariantIndex: z77.number().int().min(0).optional()
19896
- });
19897
- var GroupedMediaSource = z77.object({
19898
- type: z77.literal("media"),
19899
- url: z77.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
19900
- path: z77.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
19901
- thumbnailUrl: z77.string().url().optional(),
19902
- thumbnailPath: z77.string().min(1).optional()
20031
+ imageVariantIndex: z78.number().int().min(0).optional()
20032
+ });
20033
+ var GroupedMediaSource = z78.object({
20034
+ type: z78.literal("media"),
20035
+ url: z78.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
20036
+ path: z78.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
20037
+ thumbnailUrl: z78.string().url().optional(),
20038
+ thumbnailPath: z78.string().min(1).optional()
19903
20039
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
19904
20040
  message: "media source needs exactly one of `url` or `path`"
19905
20041
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
19906
20042
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
19907
20043
  });
19908
- var GroupedUploadedAssetSource = z77.object({
19909
- type: z77.literal("asset"),
20044
+ var GroupedUploadedAssetSource = z78.object({
20045
+ type: z78.literal("asset"),
19910
20046
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
19911
- assetId: z77.string().uuid(),
19912
- thumbnailAssetId: z77.string().uuid().optional()
20047
+ assetId: z78.string().uuid(),
20048
+ thumbnailAssetId: z78.string().uuid().optional()
19913
20049
  });
19914
- var GroupedCreative = z77.object({
19915
- type: z77.enum([
20050
+ var GroupedCreative = z78.object({
20051
+ type: z78.enum([
19916
20052
  "image",
19917
20053
  "video"
19918
20054
  ]),
19919
- source: z77.union([
20055
+ source: z78.union([
19920
20056
  GroupedTaskSource,
19921
20057
  GroupedMediaSource,
19922
20058
  GroupedUploadedAssetSource
19923
20059
  ]),
19924
- title: z77.string().max(120).optional(),
19925
- description: z77.string().max(500).optional(),
20060
+ title: z78.string().max(120).optional(),
20061
+ description: z78.string().max(500).optional(),
19926
20062
  cta: MetaCtaType.optional(),
19927
- creativeId: z77.string().min(1).optional()
20063
+ creativeId: z78.string().min(1).optional()
19928
20064
  });
19929
- var GroupedCampaignConfigBase = z77.object({
20065
+ var GroupedCampaignConfigBase = z78.object({
19930
20066
  campaignType: MetaCampaignType.default("sales"),
19931
20067
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
19932
20068
  budgetMode: MetaBudgetMode.optional(),
19933
- campaignDailyBudget: z77.number().int().positive().optional(),
19934
- adSets: z77.array(z77.object({
19935
- tempId: z77.string().min(1).max(80),
19936
- name: z77.string().min(1).max(100),
19937
- dailyBudget: z77.number().int().positive().optional(),
19938
- creativeIds: z77.array(z77.string().min(1)).min(1)
20069
+ campaignDailyBudget: z78.number().int().positive().optional(),
20070
+ adSets: z78.array(z78.object({
20071
+ tempId: z78.string().min(1).max(80),
20072
+ name: z78.string().min(1).max(100),
20073
+ dailyBudget: z78.number().int().positive().optional(),
20074
+ creativeIds: z78.array(z78.string().min(1)).min(1)
19939
20075
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
19940
20076
  /**
19941
20077
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -19943,17 +20079,17 @@ var GroupedCampaignConfigBase = z77.object({
19943
20079
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
19944
20080
  * the API since #849 — unreachable from this tool.
19945
20081
  */
19946
- destination: z77.discriminatedUnion("type", [
19947
- z77.object({
19948
- type: z77.literal("landing"),
19949
- landingUrl: z77.string().url()
20082
+ destination: z78.discriminatedUnion("type", [
20083
+ z78.object({
20084
+ type: z78.literal("landing"),
20085
+ landingUrl: z78.string().url()
19950
20086
  }),
19951
- z77.object({
19952
- type: z77.literal("whatsapp"),
19953
- phoneNumber: z77.string().min(8).max(32)
20087
+ z78.object({
20088
+ type: z78.literal("whatsapp"),
20089
+ phoneNumber: z78.string().min(8).max(32)
19954
20090
  })
19955
20091
  ]),
19956
- saveAsDefault: z77.boolean().default(false),
20092
+ saveAsDefault: z78.boolean().default(false),
19957
20093
  budgetPolicy: MetaBudgetPolicy.optional()
19958
20094
  });
19959
20095
  function resolveBudgetMode(value) {
@@ -19967,7 +20103,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
19967
20103
  const budgetMode = resolveBudgetMode(value);
19968
20104
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
19969
20105
  ctx.addIssue({
19970
- code: z77.ZodIssueCode.custom,
20106
+ code: z78.ZodIssueCode.custom,
19971
20107
  path: [
19972
20108
  "campaignDailyBudget"
19973
20109
  ],
@@ -19978,7 +20114,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
19978
20114
  value.adSets.forEach((adSet, index) => {
19979
20115
  if (adSet.dailyBudget === void 0) {
19980
20116
  ctx.addIssue({
19981
- code: z77.ZodIssueCode.custom,
20117
+ code: z78.ZodIssueCode.custom,
19982
20118
  path: [
19983
20119
  "adSets",
19984
20120
  index,
@@ -19993,28 +20129,28 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
19993
20129
  ...value,
19994
20130
  budgetMode: resolveBudgetMode(value)
19995
20131
  }));
19996
- var PublishCreativesToMetaInputBase = z77.object({
19997
- creatives: z77.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
20132
+ var PublishCreativesToMetaInputBase = z78.object({
20133
+ creatives: z78.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
19998
20134
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
19999
- portfolioId: z77.string().trim().min(1),
20135
+ portfolioId: z78.string().trim().min(1),
20000
20136
  /** Exact Facebook Page selected from `list_meta_destinations`. */
20001
- pageId: z77.string().trim().min(1),
20137
+ pageId: z78.string().trim().min(1),
20002
20138
  adAccountId: McpAdAccountId,
20003
- pixelId: z77.string().min(1).optional(),
20139
+ pixelId: z78.string().min(1).optional(),
20004
20140
  /** Required unless `campaignConfig.destination` is whatsapp — see the
20005
20141
  * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
20006
- landingUrl: z77.string().url().optional(),
20142
+ landingUrl: z78.string().url().optional(),
20007
20143
  /** ISO-2 code or resolvable country name — mirrors the API contract
20008
20144
  * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
20009
20145
  targetCountry: CountryIso2Schema,
20010
- campaignName: z77.string().trim().min(1).max(100),
20146
+ campaignName: z78.string().trim().min(1).max(100),
20011
20147
  campaignConfig: GroupedCampaignConfig.optional()
20012
20148
  });
20013
20149
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
20014
20150
  const destination = value.campaignConfig?.destination;
20015
20151
  if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
20016
20152
  ctx.addIssue({
20017
- code: z77.ZodIssueCode.custom,
20153
+ code: z78.ZodIssueCode.custom,
20018
20154
  path: [
20019
20155
  "landingUrl"
20020
20156
  ],
@@ -20023,7 +20159,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
20023
20159
  }
20024
20160
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
20025
20161
  ctx.addIssue({
20026
- code: z77.ZodIssueCode.custom,
20162
+ code: z78.ZodIssueCode.custom,
20027
20163
  path: [
20028
20164
  "campaignConfig",
20029
20165
  "destination",
@@ -20042,16 +20178,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
20042
20178
  }
20043
20179
  return value;
20044
20180
  });
20045
- var PresignUploadResponseSchema = z77.object({
20046
- uploadUrl: z77.string().url().refine((value) => {
20181
+ var PresignUploadResponseSchema = z78.object({
20182
+ uploadUrl: z78.string().url().refine((value) => {
20047
20183
  const url = new URL(value);
20048
20184
  return !url.username && !url.password && url.protocol === "https:";
20049
20185
  }, "presigned upload URL must be HTTPS without embedded credentials"),
20050
- publicUrl: z77.string().url().refine((value) => {
20186
+ publicUrl: z78.string().url().refine((value) => {
20051
20187
  const url = new URL(value);
20052
20188
  return !url.username && !url.password;
20053
20189
  }, "public media URL must not contain embedded credentials"),
20054
- stagingAssetId: z77.string().uuid()
20190
+ stagingAssetId: z78.string().uuid()
20055
20191
  });
20056
20192
  async function uploadResolvedMedia(api, media, assetRole) {
20057
20193
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -20076,16 +20212,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
20076
20212
  return uploadResolvedMedia(api, media, assetRole);
20077
20213
  }
20078
20214
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
20079
- var TikTokInput = z77.object({
20080
- taskId: z77.string().min(1),
20081
- advertiserId: z77.string().min(1),
20082
- pixelId: z77.string().min(1).optional(),
20083
- landingUrl: z77.string().url().optional(),
20084
- angleIndexes: z77.array(z77.number().int().nonnegative()).optional(),
20215
+ var TikTokInput = z78.object({
20216
+ taskId: z78.string().min(1),
20217
+ advertiserId: z78.string().min(1),
20218
+ pixelId: z78.string().min(1).optional(),
20219
+ landingUrl: z78.string().url().optional(),
20220
+ angleIndexes: z78.array(z78.number().int().nonnegative()).optional(),
20085
20221
  campaignConfig: McpCampaignConfig.optional(),
20086
20222
  /** Override the ad's description (TikTok's body copy). If omitted,
20087
20223
  * ProductMaker uses the auto-generated copy attached to the task. */
20088
- primaryText: z77.string().trim().min(1).max(500).optional()
20224
+ primaryText: z78.string().trim().min(1).max(500).optional()
20089
20225
  });
20090
20226
  function registerPublishTools(server, api, opts = {}) {
20091
20227
  const transport = opts.transport ?? "http";
@@ -20413,39 +20549,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
20413
20549
 
20414
20550
  // src/tools/meta-upload.ts
20415
20551
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
20416
- import { z as z78 } from "zod";
20552
+ import { z as z79 } from "zod";
20417
20553
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
20418
- var UploadSessionInputBase = z78.object({
20419
- mediaKind: z78.enum([
20554
+ var UploadSessionInputBase = z79.object({
20555
+ mediaKind: z79.enum([
20420
20556
  "image",
20421
20557
  "video",
20422
20558
  "mixed"
20423
20559
  ]).default("mixed").describe("The kind of file the user will select. Use image for product references and landing pages, video for a single video, and mixed only when the consumer supports both."),
20424
- assetRole: z78.enum([
20560
+ assetRole: z79.enum([
20425
20561
  "media",
20426
20562
  "thumbnail"
20427
20563
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
20428
- uploadPurpose: z78.enum([
20564
+ uploadPurpose: z79.enum([
20429
20565
  "product_reference",
20430
20566
  "creative",
20431
20567
  "generic"
20432
20568
  ]).default("generic").describe("The user's purpose for these files. Use product_reference for a product photo used by tasks or landings, creative for media that will become an ad or creative, and generic only when neither applies."),
20433
- maxFiles: z78.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
20569
+ maxFiles: z79.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
20434
20570
  });
20435
- var OpenAiFileReference = z78.object({
20436
- download_url: z78.string().url().optional().describe("Optional host-provided download URL. The App prefers getFileDownloadUrl(file_id) and the server never fetches this URL."),
20437
- file_id: z78.string().min(1),
20438
- mime_type: z78.string().min(1).optional(),
20439
- file_name: z78.string().min(1).optional()
20571
+ var OpenAiFileReference = z79.object({
20572
+ download_url: z79.string().url().describe("Required by ChatGPT's openai/fileParams schema. The App prefers getFileDownloadUrl(file_id) for a fresh URL, and the server never fetches this value."),
20573
+ file_id: z79.string().min(1),
20574
+ mime_type: z79.string().min(1).optional(),
20575
+ file_name: z79.string().min(1).optional()
20440
20576
  });
20441
20577
  var UploadSessionToolInputShape = {
20442
20578
  ...UploadSessionInputBase.shape,
20443
- files: z78.array(OpenAiFileReference).max(10).optional().describe("Optional OpenAI-hosted file references provided by ChatGPT. They are only metadata for the UI bridge and are never forwarded to ProductMaker.")
20579
+ files: z79.array(OpenAiFileReference).max(10).optional().describe("Optional OpenAI-hosted file references provided by ChatGPT. They are only metadata for the UI bridge and are never forwarded to ProductMaker.")
20444
20580
  };
20445
- var UploadSessionToolInput = z78.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
20581
+ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
20446
20582
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
20447
20583
  ctx.addIssue({
20448
- code: z78.ZodIssueCode.custom,
20584
+ code: z79.ZodIssueCode.custom,
20449
20585
  path: [
20450
20586
  "mediaKind"
20451
20587
  ],
@@ -20454,7 +20590,7 @@ var UploadSessionToolInput = z78.object(UploadSessionToolInputShape).superRefine
20454
20590
  }
20455
20591
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
20456
20592
  ctx.addIssue({
20457
- code: z78.ZodIssueCode.custom,
20593
+ code: z79.ZodIssueCode.custom,
20458
20594
  path: [
20459
20595
  "maxFiles"
20460
20596
  ],
@@ -20463,7 +20599,7 @@ var UploadSessionToolInput = z78.object(UploadSessionToolInputShape).superRefine
20463
20599
  }
20464
20600
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
20465
20601
  ctx.addIssue({
20466
- code: z78.ZodIssueCode.custom,
20602
+ code: z79.ZodIssueCode.custom,
20467
20603
  path: [
20468
20604
  "maxFiles"
20469
20605
  ],
@@ -20471,38 +20607,38 @@ var UploadSessionToolInput = z78.object(UploadSessionToolInputShape).superRefine
20471
20607
  });
20472
20608
  }
20473
20609
  });
20474
- var UploadSessionResponse = z78.object({
20475
- sessionId: z78.string().uuid(),
20476
- uploadPageUrl: z78.string().url(),
20477
- mediaKind: z78.enum([
20610
+ var UploadSessionResponse = z79.object({
20611
+ sessionId: z79.string().uuid(),
20612
+ uploadPageUrl: z79.string().url(),
20613
+ mediaKind: z79.enum([
20478
20614
  "image",
20479
20615
  "video",
20480
20616
  "mixed"
20481
20617
  ]),
20482
- assetRole: z78.enum([
20618
+ assetRole: z79.enum([
20483
20619
  "media",
20484
20620
  "thumbnail"
20485
20621
  ]),
20486
- maxFiles: z78.number().int().positive(),
20487
- expiresAt: z78.string().datetime()
20622
+ maxFiles: z79.number().int().positive(),
20623
+ expiresAt: z79.string().datetime()
20488
20624
  });
20489
- var UploadStatusInput = z78.object({
20490
- sessionId: z78.string().uuid().describe("The sessionId returned by request_media_upload.")
20625
+ var UploadStatusInput = z79.object({
20626
+ sessionId: z79.string().uuid().describe("The sessionId returned by request_media_upload.")
20491
20627
  });
20492
- var UniversalUploadStatusResponse = z78.discriminatedUnion("status", [
20493
- z78.object({
20494
- status: z78.literal("pending"),
20495
- assets: z78.array(z78.never()).length(0)
20628
+ var UniversalUploadStatusResponse = z79.discriminatedUnion("status", [
20629
+ z79.object({
20630
+ status: z79.literal("pending"),
20631
+ assets: z79.array(z79.never()).length(0)
20496
20632
  }),
20497
- z78.object({
20498
- status: z78.literal("uploaded"),
20499
- assets: z78.array(z78.object({
20500
- assetId: z78.string().uuid(),
20501
- mediaKind: z78.enum([
20633
+ z79.object({
20634
+ status: z79.literal("uploaded"),
20635
+ assets: z79.array(z79.object({
20636
+ assetId: z79.string().uuid(),
20637
+ mediaKind: z79.enum([
20502
20638
  "image",
20503
20639
  "video"
20504
20640
  ]),
20505
- assetRole: z78.enum([
20641
+ assetRole: z79.enum([
20506
20642
  "media",
20507
20643
  "thumbnail"
20508
20644
  ])
@@ -20510,13 +20646,13 @@ var UniversalUploadStatusResponse = z78.discriminatedUnion("status", [
20510
20646
  })
20511
20647
  ]);
20512
20648
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
20513
- uploadPurpose: z78.enum([
20649
+ uploadPurpose: z79.enum([
20514
20650
  "product_reference",
20515
20651
  "creative",
20516
20652
  "generic"
20517
20653
  ]),
20518
- checkToolName: z78.literal("check_media_upload"),
20519
- resolveEndpoint: z78.string().url()
20654
+ checkToolName: z79.literal("check_media_upload"),
20655
+ resolveEndpoint: z79.string().url()
20520
20656
  });
20521
20657
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
20522
20658
  const url = new URL(uploadPageUrl);
@@ -20548,7 +20684,7 @@ __name(resolveEndpointForSession, "resolveEndpointForSession");
20548
20684
  function registerMediaUploadTools(server, api) {
20549
20685
  registerAppTool(server, "request_media_upload", {
20550
20686
  title: "Subir archivos",
20551
- description: requestMediaUploadGuidance.summary + " Cuando la foto o el video sea el siguiente dato faltante, ll\xE1malo en esa misma respuesta: no te limites a pedir que lo adjunte en el chat y esperar otro turno. Ll\xE1malo tambi\xE9n autom\xE1ticamente y antes de preguntar por campos faltantes adicionales cuando una petici\xF3n natural adjunte o mencione un archivo local, por ejemplo \u2018crea una landing con este producto\u2019, \u2018haz creativos con esta foto\u2019 o \u2018sube este video a Meta\u2019; hazlo aunque el usuario diga que todav\xEDa no generes ni publiques, porque esta herramienta solo prepara el archivo y no consume cr\xE9ditos, salvo que proh\xEDba expl\xEDcitamente subir, compartir o almacenar el archivo; no pidas una ruta local ni URL. Es la \xFAnica ruta de carga para create_product_task, generate_image_creatives, generate_video_creative, generate_free_video, generate_landing y publish_creatives_to_meta. Pasa las referencias opcionales de ChatGPT en files; si el host no puede transferirlas, el mismo App muestra el selector inline. Usa uploadPurpose=product_reference para fotos de producto y landings, creative para creativos o anuncios, y generic solo cuando ninguno aplique. Usa mediaKind=image para referencias de producto y landings; mixed solo cuando el consumidor acepte ambos tipos. El App NO te avisa cuando termina: en cuanto el usuario diga que ya subi\xF3 el archivo o que sigas, llama `check_media_upload` con este sessionId para obtener los assetId, y reanuda la intenci\xF3n original usando \xFAnicamente assetId y mediaKind, sin pedir que vuelva a subir ni mostrar datos t\xE9cnicos. El enlace externo es fallback solo si el App inline falla. Esta herramienta no genera, publica ni consume cr\xE9ditos.",
20687
+ description: requestMediaUploadGuidance.summary + " Cuando la foto o el video sea el siguiente dato faltante, ll\xE1malo en esa misma respuesta: no te limites a pedir que lo adjunte en el chat y esperar otro turno. Ll\xE1malo tambi\xE9n autom\xE1ticamente y antes de preguntar por campos faltantes adicionales cuando una petici\xF3n natural adjunte o mencione un archivo local, por ejemplo \u2018crea una landing con este producto\u2019, \u2018haz creativos con esta foto\u2019 o \u2018sube este video a Meta\u2019; hazlo aunque el usuario diga que todav\xEDa no generes ni publiques, porque esta herramienta solo prepara el archivo y no consume cr\xE9ditos, salvo que proh\xEDba expl\xEDcitamente subir, compartir o almacenar el archivo; no pidas una ruta local ni URL. Es la \xFAnica ruta de carga para create_product_task, generate_image_creatives, generate_video_creative, generate_free_video, generate_landing y publish_creatives_to_meta. Pasa las referencias de ChatGPT en files con download_url y file_id. Si otro host no puede proporcionar ambos, omite files para que el App abra el selector inline o el enlace de carga. Usa uploadPurpose=product_reference para fotos de producto y landings, creative para creativos o anuncios, y generic solo cuando ninguno aplique. Usa mediaKind=image para referencias de producto y landings; mixed solo cuando el consumidor acepte ambos tipos. El App NO te avisa cuando termina: en cuanto el usuario diga que ya subi\xF3 el archivo o que sigas, llama `check_media_upload` con este sessionId para obtener los assetId, y reanuda la intenci\xF3n original usando \xFAnicamente assetId y mediaKind, sin pedir que vuelva a subir ni mostrar datos t\xE9cnicos. El enlace externo es fallback solo si el App inline falla. Esta herramienta no genera, publica ni consume cr\xE9ditos.",
20552
20688
  inputSchema: UploadSessionToolInputShape,
20553
20689
  annotations: CREATES_INTERNAL,
20554
20690
  outputSchema: UniversalUploadStructuredResponse.shape,
@@ -20607,15 +20743,15 @@ function registerMediaUploadTools(server, api) {
20607
20743
  __name(registerMediaUploadTools, "registerMediaUploadTools");
20608
20744
 
20609
20745
  // src/tools/campaigns.ts
20610
- import { z as z79 } from "zod";
20746
+ import { z as z80 } from "zod";
20611
20747
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
20612
20748
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
20613
- var MetaStatusInput = z79.object({
20614
- campaignId: z79.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
20749
+ var MetaStatusInput = z80.object({
20750
+ campaignId: z80.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
20615
20751
  });
20616
- var TikTokStatusInput = z79.object({
20617
- campaignId: z79.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
20618
- advertiserId: z79.string().min(1).describe("The same advertiserId used to publish the campaign.")
20752
+ var TikTokStatusInput = z80.object({
20753
+ campaignId: z80.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
20754
+ advertiserId: z80.string().min(1).describe("The same advertiserId used to publish the campaign.")
20619
20755
  });
20620
20756
  function registerCampaignTools(server, api) {
20621
20757
  server.tool("get_meta_campaign_status", getMetaCampaignStatusGuidance.summary + " Llama esto DESPU\xC9S de `publish_to_meta` para confirmar que la campa\xF1a se cre\xF3 correctamente y para reportar performance al usuario. Es read-only \u2014 no modifica nada en Meta Ads Manager.", MetaStatusInput.shape, READS_EXTERNAL, async (input) => {
@@ -20712,10 +20848,10 @@ function renderTikTokStatusMarkdown(r) {
20712
20848
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
20713
20849
 
20714
20850
  // ../../packages/product-economics/src/product-costing.ts
20715
- import { z as z81 } from "zod";
20851
+ import { z as z82 } from "zod";
20716
20852
 
20717
20853
  // ../../packages/product-economics/src/product-costing-countries.ts
20718
- import { z as z80 } from "zod";
20854
+ import { z as z81 } from "zod";
20719
20855
 
20720
20856
  // ../../packages/product-economics/src/product-costing-shipping-references.json
20721
20857
  var product_costing_shipping_references_default = {
@@ -20779,21 +20915,21 @@ var product_costing_shipping_references_default = {
20779
20915
  };
20780
20916
 
20781
20917
  // ../../packages/product-economics/src/product-costing-countries.ts
20782
- var ShippingReferenceSchema = z80.object({
20783
- reference: z80.number().positive(),
20784
- min: z80.number().nonnegative(),
20785
- max: z80.number().positive(),
20786
- updatedAt: z80.string().date(),
20787
- confidence: z80.enum([
20918
+ var ShippingReferenceSchema = z81.object({
20919
+ reference: z81.number().positive(),
20920
+ min: z81.number().nonnegative(),
20921
+ max: z81.number().positive(),
20922
+ updatedAt: z81.string().date(),
20923
+ confidence: z81.enum([
20788
20924
  "high",
20789
20925
  "medium",
20790
20926
  "medium-low"
20791
20927
  ]),
20792
- sources: z80.array(z80.string().url().startsWith("https://")).min(1).max(3)
20928
+ sources: z81.array(z81.string().url().startsWith("https://")).min(1).max(3)
20793
20929
  }).superRefine(({ reference, min, max }, context) => {
20794
20930
  if (min > reference || reference > max) {
20795
20931
  context.addIssue({
20796
- code: z80.ZodIssueCode.custom,
20932
+ code: z81.ZodIssueCode.custom,
20797
20933
  message: "shipping_reference_outside_range",
20798
20934
  path: [
20799
20935
  "reference"
@@ -20801,7 +20937,7 @@ var ShippingReferenceSchema = z80.object({
20801
20937
  });
20802
20938
  }
20803
20939
  });
20804
- var SHIPPING_REFERENCES = z80.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
20940
+ var SHIPPING_REFERENCES = z81.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
20805
20941
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
20806
20942
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
20807
20943
  "MX",
@@ -20983,18 +21119,18 @@ function getProductCostingCountryName(country) {
20983
21119
  __name(getProductCostingCountryName, "getProductCostingCountryName");
20984
21120
 
20985
21121
  // ../../packages/product-economics/src/product-costing.ts
20986
- var ProductCostingInputSchema = z81.object({
20987
- country: z81.string().refine(isProductCostingCountryCode, "unsupported_country"),
20988
- supplierCost: z81.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
20989
- shippingCost: z81.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
20990
- returnRate: z81.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
20991
- cancellationRate: z81.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
20992
- adsManagerCpa: z81.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
20993
- desiredMargin: z81.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
21122
+ var ProductCostingInputSchema = z82.object({
21123
+ country: z82.string().refine(isProductCostingCountryCode, "unsupported_country"),
21124
+ supplierCost: z82.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
21125
+ shippingCost: z82.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
21126
+ returnRate: z82.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
21127
+ cancellationRate: z82.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
21128
+ adsManagerCpa: z82.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
21129
+ desiredMargin: z82.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
20994
21130
  }).superRefine(({ returnRate, cancellationRate }, context) => {
20995
21131
  if (returnRate + cancellationRate >= 1) {
20996
21132
  context.addIssue({
20997
- code: z81.ZodIssueCode.custom,
21133
+ code: z82.ZodIssueCode.custom,
20998
21134
  message: "delivery_rate_positive",
20999
21135
  path: [
21000
21136
  "cancellationRate"
@@ -21091,15 +21227,15 @@ function calculateProductCosting(rawInput) {
21091
21227
  __name(calculateProductCosting, "calculateProductCosting");
21092
21228
 
21093
21229
  // src/tools/product-costing.ts
21094
- import { z as z82 } from "zod";
21230
+ import { z as z83 } from "zod";
21095
21231
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
21096
- var optionalAmount = /* @__PURE__ */ __name((description) => z82.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
21097
- var optionalPercent = /* @__PURE__ */ __name((description) => z82.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
21098
- var ProductCostingToolInput = z82.object({
21099
- country: z82.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
21232
+ var optionalAmount = /* @__PURE__ */ __name((description) => z83.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
21233
+ var optionalPercent = /* @__PURE__ */ __name((description) => z83.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
21234
+ var ProductCostingToolInput = z83.object({
21235
+ country: z83.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
21100
21236
  message: "Pa\xEDs no soportado por ProductMaker."
21101
21237
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
21102
- supplierCost: z82.number().finite().max(Number.MAX_SAFE_INTEGER).positive().optional().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. Requerido salvo que uses supplierCostCop para Colombia."),
21238
+ supplierCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER).positive().optional().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. Requerido salvo que uses supplierCostCop para Colombia."),
21103
21239
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
21104
21240
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
21105
21241
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -21258,7 +21394,7 @@ function formatPercent(value) {
21258
21394
  __name(formatPercent, "formatPercent");
21259
21395
 
21260
21396
  // src/tools/product-research.ts
21261
- import { z as z83 } from "zod";
21397
+ import { z as z84 } from "zod";
21262
21398
 
21263
21399
  // src/tools/product-research-idempotency.ts
21264
21400
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -21629,17 +21765,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
21629
21765
  ]);
21630
21766
  var POLL_INTERVAL_MS = 5e3;
21631
21767
  var MAX_WAIT_SECONDS = 120;
21632
- var FindInput = z83.object({
21768
+ var FindInput = z84.object({
21633
21769
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
21634
21770
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
21635
- confirmed: z83.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
21636
- waitSeconds: z83.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
21771
+ confirmed: z84.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
21772
+ waitSeconds: z84.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
21637
21773
  });
21638
- var GetInput = z83.object({
21639
- runId: z83.string().uuid().describe("ID del run devuelto por find_winning_products.")
21774
+ var GetInput = z84.object({
21775
+ runId: z84.string().uuid().describe("ID del run devuelto por find_winning_products.")
21640
21776
  });
21641
- var ListInput = z83.object({
21642
- limit: z83.number().int().min(1).max(20).default(10)
21777
+ var ListInput = z84.object({
21778
+ limit: z84.number().int().min(1).max(20).default(10)
21643
21779
  });
21644
21780
  function textResult(text) {
21645
21781
  return {
@@ -21676,7 +21812,7 @@ async function pollUntilTerminal(api, runId, waitSeconds) {
21676
21812
  }
21677
21813
  __name(pollUntilTerminal, "pollUntilTerminal");
21678
21814
  function registerProductResearchTools(server, api) {
21679
- server.tool("find_winning_products", `${findWinningProductsGuidance.summary} CUESTA ${PRICE_CREDITS} CR\xC9DITOS por ejecuci\xF3n. ANTES de invocar, dile al usuario el costo y espera su aceptaci\xF3n expl\xEDcita; s\xF3lo entonces pasa confirmed: true. Consulta primero list_product_research_runs (GRATIS) \u2014 puede que el usuario ya tenga un reporte pagado para ese pa\xEDs/categor\xEDa y no necesites cobrar de nuevo. Pa\xEDses disponibles: CO, MX, PE, EC, CL. Tarda varios minutos: usa waitSeconds para esperar, y si expira consulta el resultado con get_product_research_run \u2014 el reporte NO se pierde.`, FindInput.shape, CREATES_EXTERNAL, async (input) => {
21815
+ server.tool("find_winning_products", `${findWinningProductsGuidance.summary} CUESTA ${PRICE_CREDITS} CR\xC9DITOS por ejecuci\xF3n. ANTES de invocar, dile al usuario el costo y espera su aceptaci\xF3n expl\xEDcita; s\xF3lo entonces pasa confirmed: true. Consulta primero list_product_research_runs (GRATIS) \u2014 puede que el usuario ya tenga un reporte pagado para ese pa\xEDs/categor\xEDa y no necesites cobrar de nuevo. Pa\xEDses disponibles: CO, MX, PE, EC, CL. Tarda varios minutos: usa waitSeconds para esperar, y si expira consulta el resultado con get_product_research_run \u2014 el reporte NO se pierde.`, FindInput.shape, CREATES_PAID_OPEN_WORLD, async (input) => {
21680
21816
  const parsed = FindInput.parse(input);
21681
21817
  if (!parsed.confirmed) {
21682
21818
  throw mcp(McpErrorCode.INVALID_INPUT, `This research run costs ${PRICE_CREDITS} credits. Tell the user the cost, get an explicit yes, then call again with confirmed: true.`);
@@ -21731,7 +21867,7 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
21731
21867
  throw translateError(error);
21732
21868
  }
21733
21869
  });
21734
- server.tool("prepare_winning_product_image", prepareWinningProductImageGuidance.summary + " GRATIS. \xDAsalo s\xF3lo despu\xE9s de que el usuario elija un candidato del reporte. Importa de forma segura la foto exacta a ProductMaker, la muestra y luego pide elegir: usarla, usarla y agregar m\xE1s, o subir s\xF3lo fotos propias.", WinnerReferenceInput.shape, CREATES_EXTERNAL, async (input) => {
21870
+ server.tool("prepare_winning_product_image", prepareWinningProductImageGuidance.summary + " GRATIS. \xDAsalo s\xF3lo despu\xE9s de que el usuario elija un candidato del reporte. Importa de forma segura la foto exacta a ProductMaker, la muestra y luego pide elegir: usarla, usarla y agregar m\xE1s, o subir s\xF3lo fotos propias.", WinnerReferenceInput.shape, CREATES_OPEN_WORLD, async (input) => {
21735
21871
  const parsed = WinnerReferenceInput.parse(input);
21736
21872
  try {
21737
21873
  const prepared = WinningProductPreparedImageSchema.parse(await api.postJson(`/v1/product-research/runs/${encodeURIComponent(parsed.runId)}/candidates/${encodeURIComponent(parsed.candidateSourceId)}/image-asset`, {}));
@@ -21762,17 +21898,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
21762
21898
  __name(registerProductResearchTools, "registerProductResearchTools");
21763
21899
 
21764
21900
  // src/tools/dropshipping-projects.ts
21765
- import { z as z84 } from "zod";
21901
+ import { z as z85 } from "zod";
21766
21902
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
21767
21903
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
21768
21904
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
21769
- var ProjectId = z84.string().uuid();
21770
- var DropshippingProjectStatus = z84.enum([
21905
+ var ProjectId = z85.string().uuid();
21906
+ var DropshippingProjectStatus = z85.enum([
21771
21907
  "active",
21772
21908
  "completed",
21773
21909
  "archived"
21774
21910
  ]);
21775
- var DropshippingProjectPhase = z84.enum([
21911
+ var DropshippingProjectPhase = z85.enum([
21776
21912
  "research",
21777
21913
  "costing",
21778
21914
  "media",
@@ -21781,21 +21917,21 @@ var DropshippingProjectPhase = z84.enum([
21781
21917
  "advertising",
21782
21918
  "complete"
21783
21919
  ]);
21784
- var DropshippingRewardMilestone = z84.enum([
21920
+ var DropshippingRewardMilestone = z85.enum([
21785
21921
  "product_selected",
21786
21922
  "costing_saved",
21787
21923
  "product_media_ready",
21788
21924
  "creatives_completed",
21789
21925
  "campaign_created"
21790
21926
  ]);
21791
- var TargetCountry = z84.enum([
21927
+ var TargetCountry = z85.enum([
21792
21928
  "CO",
21793
21929
  "MX",
21794
21930
  "PE",
21795
21931
  "EC",
21796
21932
  "CL"
21797
21933
  ]);
21798
- var ResearchCategory = z84.enum([
21934
+ var ResearchCategory = z85.enum([
21799
21935
  "auto",
21800
21936
  "automotive",
21801
21937
  "kitchen",
@@ -21810,7 +21946,7 @@ var ResearchCategory = z84.enum([
21810
21946
  "garden",
21811
21947
  "cleaning"
21812
21948
  ]);
21813
- var HttpUrl3 = z84.string().url().max(2e3).refine((value) => {
21949
+ var HttpUrl3 = z85.string().url().max(2e3).refine((value) => {
21814
21950
  try {
21815
21951
  return [
21816
21952
  "http:",
@@ -21820,45 +21956,45 @@ var HttpUrl3 = z84.string().url().max(2e3).refine((value) => {
21820
21956
  return false;
21821
21957
  }
21822
21958
  }, "URL must use HTTP(S)");
21823
- var ResearchCandidateOrigin = z84.object({
21824
- type: z84.literal("research_candidate"),
21959
+ var ResearchCandidateOrigin = z85.object({
21960
+ type: z85.literal("research_candidate"),
21825
21961
  runId: ProjectId,
21826
- candidateSourceId: z84.string().min(1).max(160)
21962
+ candidateSourceId: z85.string().min(1).max(160)
21827
21963
  });
21828
- var TaskOrigin = z84.object({
21829
- type: z84.literal("task"),
21964
+ var TaskOrigin = z85.object({
21965
+ type: z85.literal("task"),
21830
21966
  taskId: ProjectId
21831
21967
  });
21832
- var ManualOrigin = z84.object({
21833
- type: z84.literal("manual"),
21968
+ var ManualOrigin = z85.object({
21969
+ type: z85.literal("manual"),
21834
21970
  clientRequestId: ProjectId,
21835
- country: z84.string().min(2).max(3).optional()
21971
+ country: z85.string().min(2).max(3).optional()
21836
21972
  });
21837
- var StartProjectInput = z84.object({
21838
- origin: z84.discriminatedUnion("type", [
21973
+ var StartProjectInput = z85.object({
21974
+ origin: z85.discriminatedUnion("type", [
21839
21975
  ResearchCandidateOrigin,
21840
21976
  TaskOrigin,
21841
21977
  ManualOrigin
21842
21978
  ]),
21843
- productName: z84.string().trim().min(1).max(240).optional(),
21979
+ productName: z85.string().trim().min(1).max(240).optional(),
21844
21980
  productUrl: HttpUrl3.optional(),
21845
- country: z84.string().min(2).max(3).optional(),
21846
- languageCode: z84.string().min(2).max(16).optional()
21981
+ country: z85.string().min(2).max(3).optional(),
21982
+ languageCode: z85.string().min(2).max(16).optional()
21847
21983
  }).strict();
21848
- var CostProjectInput = z84.object({
21984
+ var CostProjectInput = z85.object({
21849
21985
  projectId: ProjectId,
21850
- version: z84.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
21851
- country: z84.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
21986
+ version: z85.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
21987
+ country: z85.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
21852
21988
  message: "Pa\xEDs no soportado por ProductMaker."
21853
21989
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
21854
- supplierCost: z84.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
21855
- shippingCost: z84.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
21856
- returnRate: z84.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
21857
- cancellationRate: z84.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
21858
- adsManagerCpa: z84.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
21859
- desiredMargin: z84.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
21860
- });
21861
- var GuideInput = z84.object({
21990
+ supplierCost: z85.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
21991
+ shippingCost: z85.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
21992
+ returnRate: z85.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
21993
+ cancellationRate: z85.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
21994
+ adsManagerCpa: z85.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
21995
+ desiredMargin: z85.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
21996
+ });
21997
+ var GuideInput = z85.object({
21862
21998
  projectId: ProjectId.optional()
21863
21999
  }).strict();
21864
22000
  var NEXT_ACTION_KINDS = [
@@ -21876,29 +22012,29 @@ var NEXT_ACTION_KINDS = [
21876
22012
  "repair_meta_campaign",
21877
22013
  "review_paused_campaign"
21878
22014
  ];
21879
- var DropshippingProjectNextAction = z84.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z84.object({
21880
- kind: z84.literal(kind),
21881
- href: z84.string().min(1)
22015
+ var DropshippingProjectNextAction = z85.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z85.object({
22016
+ kind: z85.literal(kind),
22017
+ href: z85.string().min(1)
21882
22018
  })));
21883
- var CostingInputSchema = z84.object({
21884
- country: z84.string().min(2).max(3),
21885
- supplierCost: z84.number().finite().positive(),
21886
- shippingCost: z84.number().finite().nonnegative(),
21887
- returnRate: z84.number().finite().min(0).lt(1),
21888
- cancellationRate: z84.number().finite().min(0).lt(1),
21889
- adsManagerCpa: z84.number().finite().nonnegative(),
21890
- desiredMargin: z84.number().finite().min(0).lt(1)
22019
+ var CostingInputSchema = z85.object({
22020
+ country: z85.string().min(2).max(3),
22021
+ supplierCost: z85.number().finite().positive(),
22022
+ shippingCost: z85.number().finite().nonnegative(),
22023
+ returnRate: z85.number().finite().min(0).lt(1),
22024
+ cancellationRate: z85.number().finite().min(0).lt(1),
22025
+ adsManagerCpa: z85.number().finite().nonnegative(),
22026
+ desiredMargin: z85.number().finite().min(0).lt(1)
21891
22027
  }).superRefine(({ returnRate, cancellationRate }, context) => {
21892
22028
  if (returnRate + cancellationRate >= 1) context.addIssue({
21893
- code: z84.ZodIssueCode.custom,
22029
+ code: z85.ZodIssueCode.custom,
21894
22030
  path: [
21895
22031
  "cancellationRate"
21896
22032
  ]
21897
22033
  });
21898
22034
  });
21899
- var FiniteCostingNumber = z84.number().finite();
21900
- var CostingResultSchema = z84.object({
21901
- country: z84.string().min(2).max(3),
22035
+ var FiniteCostingNumber = z85.number().finite();
22036
+ var CostingResultSchema = z85.object({
22037
+ country: z85.string().min(2).max(3),
21902
22038
  deliveryRate: FiniteCostingNumber,
21903
22039
  adjustedShippingCost: FiniteCostingNumber,
21904
22040
  adjustedCpa: FiniteCostingNumber,
@@ -21911,45 +22047,45 @@ var CostingResultSchema = z84.object({
21911
22047
  estimatedProfit: FiniteCostingNumber,
21912
22048
  actualMargin: FiniteCostingNumber,
21913
22049
  breakEvenAdsManagerCpa: FiniteCostingNumber,
21914
- wasPriceAutoAdjusted: z84.boolean(),
21915
- profitabilityStatus: z84.literal("healthy")
21916
- });
21917
- var RewardProgressSchema = z84.object({
21918
- campaignKey: z84.literal("dropshipping-launch-v1"),
21919
- totalCredits: z84.number().int().positive(),
21920
- earnedCredits: z84.number().int().nonnegative(),
21921
- milestones: z84.array(z84.object({
22050
+ wasPriceAutoAdjusted: z85.boolean(),
22051
+ profitabilityStatus: z85.literal("healthy")
22052
+ });
22053
+ var RewardProgressSchema = z85.object({
22054
+ campaignKey: z85.literal("dropshipping-launch-v1"),
22055
+ totalCredits: z85.number().int().positive(),
22056
+ earnedCredits: z85.number().int().nonnegative(),
22057
+ milestones: z85.array(z85.object({
21922
22058
  milestone: DropshippingRewardMilestone,
21923
- credits: z84.number().int().positive(),
21924
- available: z84.boolean().optional(),
21925
- earned: z84.boolean(),
22059
+ credits: z85.number().int().positive(),
22060
+ available: z85.boolean().optional(),
22061
+ earned: z85.boolean(),
21926
22062
  grantId: ProjectId.nullable(),
21927
- grantedAt: z84.string().datetime().nullable()
22063
+ grantedAt: z85.string().datetime().nullable()
21928
22064
  })).length(DropshippingRewardMilestone.options.length)
21929
22065
  });
21930
- var ProjectResponseSchema = z84.object({
22066
+ var ProjectResponseSchema = z85.object({
21931
22067
  id: ProjectId,
21932
22068
  taskId: ProjectId.nullable(),
21933
22069
  status: DropshippingProjectStatus,
21934
- originKey: z84.string().min(1),
22070
+ originKey: z85.string().min(1),
21935
22071
  researchRunId: ProjectId.nullable(),
21936
- candidateSourceId: z84.string().nullable(),
21937
- productName: z84.string().nullable(),
22072
+ candidateSourceId: z85.string().nullable(),
22073
+ productName: z85.string().nullable(),
21938
22074
  productUrl: HttpUrl3.nullable(),
21939
22075
  referenceImageUrl: HttpUrl3.nullable(),
21940
- targetCountry: z84.string().nullable(),
21941
- languageCode: z84.string().nullable(),
21942
- hasReferenceImage: z84.boolean(),
21943
- hasWinnerReferenceImage: z84.boolean(),
22076
+ targetCountry: z85.string().nullable(),
22077
+ languageCode: z85.string().nullable(),
22078
+ hasReferenceImage: z85.boolean(),
22079
+ hasWinnerReferenceImage: z85.boolean(),
21944
22080
  costingInput: CostingInputSchema.nullable(),
21945
22081
  costingResult: CostingResultSchema.nullable(),
21946
- costingVersion: z84.number().int().positive().nullable(),
21947
- version: z84.number().int().positive(),
22082
+ costingVersion: z85.number().int().positive().nullable(),
22083
+ version: z85.number().int().positive(),
21948
22084
  phase: DropshippingProjectPhase,
21949
22085
  nextAction: DropshippingProjectNextAction.nullable(),
21950
22086
  rewards: RewardProgressSchema,
21951
- createdAt: z84.string().datetime(),
21952
- updatedAt: z84.string().datetime()
22087
+ createdAt: z85.string().datetime(),
22088
+ updatedAt: z85.string().datetime()
21953
22089
  }).passthrough();
21954
22090
  var NEXT_ACTION_GUIDANCE = {
21955
22091
  cost_product: "Llama `cost_dropshipping_project` con el costo real del proveedor. Nunca lo inventes: p\xEDdeselo al usuario. Es el \xDANICO dato que debes pedirle: omite env\xEDo, devoluciones, cancelaciones, CPA y margen para que ProductMaker use los valores gu\xEDa del pa\xEDs, y luego dile al usuario cu\xE1les us\xF3 por si quiere corregirlos.",
@@ -22067,58 +22203,58 @@ function registerDropshippingProjectTools(server, api) {
22067
22203
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
22068
22204
 
22069
22205
  // src/tools/daily-control.ts
22070
- import { z as z85 } from "zod";
22206
+ import { z as z86 } from "zod";
22071
22207
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
22072
22208
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
22073
22209
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
22074
- var ProviderCampaignIdentifier = z85.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
22075
- var DateOnly = z85.string().regex(/^\d{4}-\d{2}-\d{2}$/);
22076
- var DailyControlInput = z85.object({
22210
+ var ProviderCampaignIdentifier = z86.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
22211
+ var DateOnly = z86.string().regex(/^\d{4}-\d{2}-\d{2}$/);
22212
+ var DailyControlInput = z86.object({
22077
22213
  date: DateOnly.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, la ventana termina AYER en UTC \u2014 nunca hoy, porque el d\xEDa en curso est\xE1 incompleto \u2014 y el servidor puede correrla un d\xEDa m\xE1s atr\xE1s si en la zona horaria de la tienda ese d\xEDa todav\xEDa no ha cerrado."),
22078
- days: z85.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
22079
- projectId: z85.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
22214
+ days: z86.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
22215
+ projectId: z86.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
22080
22216
  }).strict();
22081
- var LinkCampaignInput = z85.object({
22082
- projectId: z85.string().uuid(),
22083
- provider: z85.enum([
22217
+ var LinkCampaignInput = z86.object({
22218
+ projectId: z86.string().uuid(),
22219
+ provider: z86.enum([
22084
22220
  "meta",
22085
22221
  "tiktok"
22086
22222
  ]),
22087
22223
  accountId: ProviderCampaignIdentifier.describe("Cuenta publicitaria del proveedor. Para Meta el servidor la IGNORA y deriva la cuenta real de la campa\xF1a \u2014 se sigue pidiendo aqu\xED solo porque TikTok s\xED la necesita para resolver la campa\xF1a."),
22088
22224
  campaignId: ProviderCampaignIdentifier
22089
22225
  }).strict();
22090
- var ReportReturnsInput = z85.object({
22091
- projectId: z85.string().uuid(),
22226
+ var ReportReturnsInput = z86.object({
22227
+ projectId: z86.string().uuid(),
22092
22228
  date: DateOnly,
22093
- returnedOrders: z85.number().int().min(0).max(1e5),
22094
- note: z85.string().trim().max(280).optional()
22229
+ returnedOrders: z86.number().int().min(0).max(1e5),
22230
+ note: z86.string().trim().max(280).optional()
22095
22231
  }).strict();
22096
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z85.string());
22097
- var DailyControlLightMirror = DailyControlLightEnum.or(z85.string());
22098
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z85.string());
22099
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z85.string());
22100
- var DailyControlDayMirror = z85.object({
22101
- date: z85.string(),
22102
- returnedOrders: z85.number(),
22232
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z86.string());
22233
+ var DailyControlLightMirror = DailyControlLightEnum.or(z86.string());
22234
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z86.string());
22235
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z86.string());
22236
+ var DailyControlDayMirror = z86.object({
22237
+ date: z86.string(),
22238
+ returnedOrders: z86.number(),
22103
22239
  returnedSource: DailyControlSourceMirror,
22104
22240
  cancelledSource: DailyControlSourceMirror,
22105
- hasEstimates: z85.boolean(),
22241
+ hasEstimates: z86.boolean(),
22106
22242
  light: DailyControlLightMirror
22107
22243
  }).passthrough();
22108
- var DailyControlProductMirror = z85.object({
22109
- projectId: z85.string().uuid(),
22110
- productName: z85.string().nullable(),
22244
+ var DailyControlProductMirror = z86.object({
22245
+ projectId: z86.string().uuid(),
22246
+ productName: z86.string().nullable(),
22111
22247
  status: DailyControlStatusMirror,
22112
- statusMessage: z85.string().nullable(),
22113
- days: z85.array(DailyControlDayMirror),
22248
+ statusMessage: z86.string().nullable(),
22249
+ days: z86.array(DailyControlDayMirror),
22114
22250
  verdict: DailyControlVerdictMirror.nullable(),
22115
- rationale: z85.string().nullable()
22251
+ rationale: z86.string().nullable()
22116
22252
  }).passthrough();
22117
- var DailyControlResponseMirror = z85.object({
22118
- since: z85.string(),
22119
- until: z85.string(),
22120
- products: z85.array(DailyControlProductMirror),
22121
- archivedProjectSpend: z85.array(z85.unknown())
22253
+ var DailyControlResponseMirror = z86.object({
22254
+ since: z86.string(),
22255
+ until: z86.string(),
22256
+ products: z86.array(DailyControlProductMirror),
22257
+ archivedProjectSpend: z86.array(z86.unknown())
22122
22258
  }).passthrough();
22123
22259
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
22124
22260
  function withWarnings(response) {
@@ -22202,42 +22338,42 @@ function registerDailyControlTools(server, api) {
22202
22338
  __name(registerDailyControlTools, "registerDailyControlTools");
22203
22339
 
22204
22340
  // src/tools/product-control.ts
22205
- import { z as z86 } from "zod";
22341
+ import { z as z87 } from "zod";
22206
22342
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
22207
22343
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
22208
22344
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
22209
22345
  var setProductCostingGuidance = getProductMakerCapabilityModelGuidance("set_product_costing");
22210
22346
  var reportProductCountsGuidance = getProductMakerCapabilityModelGuidance("report_product_counts");
22211
- var DateOnly2 = z86.string().regex(/^\d{4}-\d{2}-\d{2}$/);
22347
+ var DateOnly2 = z87.string().regex(/^\d{4}-\d{2}-\d{2}$/);
22212
22348
  var IMPORT_BATCH_MAX2 = 50;
22213
- var ProductControlListInput = z86.object({
22214
- days: z86.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
22349
+ var ProductControlListInput = z87.object({
22350
+ days: z87.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
22215
22351
  date: DateOnly2.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, termina en el \xFAltimo d\xEDa cerrado \u2014 nunca hoy, que est\xE1 incompleto."),
22216
- shopDomain: z86.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
22352
+ shopDomain: z87.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
22217
22353
  }).strict();
22218
- var ImportableProductsInput = z86.object({
22219
- q: z86.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
22220
- after: z86.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
22221
- shopDomain: z86.string().min(1).optional()
22354
+ var ImportableProductsInput = z87.object({
22355
+ q: z87.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
22356
+ after: z87.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
22357
+ shopDomain: z87.string().min(1).optional()
22222
22358
  }).strict();
22223
- var ImportProductControlsInput = z86.object({
22224
- shopifyProductIds: z86.array(z86.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
22359
+ var ImportProductControlsInput = z87.object({
22360
+ shopifyProductIds: z87.array(z87.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
22225
22361
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
22226
22362
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
22227
- shopDomain: z86.string().min(1)
22363
+ shopDomain: z87.string().min(1)
22228
22364
  }).strict();
22229
- var SetProductCostingInput = z86.object({
22230
- shopDomain: z86.string().min(1),
22231
- shopifyProductId: z86.string().min(1).max(64),
22232
- targetCountry: z86.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
22233
- supplierCost: z86.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
22234
- shippingCost: z86.number().finite().nonnegative(),
22235
- returnRate: z86.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
22236
- cancellationRate: z86.number().finite().min(0).lt(1)
22365
+ var SetProductCostingInput = z87.object({
22366
+ shopDomain: z87.string().min(1),
22367
+ shopifyProductId: z87.string().min(1).max(64),
22368
+ targetCountry: z87.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
22369
+ supplierCost: z87.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
22370
+ shippingCost: z87.number().finite().nonnegative(),
22371
+ returnRate: z87.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
22372
+ cancellationRate: z87.number().finite().min(0).lt(1)
22237
22373
  }).strict();
22238
- var Count = z86.number().int().min(0).max(1e5).nullable().optional();
22239
- var ReportProductCountsInput = z86.object({
22240
- productControlId: z86.string().uuid().describe("El identificador que devuelve get_product_control."),
22374
+ var Count = z87.number().int().min(0).max(1e5).nullable().optional();
22375
+ var ReportProductCountsInput = z87.object({
22376
+ productControlId: z87.string().uuid().describe("El identificador que devuelve get_product_control."),
22241
22377
  date: DateOnly2,
22242
22378
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
22243
22379
  cancelledOrders: Count,