@productmaker/mcp 8.0.0 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +8 -0
  2. package/dist/http.js +1632 -802
  3. package/dist/stdio.js +1616 -786
  4. package/package.json +1 -1
package/dist/stdio.js CHANGED
@@ -90,6 +90,23 @@ var VideoPreset = z.enum([
90
90
  ]);
91
91
  var VoiceId = z.string();
92
92
  var _VIDEO_MODEL_SET = new Set(VideoModel.options);
93
+ var BROLL_VIDEO_MODES = new Set(VideoModel.options);
94
+ var PersistedVideoMode = z.enum([
95
+ ...VideoModel.options,
96
+ "avatar_talking",
97
+ "hybrid",
98
+ "sora"
99
+ ]);
100
+ var PersistedVideoModel = z.enum([
101
+ ...VideoModel.options,
102
+ "sora",
103
+ "infinitalk"
104
+ ]);
105
+ var PLAN_VIDEO_MODES = [
106
+ ...VideoModel.options,
107
+ "avatar_talking",
108
+ "hybrid"
109
+ ];
93
110
 
94
111
  // ../../packages/types/src/video-creation.ts
95
112
  import { z as z3 } from "zod";
@@ -1060,40 +1077,206 @@ var VideoTier = z8.preprocess((v) => v === "grok" ? "single_call" : v, z8.enum([
1060
1077
  "single_call"
1061
1078
  ]));
1062
1079
  var DEFAULT_VIDEO_TIER = "single_call";
1080
+ var WritableVideoTier = VideoTier.refine((tier) => tier !== "legacy", {
1081
+ message: "VIDEO_TIER_RETIRED"
1082
+ });
1063
1083
 
1064
- // ../../packages/types/src/image-provider.ts
1065
- var GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K = [
1066
- "4:5",
1067
- "5:4"
1084
+ // ../../packages/types/src/image-models.ts
1085
+ var IMAGE_RESOLUTIONS = [
1086
+ "1k",
1087
+ "2k",
1088
+ "4k"
1068
1089
  ];
1069
- var GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K = [
1070
- "4:5",
1071
- "5:4",
1072
- "27:16",
1073
- "16:27",
1074
- "9:8",
1075
- "8:9"
1090
+ var GPT_IMAGE_2_5_TOKENS = {
1091
+ "1k": "gpt-image-2-5:1k",
1092
+ "2k": "gpt-image-2-5:2k",
1093
+ "4k": "gpt-image-2-5:4k"
1094
+ };
1095
+ var GPT_IMAGE_2_TOKENS = {
1096
+ "1k": "gpt-image-2:1k",
1097
+ "2k": "gpt-image-2:2k",
1098
+ "4k": "gpt-image-2:4k"
1099
+ };
1100
+ var GPT_IMAGE_2_5 = {
1101
+ id: "gpt-image-2.5",
1102
+ status: "active",
1103
+ renderedBy: "gpt-image-2.5",
1104
+ tokens: GPT_IMAGE_2_5_TOKENS,
1105
+ kie: {
1106
+ imageToImage: [
1107
+ "gpt-image-2-5-sunburst-image-to-image",
1108
+ "gpt-image-2-5-flare-image-to-image"
1109
+ ],
1110
+ textToImage: [
1111
+ "gpt-image-2-5-sunburst-text-to-image",
1112
+ "gpt-image-2-5-flare-text-to-image"
1113
+ ],
1114
+ shorthands: [
1115
+ "gpt-image-2-5"
1116
+ ]
1117
+ },
1118
+ fal: {
1119
+ edit: "openai/gpt-image-2.5/sunburst/edit",
1120
+ textToImage: "openai/gpt-image-2.5/sunburst/text-to-image",
1121
+ quality: {
1122
+ "1k": "low",
1123
+ "2k": "medium",
1124
+ "4k": "high"
1125
+ },
1126
+ ourCostCents: {
1127
+ "1k": 1.5,
1128
+ "2k": 6.1,
1129
+ "4k": 17.8
1130
+ }
1131
+ },
1132
+ // Docs KIE de gpt-image-2-5 (sunburst/flare): 27:16, 16:27, 9:8, 8:9 solo 1K;
1133
+ // 4:5 y 5:4 también bloqueados por encima de 1K.
1134
+ ratiosBlockedAbove1k: [
1135
+ "4:5",
1136
+ "5:4",
1137
+ "27:16",
1138
+ "16:27",
1139
+ "9:8",
1140
+ "8:9"
1141
+ ],
1142
+ ledgerSuffix: {
1143
+ "1k": "gpt-image-2",
1144
+ "2k": "gpt-image-2:medium",
1145
+ "4k": "gpt-image-2:high"
1146
+ },
1147
+ falLedgerSuffix: {
1148
+ "1k": "gpt-image-2:1k",
1149
+ "2k": "gpt-image-2:2k",
1150
+ "4k": "gpt-image-2:4k"
1151
+ }
1152
+ };
1153
+ var GPT_IMAGE_2 = {
1154
+ ...GPT_IMAGE_2_5,
1155
+ id: "gpt-image-2",
1156
+ status: "retired",
1157
+ renderedBy: GPT_IMAGE_2_5.id,
1158
+ tokens: GPT_IMAGE_2_TOKENS,
1159
+ kie: {
1160
+ imageToImage: [
1161
+ "gpt-image-2-image-to-image"
1162
+ ],
1163
+ textToImage: [
1164
+ "gpt-image-2-text-to-image"
1165
+ ],
1166
+ shorthands: [
1167
+ "gpt-image-2"
1168
+ ]
1169
+ },
1170
+ ratiosBlockedAbove1k: [
1171
+ "4:5",
1172
+ "5:4"
1173
+ ]
1174
+ };
1175
+ var IMAGE_MODELS = [
1176
+ GPT_IMAGE_2_5,
1177
+ GPT_IMAGE_2
1076
1178
  ];
1077
- function gptImage2SupportsTier(aspectRatio, tier) {
1078
- if (tier === "gpt-image-2:1k" || tier === "gpt-image-2-5:1k") return true;
1079
- if (tier.startsWith("gpt-image-2-5:")) {
1080
- return !GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K.includes(aspectRatio);
1179
+ var ACTIVE_IMAGE_MODEL = GPT_IMAGE_2_5;
1180
+ var IMAGE_WRITE_TOKENS = GPT_IMAGE_2_5_TOKENS;
1181
+ var LEGACY_IMAGE_TOKENS = GPT_IMAGE_2_TOKENS;
1182
+ var PUBLIC_IMAGE_QUALITY_INPUTS = [
1183
+ IMAGE_WRITE_TOKENS["1k"],
1184
+ IMAGE_WRITE_TOKENS["2k"],
1185
+ LEGACY_IMAGE_TOKENS["1k"],
1186
+ LEGACY_IMAGE_TOKENS["2k"],
1187
+ "image:1k",
1188
+ "image:2k"
1189
+ ];
1190
+ function entryById(id) {
1191
+ const found = IMAGE_MODELS.find((entry) => entry.id === id);
1192
+ if (!found) throw new Error(`IMAGE_MODEL_UNKNOWN:${id}`);
1193
+ return found;
1194
+ }
1195
+ __name(entryById, "entryById");
1196
+ function resolveImageToken(raw) {
1197
+ if (typeof raw !== "string") return null;
1198
+ let normalized = raw.trim().toLowerCase();
1199
+ let viaFal = false;
1200
+ if (normalized.startsWith("fal:")) {
1201
+ viaFal = true;
1202
+ normalized = normalized.slice("fal:".length);
1203
+ }
1204
+ for (const resolution of IMAGE_RESOLUTIONS) {
1205
+ if (normalized === `image:${resolution}`) {
1206
+ return {
1207
+ resolution,
1208
+ model: ACTIVE_IMAGE_MODEL,
1209
+ declared: ACTIVE_IMAGE_MODEL,
1210
+ spelling: "intent",
1211
+ viaFal
1212
+ };
1213
+ }
1081
1214
  }
1082
- return !GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K.includes(aspectRatio);
1215
+ for (const entry of IMAGE_MODELS) {
1216
+ for (const resolution of IMAGE_RESOLUTIONS) {
1217
+ if (entry.tokens[resolution] === normalized) {
1218
+ return {
1219
+ resolution,
1220
+ model: entryById(entry.renderedBy),
1221
+ declared: entry,
1222
+ spelling: entry.status === "active" ? "current" : "retired",
1223
+ viaFal
1224
+ };
1225
+ }
1226
+ }
1227
+ }
1228
+ return null;
1229
+ }
1230
+ __name(resolveImageToken, "resolveImageToken");
1231
+ function imageResolutionOf(raw) {
1232
+ const token = resolveImageToken(raw);
1233
+ return token && !token.viaFal ? token.resolution : null;
1234
+ }
1235
+ __name(imageResolutionOf, "imageResolutionOf");
1236
+ function requireKieImageId(ids, index, label) {
1237
+ const id = ids[index];
1238
+ if (!id) throw new Error(`IMAGE_MODEL_NO_KIE_ID:${label}`);
1239
+ return id;
1240
+ }
1241
+ __name(requireKieImageId, "requireKieImageId");
1242
+ var KIE_FLARE_IMAGE_TO_IMAGE_MODEL = requireKieImageId(GPT_IMAGE_2_5.kie.imageToImage, 1, "flare-imageToImage");
1243
+ function canonicalImageModelInput(raw) {
1244
+ if (raw === void 0) return void 0;
1245
+ const token = resolveImageToken(raw);
1246
+ if (!token || token.viaFal || token.spelling !== "intent") return raw;
1247
+ return IMAGE_WRITE_TOKENS[token.resolution];
1248
+ }
1249
+ __name(canonicalImageModelInput, "canonicalImageModelInput");
1250
+ function imageTokenSupportsRatio(aspectRatio, rawToken) {
1251
+ const token = resolveImageToken(rawToken);
1252
+ if (!token) return true;
1253
+ if (token.resolution === "1k") return true;
1254
+ return !token.declared.ratiosBlockedAbove1k.includes(aspectRatio);
1255
+ }
1256
+ __name(imageTokenSupportsRatio, "imageTokenSupportsRatio");
1257
+
1258
+ // ../../packages/types/src/image-provider.ts
1259
+ var GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K = GPT_IMAGE_2.ratiosBlockedAbove1k;
1260
+ var GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K = GPT_IMAGE_2_5.ratiosBlockedAbove1k;
1261
+ function gptImage2SupportsTier(aspectRatio, tier) {
1262
+ return imageTokenSupportsRatio(aspectRatio, tier);
1083
1263
  }
1084
1264
  __name(gptImage2SupportsTier, "gptImage2SupportsTier");
1085
1265
  var IMAGE_TIER_UNSUPPORTED_FOR_RATIO_RULE = "image_tier_unsupported_for_ratio";
1086
1266
  var IMAGE_TIER_LIST = [
1087
- "gpt-image-2-5:1k",
1088
- "gpt-image-2-5:2k",
1089
- "gpt-image-2-5:4k",
1090
- "gpt-image-2:1k",
1091
- "gpt-image-2:2k",
1092
- "gpt-image-2:4k"
1267
+ ...Object.values(IMAGE_WRITE_TOKENS),
1268
+ ...Object.values(LEGACY_IMAGE_TOKENS)
1093
1269
  ];
1270
+ function isImageTier(value) {
1271
+ return IMAGE_TIER_LIST.includes(value);
1272
+ }
1273
+ __name(isImageTier, "isImageTier");
1094
1274
  function parseImageTier(imageModel) {
1095
- const normalized = imageModel.trim().toLowerCase();
1096
- return IMAGE_TIER_LIST.includes(normalized) ? normalized : null;
1275
+ const token = resolveImageToken(imageModel);
1276
+ if (!token || token.viaFal) return null;
1277
+ if (token.spelling === "intent") return IMAGE_WRITE_TOKENS[token.resolution];
1278
+ const declared = token.declared.tokens[token.resolution];
1279
+ return isImageTier(declared) ? declared : null;
1097
1280
  }
1098
1281
  __name(parseImageTier, "parseImageTier");
1099
1282
  function validateImageTierForRatio(aspectRatio, imageModel) {
@@ -3830,7 +4013,7 @@ var IngestOptions = z22.object({
3830
4013
  durationSeconds: FreeVideoOptionsSchema.shape.durationSeconds.optional(),
3831
4014
  addSubtitles: FreeVideoOptionsSchema.shape.addSubtitles.optional(),
3832
4015
  subtitleText: z22.string().transform((value) => value.trim()).pipe(z22.string().max(FREE_VIDEO_SUBTITLE_MAX_CHARS)).optional(),
3833
- videoTier: VideoTier.default(DEFAULT_VIDEO_TIER),
4016
+ videoTier: WritableVideoTier.default(DEFAULT_VIDEO_TIER),
3834
4017
  narrativeStyle: NarrativeStyle.default("review"),
3835
4018
  videoPreset: VideoPreset.optional(),
3836
4019
  multiAngleVideos: z22.boolean().default(false),
@@ -3904,7 +4087,9 @@ var IngestOptions = z22.object({
3904
4087
  aspectRatio: z22.string().optional(),
3905
4088
  brandColors: z22.string().optional(),
3906
4089
  nVariants: z22.number().int().min(1).max(6).optional(),
3907
- imageModel: z22.string().optional(),
4090
+ // O7: `image:Nk` is accepted and stored as the spelling written today
4091
+ // (IMAGE_WRITE_TOKENS); see packages/types/src/image-models.ts.
4092
+ imageModel: z22.string().optional().transform((value) => canonicalImageModelInput(value)),
3908
4093
  styleMix: z22.string().optional(),
3909
4094
  aiDecidesAll: z22.boolean().optional(),
3910
4095
  /** Opt out of the competitor-spy analysis. When false the worker skips
@@ -4023,7 +4208,7 @@ var VideoOptionsOverride = z22.object({
4023
4208
  videoStructure: VideoStructure.optional(),
4024
4209
  videoQuality: VideoQuality.optional(),
4025
4210
  videoModel: VideoModel.optional(),
4026
- videoTier: VideoTier.optional(),
4211
+ videoTier: WritableVideoTier.optional(),
4027
4212
  ugcFormat: VideoFormat.optional(),
4028
4213
  videoStyle: VideoStyle.optional(),
4029
4214
  narrativeStyle: NarrativeStyle.optional(),
@@ -4106,6 +4291,11 @@ var IngestResumePayload = z22.object({
4106
4291
  // "keep what the task has". See angle-management.service.ts resumeAfterAngles.
4107
4292
  videoStyle: VideoStyle.optional(),
4108
4293
  videoModel: VideoModel.default("veo"),
4294
+ // READ schema on purpose, unlike IngestOptions/VideoOptionsOverride: resume
4295
+ // does not write the tier — `resumeAfterAngles` projects the route from the
4296
+ // task's OWN persisted tier and ignores this field. MCP and WhatsApp echo
4297
+ // `status.videoTier`, which is still `legacy` for historical rows; refusing
4298
+ // it made those tasks impossible to resume from both channels.
4109
4299
  videoTier: VideoTier.optional(),
4110
4300
  videoStructure: VideoStructure.optional(),
4111
4301
  videoQuality: VideoQuality.optional(),
@@ -4916,17 +5106,7 @@ var VideoGenerator = z26.object({
4916
5106
  format: VideoFormat.optional(),
4917
5107
  videoStyle: VideoStyle.optional(),
4918
5108
  narrativeStyle: NarrativeStyle.optional(),
4919
- videoMode: z26.enum([
4920
- "veo",
4921
- "wan",
4922
- "bytedance",
4923
- "seedance",
4924
- "grok",
4925
- "kling",
4926
- "avatar_talking",
4927
- "hybrid",
4928
- "sora"
4929
- ]).optional(),
5109
+ videoMode: PersistedVideoMode.optional(),
4930
5110
  videoResolution: VideoResolution.optional(),
4931
5111
  videoStructure: VideoStructure.optional(),
4932
5112
  videoQuality: VideoQuality.optional(),
@@ -6940,7 +7120,10 @@ var ServiceCreativeEstimationOptions = z34.object({
6940
7120
  uploadedVideoDurationSeconds: z34.number().min(0).max(240).optional(),
6941
7121
  /** Quality the panels render at (its registry model sets the per-second
6942
7122
  * price). Absent = economy, the pre-quality service default. */
6943
- videoQuality: VideoQuality.optional()
7123
+ videoQuality: VideoQuality.optional(),
7124
+ /** Semantic resolution the panels render at (H3 maps 480p/720p to its
7125
+ * native 768P/2K). Absent = 480p, the pre-resolution service default. */
7126
+ videoResolution: VideoResolution.optional()
6944
7127
  });
6945
7128
  var ActorGridEstimationOptions = z34.object({}).strict();
6946
7129
  var CostEstimationRequest = z34.discriminatedUnion("type", [
@@ -7288,7 +7471,8 @@ var IMAGE_QA_GATES = [
7288
7471
  "limb",
7289
7472
  "device_panel",
7290
7473
  "critical_feature",
7291
- "cross_section"
7474
+ "cross_section",
7475
+ "usage_fidelity"
7292
7476
  ];
7293
7477
  var ImageQaGate = z36.enum(IMAGE_QA_GATES);
7294
7478
  var ImageQaGateOutcome = z36.enum([
@@ -8334,6 +8518,10 @@ var GEMINI_OMNI_FLAT_USER_PRICE_CENTS = 168;
8334
8518
  // ../../packages/types/src/pricing.ts
8335
8519
  var CREDITS_PER_USD_CENT = 10;
8336
8520
  var CREDITS_PER_DOLLAR = 100 * CREDITS_PER_USD_CENT;
8521
+ var AD_CREATIVE_MODELS = {
8522
+ STANDARD: IMAGE_WRITE_TOKENS["1k"],
8523
+ PREMIUM: IMAGE_WRITE_TOKENS["2k"]
8524
+ };
8337
8525
  var KALODATA_USD_CENTS_PER_PROVIDER_CREDIT = 9;
8338
8526
  var KALODATA_PROVIDER_CREDITS_PER_SOURCE_CEILING = 7.5;
8339
8527
  var DEFAULT_PRICING = {
@@ -9292,6 +9480,27 @@ var DEFAULT_PRICING = {
9292
9480
  ourCostCents: 1.88,
9293
9481
  userPriceCents: 3.76
9294
9482
  },
9483
+ // Usage decider (role `usage-decider`: Gemini 3.8 Flash effort:'high' since
9484
+ // 05f543eae, ≤6 images + seller text, temperature 0 json_object, once per
9485
+ // classic landing, always on). Was 3¢ measured on Claude
9486
+ // Sonnet 5 (spike 2026-09-24, 17 prod tasks). NOT re-measured on Flash — no
9487
+ // local BillingEntry row carries the Flash decider yet — so it is priced as
9488
+ // the product truth (`openrouter:product-truth`, 2.2¢ measured from
9489
+ // OpenRouter usage.cost): same model, same effort, same ≤6-photo input and a
9490
+ // JSON answer of similar size. Refine from usage.cost after the e2e. Fallback
9491
+ // only (OpenRouter's usage.cost is billed when present).
9492
+ "openrouter:usage-decision": {
9493
+ ourCostCents: 2.2,
9494
+ userPriceCents: 4.4
9495
+ },
9496
+ // Usage-fidelity QA judge (records misuse; regen gated separately behind
9497
+ // always on, bounded by USAGE_FIDELITY_MAX_REGENS). Sized off landing-image-qa beside it: same
9498
+ // shape of call (1-2 images, a verdict), so quoted at the same rate until
9499
+ // it has its own BillingEntry volume to re-derive from.
9500
+ "openrouter:usage-fidelity": {
9501
+ ourCostCents: 1.88,
9502
+ userPriceCents: 3.76
9503
+ },
9295
9504
  // Landing commercial-facts extraction (gemini-3.8-flash, ONE text-only call over
9296
9505
  // the seller's offer/context/features). Sized off the image-QA key beside it,
9297
9506
  // which measured 1.88¢ at ~11.1K prompt tokens: this prompt is capped at ~3K in
@@ -10030,6 +10239,24 @@ var DEFAULT_PRICING = {
10030
10239
  ourCostCents: 0.2,
10031
10240
  userPriceCents: 0.4
10032
10241
  },
10242
+ // Product truth (Gemini 3.8 Flash effort:'high', ≤6 photos + all seller text, once per
10243
+ // extract, always on). Plan C spike 2026-09-24: 6 calls, US$0.132 total ⇒
10244
+ // 2.2¢/call measured from OpenRouter usage.cost. Replaces usage spec + functional demo +
10245
+ // product-use sheet (+ landing visual-context-fusion) on the same task. Fallback only.
10246
+ "openrouter:product-truth": {
10247
+ ourCostCents: 2.2,
10248
+ userPriceCents: 4.4
10249
+ },
10250
+ // Landing creative director, «categorías» arm (Gemini 3.8 Flash effort:'high', ≤6 photos +
10251
+ // all seller text + the section plan, once per classic landing behind
10252
+ // LANDING_DIRECTOR_ENABLED). ESTIMATE, not measured: same call shape as the product truth
10253
+ // (2.2¢) with a ~2-3x longer JSON answer (one content spec per section) ⇒ ~4¢. Replaces
10254
+ // the visual brief (4¢) + visual-context fusion (0.4¢) + usage decision (2.2¢) on that
10255
+ // landing. Refine from OpenRouter usage.cost after the e2e. Fallback only.
10256
+ "openrouter:landing-director": {
10257
+ ourCostCents: 4,
10258
+ userPriceCents: 8
10259
+ },
10033
10260
  // Unit = one reference-grouping pass over the user's product images (0.1241¢).
10034
10261
  "openrouter:product-reference-grouping": {
10035
10262
  ourCostCents: 0.15,
@@ -13374,7 +13601,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13374
13601
  "task",
13375
13602
  "product"
13376
13603
  ]),
13377
- defineCapability("create_service_video", "863884c1af5de3e168cbbe825ea3961901c84dae1899ca400f8f7fa01df91c0a", "credit_consuming", "creative", [
13604
+ defineCapability("create_service_video", "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21", "credit_consuming", "creative", [
13378
13605
  "credit_consuming",
13379
13606
  "state_change"
13380
13607
  ], [
@@ -13402,6 +13629,9 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13402
13629
  // MCP-only for now: WhatsApp's service flow keeps the economy default.
13403
13630
  slot("video_quality", false, [
13404
13631
  "videoQuality"
13632
+ ], []),
13633
+ slot("video_resolution", false, [
13634
+ "videoResolution"
13405
13635
  ], [])
13406
13636
  ], [
13407
13637
  "service_context"
@@ -13544,7 +13774,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13544
13774
  "video"
13545
13775
  ]
13546
13776
  ),
13547
- defineCapability("generate_image_creatives", "eb2c3f6a0d8974ccf33c42f2b4cc9e09918dabf29182acce1418ea2842a01ec3", "credit_consuming", "creative", [
13777
+ defineCapability("generate_image_creatives", "2f1698b623d98645b7c618a17988f3aac30f403a9c3f3dc26eb5bdbd9c6ef23e", "credit_consuming", "creative", [
13548
13778
  "credit_consuming",
13549
13779
  "state_change"
13550
13780
  ], [
@@ -14941,79 +15171,696 @@ var WhatsAppPresentationManifestSchema = z67.object({
14941
15171
  }
14942
15172
  });
14943
15173
 
14944
- // ../../packages/types/src/flight-recorder.ts
15174
+ // ../../packages/types/src/usage-decision.ts
14945
15175
  import { z as z68 } from "zod";
14946
- var FlightRecorderGenerationTypeSchema = z68.enum([
15176
+
15177
+ // ../../packages/types/src/text-clamp.ts
15178
+ function clampAtWordBoundary(value, max) {
15179
+ if (typeof value !== "string") return value;
15180
+ if (value.length <= max) return value;
15181
+ const cut = value.slice(0, max);
15182
+ const lastSpace = cut.lastIndexOf(" ");
15183
+ const atWordBoundary = lastSpace > 0 ? cut.slice(0, lastSpace) : cut;
15184
+ return atWordBoundary.replace(/[,;:\s]+$/, "");
15185
+ }
15186
+ __name(clampAtWordBoundary, "clampAtWordBoundary");
15187
+ function clampStringArray(max) {
15188
+ return (value) => {
15189
+ if (!Array.isArray(value)) return value;
15190
+ const nonEmpty = value.filter((item) => typeof item === "string" && item.trim().length > 0);
15191
+ return nonEmpty.slice(0, max);
15192
+ };
15193
+ }
15194
+ __name(clampStringArray, "clampStringArray");
15195
+
15196
+ // ../../packages/types/src/usage-decision.ts
15197
+ var USAGE_SCENE_RULE_MAX_CHARS = 240;
15198
+ var USAGE_DECISION_MAX_REQUIRED_PARTS = 6;
15199
+ var USAGE_DECISION_MAX_ALTERNATE_USES = 4;
15200
+ var USAGE_DECISION_MAX_MISUSE = 5;
15201
+ function clampRule(value) {
15202
+ return clampAtWordBoundary(value, USAGE_SCENE_RULE_MAX_CHARS);
15203
+ }
15204
+ __name(clampRule, "clampRule");
15205
+ var UsageDecisionSchema = z68.object({
15206
+ productIdentity: z68.string().min(1),
15207
+ endUser: z68.object({
15208
+ who: z68.string(),
15209
+ appliedTo: z68.string()
15210
+ }),
15211
+ promise: z68.string().min(1),
15212
+ primaryUse: z68.object({
15213
+ scene: z68.string().min(1),
15214
+ postureAndGrip: z68.string(),
15215
+ contactPoint: z68.string(),
15216
+ requiredParts: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_REQUIRED_PARTS), z68.array(z68.string()).max(USAGE_DECISION_MAX_REQUIRED_PARTS))
15217
+ }),
15218
+ validAlternateUses: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_ALTERNATE_USES), z68.array(z68.string()).max(USAGE_DECISION_MAX_ALTERNATE_USES)),
15219
+ misuse: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_MISUSE), z68.array(z68.string().min(1)).max(USAGE_DECISION_MAX_MISUSE)),
15220
+ useSceneRule: z68.preprocess(clampRule, z68.string().min(1).max(USAGE_SCENE_RULE_MAX_CHARS)),
15221
+ /**
15222
+ * True when the promise can ONLY be shown with the primary use (the pain is bending over and
15223
+ * the product has an extension pole: without the pole there is no promise); false when the
15224
+ * valid alternates sell it equally. Drives whether an alternate use in a use scene is a
15225
+ * failure (`requirePrimary` in the usage judge) and whether the prompts' primary use is
15226
+ * mandatory. Optional and fail-safe: missing (decisions stored before the field) or not a
15227
+ * boolean ⇒ `undefined`, read as false by every caller — never a rejected decision.
15228
+ */
15229
+ primaryRequired: z68.boolean().optional().catch(void 0),
15230
+ confidence: z68.number().min(0).max(1),
15231
+ modelId: z68.string(),
15232
+ decidedAt: z68.string()
15233
+ });
15234
+
15235
+ // ../../packages/types/src/product-truth.ts
15236
+ import { z as z70 } from "zod";
15237
+
15238
+ // ../../packages/types/src/lenient-zod.ts
15239
+ import { z as z69 } from "zod";
15240
+ function trimAndClamp(value, max) {
15241
+ if (typeof value !== "string") return value;
15242
+ return clampAtWordBoundary(value.replace(/\s+/g, " ").trim(), max);
15243
+ }
15244
+ __name(trimAndClamp, "trimAndClamp");
15245
+ function lenientText(max) {
15246
+ return z69.preprocess((v) => trimAndClamp(v, max), z69.string().min(1).max(max));
15247
+ }
15248
+ __name(lenientText, "lenientText");
15249
+ function lenientOptionalText(max) {
15250
+ return z69.preprocess((v) => {
15251
+ if (typeof v !== "string") return void 0;
15252
+ const clamped = trimAndClamp(v, max);
15253
+ return typeof clamped === "string" && clamped.length > 0 ? clamped : void 0;
15254
+ }, z69.string().max(max).optional());
15255
+ }
15256
+ __name(lenientOptionalText, "lenientOptionalText");
15257
+ function lenientTextList(maxItems, maxChars) {
15258
+ return z69.preprocess((v) => {
15259
+ if (!Array.isArray(v)) return [];
15260
+ return v.map((item) => trimAndClamp(item, maxChars)).filter((item) => typeof item === "string" && item.length > 0).slice(0, maxItems);
15261
+ }, z69.array(z69.string().min(1).max(maxChars)).max(maxItems));
15262
+ }
15263
+ __name(lenientTextList, "lenientTextList");
15264
+ function lenientList(item, maxItems) {
15265
+ return z69.preprocess((v) => {
15266
+ if (!Array.isArray(v)) return [];
15267
+ return v.filter((entry) => item.safeParse(entry).success).slice(0, maxItems);
15268
+ }, z69.array(item).max(maxItems));
15269
+ }
15270
+ __name(lenientList, "lenientList");
15271
+
15272
+ // ../../packages/types/src/product-truth.ts
15273
+ var PRODUCT_TRUTH_SCHEMA_VERSION = 1;
15274
+ var PRODUCT_TRUTH_CAPS = {
15275
+ whatItIs: 160,
15276
+ deliveryForm: 120,
15277
+ distinctiveMarks: 6,
15278
+ distinctiveMarkChars: 160,
15279
+ parts: 12,
15280
+ partNameChars: 80,
15281
+ criticalFeatures: 6,
15282
+ connections: 6,
15283
+ connectionChars: 80,
15284
+ states: 4,
15285
+ stateKeyChars: 60,
15286
+ stateLabelChars: 80,
15287
+ partsPresent: 10,
15288
+ orientationInUseChars: 200,
15289
+ appliedToChars: 120,
15290
+ environmentChars: 120,
15291
+ summaryChars: 200,
15292
+ sceneChars: 300,
15293
+ postureAndGripChars: 160,
15294
+ contactPointChars: 120,
15295
+ steps: 8,
15296
+ stepNameChars: 120,
15297
+ stepInstructionChars: 300,
15298
+ visibleEffectChars: 200,
15299
+ beforeStateChars: 200,
15300
+ requiredProps: 8,
15301
+ requiredPropChars: 120,
15302
+ alternates: 3,
15303
+ misuse: 5,
15304
+ misuseChars: 200,
15305
+ mustShowFeatures: 5,
15306
+ mustShowFeatureChars: 100,
15307
+ safety: 5,
15308
+ safetyChars: 200,
15309
+ forbiddenClaims: 8,
15310
+ unsupportedClaims: 5,
15311
+ claimChars: 200,
15312
+ visualSummaryEnChars: 400
15313
+ };
15314
+ var PRODUCT_TRUTH_END_USER_AGE_BANDS = [
15315
+ "baby",
15316
+ "child",
15317
+ "teen",
15318
+ "adult",
15319
+ "any"
15320
+ ];
15321
+ var PRODUCT_TRUTH_END_USER_GENDERS = [
15322
+ "female",
15323
+ "male",
15324
+ "any"
15325
+ ];
15326
+ var PRODUCT_TRUTH_UNKNOWN_REASONS = [
15327
+ "model_unsure",
15328
+ "no_signal",
15329
+ "invalid_response",
15330
+ "provider_error"
15331
+ ];
15332
+ var text = lenientText;
15333
+ var optionalText = lenientOptionalText;
15334
+ var textList = lenientTextList;
15335
+ function toProductTruthStateKey(value) {
15336
+ if (typeof value !== "string") return void 0;
15337
+ const slug = value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, PRODUCT_TRUTH_CAPS.stateKeyChars);
15338
+ return slug.length > 0 ? slug : void 0;
15339
+ }
15340
+ __name(toProductTruthStateKey, "toProductTruthStateKey");
15341
+ var stateKey = z70.preprocess(toProductTruthStateKey, z70.string().min(1).max(PRODUCT_TRUTH_CAPS.stateKeyChars));
15342
+ var optionalStateKey = z70.preprocess(toProductTruthStateKey, z70.string().min(1).max(PRODUCT_TRUTH_CAPS.stateKeyChars).optional());
15343
+ var AGE_BAND_ALIASES = {
15344
+ baby: "baby",
15345
+ babies: "baby",
15346
+ infant: "baby",
15347
+ infants: "baby",
15348
+ toddler: "child",
15349
+ child: "child",
15350
+ children: "child",
15351
+ kid: "child",
15352
+ kids: "child",
15353
+ teen: "teen",
15354
+ teens: "teen",
15355
+ teenager: "teen",
15356
+ teenagers: "teen",
15357
+ adult: "adult",
15358
+ adults: "adult",
15359
+ any: "any",
15360
+ all: "any",
15361
+ "all ages": "any"
15362
+ };
15363
+ var GENDER_ALIASES = {
15364
+ female: "female",
15365
+ woman: "female",
15366
+ women: "female",
15367
+ girl: "female",
15368
+ male: "male",
15369
+ man: "male",
15370
+ men: "male",
15371
+ boy: "male",
15372
+ any: "any",
15373
+ unisex: "any",
15374
+ both: "any",
15375
+ all: "any"
15376
+ };
15377
+ function matchAlias(raw, aliases) {
15378
+ if (typeof raw !== "string") return void 0;
15379
+ const text2 = raw.trim().toLowerCase();
15380
+ const exact = aliases[text2];
15381
+ if (exact) return exact;
15382
+ const words = new Set(text2.split(/[^a-z]+/).filter(Boolean));
15383
+ for (const [alias, value] of Object.entries(aliases)) {
15384
+ if (words.has(alias)) return value;
15385
+ }
15386
+ return void 0;
15387
+ }
15388
+ __name(matchAlias, "matchAlias");
15389
+ function normalizeEndUser(value) {
15390
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
15391
+ const v = value;
15392
+ const age = matchAlias(v.ageBand, AGE_BAND_ALIASES);
15393
+ const gender = matchAlias(v.gender, GENDER_ALIASES);
15394
+ if (!age || !gender || typeof v.usedByBuyer !== "boolean") return void 0;
15395
+ return {
15396
+ ageBand: age,
15397
+ gender,
15398
+ usedByBuyer: v.usedByBuyer
15399
+ };
15400
+ }
15401
+ __name(normalizeEndUser, "normalizeEndUser");
15402
+ var ProductTruthEndUserSchema = z70.object({
15403
+ ageBand: z70.enum(PRODUCT_TRUTH_END_USER_AGE_BANDS),
15404
+ gender: z70.enum(PRODUCT_TRUTH_END_USER_GENDERS),
15405
+ usedByBuyer: z70.boolean()
15406
+ });
15407
+ var MATERIAL_HINTS = ProductMorphology.shape.materialHints.unwrap().element.options;
15408
+ var DEMO_TYPES = FunctionalDemonstration.shape.demoType;
15409
+ var PartSchema = z70.object({
15410
+ name: text(PRODUCT_TRUTH_CAPS.partNameChars),
15411
+ kind: z70.enum([
15412
+ "rigid",
15413
+ "flexible",
15414
+ "joint"
15415
+ ]).catch("rigid"),
15416
+ count: z70.number().int().min(1).max(20).catch(1)
15417
+ });
15418
+ var CriticalFeatureSchema = z70.object({
15419
+ name: text(60),
15420
+ importance: text(120),
15421
+ antiPattern: optionalText(80),
15422
+ expectedCount: z70.number().int().min(1).max(20).optional().catch(void 0)
15423
+ });
15424
+ var ConnectionSchema = z70.object({
15425
+ part: text(PRODUCT_TRUTH_CAPS.connectionChars),
15426
+ attachesTo: text(PRODUCT_TRUTH_CAPS.connectionChars),
15427
+ where: optionalText(PRODUCT_TRUTH_CAPS.connectionChars)
15428
+ });
15429
+ var StateSchema = z70.object({
15430
+ key: stateKey,
15431
+ label: optionalText(PRODUCT_TRUTH_CAPS.stateLabelChars),
15432
+ partsPresent: textList(PRODUCT_TRUTH_CAPS.partsPresent, PRODUCT_TRUTH_CAPS.partNameChars),
15433
+ orientationInUse: text(PRODUCT_TRUTH_CAPS.orientationInUseChars),
15434
+ naturalOrientation: ProductNaturalOrientation.optional().catch(void 0)
15435
+ });
15436
+ var StepSchema = z70.object({
15437
+ name: text(PRODUCT_TRUTH_CAPS.stepNameChars),
15438
+ instruction: text(PRODUCT_TRUTH_CAPS.stepInstructionChars),
15439
+ kind: z70.enum([
15440
+ "setup",
15441
+ "use",
15442
+ "finish"
15443
+ ]).catch("use")
15444
+ });
15445
+ var AlternateSchema = z70.object({
15446
+ summary: text(PRODUCT_TRUTH_CAPS.summaryChars),
15447
+ stateKey: optionalStateKey,
15448
+ advertisedBySeller: z70.boolean().catch(false)
15449
+ });
15450
+ var DemoSchema = z70.object({
15451
+ demoType: DEMO_TYPES.nullable().catch(null),
15452
+ mustShowFeatures: textList(PRODUCT_TRUTH_CAPS.mustShowFeatures, PRODUCT_TRUTH_CAPS.mustShowFeatureChars),
15453
+ importance: z70.enum([
15454
+ "critical",
15455
+ "important",
15456
+ "nice_to_have"
15457
+ ]).catch("important")
15458
+ });
15459
+ var objectOrEmpty = /* @__PURE__ */ __name((v) => v && typeof v === "object" && !Array.isArray(v) ? v : {}, "objectOrEmpty");
15460
+ var ProductTruthBody = z70.object({
15461
+ identity: z70.object({
15462
+ whatItIs: text(PRODUCT_TRUTH_CAPS.whatItIs),
15463
+ deliveryForm: optionalText(PRODUCT_TRUTH_CAPS.deliveryForm),
15464
+ distinctiveMarks: textList(PRODUCT_TRUTH_CAPS.distinctiveMarks, PRODUCT_TRUTH_CAPS.distinctiveMarkChars)
15465
+ }),
15466
+ morphology: z70.preprocess(objectOrEmpty, z70.object({
15467
+ shape: ProductGeometryShape.optional().catch(void 0),
15468
+ crossSection: ProductCrossSection.optional().catch(void 0),
15469
+ cornerProfile: ProductCornerProfile.optional().catch(void 0),
15470
+ silhouetteWidthToHeightRatio: z70.number().min(0.05).max(20).optional().catch(void 0),
15471
+ parts: lenientList(PartSchema, PRODUCT_TRUTH_CAPS.parts),
15472
+ criticalFeatures: lenientList(CriticalFeatureSchema, PRODUCT_TRUTH_CAPS.criticalFeatures),
15473
+ shapeLockLevel: z70.enum([
15474
+ "strict",
15475
+ "moderate",
15476
+ "relaxed"
15477
+ ]).optional().catch(void 0),
15478
+ materialHints: z70.preprocess((v) => Array.isArray(v) ? [
15479
+ ...new Set(v.filter((m) => MATERIAL_HINTS.includes(m)))
15480
+ ].slice(0, 3) : [], z70.array(z70.enum(MATERIAL_HINTS)).max(3))
15481
+ })),
15482
+ assembly: z70.object({
15483
+ connections: lenientList(ConnectionSchema, PRODUCT_TRUTH_CAPS.connections),
15484
+ states: z70.preprocess((v) => {
15485
+ if (!Array.isArray(v)) return v;
15486
+ const seen = /* @__PURE__ */ new Set();
15487
+ return v.filter((entry) => {
15488
+ const parsed = StateSchema.safeParse(entry);
15489
+ if (!parsed.success || seen.has(parsed.data.key)) return false;
15490
+ seen.add(parsed.data.key);
15491
+ return true;
15492
+ }).slice(0, PRODUCT_TRUTH_CAPS.states);
15493
+ }, z70.array(StateSchema).min(1).max(PRODUCT_TRUTH_CAPS.states)),
15494
+ defaultStateKey: optionalStateKey
15495
+ }),
15496
+ use: z70.object({
15497
+ endUser: z70.preprocess(normalizeEndUser, ProductTruthEndUserSchema.optional()).catch(void 0),
15498
+ appliedTo: optionalText(PRODUCT_TRUTH_CAPS.appliedToChars),
15499
+ environment: optionalText(PRODUCT_TRUTH_CAPS.environmentChars),
15500
+ primary: z70.object({
15501
+ summary: text(PRODUCT_TRUTH_CAPS.summaryChars),
15502
+ scene: text(PRODUCT_TRUTH_CAPS.sceneChars),
15503
+ postureAndGrip: optionalText(PRODUCT_TRUTH_CAPS.postureAndGripChars),
15504
+ contactPoint: optionalText(PRODUCT_TRUTH_CAPS.contactPointChars),
15505
+ stateKey: optionalStateKey,
15506
+ steps: z70.preprocess((v) => Array.isArray(v) ? v.filter((s) => StepSchema.safeParse(s).success).slice(0, PRODUCT_TRUTH_CAPS.steps) : v, z70.array(StepSchema).min(1).max(PRODUCT_TRUTH_CAPS.steps)),
15507
+ visibleEffect: optionalText(PRODUCT_TRUTH_CAPS.visibleEffectChars),
15508
+ beforeState: optionalText(PRODUCT_TRUTH_CAPS.beforeStateChars),
15509
+ requiredProps: textList(PRODUCT_TRUTH_CAPS.requiredProps, PRODUCT_TRUTH_CAPS.requiredPropChars)
15510
+ }),
15511
+ alternates: lenientList(AlternateSchema, PRODUCT_TRUTH_CAPS.alternates),
15512
+ misuse: textList(PRODUCT_TRUTH_CAPS.misuse, PRODUCT_TRUTH_CAPS.misuseChars),
15513
+ demo: z70.preprocess(objectOrEmpty, DemoSchema),
15514
+ safety: textList(PRODUCT_TRUTH_CAPS.safety, PRODUCT_TRUTH_CAPS.safetyChars)
15515
+ }),
15516
+ claims: z70.preprocess(objectOrEmpty, z70.object({
15517
+ forbidden: textList(PRODUCT_TRUTH_CAPS.forbiddenClaims, PRODUCT_TRUTH_CAPS.claimChars),
15518
+ unsupported: textList(PRODUCT_TRUTH_CAPS.unsupportedClaims, PRODUCT_TRUTH_CAPS.claimChars)
15519
+ })),
15520
+ visualSummaryEn: optionalText(PRODUCT_TRUTH_CAPS.visualSummaryEnChars),
15521
+ evidence: z70.preprocess(objectOrEmpty, z70.object({
15522
+ photoIndexForState: z70.preprocess((v) => {
15523
+ const out = {};
15524
+ if (!v || typeof v !== "object" || Array.isArray(v)) return out;
15525
+ for (const [rawKey, rawIndexes] of Object.entries(v)) {
15526
+ const key = toProductTruthStateKey(rawKey);
15527
+ if (!key || !Array.isArray(rawIndexes)) continue;
15528
+ out[key] = rawIndexes.filter((i) => typeof i === "number" && Number.isInteger(i) && i >= 0 && i < 20);
15529
+ }
15530
+ return out;
15531
+ }, z70.record(z70.array(z70.number().int().min(0).max(19))))
15532
+ })),
15533
+ confidence: z70.preprocess((v) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : 0, z70.number().min(0).max(1))
15534
+ });
15535
+ function resolveStateRefs(body) {
15536
+ const keys = new Set(body.assembly.states.map((s) => s.key));
15537
+ const firstKey = body.assembly.states[0]?.key ?? "";
15538
+ const defaultStateKey = body.assembly.defaultStateKey && keys.has(body.assembly.defaultStateKey) ? body.assembly.defaultStateKey : firstKey;
15539
+ const primaryKey = body.use.primary.stateKey && keys.has(body.use.primary.stateKey) ? body.use.primary.stateKey : defaultStateKey;
15540
+ const photoIndexForState = Object.fromEntries(Object.entries(body.evidence.photoIndexForState).filter(([key]) => keys.has(key)));
15541
+ return {
15542
+ ...body,
15543
+ assembly: {
15544
+ ...body.assembly,
15545
+ defaultStateKey
15546
+ },
15547
+ use: {
15548
+ ...body.use,
15549
+ primary: {
15550
+ ...body.use.primary,
15551
+ stateKey: primaryKey
15552
+ },
15553
+ alternates: body.use.alternates.map((alt) => ({
15554
+ ...alt,
15555
+ stateKey: alt.stateKey && keys.has(alt.stateKey) ? alt.stateKey : defaultStateKey
15556
+ }))
15557
+ },
15558
+ evidence: {
15559
+ ...body.evidence,
15560
+ photoIndexForState
15561
+ }
15562
+ };
15563
+ }
15564
+ __name(resolveStateRefs, "resolveStateRefs");
15565
+ var ProductTruthModelResponseSchema = ProductTruthBody.transform(resolveStateRefs);
15566
+ var provenance = {
15567
+ schemaVersion: z70.literal(PRODUCT_TRUTH_SCHEMA_VERSION),
15568
+ modelId: z70.string().min(1),
15569
+ derivedAt: z70.string().min(1),
15570
+ /** Hash of (image keys + seller text + features): a reader that sees a different current
15571
+ * fingerprint treats the truth as absent. See `computeProductTruthFingerprint` in packages/ai. */
15572
+ sourceFingerprint: z70.string().min(1),
15573
+ /** The seller upload KEYS (deduped, sorted) the fingerprint was computed over. Stored so a
15574
+ * reader can recompute the CURRENT fingerprint from today's seller text + features without
15575
+ * knowing the extract job's inputs (plan Global Constraint "Invalidez"). */
15576
+ sourceImageKeys: z70.array(z70.string().min(1)).max(20).optional()
15577
+ };
15578
+ var ProductTruthKnownSchema = ProductTruthBody.extend({
15579
+ ...provenance,
15580
+ known: z70.literal(true)
15581
+ }).transform(resolveStateRefs);
15582
+ var ProductTruthUnknownSchema = z70.object({
15583
+ schemaVersion: z70.literal(PRODUCT_TRUTH_SCHEMA_VERSION),
15584
+ known: z70.literal(false),
15585
+ unknownReason: z70.enum(PRODUCT_TRUTH_UNKNOWN_REASONS),
15586
+ modelId: z70.string().optional(),
15587
+ derivedAt: z70.string().min(1),
15588
+ sourceFingerprint: z70.string().min(1),
15589
+ sourceImageKeys: z70.array(z70.string().min(1)).max(20).optional()
15590
+ });
15591
+ var ProductTruthSchema = z70.union([
15592
+ ProductTruthKnownSchema,
15593
+ ProductTruthUnknownSchema
15594
+ ]);
15595
+
15596
+ // ../../packages/types/src/landing-director.ts
15597
+ import { z as z71 } from "zod";
15598
+ var LANDING_DIRECTOR_SCHEMA_VERSION = 1;
15599
+ var LANDING_DIRECTOR_ARM = "categories";
15600
+ var LANDING_DIRECTOR_CAPS = {
15601
+ productIdentity: 200,
15602
+ parts: 8,
15603
+ partName: 40,
15604
+ promise: 200,
15605
+ endUserWho: 80,
15606
+ endUserAppliedTo: 80,
15607
+ forbiddenClaims: 10,
15608
+ claimChars: 80,
15609
+ misuse: 5,
15610
+ misuseChars: 120,
15611
+ assembledStates: 3,
15612
+ statePartsMax: 6,
15613
+ orientation: 160,
15614
+ handling: 140,
15615
+ primaryScene: 200,
15616
+ postureAndGrip: 140,
15617
+ contactPoint: 100,
15618
+ alternates: 3,
15619
+ alternateChars: 120,
15620
+ ambiguities: 4,
15621
+ ambiguityChars: 160,
15622
+ sectionKeyChars: 40,
15623
+ personWho: 80,
15624
+ personPosture: 120,
15625
+ personGrip: 120,
15626
+ scene: 450,
15627
+ panels: 4,
15628
+ panelScene: 200,
15629
+ panelCaption: 60,
15630
+ /** Rendered text: an item over its cap is DROPPED, never cut. The headline cap is 80, not
15631
+ * the design's 70: a dropped headline costs the whole director headline, and 7-10 Spanish
15632
+ * words routinely run 70-80 chars. */
15633
+ headline: 80,
15634
+ subheadline: 90,
15635
+ labels: 3,
15636
+ labelChars: 40,
15637
+ captions: 3,
15638
+ captionChars: 60,
15639
+ props: 4,
15640
+ propChars: 40,
15641
+ mustNotShow: 5,
15642
+ mustNotShowChars: 80
15643
+ };
15644
+ var STATE_KEY_PATTERN = /^[a-z][a-z_]{1,23}$/;
15645
+ function toLandingDirectorStateKey(value) {
15646
+ if (typeof value !== "string") return void 0;
15647
+ const slug = value.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 24).replace(/_+$/g, "");
15648
+ return STATE_KEY_PATTERN.test(slug) ? slug : void 0;
15649
+ }
15650
+ __name(toLandingDirectorStateKey, "toLandingDirectorStateKey");
15651
+ var stateKey2 = z71.preprocess(toLandingDirectorStateKey, z71.string().regex(STATE_KEY_PATTERN));
15652
+ function renderedOptionalText(max) {
15653
+ return z71.preprocess((v) => {
15654
+ if (typeof v !== "string") return void 0;
15655
+ const trimmed = v.replace(/\s+/g, " ").trim();
15656
+ return trimmed.length > 0 && trimmed.length <= max ? trimmed : void 0;
15657
+ }, z71.string().min(1).max(max).optional());
15658
+ }
15659
+ __name(renderedOptionalText, "renderedOptionalText");
15660
+ function renderedTextList(maxItems, maxChars) {
15661
+ return z71.preprocess((v) => {
15662
+ if (!Array.isArray(v)) return [];
15663
+ return v.map((item) => typeof item === "string" ? item.replace(/\s+/g, " ").trim() : "").filter((item) => item.length > 0 && item.length <= maxChars).slice(0, maxItems);
15664
+ }, z71.array(z71.string().min(1).max(maxChars)).max(maxItems));
15665
+ }
15666
+ __name(renderedTextList, "renderedTextList");
15667
+ var C = LANDING_DIRECTOR_CAPS;
15668
+ var PartSchema2 = z71.object({
15669
+ name: lenientText(C.partName),
15670
+ critical: z71.boolean().catch(false)
15671
+ });
15672
+ var AssembledStateSchema = z71.object({
15673
+ key: stateKey2,
15674
+ parts: lenientTextList(C.statePartsMax, C.partName),
15675
+ orientation: lenientText(C.orientation),
15676
+ handling: lenientOptionalText(C.handling)
15677
+ });
15678
+ var END_USER_GENDERS = [
15679
+ "female",
15680
+ "male",
15681
+ "any"
15682
+ ];
15683
+ var END_USER_AGE_BANDS = [
15684
+ "child",
15685
+ "teen",
15686
+ "adult",
15687
+ "senior",
15688
+ "any"
15689
+ ];
15690
+ var EndUserSchema = z71.object({
15691
+ who: lenientText(C.endUserWho),
15692
+ appliedTo: lenientOptionalText(C.endUserAppliedTo),
15693
+ gender: z71.enum(END_USER_GENDERS).catch("any"),
15694
+ ageBand: z71.enum(END_USER_AGE_BANDS).catch("any")
15695
+ });
15696
+ var LandingDirectorGlobalSchema = z71.object({
15697
+ productIdentity: lenientText(C.productIdentity),
15698
+ parts: lenientList(PartSchema2, C.parts),
15699
+ promise: lenientText(C.promise),
15700
+ endUser: EndUserSchema,
15701
+ forbiddenClaims: lenientTextList(C.forbiddenClaims, C.claimChars),
15702
+ misuse: lenientTextList(C.misuse, C.misuseChars),
15703
+ assembledStates: z71.preprocess((v) => {
15704
+ if (!Array.isArray(v)) return v;
15705
+ const seen = /* @__PURE__ */ new Set();
15706
+ return v.filter((entry) => {
15707
+ const parsed = AssembledStateSchema.safeParse(entry);
15708
+ if (!parsed.success || seen.has(parsed.data.key)) return false;
15709
+ seen.add(parsed.data.key);
15710
+ return true;
15711
+ }).slice(0, C.assembledStates);
15712
+ }, z71.array(AssembledStateSchema).min(1).max(C.assembledStates)),
15713
+ primaryUse: z71.object({
15714
+ assembledState: stateKey2,
15715
+ scene: lenientText(C.primaryScene),
15716
+ postureAndGrip: lenientText(C.postureAndGrip),
15717
+ contactPoint: lenientOptionalText(C.contactPoint)
15718
+ }),
15719
+ primaryRequired: z71.boolean().catch(false),
15720
+ validAlternateUses: lenientTextList(C.alternates, C.alternateChars),
15721
+ ambiguities: lenientTextList(C.ambiguities, C.ambiguityChars)
15722
+ });
15723
+ var LANDING_DIRECTOR_BODY_PARTS = [
15724
+ "hands",
15725
+ "face",
15726
+ "torso",
15727
+ "legs",
15728
+ "feet",
15729
+ "full_body"
15730
+ ];
15731
+ var PersonSchema = z71.object({
15732
+ who: lenientText(C.personWho),
15733
+ posture: lenientText(C.personPosture),
15734
+ grip: lenientOptionalText(C.personGrip),
15735
+ bodyPartsVisible: z71.preprocess((v) => Array.isArray(v) ? [
15736
+ ...new Set(v.filter((part) => LANDING_DIRECTOR_BODY_PARTS.includes(part)))
15737
+ ] : [], z71.array(z71.enum(LANDING_DIRECTOR_BODY_PARTS)))
15738
+ });
15739
+ var LandingDirectorTextSchema = z71.object({
15740
+ headline: renderedOptionalText(C.headline),
15741
+ subheadline: renderedOptionalText(C.subheadline),
15742
+ labels: renderedTextList(C.labels, C.labelChars),
15743
+ captions: renderedTextList(C.captions, C.captionChars)
15744
+ });
15745
+ var PanelSchema = z71.object({
15746
+ scene: lenientText(C.panelScene),
15747
+ caption: renderedOptionalText(C.panelCaption)
15748
+ });
15749
+ var PRODUCT_IN_FRAME_VALUES = [
15750
+ "none",
15751
+ "packshot",
15752
+ "in_use"
15753
+ ];
15754
+ var LandingDirectorSectionSchema = z71.object({
15755
+ sectionKey: z71.string().trim().min(1).max(C.sectionKeyChars),
15756
+ /** Present only in the «director» arm. Kept as a flag so the «categorías» validation can
15757
+ * invalidate the section (design §2.3) instead of silently dropping the model's choice. */
15758
+ hasComposition: z71.boolean().default(false),
15759
+ productInFrame: z71.enum(PRODUCT_IN_FRAME_VALUES),
15760
+ assembledState: z71.preprocess((v) => v === null || v === void 0 ? null : toLandingDirectorStateKey(v), z71.string().regex(STATE_KEY_PATTERN).nullable()),
15761
+ usesPrimary: z71.boolean().catch(false),
15762
+ person: z71.preprocess((v) => v === void 0 ? null : v, PersonSchema.nullable()),
15763
+ scene: lenientText(C.scene),
15764
+ panels: lenientList(PanelSchema, C.panels),
15765
+ textToRender: z71.preprocess((v) => v && typeof v === "object" && !Array.isArray(v) ? v : {}, LandingDirectorTextSchema),
15766
+ props: lenientTextList(C.props, C.propChars),
15767
+ mustNotShow: lenientTextList(C.mustNotShow, C.mustNotShowChars)
15768
+ });
15769
+ var LandingDirectorOutputSchema = z71.object({
15770
+ version: z71.literal(LANDING_DIRECTOR_SCHEMA_VERSION),
15771
+ confidence: z71.number().min(0).max(1),
15772
+ global: LandingDirectorGlobalSchema,
15773
+ sections: z71.array(LandingDirectorSectionSchema)
15774
+ });
15775
+ var StoredLandingDirectorSchema = z71.object({
15776
+ version: z71.literal(LANDING_DIRECTOR_SCHEMA_VERSION),
15777
+ arm: z71.literal(LANDING_DIRECTOR_ARM),
15778
+ modelId: z71.string().min(1),
15779
+ generatedAt: z71.string().min(1),
15780
+ confidence: z71.number().min(0).max(1),
15781
+ /** The plan the answer was validated against (sectionKey, or the role on classic). */
15782
+ planSectionKeys: z71.array(z71.string().min(1)),
15783
+ output: LandingDirectorOutputSchema,
15784
+ /** Sections that fell back to the category composition, and why. */
15785
+ fallbackSections: z71.array(z71.object({
15786
+ sectionKey: z71.string().min(1),
15787
+ reason: z71.string().min(1)
15788
+ }))
15789
+ });
15790
+
15791
+ // ../../packages/types/src/flight-recorder.ts
15792
+ import { z as z72 } from "zod";
15793
+ var FlightRecorderGenerationTypeSchema = z72.enum([
14947
15794
  "initial",
14948
15795
  "regeneration",
14949
15796
  "edit",
14950
15797
  "retry"
14951
15798
  ]);
14952
- var FlightRecorderProviderSchema = z68.enum([
15799
+ var FlightRecorderProviderSchema = z72.enum([
14953
15800
  "kie",
14954
15801
  "fal"
14955
15802
  ]);
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([
15803
+ var FlightRecorderElementSchema = z72.object({
15804
+ name: z72.string().optional(),
15805
+ description: z72.string().optional(),
15806
+ frontalImageUrl: z72.string().optional(),
15807
+ referenceImageUrls: z72.array(z72.string()).optional(),
15808
+ videoUrl: z72.string().optional()
15809
+ });
15810
+ var FlightRecorderDistillationSchema = z72.object({
15811
+ actorGender: z72.enum([
14965
15812
  "female",
14966
15813
  "male",
14967
15814
  "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(),
15815
+ ]).or(z72.string()).optional(),
15816
+ voiceId: z72.string().optional(),
15817
+ cameraMotion: z72.string().optional()
15818
+ }).catchall(z72.unknown());
15819
+ var FlightRecorderEntrySchema = z72.object({
15820
+ schemaVersion: z72.literal(1).optional(),
15821
+ id: z72.string().min(1),
15822
+ taskId: z72.string().min(1),
15823
+ runId: z72.string().min(1),
15824
+ sequence: z72.number().int().nonnegative(),
15825
+ timestamp: z72.string().min(1),
15826
+ provider: FlightRecorderProviderSchema.or(z72.string()),
15827
+ model: z72.string().min(1),
15828
+ prompt: z72.string(),
15829
+ durationSeconds: z72.number().nonnegative(),
15830
+ aspectRatio: z72.string().optional(),
15831
+ resolution: z72.string().optional(),
15832
+ startImageUrl: z72.string().optional(),
15833
+ endImageUrl: z72.string().optional(),
15834
+ generateAudio: z72.boolean().optional(),
14988
15835
  // Correlation & pipeline metadata
14989
- angleKey: z68.string().optional(),
14990
- sceneIndex: z68.number().int().nonnegative().optional(),
15836
+ angleKey: z72.string().optional(),
15837
+ sceneIndex: z72.number().int().nonnegative().optional(),
14991
15838
  generationType: FlightRecorderGenerationTypeSchema,
14992
- operationId: z68.string().min(1).optional(),
14993
- revisionId: z68.string().min(1).optional(),
14994
- attemptNumber: z68.number().int().nonnegative().default(1),
15839
+ operationId: z72.string().min(1).optional(),
15840
+ revisionId: z72.string().min(1).optional(),
15841
+ attemptNumber: z72.number().int().nonnegative().default(1),
14995
15842
  // Elements & Distillation
14996
- elements: z68.array(FlightRecorderElementSchema).optional(),
15843
+ elements: z72.array(FlightRecorderElementSchema).optional(),
14997
15844
  distillation: FlightRecorderDistillationSchema.optional(),
14998
15845
  // Raw payload (sanitized of secrets)
14999
- rawPayload: z68.record(z68.unknown())
15846
+ rawPayload: z72.record(z72.unknown())
15000
15847
  });
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(),
15848
+ var FlightRecorderQuerySchema = z72.object({
15849
+ taskId: z72.string().min(1),
15850
+ runId: z72.string().optional(),
15851
+ sceneIndex: z72.number().int().nonnegative().optional(),
15852
+ angleKey: z72.string().optional(),
15006
15853
  generationType: FlightRecorderGenerationTypeSchema.optional(),
15007
- cursor: z68.number().int().nonnegative().optional(),
15008
- limit: z68.number().int().positive().optional()
15854
+ cursor: z72.number().int().nonnegative().optional(),
15855
+ limit: z72.number().int().positive().optional()
15009
15856
  });
15010
- var FlightRecorderResponseSchema = z68.object({
15011
- taskId: z68.string().min(1),
15012
- runId: z68.string().min(1),
15013
- entries: z68.array(FlightRecorderEntrySchema),
15857
+ var FlightRecorderResponseSchema = z72.object({
15858
+ taskId: z72.string().min(1),
15859
+ runId: z72.string().min(1),
15860
+ entries: z72.array(FlightRecorderEntrySchema),
15014
15861
  lastCall: FlightRecorderEntrySchema.nullable(),
15015
- count: z68.number().int().nonnegative(),
15016
- nextCursor: z68.number().int().nonnegative().nullable()
15862
+ count: z72.number().int().nonnegative(),
15863
+ nextCursor: z72.number().int().nonnegative().nullable()
15017
15864
  });
15018
15865
 
15019
15866
  // src/response-body.ts
@@ -15255,7 +16102,7 @@ var ApiClient = class {
15255
16102
  };
15256
16103
 
15257
16104
  // src/index.ts
15258
- var MCP_VERSION = "8.0.0";
16105
+ var MCP_VERSION = "8.2.0";
15259
16106
 
15260
16107
  // src/meta-upload-app.ts
15261
16108
  import { readFileSync } from "fs";
@@ -15327,7 +16174,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
15327
16174
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
15328
16175
 
15329
16176
  // src/tools/tasks.ts
15330
- import { z as z72 } from "zod";
16177
+ import { z as z76 } from "zod";
15331
16178
 
15332
16179
  // src/resolve-image.ts
15333
16180
  import { lookup as dnsLookup } from "dns/promises";
@@ -15888,10 +16735,10 @@ async function resolveMediaRef(ref, opts) {
15888
16735
  __name(resolveMediaRef, "resolveMediaRef");
15889
16736
 
15890
16737
  // src/tools/shared.ts
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([
16738
+ import { z as z73 } from "zod";
16739
+ var Lang = z73.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);
16740
+ var Country = z73.string().min(2).max(3);
16741
+ var LandingStrategyEnum = z73.enum([
15895
16742
  "auto",
15896
16743
  "classic",
15897
16744
  "pain_solution",
@@ -15900,12 +16747,12 @@ var LandingStrategyEnum = z69.enum([
15900
16747
  "offer_value",
15901
16748
  "lifestyle_identity"
15902
16749
  ]);
15903
- var LandingImageFormatEnum = z69.enum([
16750
+ var LandingImageFormatEnum = z73.enum([
15904
16751
  "9:16",
15905
16752
  "4:5",
15906
16753
  "1:1"
15907
16754
  ]);
15908
- var VideoPresetEnum = z69.enum([
16755
+ var VideoPresetEnum = z73.enum([
15909
16756
  "auto",
15910
16757
  "ugc_dynamic",
15911
16758
  "ugc_how_to",
@@ -15918,21 +16765,21 @@ var VideoPresetEnum = z69.enum([
15918
16765
  "pixar_problem",
15919
16766
  "pixar_sassy"
15920
16767
  ]);
15921
- var VideoStructureEnum = z69.enum([
16768
+ var VideoStructureEnum = z73.enum([
15922
16769
  "single_take",
15923
16770
  "multi_scene"
15924
16771
  ]);
15925
- var VideoQualityEnum = z69.enum([
16772
+ var VideoQualityEnum = z73.enum([
15926
16773
  "economy",
15927
16774
  "medium",
15928
16775
  "pro"
15929
16776
  ]);
15930
- var VideoRouteIdEnum = z69.enum([
16777
+ var VideoRouteIdEnum = z73.enum([
15931
16778
  "single_take",
15932
16779
  "multi_scene",
15933
16780
  "free"
15934
16781
  ]);
15935
- var TaskCreativeVariantVideoPresetEnum = z69.enum([
16782
+ var TaskCreativeVariantVideoPresetEnum = z73.enum([
15936
16783
  "auto",
15937
16784
  "ugc_dynamic",
15938
16785
  "ugc_how_to",
@@ -15949,53 +16796,43 @@ var VIDEO_PRESET_RESOLUTION = {
15949
16796
  auto: null,
15950
16797
  ugc_dynamic: {
15951
16798
  videoStyle: "ai_dynamic",
15952
- narrativeStyle: "review",
15953
- videoModel: "veo"
16799
+ narrativeStyle: "review"
15954
16800
  },
15955
16801
  ugc_how_to: {
15956
16802
  videoStyle: "ai_dynamic",
15957
- narrativeStyle: "ugc_how_to",
15958
- videoModel: "veo"
16803
+ narrativeStyle: "ugc_how_to"
15959
16804
  },
15960
16805
  ugc_unboxing_chaos: {
15961
16806
  videoStyle: "ai_dynamic",
15962
- narrativeStyle: "ugc_unboxing_chaos",
15963
- videoModel: "veo"
16807
+ narrativeStyle: "ugc_unboxing_chaos"
15964
16808
  },
15965
16809
  problem_solution: {
15966
16810
  videoStyle: "ai_dynamic",
15967
- narrativeStyle: "problem_product_cta",
15968
- videoModel: "kling"
16811
+ narrativeStyle: "problem_product_cta"
15969
16812
  },
15970
16813
  pixar_problem: {
15971
16814
  videoStyle: "ai_dynamic",
15972
- narrativeStyle: "animated_problem_pixar",
15973
- videoModel: "kling"
16815
+ narrativeStyle: "animated_problem_pixar"
15974
16816
  },
15975
16817
  pixar_sassy: {
15976
16818
  videoStyle: "ai_dynamic",
15977
- narrativeStyle: "sassy_product_pixar",
15978
- videoModel: "seedance"
16819
+ narrativeStyle: "sassy_product_pixar"
15979
16820
  },
15980
16821
  product_showcase: {
15981
16822
  videoStyle: "product_only",
15982
- narrativeStyle: "product_showcase",
15983
- videoModel: "veo"
16823
+ narrativeStyle: "product_showcase"
15984
16824
  },
15985
16825
  wearable_showcase: {
15986
16826
  videoStyle: "ugc",
15987
- narrativeStyle: "wearable_showcase",
15988
- videoModel: "veo"
16827
+ narrativeStyle: "wearable_showcase"
15989
16828
  },
15990
16829
  cinematic: {
15991
16830
  videoStyle: "product_only",
15992
- narrativeStyle: "cinematic",
15993
- videoModel: "grok"
16831
+ narrativeStyle: "cinematic"
15994
16832
  },
15995
16833
  wild_card: {
15996
16834
  videoStyle: "product_only",
15997
- narrativeStyle: "wild_card",
15998
- videoModel: "grok"
16835
+ narrativeStyle: "wild_card"
15999
16836
  }
16000
16837
  };
16001
16838
  function resolveVideoPreset(preset) {
@@ -16003,7 +16840,7 @@ function resolveVideoPreset(preset) {
16003
16840
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
16004
16841
  }
16005
16842
  __name(resolveVideoPreset, "resolveVideoPreset");
16006
- var VideoTierEnum = z69.enum([
16843
+ var VideoTierEnum = z73.enum([
16007
16844
  "basic"
16008
16845
  ]);
16009
16846
  function resolveVideoTier(_tier) {
@@ -16043,22 +16880,22 @@ function assertSemanticVideoDurationCompatibility(structure, quality, durationSe
16043
16880
  }
16044
16881
  }
16045
16882
  __name(assertSemanticVideoDurationCompatibility, "assertSemanticVideoDurationCompatibility");
16046
- var VideoResolutionEnum = z69.enum([
16883
+ var VideoResolutionEnum = z73.enum([
16047
16884
  "480p",
16048
16885
  "720p"
16049
16886
  ]);
16050
- var CreativeGenderEnum = z69.enum([
16887
+ var CreativeGenderEnum = z73.enum([
16051
16888
  "female",
16052
16889
  "male",
16053
16890
  "mixed"
16054
16891
  ]);
16055
- var VideoStyleEnum = z69.enum([
16892
+ var VideoStyleEnum = z73.enum([
16056
16893
  "ugc",
16057
16894
  "cartoon_3d",
16058
16895
  "product_only",
16059
16896
  "ai_dynamic"
16060
16897
  ]);
16061
- var NarrativeStyleEnum = z69.enum([
16898
+ var NarrativeStyleEnum = z73.enum([
16062
16899
  "review",
16063
16900
  "ugc_how_to",
16064
16901
  "problem_product_cta",
@@ -16076,7 +16913,7 @@ var NarrativeStyleEnum = z69.enum([
16076
16913
  "ugc_demo_review",
16077
16914
  "market"
16078
16915
  ]);
16079
- var PublicNarrativeStyleEnum = z69.enum([
16916
+ var PublicNarrativeStyleEnum = z73.enum([
16080
16917
  "review",
16081
16918
  "ugc_how_to",
16082
16919
  "ugc_unboxing_chaos",
@@ -16089,7 +16926,7 @@ var PublicNarrativeStyleEnum = z69.enum([
16089
16926
  "sassy_product_pixar",
16090
16927
  "market"
16091
16928
  ]);
16092
- var VideoModelEnum = z69.enum([
16929
+ var TaskVideoModelEnum = z73.enum([
16093
16930
  "veo",
16094
16931
  "wan",
16095
16932
  "bytedance",
@@ -16097,29 +16934,29 @@ var VideoModelEnum = z69.enum([
16097
16934
  "grok",
16098
16935
  "kling"
16099
16936
  ]);
16100
- var ProductReferenceUserChoiceEnum = z69.enum([
16937
+ var ProductReferenceUserChoiceEnum = z73.enum([
16101
16938
  "same_product",
16102
16939
  "variants",
16103
16940
  "different_products",
16104
16941
  "combo_distinct"
16105
16942
  ]);
16106
- var ProductReferenceCandidateGroupingEnum = z69.enum([
16943
+ var ProductReferenceCandidateGroupingEnum = z73.enum([
16107
16944
  "same_product_same_variant",
16108
16945
  "same_product_different_variants",
16109
16946
  "different_products",
16110
16947
  "unclear"
16111
16948
  ]);
16112
- var ProductReferenceScopeEnum = z69.enum([
16949
+ var ProductReferenceScopeEnum = z73.enum([
16113
16950
  "base",
16114
16951
  "video_view_pack"
16115
16952
  ]);
16116
- var ProductReferenceResolutionDecisionEnum = z69.enum([
16953
+ var ProductReferenceResolutionDecisionEnum = z73.enum([
16117
16954
  "approve",
16118
16955
  "reject",
16119
16956
  "observed_only",
16120
16957
  "correct_view"
16121
16958
  ]);
16122
- var ProductReferenceRejectionReasonEnum = z69.enum([
16959
+ var ProductReferenceRejectionReasonEnum = z73.enum([
16123
16960
  "replacement_requested",
16124
16961
  "wrong_product_identity",
16125
16962
  "wrong_variant",
@@ -16130,13 +16967,13 @@ var ProductReferenceRejectionReasonEnum = z69.enum([
16130
16967
  "not_a_product_photo",
16131
16968
  "other"
16132
16969
  ]);
16133
- var GapDurationChoiceMirror = z69.object({
16134
- angleIndex: z69.number().int().nonnegative(),
16135
- recommendedSec: z69.union([
16136
- z69.literal(15),
16137
- z69.literal(30)
16970
+ var GapDurationChoiceMirror = z73.object({
16971
+ angleIndex: z73.number().int().nonnegative(),
16972
+ recommendedSec: z73.union([
16973
+ z73.literal(15),
16974
+ z73.literal(30)
16138
16975
  ]),
16139
- estimatedDeltaCredits: z69.number().int().nonnegative().optional()
16976
+ estimatedDeltaCredits: z73.number().int().nonnegative().optional()
16140
16977
  });
16141
16978
  function buildSelectedImageUrlsHash(urls) {
16142
16979
  const input = [
@@ -16146,13 +16983,13 @@ function buildSelectedImageUrlsHash(urls) {
16146
16983
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
16147
16984
  }
16148
16985
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
16149
- var ImageCreativeStyleEnum = z69.enum([
16986
+ var ImageCreativeStyleEnum = z73.enum([
16150
16987
  "studio",
16151
16988
  "floating",
16152
16989
  "ingredients",
16153
16990
  "in_use"
16154
16991
  ]);
16155
- var ImageCreativeArchetypeEnum = z69.enum([
16992
+ var ImageCreativeArchetypeEnum = z73.enum([
16156
16993
  "direct_response_product_ad",
16157
16994
  "hero_outcome",
16158
16995
  "offer_value_prop",
@@ -16161,20 +16998,20 @@ var ImageCreativeArchetypeEnum = z69.enum([
16161
16998
  "problem_solution",
16162
16999
  "lifestyle_identity"
16163
17000
  ]);
16164
- var ImageCreativeVisualTreatmentEnum = z69.enum([
17001
+ var ImageCreativeVisualTreatmentEnum = z73.enum([
16165
17002
  "performance_product_ad",
16166
17003
  "premium_dtc_carousel"
16167
17004
  ]);
16168
- var ImageCreativeAspectRatioEnum = z69.enum([
17005
+ var ImageCreativeAspectRatioEnum = z73.enum([
16169
17006
  "1:1",
16170
17007
  "4:5",
16171
17008
  "9:16",
16172
17009
  "16:9"
16173
17010
  ]);
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.")
17011
+ var ImageRefSchema = z73.object({
17012
+ url: z73.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.'),
17013
+ path: z73.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`.'),
17014
+ assetId: z73.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.")
16178
17015
  }).refine((v) => [
16179
17016
  v.url,
16180
17017
  v.path,
@@ -16182,11 +17019,11 @@ var ImageRefSchema = z69.object({
16182
17019
  ].filter(Boolean).length === 1, {
16183
17020
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
16184
17021
  });
16185
- var ImagesInput = z69.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
17022
+ var ImagesInput = z73.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
16186
17023
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
16187
17024
  if (assetCount > 0 && assetCount !== images.length) {
16188
17025
  ctx.addIssue({
16189
- code: z69.ZodIssueCode.custom,
17026
+ code: z73.ZodIssueCode.custom,
16190
17027
  message: "all image entries must use assetId, or all must use URL/path sources"
16191
17028
  });
16192
17029
  }
@@ -16254,14 +17091,14 @@ async function submitCreative(api, opts) {
16254
17091
  });
16255
17092
  }
16256
17093
  __name(submitCreative, "submitCreative");
16257
- var ResearchTargetCountryEnum = z69.enum([
17094
+ var ResearchTargetCountryEnum = z73.enum([
16258
17095
  "CO",
16259
17096
  "MX",
16260
17097
  "PE",
16261
17098
  "EC",
16262
17099
  "CL"
16263
17100
  ]);
16264
- var ResearchCategoryEnum = z69.enum([
17101
+ var ResearchCategoryEnum = z73.enum([
16265
17102
  "auto",
16266
17103
  "automotive",
16267
17104
  "kitchen",
@@ -16330,7 +17167,7 @@ var OVERWRITES_EXTERNAL = {
16330
17167
  idempotentHint: false,
16331
17168
  openWorldHint: false
16332
17169
  };
16333
- var DailyControlStatusEnum = z69.enum([
17170
+ var DailyControlStatusEnum = z73.enum([
16334
17171
  "ok",
16335
17172
  "sales_unavailable",
16336
17173
  "timezone_unavailable",
@@ -16343,19 +17180,19 @@ var DailyControlStatusEnum = z69.enum([
16343
17180
  "product_missing",
16344
17181
  "store_unreachable"
16345
17182
  ]);
16346
- var DailyControlLightEnum = z69.enum([
17183
+ var DailyControlLightEnum = z73.enum([
16347
17184
  "green",
16348
17185
  "amber",
16349
17186
  "red",
16350
17187
  "none"
16351
17188
  ]);
16352
- var DailyControlVerdictEnum = z69.enum([
17189
+ var DailyControlVerdictEnum = z73.enum([
16353
17190
  "scale",
16354
17191
  "hold",
16355
17192
  "kill",
16356
17193
  "insufficient_sample"
16357
17194
  ]);
16358
- var DailyControlSourceEnum = z69.enum([
17195
+ var DailyControlSourceEnum = z73.enum([
16359
17196
  "shopify",
16360
17197
  "shopify_settling",
16361
17198
  "user",
@@ -17496,29 +18333,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
17496
18333
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
17497
18334
 
17498
18335
  // src/tools/media-presentation.ts
17499
- import { z as z70 } from "zod";
17500
- var HttpsPresentationUrlSchema = z70.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
18336
+ import { z as z74 } from "zod";
18337
+ var HttpsPresentationUrlSchema = z74.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
17501
18338
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
17502
18339
  const hostname = new URL(value).hostname.toLowerCase();
17503
18340
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
17504
18341
  }, "preview URL must be owned by ProductMaker");
17505
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z70.number().int().positive().max(maximum), "positiveIntAtMost");
17506
- var PresentationImageSchema = z70.object({
17507
- kind: z70.literal("image"),
18342
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z74.number().int().positive().max(maximum), "positiveIntAtMost");
18343
+ var PresentationImageSchema = z74.object({
18344
+ kind: z74.literal("image"),
17508
18345
  url: HttpsPresentationUrlSchema,
17509
- mimeType: z70.enum([
18346
+ mimeType: z74.enum([
17510
18347
  "image/jpeg",
17511
18348
  "image/png"
17512
18349
  ]),
17513
18350
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
17514
18351
  width: positiveIntAtMost(16384),
17515
18352
  height: positiveIntAtMost(16384),
17516
- alt: z70.string().trim().min(1).max(240)
18353
+ alt: z74.string().trim().min(1).max(240)
17517
18354
  }).strict();
17518
18355
  var McpMediaPresentationSchema = PresentationImageSchema;
17519
- var GalleryImageSchema = z70.object({
18356
+ var GalleryImageSchema = z74.object({
17520
18357
  url: ProductMakerPreviewUrlSchema,
17521
- alt: z70.string().trim().min(1).max(240)
18358
+ alt: z74.string().trim().min(1).max(240)
17522
18359
  });
17523
18360
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
17524
18361
  async function imageBlocks(image, transport) {
@@ -17668,10 +18505,10 @@ ${summary}`,
17668
18505
  __name(requirePaidCreativeConfirmation, "requirePaidCreativeConfirmation");
17669
18506
 
17670
18507
  // src/tools/winning-product-image.ts
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)
18508
+ import { z as z75 } from "zod";
18509
+ var WinnerReferenceInput = z75.object({
18510
+ runId: z75.string().uuid(),
18511
+ candidateSourceId: z75.string().trim().min(1).max(160)
17675
18512
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
17676
18513
  async function resolveWinnerImages(api, winnerReference, images) {
17677
18514
  if (!winnerReference) return images;
@@ -17708,189 +18545,190 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
17708
18545
  var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
17709
18546
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
17710
18547
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
17711
- var CreateProductTaskInput = z72.object({
18548
+ var CreateProductTaskInput = z76.object({
17712
18549
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
17713
18550
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
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."),
18551
+ projectId: z76.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
18552
+ productUrl: z76.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."),
17716
18553
  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.'),
17717
18554
  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.'),
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.'),
18555
+ price: z76.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.'),
18556
+ compareAtPrice: z76.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".'),
18557
+ offer: z76.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.'),
18558
+ paymentMethods: z76.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.'),
18559
+ productContext: z76.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."),
18560
+ productLabel: z76.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.'),
17724
18561
  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.'),
17725
- durationSeconds: z72.union([
17726
- z72.literal(15),
17727
- z72.literal(30)
18562
+ durationSeconds: z76.union([
18563
+ z76.literal(15),
18564
+ z76.literal(30)
17728
18565
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
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."),
18566
+ pauseForAngleReview: z76.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."),
18567
+ aiDecidesAll: z76.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."),
17731
18568
  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.'),
17732
18569
  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.'),
17733
18570
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
17734
18571
  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).'),
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."),
18572
+ videoAngleCount: z76.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."),
17736
18573
  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.'),
17737
- outputs: z72.array(z72.enum([
18574
+ outputs: z76.array(z76.enum([
17738
18575
  "landing",
17739
18576
  "video",
17740
18577
  "image"
17741
18578
  ])).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}`),
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."),
18579
+ competitorScanEnabled: z76.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."),
18580
+ replicateWinnerWhenFound: z76.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."),
18581
+ brandId: z76.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."),
18582
+ actorId: z76.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."),
17746
18583
  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.'),
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."),
18584
+ creativeDirection: z76.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.'),
18585
+ headline: z76.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."),
18586
+ subheadline: z76.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."),
17750
18587
  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".'),
17751
18588
  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".')
17752
18589
  }).strict();
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.'),
18590
+ var CreateServiceVideoInput = z76.object({
18591
+ landingUrl: z76.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
18592
+ additionalContext: z76.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
17756
18593
  language: Lang.describe("Idioma del video: es, en o pt."),
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([
18594
+ voiceId: z76.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.'),
18595
+ brandId: z76.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
18596
+ reviewMode: z76.enum([
17760
18597
  "automatic",
17761
18598
  "guided"
17762
18599
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
17763
- videoPreset: z72.enum([
18600
+ videoPreset: z76.enum([
17764
18601
  "auto",
17765
18602
  "ugc_dynamic",
17766
18603
  "ugc_how_to",
17767
18604
  "cinematic",
17768
18605
  "wild_card"
17769
18606
  ]).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.')
18607
+ videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
18608
+ videoResolution: VideoResolutionEnum.default("480p").describe('Opcional. Resoluci\xF3n: "480p" o "720p". 720p cuesta m\xE1s por segundo y solo est\xE1 disponible en "economy" y "pro" (Medio = 768P). Default: 480p.')
17771
18609
  }).strict();
17772
- var GetTaskStatusInput = z72.object({
17773
- taskId: z72.string().min(1),
17774
- waitSeconds: z72.number().int().min(0).max(120).optional()
18610
+ var GetTaskStatusInput = z76.object({
18611
+ taskId: z76.string().min(1),
18612
+ waitSeconds: z76.number().int().min(0).max(120).optional()
17775
18613
  });
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()
18614
+ var ListTasksInput = z76.object({
18615
+ limit: z76.number().int().min(1).max(50).optional(),
18616
+ offset: z76.number().int().min(0).optional(),
18617
+ search: z76.string().optional()
17780
18618
  });
17781
18619
  var MCP_REVIEW_LIST_FIELD_MAX = 1500;
17782
18620
  var MCP_REVIEW_FEATURE_ITEM_MAX = 240;
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([
18621
+ var EditTaskDraftInput = z76.object({
18622
+ taskId: z76.string().min(1),
18623
+ angleIndex: z76.number().int().min(0),
18624
+ angle: z76.object({
18625
+ angle: z76.string().min(1).max(480),
18626
+ buyerPersona: z76.string().min(1).max(360),
18627
+ actor: z76.string().min(1).max(360).optional(),
18628
+ actorId: z76.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."),
18629
+ gender: z76.enum([
17792
18630
  "female",
17793
18631
  "male"
17794
18632
  ]).optional(),
17795
- scriptNotes: z72.string().max(2e3).optional()
18633
+ scriptNotes: z76.string().max(2e3).optional()
17796
18634
  })
17797
18635
  });
17798
- var PendingActionPayload = z72.discriminatedUnion("kind", [
17799
- z72.object({
17800
- kind: z72.literal("product_reference_set_approval"),
18636
+ var PendingActionPayload = z76.discriminatedUnion("kind", [
18637
+ z76.object({
18638
+ kind: z76.literal("product_reference_set_approval"),
17801
18639
  scope: ProductReferenceScopeEnum.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(),
18640
+ scopeKey: z76.string().min(1).max(120).optional(),
18641
+ scopeSnapshotId: z76.string().uuid().optional(),
18642
+ expectedScopeHash: z76.string().min(1).max(128).optional(),
17805
18643
  decision: ProductReferenceResolutionDecisionEnum,
17806
18644
  reason: ProductReferenceRejectionReasonEnum.optional(),
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([
18645
+ affectedRefKeys: z76.array(z76.string().min(1).max(200)).min(1).optional(),
18646
+ affectedPhotoNumbers: z76.array(z76.number().int().positive()).min(1).optional(),
18647
+ recoveryAction: z76.enum([
17810
18648
  "remove",
17811
18649
  "replace",
17812
18650
  "upload",
17813
18651
  "return_to_selection"
17814
18652
  ]).optional()
17815
18653
  }),
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."),
18654
+ z76.object({
18655
+ kind: z76.literal("product_reference_confirmation"),
18656
+ selectedPhotoNumbers: z76.array(z76.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."),
17819
18657
  userChoice: ProductReferenceUserChoiceEnum.optional(),
17820
- confirmedProductNames: z72.array(z72.string().min(1).max(120)).min(2).max(8).optional(),
18658
+ confirmedProductNames: z76.array(z76.string().min(1).max(120)).min(2).max(8).optional(),
17821
18659
  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."),
17822
18660
  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."),
17823
- useMultiSceneShowcase: z72.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
18661
+ useMultiSceneShowcase: z76.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
17824
18662
  }),
17825
- z72.object({
17826
- kind: z72.literal("angle_review_approval"),
18663
+ z76.object({
18664
+ kind: z76.literal("angle_review_approval"),
17827
18665
  // All edits are optional — empty action body just approves the
17828
18666
  // backend-generated draft as-is. Field shapes mirror the angle-review
17829
18667
  // request contracts in @packages/types/wizard.ts; the handler routes to
17830
18668
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
17831
- customAngle: z72.string().min(1).max(480).optional(),
18669
+ customAngle: z76.string().min(1).max(480).optional(),
17832
18670
  // Keep the shared MCP action within the strictest downstream contract:
17833
18671
  // autopilot/image resume endpoints cap these fields at 1500 characters.
17834
- painPoints: z72.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
17835
- benefits: z72.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
18672
+ painPoints: z76.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
18673
+ benefits: z76.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
17836
18674
  // Same policy as the two fields above: the strictest downstream contract
17837
18675
  // wins. The image endpoint caps each feature at 240 while landing/video
17838
18676
  // accept 300, and this single action routes to whichever the task is — so
17839
18677
  // accepting 300 here turns a 250-character feature on an image task into
17840
18678
  // an opaque HTTP 400 after the model already believed it had been saved.
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(),
18679
+ features: z76.array(z76.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
18680
+ buyerPersona: z76.string().min(1).max(360).optional(),
17843
18681
  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.'),
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([
18682
+ actor: z76.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."),
18683
+ actorId: z76.string().max(120).nullable().optional(),
18684
+ creativeDirection: z76.string().max(2e3).optional(),
18685
+ selectedAngleNumbers: z76.array(z76.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."),
18686
+ angleEdits: z76.array(z76.object({
18687
+ angleNumber: z76.number().int().positive(),
18688
+ narrativeSelection: z76.enum([
17851
18689
  "market",
17852
18690
  "guided"
17853
18691
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
17854
- angle: z72.string().min(1).max(480).optional(),
17855
- buyerPersona: z72.string().min(1).max(360).optional(),
18692
+ angle: z76.string().min(1).max(480).optional(),
18693
+ buyerPersona: z76.string().min(1).max(360).optional(),
17856
18694
  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.'),
17857
- actor: z72.string().min(1).max(360).optional(),
17858
- actorId: z72.string().max(120).nullable().optional(),
17859
- creativeDirection: z72.string().max(2e3).optional()
18695
+ actor: z76.string().min(1).max(360).optional(),
18696
+ actorId: z76.string().max(120).nullable().optional(),
18697
+ creativeDirection: z76.string().max(2e3).optional()
17860
18698
  }).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)."),
17861
- gapDurationSeconds: z72.union([
17862
- z72.literal(15),
17863
- z72.literal(30)
18699
+ gapDurationSeconds: z76.union([
18700
+ z76.literal(15),
18701
+ z76.literal(30)
17864
18702
  ]).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.")
17865
18703
  }),
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()
18704
+ z76.object({
18705
+ kind: z76.literal("service_angle_approval"),
18706
+ angleId: z76.string().uuid().optional(),
18707
+ angleNumber: z76.number().int().positive().optional(),
18708
+ content: z76.string().min(1).max(480).optional(),
18709
+ creativeDirection: z76.string().min(1).max(1500).optional(),
18710
+ actor: z76.string().min(1).max(360).optional()
17873
18711
  }),
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()
18712
+ z76.object({
18713
+ kind: z76.literal("service_script_approval"),
18714
+ voiceovers: z76.record(z76.string(), z76.string().min(1).max(600)).optional(),
18715
+ visualDirections: z76.record(z76.string(), z76.string().min(1).max(1200)).optional(),
18716
+ voiceoversByScene: z76.record(z76.string(), z76.string().min(1).max(600)).optional(),
18717
+ visualDirectionsByScene: z76.record(z76.string(), z76.string().min(1).max(1200)).optional()
17880
18718
  })
17881
18719
  ]);
17882
- var ResolvePendingActionInput = z72.object({
17883
- taskId: z72.string().min(1),
18720
+ var ResolvePendingActionInput = z76.object({
18721
+ taskId: z76.string().min(1),
17884
18722
  action: PendingActionPayload
17885
18723
  }).strict();
17886
18724
  function resolveVariantConfirmVideoTier(action) {
17887
18725
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
17888
18726
  }
17889
18727
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
17890
- var StatusForResolveSchema = z72.object({
18728
+ var StatusForResolveSchema = z76.object({
17891
18729
  // Metadata used to select the backend resume contract. Older API responses
17892
18730
  // may omit these fields, so the resolver keeps the generic fallback.
17893
- kind: z72.enum([
18731
+ kind: z76.enum([
17894
18732
  "autopilot",
17895
18733
  "video",
17896
18734
  "image",
@@ -17898,18 +18736,18 @@ var StatusForResolveSchema = z72.object({
17898
18736
  "mix",
17899
18737
  "service"
17900
18738
  ]).optional(),
17901
- selectedOutputs: z72.array(z72.enum([
18739
+ selectedOutputs: z76.array(z76.enum([
17902
18740
  "landing",
17903
18741
  "video",
17904
18742
  "image"
17905
18743
  ])).optional(),
17906
- videoAngleCount: z72.number().int().min(1).max(3).optional(),
17907
- ugcFormat: z72.enum([
18744
+ videoAngleCount: z76.number().int().min(1).max(3).optional(),
18745
+ ugcFormat: z76.enum([
17908
18746
  "single_8s",
17909
18747
  "single_15s",
17910
18748
  "double_30s"
17911
18749
  ]).optional(),
17912
- videoStyle: z72.enum([
18750
+ videoStyle: z76.enum([
17913
18751
  "ugc",
17914
18752
  "cartoon_3d",
17915
18753
  "product_only",
@@ -17918,79 +18756,72 @@ var StatusForResolveSchema = z72.object({
17918
18756
  videoStructure: VideoStructureEnum.optional(),
17919
18757
  videoQuality: VideoQualityEnum.optional(),
17920
18758
  videoRouteId: VideoRouteIdEnum.optional(),
17921
- videoModel: z72.enum([
17922
- "veo",
17923
- "wan",
17924
- "bytedance",
17925
- "seedance",
17926
- "grok",
17927
- "kling"
17928
- ]).optional(),
17929
- videoTier: z72.enum([
18759
+ videoModel: TaskVideoModelEnum.optional(),
18760
+ videoTier: z76.enum([
17930
18761
  "legacy",
17931
18762
  "standard",
17932
18763
  "pro",
17933
18764
  "single_call"
17934
18765
  ]).optional(),
17935
- videoResolution: z72.enum([
18766
+ videoResolution: z76.enum([
17936
18767
  "480p",
17937
18768
  "720p"
17938
18769
  ]).optional(),
17939
18770
  narrativeStyle: NarrativeStyleEnum.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(),
18771
+ pauseForVideoScriptReview: z76.boolean().optional(),
18772
+ pendingUserAction: z76.object({
18773
+ kind: z76.string(),
18774
+ candidateGrouping: z76.string().optional(),
18775
+ selectedImageUrls: z76.array(z76.string()).optional(),
18776
+ proposedProductNames: z76.array(z76.string()).optional(),
17946
18777
  // Adaptive reference questions are server-owned. Echo only the evidence
17947
18778
  // identity and the choices shown by the current snapshot; never accept a
17948
18779
  // client-supplied reference set as authorization.
17949
- options: z72.array(ProductReferenceUserChoiceEnum).max(4).optional(),
17950
- mode: z72.enum([
18780
+ options: z76.array(ProductReferenceUserChoiceEnum).max(4).optional(),
18781
+ mode: z76.enum([
17951
18782
  "question",
17952
18783
  "visual_recovery"
17953
18784
  ]).optional(),
17954
18785
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
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)
18786
+ canKeepSelection: z76.boolean().optional(),
18787
+ decisionKey: z76.string().optional(),
18788
+ questionOrdinal: z76.number().int().min(1).max(5).optional(),
18789
+ questionCeiling: z76.union([
18790
+ z76.literal(3),
18791
+ z76.literal(5)
17961
18792
  ]).optional(),
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({
18793
+ referenceEvidenceVersion: z76.number().int().positive().optional(),
18794
+ expectedEvidenceHash: z76.string().optional(),
18795
+ question: z76.object({
18796
+ prompt: z76.string().min(1).max(240),
18797
+ helpText: z76.string().min(1).max(300).optional(),
18798
+ options: z76.array(z76.object({
17968
18799
  value: ProductReferenceUserChoiceEnum,
17969
- label: z72.string().min(1).max(120),
17970
- description: z72.string().min(1).max(240).optional()
18800
+ label: z76.string().min(1).max(120),
18801
+ description: z76.string().min(1).max(240).optional()
17971
18802
  })).min(2).max(4)
17972
18803
  }).optional(),
17973
18804
  scope: ProductReferenceScopeEnum.optional(),
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([
18805
+ scopeKey: z76.string().optional(),
18806
+ scopeSnapshotId: z76.string().uuid().optional(),
18807
+ scopeHash: z76.string().optional(),
18808
+ baseReferenceSetHash: z76.string().optional(),
18809
+ phase: z76.enum([
17979
18810
  "preparation",
17980
18811
  "final"
17981
18812
  ]).optional(),
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)
18813
+ selectedRefKeys: z76.array(z76.string().min(1).max(200)).optional(),
18814
+ allowedDecisions: z76.array(ProductReferenceResolutionDecisionEnum).optional(),
18815
+ previews: z76.array(z76.object({
18816
+ refKey: z76.string().min(1).max(200)
17986
18817
  }).passthrough()).optional(),
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)
18818
+ customAngleDraft: z76.string().optional(),
18819
+ painPointsDraft: z76.string().optional(),
18820
+ benefitsDraft: z76.string().optional(),
18821
+ featuresDraft: z76.array(z76.string()).optional(),
18822
+ angleOptions: z76.array(z76.object({
18823
+ index: z76.number().int().nonnegative(),
18824
+ angle: z76.string().min(1)
17994
18825
  }).passthrough()).min(1).max(5).optional(),
17995
18826
  // Recommendation consumed only when the caller explicitly sends
17996
18827
  // gapDurationSeconds: 30 in the angle approval action.
@@ -18000,17 +18831,17 @@ var StatusForResolveSchema = z72.object({
18000
18831
  // keys. `actorId` (the saved custom actor the picker stored) was silently
18001
18832
  // dropped here, so the approval handler below could not echo it back on the
18002
18833
  // PATCH — the selection looked accepted and reached no render.
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()
18834
+ angles: z76.array(z76.object({
18835
+ id: z76.string().uuid(),
18836
+ content: z76.string(),
18837
+ creativeDirection: z76.string(),
18838
+ actor: z76.string(),
18839
+ actorId: z76.string().nullable().optional()
18009
18840
  }).passthrough()).optional(),
18010
- panels: z72.array(z72.object({
18011
- beatId: z72.string(),
18012
- voiceover: z72.string(),
18013
- visualDirection: z72.string()
18841
+ panels: z76.array(z76.object({
18842
+ beatId: z76.string(),
18843
+ voiceover: z76.string(),
18844
+ visualDirection: z76.string()
18014
18845
  }).passthrough()).optional()
18015
18846
  }).optional()
18016
18847
  }).passthrough();
@@ -18224,6 +19055,9 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
18224
19055
  });
18225
19056
  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) => {
18226
19057
  try {
19058
+ if (input.videoQuality === "medium" && input.videoResolution === "720p") {
19059
+ throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
19060
+ }
18227
19061
  await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
18228
19062
  const created = await api.postJson("/v2/ingest", {
18229
19063
  taskType: "service",
@@ -18237,6 +19071,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
18237
19071
  } : {},
18238
19072
  videoPreset: input.videoPreset,
18239
19073
  videoQuality: input.videoQuality,
19074
+ videoResolution: input.videoResolution,
18240
19075
  reviewMode: input.reviewMode,
18241
19076
  ...input.brandId ? {
18242
19077
  brandId: input.brandId
@@ -18841,7 +19676,7 @@ __name(registerTaskTools, "registerTaskTools");
18841
19676
 
18842
19677
  // src/tools/creatives.ts
18843
19678
  import { randomUUID } from "crypto";
18844
- import { z as z73 } from "zod";
19679
+ import { z as z77 } from "zod";
18845
19680
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
18846
19681
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
18847
19682
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -18851,70 +19686,70 @@ var CreativeRefs = {
18851
19686
  images: ImagesInput,
18852
19687
  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.'),
18853
19688
  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.'),
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.")
19689
+ price: z77.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.'),
19690
+ offer: z77.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.'),
19691
+ compareAtPrice: z77.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
19692
+ productContext: z77.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."),
19693
+ productLabel: z77.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.'),
19694
+ buyerPersona: z77.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.'),
19695
+ isCombo: z77.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
19696
+ competitorScanEnabled: z77.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."),
19697
+ brandId: z77.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.")
18863
19698
  };
18864
- var VideoPresenter = z73.discriminatedUnion("mode", [
18865
- z73.object({
18866
- mode: z73.literal("none")
19699
+ var VideoPresenter = z77.discriminatedUnion("mode", [
19700
+ z77.object({
19701
+ mode: z77.literal("none")
18867
19702
  }).strict(),
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.")
19703
+ z77.object({
19704
+ mode: z77.literal("saved_actor"),
19705
+ actorId: z77.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
18871
19706
  }).strict(),
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.")
19707
+ z77.object({
19708
+ mode: z77.literal("described"),
19709
+ description: z77.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
18875
19710
  }).strict()
18876
19711
  ]);
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".')
19712
+ var VideoCreativeSetup = z77.discriminatedUnion("mode", [
19713
+ z77.object({
19714
+ mode: z77.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
18880
19715
  }).strict(),
18881
- z73.object({
18882
- mode: z73.literal("guided"),
19716
+ z77.object({
19717
+ mode: z77.literal("guided"),
18883
19718
  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.'),
18884
- buyerPersona: z73.string().trim().min(1).max(360),
19719
+ buyerPersona: z77.string().trim().min(1).max(360),
18885
19720
  presenter: VideoPresenter,
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.")
19721
+ creativeDirection: z77.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
18887
19722
  }).strict()
18888
19723
  ]);
18889
- var VideoInput = z73.object({
19724
+ var VideoInput = z77.object({
18890
19725
  images: CreativeRefs.images.optional(),
18891
19726
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
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".'),
19727
+ title: z77.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
19728
+ primaryAngle: z77.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".'),
18894
19729
  language: CreativeRefs.language,
18895
19730
  country: CreativeRefs.country,
18896
- aspectRatio: z73.enum([
19731
+ aspectRatio: z77.enum([
18897
19732
  "9:16",
18898
19733
  "16:9",
18899
19734
  "Auto"
18900
19735
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
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."),
19736
+ durationSeconds: z77.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."),
19737
+ videoAngleCount: z77.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."),
18903
19738
  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.'),
18904
19739
  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."),
18905
19740
  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.'),
18906
19741
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
18907
19742
  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.'),
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"].'),
19743
+ features: z77.array(z77.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
18909
19744
  price: CreativeRefs.price,
18910
19745
  offer: CreativeRefs.offer,
18911
19746
  productContext: CreativeRefs.productContext,
18912
19747
  productLabel: CreativeRefs.productLabel,
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.'),
19748
+ cta: z77.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.'),
19749
+ scriptNotes: z77.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.'),
18915
19750
  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.'),
18916
19751
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
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."),
19752
+ replicateWinnerWhenFound: z77.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."),
18918
19753
  brandId: CreativeRefs.brandId
18919
19754
  }).strict();
18920
19755
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -18932,7 +19767,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
18932
19767
  length: 29
18933
19768
  }, (_, index) => index + 2)
18934
19769
  };
18935
- var FreeVideoModelIdEnum = z73.enum([
19770
+ var FreeVideoModelIdEnum = z77.enum([
18936
19771
  "grok-imagine-video-1-5-preview",
18937
19772
  "minimax-h3/reference-to-video",
18938
19773
  "wan/3-0-video",
@@ -18943,70 +19778,65 @@ var FREE_SELECTABLE_MODEL_IDS = [
18943
19778
  "minimax-h3/reference-to-video",
18944
19779
  "wan/3-0-video"
18945
19780
  ];
18946
- var FreeVideoInput = z73.object({
19781
+ var FreeVideoInput = z77.object({
18947
19782
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
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."),
19783
+ rawPrompt: z77.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."),
18949
19784
  language: CreativeRefs.language,
18950
19785
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
18951
19786
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
18952
19787
  // parsed ONLY so the handler can reject it with a message naming its
18953
19788
  // replacement — dropping it silently would turn a caller's explicit
18954
19789
  // Pro++ pick into a quiet fallback to Wan.
18955
- freeProModel: z73.enum([
19790
+ freeProModel: z77.enum([
18956
19791
  "wan",
18957
19792
  "seedance"
18958
19793
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
18959
19794
  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.'),
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."),
19795
+ durationSeconds: z77.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."),
18961
19796
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
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.")
19797
+ generateAiMusic: z77.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
19798
+ addSubtitles: z77.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
19799
+ idempotencyKey: z77.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.")
18965
19800
  }).strict();
18966
19801
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
18967
- var ImageCreativeSetup = z73.discriminatedUnion("mode", [
18968
- z73.object({
18969
- mode: z73.literal("automatic")
19802
+ var ImageCreativeSetup = z77.discriminatedUnion("mode", [
19803
+ z77.object({
19804
+ mode: z77.literal("automatic")
18970
19805
  }).strict(),
18971
- z73.object({
18972
- mode: z73.literal("guided"),
18973
- creativeArchetype: z73.union([
19806
+ z77.object({
19807
+ mode: z77.literal("guided"),
19808
+ creativeArchetype: z77.union([
18974
19809
  ImageCreativeArchetypeEnum,
18975
- z73.literal("ai_decides")
19810
+ z77.literal("ai_decides")
18976
19811
  ]),
18977
- visualTreatment: z73.union([
19812
+ visualTreatment: z77.union([
18978
19813
  ImageCreativeVisualTreatmentEnum,
18979
- z73.literal("ai_decides")
19814
+ z77.literal("ai_decides")
18980
19815
  ]),
18981
19816
  aspectRatio: ImageCreativeAspectRatioEnum,
18982
- nVariants: z73.union([
18983
- z73.literal(1),
18984
- z73.literal(2),
18985
- z73.literal(3),
18986
- z73.literal(4),
18987
- z73.literal(6)
19817
+ nVariants: z77.union([
19818
+ z77.literal(1),
19819
+ z77.literal(2),
19820
+ z77.literal(3),
19821
+ z77.literal(4),
19822
+ z77.literal(6)
18988
19823
  ]),
18989
- imageModel: z73.enum([
18990
- "gpt-image-2-5:1k",
18991
- "gpt-image-2-5:2k",
18992
- "gpt-image-2:1k",
18993
- "gpt-image-2:2k"
18994
- ]),
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()
19824
+ imageModel: z77.enum(PUBLIC_IMAGE_QUALITY_INPUTS).describe('Calidad: "image:1k" (Est\xE1ndar) o "image:2k" (Premium). Los tokens gpt-image-2-5:{1k,2k} y gpt-image-2:{1k,2k} se siguen aceptando.'),
19825
+ styleMix: z77.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
19826
+ generateAdCopy: z77.boolean(),
19827
+ competitorScanEnabled: z77.boolean(),
19828
+ productContext: z77.string().trim().min(1).max(3e3).nullable(),
19829
+ creativeDirection: z77.string().trim().min(1).max(500).nullable(),
19830
+ brandColors: z77.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.'),
19831
+ headline: z77.string().trim().min(1).max(120).nullable(),
19832
+ subheadline: z77.string().trim().min(1).max(160).nullable()
19003
19833
  }).strict()
19004
19834
  ]).superRefine((setup, context) => {
19005
19835
  if (setup.mode !== "guided") return;
19006
19836
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
19007
19837
  if (needsStyleMix && setup.styleMix === null) {
19008
19838
  context.addIssue({
19009
- code: z73.ZodIssueCode.custom,
19839
+ code: z77.ZodIssueCode.custom,
19010
19840
  path: [
19011
19841
  "styleMix"
19012
19842
  ],
@@ -19015,16 +19845,16 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
19015
19845
  }
19016
19846
  if (!needsStyleMix && setup.styleMix !== null) {
19017
19847
  context.addIssue({
19018
- code: z73.ZodIssueCode.custom,
19848
+ code: z77.ZodIssueCode.custom,
19019
19849
  path: [
19020
19850
  "styleMix"
19021
19851
  ],
19022
19852
  message: "styleMix debe ser null cuando nVariants es 1 o 6."
19023
19853
  });
19024
19854
  }
19025
- if ((setup.imageModel === "gpt-image-2:2k" || setup.imageModel === "gpt-image-2-5:2k") && setup.aspectRatio === "4:5") {
19855
+ if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
19026
19856
  context.addIssue({
19027
- code: z73.ZodIssueCode.custom,
19857
+ code: z77.ZodIssueCode.custom,
19028
19858
  path: [
19029
19859
  "aspectRatio"
19030
19860
  ],
@@ -19032,53 +19862,53 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
19032
19862
  });
19033
19863
  }
19034
19864
  });
19035
- var LandingCreativeSetup = z73.discriminatedUnion("mode", [
19036
- z73.object({
19037
- mode: z73.literal("automatic")
19865
+ var LandingCreativeSetup = z77.discriminatedUnion("mode", [
19866
+ z77.object({
19867
+ mode: z77.literal("automatic")
19038
19868
  }).strict(),
19039
- z73.object({
19040
- mode: z73.literal("guided"),
19869
+ z77.object({
19870
+ mode: z77.literal("guided"),
19041
19871
  landingStrategy: LandingStrategyEnum,
19042
19872
  landingImageFormat: LandingImageFormatEnum,
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()
19873
+ competitorScanEnabled: z77.boolean(),
19874
+ paymentMethods: z77.string().trim().min(1).max(240).nullable(),
19875
+ productContext: z77.string().trim().min(1).max(3e3).nullable(),
19876
+ creativeDirection: z77.string().trim().min(1).max(500).nullable(),
19877
+ headline: z77.string().trim().min(1).max(120).nullable(),
19878
+ subheadline: z77.string().trim().min(1).max(160).nullable()
19049
19879
  }).strict()
19050
19880
  ]);
19051
- var ImageInput = z73.object({
19881
+ var ImageInput = z77.object({
19052
19882
  images: CreativeRefs.images.optional(),
19053
19883
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
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.'),
19884
+ productTitle: z77.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
19885
+ primaryAngle: z77.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.'),
19056
19886
  buyerPersona: CreativeRefs.buyerPersona,
19057
19887
  language: CreativeRefs.language,
19058
19888
  country: CreativeRefs.country,
19059
19889
  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."),
19060
19890
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
19061
- features: z73.array(z73.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
19891
+ features: z77.array(z77.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
19062
19892
  price: CreativeRefs.price,
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."),
19893
+ omitPrice: z77.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."),
19064
19894
  compareAtPrice: CreativeRefs.compareAtPrice,
19065
19895
  offer: CreativeRefs.offer,
19066
19896
  productLabel: CreativeRefs.productLabel,
19067
19897
  isCombo: CreativeRefs.isCombo,
19068
19898
  brandId: CreativeRefs.brandId
19069
19899
  });
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".')
19900
+ var EditImageCreativeInput = z77.object({
19901
+ taskId: z77.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
19902
+ variantIndex: z77.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
19903
+ instruction: z77.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".')
19074
19904
  });
19075
- var LandingInput = z73.object({
19905
+ var LandingInput = z77.object({
19076
19906
  images: CreativeRefs.images.optional(),
19077
19907
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
19078
19908
  language: CreativeRefs.language,
19079
19909
  country: CreativeRefs.country,
19080
19910
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
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.'),
19911
+ salesAngle: z77.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.'),
19082
19912
  buyerPersona: CreativeRefs.buyerPersona,
19083
19913
  price: CreativeRefs.price,
19084
19914
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -19097,7 +19927,7 @@ function resolveImageSetup(setup) {
19097
19927
  },
19098
19928
  aspectRatio: setup.aspectRatio,
19099
19929
  nVariants: setup.nVariants,
19100
- imageModel: setup.imageModel,
19930
+ imageModel: canonicalImageModelInput(setup.imageModel),
19101
19931
  ...setup.nVariants === 6 ? {
19102
19932
  styleMix: true
19103
19933
  } : setup.styleMix === null ? {} : {
@@ -19340,10 +20170,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
19340
20170
  __name(registerCreativeTools, "registerCreativeTools");
19341
20171
 
19342
20172
  // src/tools/creative-variants.ts
19343
- import { z as z74 } from "zod";
20173
+ import { z as z78 } from "zod";
19344
20174
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
19345
20175
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
19346
- var LandingSectionKeyEnum = z74.enum([
20176
+ var LandingSectionKeyEnum = z78.enum([
19347
20177
  "problem_hook",
19348
20178
  "problem_cost",
19349
20179
  "solution_mechanism",
@@ -19383,24 +20213,24 @@ var LandingSectionKeyEnum = z74.enum([
19383
20213
  "lifestyle_fit",
19384
20214
  "join_lifestyle"
19385
20215
  ]);
19386
- var CreativeVariantKindEnum = z74.enum([
20216
+ var CreativeVariantKindEnum = z78.enum([
19387
20217
  "video",
19388
20218
  "image",
19389
20219
  "landing"
19390
20220
  ]);
19391
- var EstimateCreativeVariantInputBase = z74.object({
19392
- sourceTaskId: z74.string().uuid().describe("ID de la tarea original completada."),
20221
+ var EstimateCreativeVariantInputBase = z78.object({
20222
+ sourceTaskId: z78.string().uuid().describe("ID de la tarea original completada."),
19393
20223
  kind: CreativeVariantKindEnum,
19394
20224
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
19395
20225
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
19396
- nVariants: z74.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
20226
+ nVariants: z78.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
19397
20227
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n 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.")
20228
+ instructions: z78.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.")
19399
20229
  }).strict();
19400
20230
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
19401
20231
  if (input.kind === "video" && input.nVariants !== void 0) {
19402
20232
  ctx.addIssue({
19403
- code: z74.ZodIssueCode.custom,
20233
+ code: z78.ZodIssueCode.custom,
19404
20234
  path: [
19405
20235
  "nVariants"
19406
20236
  ],
@@ -19410,7 +20240,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19410
20240
  if (input.kind !== "video") {
19411
20241
  if (input.videoPreset !== void 0) {
19412
20242
  ctx.addIssue({
19413
- code: z74.ZodIssueCode.custom,
20243
+ code: z78.ZodIssueCode.custom,
19414
20244
  path: [
19415
20245
  "videoPreset"
19416
20246
  ],
@@ -19419,7 +20249,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19419
20249
  }
19420
20250
  if (input.videoResolution !== void 0) {
19421
20251
  ctx.addIssue({
19422
- code: z74.ZodIssueCode.custom,
20252
+ code: z78.ZodIssueCode.custom,
19423
20253
  path: [
19424
20254
  "videoResolution"
19425
20255
  ],
@@ -19429,7 +20259,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19429
20259
  }
19430
20260
  if (input.kind !== "image" && input.nVariants !== void 0) {
19431
20261
  ctx.addIssue({
19432
- code: z74.ZodIssueCode.custom,
20262
+ code: z78.ZodIssueCode.custom,
19433
20263
  path: [
19434
20264
  "nVariants"
19435
20265
  ],
@@ -19439,7 +20269,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19439
20269
  if (input.kind !== "landing") {
19440
20270
  if (input.sectionKey !== void 0) {
19441
20271
  ctx.addIssue({
19442
- code: z74.ZodIssueCode.custom,
20272
+ code: z78.ZodIssueCode.custom,
19443
20273
  path: [
19444
20274
  "sectionKey"
19445
20275
  ],
@@ -19448,7 +20278,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19448
20278
  }
19449
20279
  if (input.instructions !== void 0) {
19450
20280
  ctx.addIssue({
19451
- code: z74.ZodIssueCode.custom,
20281
+ code: z78.ZodIssueCode.custom,
19452
20282
  path: [
19453
20283
  "instructions"
19454
20284
  ],
@@ -19457,31 +20287,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
19457
20287
  }
19458
20288
  }
19459
20289
  });
19460
- var CreateCreativeVariantInputBase = z74.object({
19461
- sourceTaskId: z74.string().uuid().describe("ID de la tarea original completada."),
20290
+ var CreateCreativeVariantInputBase = z78.object({
20291
+ sourceTaskId: z78.string().uuid().describe("ID de la tarea original completada."),
19462
20292
  kind: CreativeVariantKindEnum,
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."),
20293
+ confirm: z78.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
20294
+ clientRequestId: z78.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."),
20295
+ angle: z78.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
20296
+ buyerPersona: z78.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
20297
+ scriptNotes: z78.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
20298
+ creativeDirection: z78.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
19469
20299
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
19470
20300
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
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)."),
20301
+ generateAiMusic: z78.boolean().optional().describe("Opcional para video."),
20302
+ nVariants: z78.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
19473
20303
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
19474
20304
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
19475
20305
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
19476
20306
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
19477
- styleMix: z74.boolean().optional().describe("Opcional para imagen."),
20307
+ styleMix: z78.boolean().optional().describe("Opcional para imagen."),
19478
20308
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
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.")
20309
+ instructions: z78.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.")
19480
20310
  }).strict();
19481
20311
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
19482
20312
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
19483
20313
  ctx.addIssue({
19484
- code: z74.ZodIssueCode.custom,
20314
+ code: z78.ZodIssueCode.custom,
19485
20315
  path: [
19486
20316
  "angle"
19487
20317
  ],
@@ -19490,7 +20320,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
19490
20320
  }
19491
20321
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
19492
20322
  ctx.addIssue({
19493
- code: z74.ZodIssueCode.custom,
20323
+ code: z78.ZodIssueCode.custom,
19494
20324
  path: [
19495
20325
  "instructions"
19496
20326
  ],
@@ -19536,7 +20366,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
19536
20366
  for (const field of fieldsByKind[input.kind]) {
19537
20367
  if (input[field] !== void 0) {
19538
20368
  ctx.addIssue({
19539
- code: z74.ZodIssueCode.custom,
20369
+ code: z78.ZodIssueCode.custom,
19540
20370
  path: [
19541
20371
  field
19542
20372
  ],
@@ -19653,32 +20483,32 @@ function registerCreativeVariantTools(server, api) {
19653
20483
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
19654
20484
 
19655
20485
  // src/tools/script-review.ts
19656
- import { z as z75 } from "zod";
20486
+ import { z as z79 } from "zod";
19657
20487
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
19658
20488
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
19659
20489
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
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.')
20490
+ var GetVideoScriptInput = z79.object({
20491
+ taskId: z79.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
20492
+ angleKey: z79.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.')
19663
20493
  }).strict();
19664
20494
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
19665
20495
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
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, {
20496
+ var ApproveSceneEdit = z79.object({
20497
+ index: z79.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
20498
+ dialogue: z79.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
19669
20499
  message: "dialogue no puede ser s\xF3lo espacios"
19670
20500
  }).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.")
19671
20501
  }).strict();
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.")
20502
+ var ApproveVideoScriptInput = z79.object({
20503
+ taskId: z79.string().min(1).describe("ID de la tarea."),
20504
+ angleKey: z79.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.'),
20505
+ scenes: z79.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.")
19676
20506
  }).strict();
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.'),
20507
+ var RegenerateVideoScriptInput = z79.object({
20508
+ taskId: z79.string().min(1).describe("ID de la tarea."),
20509
+ angleKey: z79.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.'),
19680
20510
  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).'),
19681
- narrativeSelection: z75.enum([
20511
+ narrativeSelection: z79.enum([
19682
20512
  "market",
19683
20513
  "guided"
19684
20514
  ]).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.")
@@ -19759,14 +20589,14 @@ function registerScriptReviewTools(server, api) {
19759
20589
  __name(registerScriptReviewTools, "registerScriptReviewTools");
19760
20590
 
19761
20591
  // src/tools/connections.ts
19762
- import { z as z76 } from "zod";
20592
+ import { z as z80 } from "zod";
19763
20593
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
19764
20594
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
19765
20595
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
19766
20596
  var listMetaDestinationsGuidance = getProductMakerCapabilityModelGuidance("list_meta_destinations");
19767
20597
  var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list_tiktok_advertisers");
19768
20598
  function registerConnectionTools(server, api) {
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 () => {
20599
+ 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.", z80.object({}).shape, READS_INTERNAL, async () => {
19770
20600
  try {
19771
20601
  const r = await api.getJson("/v1/shopify/shops");
19772
20602
  return asText(r);
@@ -19774,10 +20604,10 @@ function registerConnectionTools(server, api) {
19774
20604
  throw translateError(e);
19775
20605
  }
19776
20606
  });
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()
20607
+ 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.', z80.object({
20608
+ shopDomain: z80.string().min(3).max(120),
20609
+ query: z80.string().trim().max(120).optional(),
20610
+ taskId: z80.string().uuid().optional()
19781
20611
  }).shape, READS_EXTERNAL, async ({ shopDomain, query, taskId }) => {
19782
20612
  try {
19783
20613
  const params = new URLSearchParams({
@@ -19791,7 +20621,7 @@ function registerConnectionTools(server, api) {
19791
20621
  throw translateError(e);
19792
20622
  }
19793
20623
  });
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 () => {
20624
+ 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.", z80.object({}).shape, READS_EXTERNAL, async () => {
19795
20625
  try {
19796
20626
  const r = await api.getJson("/v1/facebook/ad-accounts");
19797
20627
  return asText(r);
@@ -19801,7 +20631,7 @@ function registerConnectionTools(server, api) {
19801
20631
  });
19802
20632
  server.registerTool("list_meta_destinations", {
19803
20633
  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.",
19804
- inputSchema: z76.object({}).shape,
20634
+ inputSchema: z80.object({}).shape,
19805
20635
  annotations: READS_EXTERNAL,
19806
20636
  _meta: {
19807
20637
  "openai/widgetAccessible": true
@@ -19814,7 +20644,7 @@ function registerConnectionTools(server, api) {
19814
20644
  throw translateError(e);
19815
20645
  }
19816
20646
  });
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 () => {
20647
+ server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z80.object({}).shape, READS_EXTERNAL, async () => {
19818
20648
  try {
19819
20649
  const r = await api.getJson("/v1/tiktok/advertisers");
19820
20650
  return asText(r);
@@ -19826,10 +20656,10 @@ function registerConnectionTools(server, api) {
19826
20656
  __name(registerConnectionTools, "registerConnectionTools");
19827
20657
 
19828
20658
  // src/tools/actors.ts
19829
- import { z as z77 } from "zod";
20659
+ import { z as z81 } from "zod";
19830
20660
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
19831
20661
  function registerActorTools(server, api) {
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 () => {
20662
+ 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.", z81.object({}).shape, READS_INTERNAL, async () => {
19833
20663
  try {
19834
20664
  const rows = await api.getJson("/v1/actors");
19835
20665
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -19850,7 +20680,7 @@ function registerActorTools(server, api) {
19850
20680
  __name(registerActorTools, "registerActorTools");
19851
20681
 
19852
20682
  // src/tools/publish.ts
19853
- import { z as z78 } from "zod";
20683
+ import { z as z82 } from "zod";
19854
20684
 
19855
20685
  // src/tools/stable-uuid.ts
19856
20686
  import { createHash as createHash2 } from "crypto";
@@ -19922,40 +20752,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
19922
20752
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
19923
20753
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
19924
20754
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
19925
- var ShopifyInput = z78.object({
19926
- taskId: z78.string().min(1),
19927
- shopDomain: z78.string().min(1),
20755
+ var ShopifyInput = z82.object({
20756
+ taskId: z82.string().min(1),
20757
+ shopDomain: z82.string().min(1),
19928
20758
  /** Override: number of landing images to include. Default = ALL images the
19929
20759
  * task generated (the MCP fetches /v1/results first to count). Bounded
19930
20760
  * generously here; the backend validates each index against
19931
20761
  * landing.images.length and rejects out-of-range. */
19932
- numLandingImages: z78.number().int().min(1).max(20).optional(),
19933
- variantIndex: z78.number().int().min(0).optional(),
20762
+ numLandingImages: z82.number().int().min(1).max(20).optional(),
20763
+ variantIndex: z82.number().int().min(0).optional(),
19934
20764
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
19935
20765
  * When true, the landing renders variant-picker pills; when false, it ships
19936
20766
  * a single-option product page. Defaults to false. */
19937
- showVariantPicker: z78.boolean().optional(),
20767
+ showVariantPicker: z82.boolean().optional(),
19938
20768
  /** Default `auto` updates the product previously published for this task and
19939
20769
  * shop. Use `existing` with targetProductId to choose another product, or
19940
20770
  * `new` only when the user explicitly wants a duplicate/new listing. */
19941
- publicationMode: z78.enum([
20771
+ publicationMode: z82.enum([
19942
20772
  "auto",
19943
20773
  "existing",
19944
20774
  "new"
19945
20775
  ]).optional(),
19946
20776
  /** Shopify product GID, numeric id, or admin product URL. Required when
19947
20777
  * publicationMode is `existing`. */
19948
- targetProductId: z78.string().trim().min(1).max(300).optional(),
20778
+ targetProductId: z82.string().trim().min(1).max(300).optional(),
19949
20779
  /** Add an announcement bar text above add-to-cart (optional). */
19950
- announcementBarEnabled: z78.boolean().optional(),
19951
- announcementBarText: z78.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
20780
+ announcementBarEnabled: z82.boolean().optional(),
20781
+ announcementBarText: z82.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
19952
20782
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
19953
- confirmed: z78.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
20783
+ confirmed: z82.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
19954
20784
  });
19955
20785
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
19956
20786
  if (value.commerceCorrection && value.confirmed !== true) {
19957
20787
  ctx.addIssue({
19958
- code: z78.ZodIssueCode.custom,
20788
+ code: z82.ZodIssueCode.custom,
19959
20789
  path: [
19960
20790
  "confirmed"
19961
20791
  ],
@@ -19964,7 +20794,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
19964
20794
  }
19965
20795
  if (value.announcementBarEnabled && !value.announcementBarText) {
19966
20796
  ctx.addIssue({
19967
- code: z78.ZodIssueCode.custom,
20797
+ code: z82.ZodIssueCode.custom,
19968
20798
  path: [
19969
20799
  "announcementBarText"
19970
20800
  ],
@@ -19973,7 +20803,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
19973
20803
  }
19974
20804
  if (!value.announcementBarEnabled && value.announcementBarText) {
19975
20805
  ctx.addIssue({
19976
- code: z78.ZodIssueCode.custom,
20806
+ code: z82.ZodIssueCode.custom,
19977
20807
  path: [
19978
20808
  "announcementBarText"
19979
20809
  ],
@@ -19987,91 +20817,91 @@ function parseShopifyInput(rawInput) {
19987
20817
  return parsed.data;
19988
20818
  }
19989
20819
  __name(parseShopifyInput, "parseShopifyInput");
19990
- var McpCampaignConfig = z78.object({
20820
+ var McpCampaignConfig = z82.object({
19991
20821
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
19992
20822
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
19993
20823
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
19994
- dailyBudgetUsd: z78.number().positive().optional(),
20824
+ dailyBudgetUsd: z82.number().positive().optional(),
19995
20825
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
19996
20826
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
19997
20827
  * TikTok takes only the first entry. */
19998
- targetCountries: z78.array(CountryIso2Schema).max(1).optional(),
19999
- campaignName: z78.string().trim().min(1).max(100).optional()
20828
+ targetCountries: z82.array(CountryIso2Schema).max(1).optional(),
20829
+ campaignName: z82.string().trim().min(1).max(100).optional()
20000
20830
  });
20001
20831
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
20002
- var MetaInput = z78.object({
20003
- taskId: z78.string().min(1),
20832
+ var MetaInput = z82.object({
20833
+ taskId: z82.string().min(1),
20004
20834
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
20005
- portfolioId: z78.string().trim().min(1),
20835
+ portfolioId: z82.string().trim().min(1),
20006
20836
  /** Exact Facebook Page selected from `list_meta_destinations`. */
20007
- pageId: z78.string().trim().min(1),
20837
+ pageId: z82.string().trim().min(1),
20008
20838
  adAccountId: McpAdAccountId,
20009
- pixelId: z78.string().min(1).optional(),
20010
- landingUrl: z78.string().url().optional(),
20839
+ pixelId: z82.string().min(1).optional(),
20840
+ landingUrl: z82.string().url().optional(),
20011
20841
  /** Select which angles to publish by 0-based index. Omit to publish all
20012
20842
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
20013
- angleIndexes: z78.array(z78.number().int().nonnegative()).optional(),
20843
+ angleIndexes: z82.array(z82.number().int().nonnegative()).optional(),
20014
20844
  campaignConfig: McpCampaignConfig.optional(),
20015
20845
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
20016
20846
  * uses the auto-generated copy attached to the task. Capped at 500 chars
20017
20847
  * (Meta's primary-text limit). */
20018
- primaryText: z78.string().trim().min(1).max(500).optional(),
20848
+ primaryText: z82.string().trim().min(1).max(500).optional(),
20019
20849
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
20020
20850
  * (wa.me) instead of a landing page. */
20021
- phoneNumber: z78.string().min(8).max(32).optional()
20851
+ phoneNumber: z82.string().min(8).max(32).optional()
20022
20852
  });
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([
20853
+ var GroupedTaskSource = z82.object({
20854
+ type: z82.literal("task"),
20855
+ taskId: z82.string().min(1),
20856
+ angleIndex: z82.number().int().min(0).optional(),
20857
+ videoVariant: z82.enum([
20028
20858
  "with_subtitles",
20029
20859
  "without_subtitles"
20030
20860
  ]).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()
20861
+ imageVariantIndex: z82.number().int().min(0).optional()
20862
+ });
20863
+ var GroupedMediaSource = z82.object({
20864
+ type: z82.literal("media"),
20865
+ url: z82.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
20866
+ path: z82.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".'),
20867
+ thumbnailUrl: z82.string().url().optional(),
20868
+ thumbnailPath: z82.string().min(1).optional()
20039
20869
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
20040
20870
  message: "media source needs exactly one of `url` or `path`"
20041
20871
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
20042
20872
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
20043
20873
  });
20044
- var GroupedUploadedAssetSource = z78.object({
20045
- type: z78.literal("asset"),
20874
+ var GroupedUploadedAssetSource = z82.object({
20875
+ type: z82.literal("asset"),
20046
20876
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
20047
- assetId: z78.string().uuid(),
20048
- thumbnailAssetId: z78.string().uuid().optional()
20877
+ assetId: z82.string().uuid(),
20878
+ thumbnailAssetId: z82.string().uuid().optional()
20049
20879
  });
20050
- var GroupedCreative = z78.object({
20051
- type: z78.enum([
20880
+ var GroupedCreative = z82.object({
20881
+ type: z82.enum([
20052
20882
  "image",
20053
20883
  "video"
20054
20884
  ]),
20055
- source: z78.union([
20885
+ source: z82.union([
20056
20886
  GroupedTaskSource,
20057
20887
  GroupedMediaSource,
20058
20888
  GroupedUploadedAssetSource
20059
20889
  ]),
20060
- title: z78.string().max(120).optional(),
20061
- description: z78.string().max(500).optional(),
20890
+ title: z82.string().max(120).optional(),
20891
+ description: z82.string().max(500).optional(),
20062
20892
  cta: MetaCtaType.optional(),
20063
- creativeId: z78.string().min(1).optional()
20893
+ creativeId: z82.string().min(1).optional()
20064
20894
  });
20065
- var GroupedCampaignConfigBase = z78.object({
20895
+ var GroupedCampaignConfigBase = z82.object({
20066
20896
  campaignType: MetaCampaignType.default("sales"),
20067
20897
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
20068
20898
  budgetMode: MetaBudgetMode.optional(),
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)
20899
+ campaignDailyBudget: z82.number().int().positive().optional(),
20900
+ adSets: z82.array(z82.object({
20901
+ tempId: z82.string().min(1).max(80),
20902
+ name: z82.string().min(1).max(100),
20903
+ dailyBudget: z82.number().int().positive().optional(),
20904
+ creativeIds: z82.array(z82.string().min(1)).min(1)
20075
20905
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
20076
20906
  /**
20077
20907
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -20079,17 +20909,17 @@ var GroupedCampaignConfigBase = z78.object({
20079
20909
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
20080
20910
  * the API since #849 — unreachable from this tool.
20081
20911
  */
20082
- destination: z78.discriminatedUnion("type", [
20083
- z78.object({
20084
- type: z78.literal("landing"),
20085
- landingUrl: z78.string().url()
20912
+ destination: z82.discriminatedUnion("type", [
20913
+ z82.object({
20914
+ type: z82.literal("landing"),
20915
+ landingUrl: z82.string().url()
20086
20916
  }),
20087
- z78.object({
20088
- type: z78.literal("whatsapp"),
20089
- phoneNumber: z78.string().min(8).max(32)
20917
+ z82.object({
20918
+ type: z82.literal("whatsapp"),
20919
+ phoneNumber: z82.string().min(8).max(32)
20090
20920
  })
20091
20921
  ]),
20092
- saveAsDefault: z78.boolean().default(false),
20922
+ saveAsDefault: z82.boolean().default(false),
20093
20923
  budgetPolicy: MetaBudgetPolicy.optional()
20094
20924
  });
20095
20925
  function resolveBudgetMode(value) {
@@ -20103,7 +20933,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
20103
20933
  const budgetMode = resolveBudgetMode(value);
20104
20934
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
20105
20935
  ctx.addIssue({
20106
- code: z78.ZodIssueCode.custom,
20936
+ code: z82.ZodIssueCode.custom,
20107
20937
  path: [
20108
20938
  "campaignDailyBudget"
20109
20939
  ],
@@ -20114,7 +20944,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
20114
20944
  value.adSets.forEach((adSet, index) => {
20115
20945
  if (adSet.dailyBudget === void 0) {
20116
20946
  ctx.addIssue({
20117
- code: z78.ZodIssueCode.custom,
20947
+ code: z82.ZodIssueCode.custom,
20118
20948
  path: [
20119
20949
  "adSets",
20120
20950
  index,
@@ -20129,28 +20959,28 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
20129
20959
  ...value,
20130
20960
  budgetMode: resolveBudgetMode(value)
20131
20961
  }));
20132
- var PublishCreativesToMetaInputBase = z78.object({
20133
- creatives: z78.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
20962
+ var PublishCreativesToMetaInputBase = z82.object({
20963
+ creatives: z82.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
20134
20964
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
20135
- portfolioId: z78.string().trim().min(1),
20965
+ portfolioId: z82.string().trim().min(1),
20136
20966
  /** Exact Facebook Page selected from `list_meta_destinations`. */
20137
- pageId: z78.string().trim().min(1),
20967
+ pageId: z82.string().trim().min(1),
20138
20968
  adAccountId: McpAdAccountId,
20139
- pixelId: z78.string().min(1).optional(),
20969
+ pixelId: z82.string().min(1).optional(),
20140
20970
  /** Required unless `campaignConfig.destination` is whatsapp — see the
20141
20971
  * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
20142
- landingUrl: z78.string().url().optional(),
20972
+ landingUrl: z82.string().url().optional(),
20143
20973
  /** ISO-2 code or resolvable country name — mirrors the API contract
20144
20974
  * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
20145
20975
  targetCountry: CountryIso2Schema,
20146
- campaignName: z78.string().trim().min(1).max(100),
20976
+ campaignName: z82.string().trim().min(1).max(100),
20147
20977
  campaignConfig: GroupedCampaignConfig.optional()
20148
20978
  });
20149
20979
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
20150
20980
  const destination = value.campaignConfig?.destination;
20151
20981
  if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
20152
20982
  ctx.addIssue({
20153
- code: z78.ZodIssueCode.custom,
20983
+ code: z82.ZodIssueCode.custom,
20154
20984
  path: [
20155
20985
  "landingUrl"
20156
20986
  ],
@@ -20159,7 +20989,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
20159
20989
  }
20160
20990
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
20161
20991
  ctx.addIssue({
20162
- code: z78.ZodIssueCode.custom,
20992
+ code: z82.ZodIssueCode.custom,
20163
20993
  path: [
20164
20994
  "campaignConfig",
20165
20995
  "destination",
@@ -20178,16 +21008,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
20178
21008
  }
20179
21009
  return value;
20180
21010
  });
20181
- var PresignUploadResponseSchema = z78.object({
20182
- uploadUrl: z78.string().url().refine((value) => {
21011
+ var PresignUploadResponseSchema = z82.object({
21012
+ uploadUrl: z82.string().url().refine((value) => {
20183
21013
  const url = new URL(value);
20184
21014
  return !url.username && !url.password && url.protocol === "https:";
20185
21015
  }, "presigned upload URL must be HTTPS without embedded credentials"),
20186
- publicUrl: z78.string().url().refine((value) => {
21016
+ publicUrl: z82.string().url().refine((value) => {
20187
21017
  const url = new URL(value);
20188
21018
  return !url.username && !url.password;
20189
21019
  }, "public media URL must not contain embedded credentials"),
20190
- stagingAssetId: z78.string().uuid()
21020
+ stagingAssetId: z82.string().uuid()
20191
21021
  });
20192
21022
  async function uploadResolvedMedia(api, media, assetRole) {
20193
21023
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -20212,16 +21042,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
20212
21042
  return uploadResolvedMedia(api, media, assetRole);
20213
21043
  }
20214
21044
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
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(),
21045
+ var TikTokInput = z82.object({
21046
+ taskId: z82.string().min(1),
21047
+ advertiserId: z82.string().min(1),
21048
+ pixelId: z82.string().min(1).optional(),
21049
+ landingUrl: z82.string().url().optional(),
21050
+ angleIndexes: z82.array(z82.number().int().nonnegative()).optional(),
20221
21051
  campaignConfig: McpCampaignConfig.optional(),
20222
21052
  /** Override the ad's description (TikTok's body copy). If omitted,
20223
21053
  * ProductMaker uses the auto-generated copy attached to the task. */
20224
- primaryText: z78.string().trim().min(1).max(500).optional()
21054
+ primaryText: z82.string().trim().min(1).max(500).optional()
20225
21055
  });
20226
21056
  function registerPublishTools(server, api, opts = {}) {
20227
21057
  const transport = opts.transport ?? "http";
@@ -20549,39 +21379,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
20549
21379
 
20550
21380
  // src/tools/meta-upload.ts
20551
21381
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
20552
- import { z as z79 } from "zod";
21382
+ import { z as z83 } from "zod";
20553
21383
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
20554
- var UploadSessionInputBase = z79.object({
20555
- mediaKind: z79.enum([
21384
+ var UploadSessionInputBase = z83.object({
21385
+ mediaKind: z83.enum([
20556
21386
  "image",
20557
21387
  "video",
20558
21388
  "mixed"
20559
21389
  ]).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."),
20560
- assetRole: z79.enum([
21390
+ assetRole: z83.enum([
20561
21391
  "media",
20562
21392
  "thumbnail"
20563
21393
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
20564
- uploadPurpose: z79.enum([
21394
+ uploadPurpose: z83.enum([
20565
21395
  "product_reference",
20566
21396
  "creative",
20567
21397
  "generic"
20568
21398
  ]).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."),
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.")
21399
+ maxFiles: z83.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
20570
21400
  });
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()
21401
+ var OpenAiFileReference = z83.object({
21402
+ download_url: z83.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."),
21403
+ file_id: z83.string().min(1),
21404
+ mime_type: z83.string().min(1).optional(),
21405
+ file_name: z83.string().min(1).optional()
20576
21406
  });
20577
21407
  var UploadSessionToolInputShape = {
20578
21408
  ...UploadSessionInputBase.shape,
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.")
21409
+ files: z83.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.")
20580
21410
  };
20581
- var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
21411
+ var UploadSessionToolInput = z83.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
20582
21412
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
20583
21413
  ctx.addIssue({
20584
- code: z79.ZodIssueCode.custom,
21414
+ code: z83.ZodIssueCode.custom,
20585
21415
  path: [
20586
21416
  "mediaKind"
20587
21417
  ],
@@ -20590,7 +21420,7 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
20590
21420
  }
20591
21421
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
20592
21422
  ctx.addIssue({
20593
- code: z79.ZodIssueCode.custom,
21423
+ code: z83.ZodIssueCode.custom,
20594
21424
  path: [
20595
21425
  "maxFiles"
20596
21426
  ],
@@ -20599,7 +21429,7 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
20599
21429
  }
20600
21430
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
20601
21431
  ctx.addIssue({
20602
- code: z79.ZodIssueCode.custom,
21432
+ code: z83.ZodIssueCode.custom,
20603
21433
  path: [
20604
21434
  "maxFiles"
20605
21435
  ],
@@ -20607,38 +21437,38 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
20607
21437
  });
20608
21438
  }
20609
21439
  });
20610
- var UploadSessionResponse = z79.object({
20611
- sessionId: z79.string().uuid(),
20612
- uploadPageUrl: z79.string().url(),
20613
- mediaKind: z79.enum([
21440
+ var UploadSessionResponse = z83.object({
21441
+ sessionId: z83.string().uuid(),
21442
+ uploadPageUrl: z83.string().url(),
21443
+ mediaKind: z83.enum([
20614
21444
  "image",
20615
21445
  "video",
20616
21446
  "mixed"
20617
21447
  ]),
20618
- assetRole: z79.enum([
21448
+ assetRole: z83.enum([
20619
21449
  "media",
20620
21450
  "thumbnail"
20621
21451
  ]),
20622
- maxFiles: z79.number().int().positive(),
20623
- expiresAt: z79.string().datetime()
21452
+ maxFiles: z83.number().int().positive(),
21453
+ expiresAt: z83.string().datetime()
20624
21454
  });
20625
- var UploadStatusInput = z79.object({
20626
- sessionId: z79.string().uuid().describe("The sessionId returned by request_media_upload.")
21455
+ var UploadStatusInput = z83.object({
21456
+ sessionId: z83.string().uuid().describe("The sessionId returned by request_media_upload.")
20627
21457
  });
20628
- var UniversalUploadStatusResponse = z79.discriminatedUnion("status", [
20629
- z79.object({
20630
- status: z79.literal("pending"),
20631
- assets: z79.array(z79.never()).length(0)
21458
+ var UniversalUploadStatusResponse = z83.discriminatedUnion("status", [
21459
+ z83.object({
21460
+ status: z83.literal("pending"),
21461
+ assets: z83.array(z83.never()).length(0)
20632
21462
  }),
20633
- z79.object({
20634
- status: z79.literal("uploaded"),
20635
- assets: z79.array(z79.object({
20636
- assetId: z79.string().uuid(),
20637
- mediaKind: z79.enum([
21463
+ z83.object({
21464
+ status: z83.literal("uploaded"),
21465
+ assets: z83.array(z83.object({
21466
+ assetId: z83.string().uuid(),
21467
+ mediaKind: z83.enum([
20638
21468
  "image",
20639
21469
  "video"
20640
21470
  ]),
20641
- assetRole: z79.enum([
21471
+ assetRole: z83.enum([
20642
21472
  "media",
20643
21473
  "thumbnail"
20644
21474
  ])
@@ -20646,13 +21476,13 @@ var UniversalUploadStatusResponse = z79.discriminatedUnion("status", [
20646
21476
  })
20647
21477
  ]);
20648
21478
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
20649
- uploadPurpose: z79.enum([
21479
+ uploadPurpose: z83.enum([
20650
21480
  "product_reference",
20651
21481
  "creative",
20652
21482
  "generic"
20653
21483
  ]),
20654
- checkToolName: z79.literal("check_media_upload"),
20655
- resolveEndpoint: z79.string().url()
21484
+ checkToolName: z83.literal("check_media_upload"),
21485
+ resolveEndpoint: z83.string().url()
20656
21486
  });
20657
21487
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
20658
21488
  const url = new URL(uploadPageUrl);
@@ -20743,15 +21573,15 @@ function registerMediaUploadTools(server, api) {
20743
21573
  __name(registerMediaUploadTools, "registerMediaUploadTools");
20744
21574
 
20745
21575
  // src/tools/campaigns.ts
20746
- import { z as z80 } from "zod";
21576
+ import { z as z84 } from "zod";
20747
21577
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
20748
21578
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
20749
- var MetaStatusInput = z80.object({
20750
- campaignId: z80.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
21579
+ var MetaStatusInput = z84.object({
21580
+ campaignId: z84.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
20751
21581
  });
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.")
21582
+ var TikTokStatusInput = z84.object({
21583
+ campaignId: z84.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
21584
+ advertiserId: z84.string().min(1).describe("The same advertiserId used to publish the campaign.")
20755
21585
  });
20756
21586
  function registerCampaignTools(server, api) {
20757
21587
  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) => {
@@ -20848,10 +21678,10 @@ function renderTikTokStatusMarkdown(r) {
20848
21678
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
20849
21679
 
20850
21680
  // ../../packages/product-economics/src/product-costing.ts
20851
- import { z as z82 } from "zod";
21681
+ import { z as z86 } from "zod";
20852
21682
 
20853
21683
  // ../../packages/product-economics/src/product-costing-countries.ts
20854
- import { z as z81 } from "zod";
21684
+ import { z as z85 } from "zod";
20855
21685
 
20856
21686
  // ../../packages/product-economics/src/product-costing-shipping-references.json
20857
21687
  var product_costing_shipping_references_default = {
@@ -20915,21 +21745,21 @@ var product_costing_shipping_references_default = {
20915
21745
  };
20916
21746
 
20917
21747
  // ../../packages/product-economics/src/product-costing-countries.ts
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([
21748
+ var ShippingReferenceSchema = z85.object({
21749
+ reference: z85.number().positive(),
21750
+ min: z85.number().nonnegative(),
21751
+ max: z85.number().positive(),
21752
+ updatedAt: z85.string().date(),
21753
+ confidence: z85.enum([
20924
21754
  "high",
20925
21755
  "medium",
20926
21756
  "medium-low"
20927
21757
  ]),
20928
- sources: z81.array(z81.string().url().startsWith("https://")).min(1).max(3)
21758
+ sources: z85.array(z85.string().url().startsWith("https://")).min(1).max(3)
20929
21759
  }).superRefine(({ reference, min, max }, context) => {
20930
21760
  if (min > reference || reference > max) {
20931
21761
  context.addIssue({
20932
- code: z81.ZodIssueCode.custom,
21762
+ code: z85.ZodIssueCode.custom,
20933
21763
  message: "shipping_reference_outside_range",
20934
21764
  path: [
20935
21765
  "reference"
@@ -20937,7 +21767,7 @@ var ShippingReferenceSchema = z81.object({
20937
21767
  });
20938
21768
  }
20939
21769
  });
20940
- var SHIPPING_REFERENCES = z81.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
21770
+ var SHIPPING_REFERENCES = z85.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
20941
21771
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
20942
21772
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
20943
21773
  "MX",
@@ -21119,18 +21949,18 @@ function getProductCostingCountryName(country) {
21119
21949
  __name(getProductCostingCountryName, "getProductCostingCountryName");
21120
21950
 
21121
21951
  // ../../packages/product-economics/src/product-costing.ts
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")
21952
+ var ProductCostingInputSchema = z86.object({
21953
+ country: z86.string().refine(isProductCostingCountryCode, "unsupported_country"),
21954
+ supplierCost: z86.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
21955
+ shippingCost: z86.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
21956
+ returnRate: z86.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
21957
+ cancellationRate: z86.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
21958
+ adsManagerCpa: z86.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
21959
+ desiredMargin: z86.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
21130
21960
  }).superRefine(({ returnRate, cancellationRate }, context) => {
21131
21961
  if (returnRate + cancellationRate >= 1) {
21132
21962
  context.addIssue({
21133
- code: z82.ZodIssueCode.custom,
21963
+ code: z86.ZodIssueCode.custom,
21134
21964
  message: "delivery_rate_positive",
21135
21965
  path: [
21136
21966
  "cancellationRate"
@@ -21227,15 +22057,15 @@ function calculateProductCosting(rawInput) {
21227
22057
  __name(calculateProductCosting, "calculateProductCosting");
21228
22058
 
21229
22059
  // src/tools/product-costing.ts
21230
- import { z as z83 } from "zod";
22060
+ import { z as z87 } from "zod";
21231
22061
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
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, {
22062
+ var optionalAmount = /* @__PURE__ */ __name((description) => z87.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
22063
+ var optionalPercent = /* @__PURE__ */ __name((description) => z87.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
22064
+ var ProductCostingToolInput = z87.object({
22065
+ country: z87.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
21236
22066
  message: "Pa\xEDs no soportado por ProductMaker."
21237
22067
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite 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."),
22068
+ supplierCost: z87.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."),
21239
22069
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
21240
22070
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
21241
22071
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -21394,7 +22224,7 @@ function formatPercent(value) {
21394
22224
  __name(formatPercent, "formatPercent");
21395
22225
 
21396
22226
  // src/tools/product-research.ts
21397
- import { z as z84 } from "zod";
22227
+ import { z as z88 } from "zod";
21398
22228
 
21399
22229
  // src/tools/product-research-idempotency.ts
21400
22230
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -21765,35 +22595,35 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
21765
22595
  ]);
21766
22596
  var POLL_INTERVAL_MS = 5e3;
21767
22597
  var MAX_WAIT_SECONDS = 120;
21768
- var FindInput = z84.object({
22598
+ var FindInput = z88.object({
21769
22599
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
21770
22600
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
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.")
22601
+ confirmed: z88.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
22602
+ waitSeconds: z88.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
21773
22603
  });
21774
- var GetInput = z84.object({
21775
- runId: z84.string().uuid().describe("ID del run devuelto por find_winning_products.")
22604
+ var GetInput = z88.object({
22605
+ runId: z88.string().uuid().describe("ID del run devuelto por find_winning_products.")
21776
22606
  });
21777
- var ListInput = z84.object({
21778
- limit: z84.number().int().min(1).max(20).default(10)
22607
+ var ListInput = z88.object({
22608
+ limit: z88.number().int().min(1).max(20).default(10)
21779
22609
  });
21780
- function textResult(text) {
22610
+ function textResult(text2) {
21781
22611
  return {
21782
22612
  content: [
21783
22613
  {
21784
22614
  type: "text",
21785
- text
22615
+ text: text2
21786
22616
  }
21787
22617
  ]
21788
22618
  };
21789
22619
  }
21790
22620
  __name(textResult, "textResult");
21791
- function researchResult(run, text) {
22621
+ function researchResult(run, text2) {
21792
22622
  return {
21793
22623
  content: [
21794
22624
  {
21795
22625
  type: "text",
21796
- text
22626
+ text: text2
21797
22627
  }
21798
22628
  ],
21799
22629
  structuredContent: run
@@ -21898,17 +22728,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
21898
22728
  __name(registerProductResearchTools, "registerProductResearchTools");
21899
22729
 
21900
22730
  // src/tools/dropshipping-projects.ts
21901
- import { z as z85 } from "zod";
22731
+ import { z as z89 } from "zod";
21902
22732
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
21903
22733
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
21904
22734
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
21905
- var ProjectId = z85.string().uuid();
21906
- var DropshippingProjectStatus = z85.enum([
22735
+ var ProjectId = z89.string().uuid();
22736
+ var DropshippingProjectStatus = z89.enum([
21907
22737
  "active",
21908
22738
  "completed",
21909
22739
  "archived"
21910
22740
  ]);
21911
- var DropshippingProjectPhase = z85.enum([
22741
+ var DropshippingProjectPhase = z89.enum([
21912
22742
  "research",
21913
22743
  "costing",
21914
22744
  "media",
@@ -21917,21 +22747,21 @@ var DropshippingProjectPhase = z85.enum([
21917
22747
  "advertising",
21918
22748
  "complete"
21919
22749
  ]);
21920
- var DropshippingRewardMilestone = z85.enum([
22750
+ var DropshippingRewardMilestone = z89.enum([
21921
22751
  "product_selected",
21922
22752
  "costing_saved",
21923
22753
  "product_media_ready",
21924
22754
  "creatives_completed",
21925
22755
  "campaign_created"
21926
22756
  ]);
21927
- var TargetCountry = z85.enum([
22757
+ var TargetCountry = z89.enum([
21928
22758
  "CO",
21929
22759
  "MX",
21930
22760
  "PE",
21931
22761
  "EC",
21932
22762
  "CL"
21933
22763
  ]);
21934
- var ResearchCategory = z85.enum([
22764
+ var ResearchCategory = z89.enum([
21935
22765
  "auto",
21936
22766
  "automotive",
21937
22767
  "kitchen",
@@ -21946,7 +22776,7 @@ var ResearchCategory = z85.enum([
21946
22776
  "garden",
21947
22777
  "cleaning"
21948
22778
  ]);
21949
- var HttpUrl3 = z85.string().url().max(2e3).refine((value) => {
22779
+ var HttpUrl3 = z89.string().url().max(2e3).refine((value) => {
21950
22780
  try {
21951
22781
  return [
21952
22782
  "http:",
@@ -21956,45 +22786,45 @@ var HttpUrl3 = z85.string().url().max(2e3).refine((value) => {
21956
22786
  return false;
21957
22787
  }
21958
22788
  }, "URL must use HTTP(S)");
21959
- var ResearchCandidateOrigin = z85.object({
21960
- type: z85.literal("research_candidate"),
22789
+ var ResearchCandidateOrigin = z89.object({
22790
+ type: z89.literal("research_candidate"),
21961
22791
  runId: ProjectId,
21962
- candidateSourceId: z85.string().min(1).max(160)
22792
+ candidateSourceId: z89.string().min(1).max(160)
21963
22793
  });
21964
- var TaskOrigin = z85.object({
21965
- type: z85.literal("task"),
22794
+ var TaskOrigin = z89.object({
22795
+ type: z89.literal("task"),
21966
22796
  taskId: ProjectId
21967
22797
  });
21968
- var ManualOrigin = z85.object({
21969
- type: z85.literal("manual"),
22798
+ var ManualOrigin = z89.object({
22799
+ type: z89.literal("manual"),
21970
22800
  clientRequestId: ProjectId,
21971
- country: z85.string().min(2).max(3).optional()
22801
+ country: z89.string().min(2).max(3).optional()
21972
22802
  });
21973
- var StartProjectInput = z85.object({
21974
- origin: z85.discriminatedUnion("type", [
22803
+ var StartProjectInput = z89.object({
22804
+ origin: z89.discriminatedUnion("type", [
21975
22805
  ResearchCandidateOrigin,
21976
22806
  TaskOrigin,
21977
22807
  ManualOrigin
21978
22808
  ]),
21979
- productName: z85.string().trim().min(1).max(240).optional(),
22809
+ productName: z89.string().trim().min(1).max(240).optional(),
21980
22810
  productUrl: HttpUrl3.optional(),
21981
- country: z85.string().min(2).max(3).optional(),
21982
- languageCode: z85.string().min(2).max(16).optional()
22811
+ country: z89.string().min(2).max(3).optional(),
22812
+ languageCode: z89.string().min(2).max(16).optional()
21983
22813
  }).strict();
21984
- var CostProjectInput = z85.object({
22814
+ var CostProjectInput = z89.object({
21985
22815
  projectId: ProjectId,
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, {
22816
+ version: z89.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
22817
+ country: z89.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
21988
22818
  message: "Pa\xEDs no soportado por ProductMaker."
21989
22819
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
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({
22820
+ supplierCost: z89.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."),
22821
+ shippingCost: z89.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
22822
+ returnRate: z89.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."),
22823
+ cancellationRate: z89.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."),
22824
+ adsManagerCpa: z89.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
22825
+ desiredMargin: z89.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
22826
+ });
22827
+ var GuideInput = z89.object({
21998
22828
  projectId: ProjectId.optional()
21999
22829
  }).strict();
22000
22830
  var NEXT_ACTION_KINDS = [
@@ -22012,29 +22842,29 @@ var NEXT_ACTION_KINDS = [
22012
22842
  "repair_meta_campaign",
22013
22843
  "review_paused_campaign"
22014
22844
  ];
22015
- var DropshippingProjectNextAction = z85.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z85.object({
22016
- kind: z85.literal(kind),
22017
- href: z85.string().min(1)
22845
+ var DropshippingProjectNextAction = z89.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z89.object({
22846
+ kind: z89.literal(kind),
22847
+ href: z89.string().min(1)
22018
22848
  })));
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)
22849
+ var CostingInputSchema = z89.object({
22850
+ country: z89.string().min(2).max(3),
22851
+ supplierCost: z89.number().finite().positive(),
22852
+ shippingCost: z89.number().finite().nonnegative(),
22853
+ returnRate: z89.number().finite().min(0).lt(1),
22854
+ cancellationRate: z89.number().finite().min(0).lt(1),
22855
+ adsManagerCpa: z89.number().finite().nonnegative(),
22856
+ desiredMargin: z89.number().finite().min(0).lt(1)
22027
22857
  }).superRefine(({ returnRate, cancellationRate }, context) => {
22028
22858
  if (returnRate + cancellationRate >= 1) context.addIssue({
22029
- code: z85.ZodIssueCode.custom,
22859
+ code: z89.ZodIssueCode.custom,
22030
22860
  path: [
22031
22861
  "cancellationRate"
22032
22862
  ]
22033
22863
  });
22034
22864
  });
22035
- var FiniteCostingNumber = z85.number().finite();
22036
- var CostingResultSchema = z85.object({
22037
- country: z85.string().min(2).max(3),
22865
+ var FiniteCostingNumber = z89.number().finite();
22866
+ var CostingResultSchema = z89.object({
22867
+ country: z89.string().min(2).max(3),
22038
22868
  deliveryRate: FiniteCostingNumber,
22039
22869
  adjustedShippingCost: FiniteCostingNumber,
22040
22870
  adjustedCpa: FiniteCostingNumber,
@@ -22047,45 +22877,45 @@ var CostingResultSchema = z85.object({
22047
22877
  estimatedProfit: FiniteCostingNumber,
22048
22878
  actualMargin: FiniteCostingNumber,
22049
22879
  breakEvenAdsManagerCpa: FiniteCostingNumber,
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({
22880
+ wasPriceAutoAdjusted: z89.boolean(),
22881
+ profitabilityStatus: z89.literal("healthy")
22882
+ });
22883
+ var RewardProgressSchema = z89.object({
22884
+ campaignKey: z89.literal("dropshipping-launch-v1"),
22885
+ totalCredits: z89.number().int().positive(),
22886
+ earnedCredits: z89.number().int().nonnegative(),
22887
+ milestones: z89.array(z89.object({
22058
22888
  milestone: DropshippingRewardMilestone,
22059
- credits: z85.number().int().positive(),
22060
- available: z85.boolean().optional(),
22061
- earned: z85.boolean(),
22889
+ credits: z89.number().int().positive(),
22890
+ available: z89.boolean().optional(),
22891
+ earned: z89.boolean(),
22062
22892
  grantId: ProjectId.nullable(),
22063
- grantedAt: z85.string().datetime().nullable()
22893
+ grantedAt: z89.string().datetime().nullable()
22064
22894
  })).length(DropshippingRewardMilestone.options.length)
22065
22895
  });
22066
- var ProjectResponseSchema = z85.object({
22896
+ var ProjectResponseSchema = z89.object({
22067
22897
  id: ProjectId,
22068
22898
  taskId: ProjectId.nullable(),
22069
22899
  status: DropshippingProjectStatus,
22070
- originKey: z85.string().min(1),
22900
+ originKey: z89.string().min(1),
22071
22901
  researchRunId: ProjectId.nullable(),
22072
- candidateSourceId: z85.string().nullable(),
22073
- productName: z85.string().nullable(),
22902
+ candidateSourceId: z89.string().nullable(),
22903
+ productName: z89.string().nullable(),
22074
22904
  productUrl: HttpUrl3.nullable(),
22075
22905
  referenceImageUrl: HttpUrl3.nullable(),
22076
- targetCountry: z85.string().nullable(),
22077
- languageCode: z85.string().nullable(),
22078
- hasReferenceImage: z85.boolean(),
22079
- hasWinnerReferenceImage: z85.boolean(),
22906
+ targetCountry: z89.string().nullable(),
22907
+ languageCode: z89.string().nullable(),
22908
+ hasReferenceImage: z89.boolean(),
22909
+ hasWinnerReferenceImage: z89.boolean(),
22080
22910
  costingInput: CostingInputSchema.nullable(),
22081
22911
  costingResult: CostingResultSchema.nullable(),
22082
- costingVersion: z85.number().int().positive().nullable(),
22083
- version: z85.number().int().positive(),
22912
+ costingVersion: z89.number().int().positive().nullable(),
22913
+ version: z89.number().int().positive(),
22084
22914
  phase: DropshippingProjectPhase,
22085
22915
  nextAction: DropshippingProjectNextAction.nullable(),
22086
22916
  rewards: RewardProgressSchema,
22087
- createdAt: z85.string().datetime(),
22088
- updatedAt: z85.string().datetime()
22917
+ createdAt: z89.string().datetime(),
22918
+ updatedAt: z89.string().datetime()
22089
22919
  }).passthrough();
22090
22920
  var NEXT_ACTION_GUIDANCE = {
22091
22921
  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.",
@@ -22203,58 +23033,58 @@ function registerDropshippingProjectTools(server, api) {
22203
23033
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
22204
23034
 
22205
23035
  // src/tools/daily-control.ts
22206
- import { z as z86 } from "zod";
23036
+ import { z as z90 } from "zod";
22207
23037
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
22208
23038
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
22209
23039
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
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({
23040
+ var ProviderCampaignIdentifier = z90.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
23041
+ var DateOnly = z90.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23042
+ var DailyControlInput = z90.object({
22213
23043
  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."),
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.")
23044
+ days: z90.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23045
+ projectId: z90.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
22216
23046
  }).strict();
22217
- var LinkCampaignInput = z86.object({
22218
- projectId: z86.string().uuid(),
22219
- provider: z86.enum([
23047
+ var LinkCampaignInput = z90.object({
23048
+ projectId: z90.string().uuid(),
23049
+ provider: z90.enum([
22220
23050
  "meta",
22221
23051
  "tiktok"
22222
23052
  ]),
22223
23053
  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."),
22224
23054
  campaignId: ProviderCampaignIdentifier
22225
23055
  }).strict();
22226
- var ReportReturnsInput = z86.object({
22227
- projectId: z86.string().uuid(),
23056
+ var ReportReturnsInput = z90.object({
23057
+ projectId: z90.string().uuid(),
22228
23058
  date: DateOnly,
22229
- returnedOrders: z86.number().int().min(0).max(1e5),
22230
- note: z86.string().trim().max(280).optional()
23059
+ returnedOrders: z90.number().int().min(0).max(1e5),
23060
+ note: z90.string().trim().max(280).optional()
22231
23061
  }).strict();
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(),
23062
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z90.string());
23063
+ var DailyControlLightMirror = DailyControlLightEnum.or(z90.string());
23064
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z90.string());
23065
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z90.string());
23066
+ var DailyControlDayMirror = z90.object({
23067
+ date: z90.string(),
23068
+ returnedOrders: z90.number(),
22239
23069
  returnedSource: DailyControlSourceMirror,
22240
23070
  cancelledSource: DailyControlSourceMirror,
22241
- hasEstimates: z86.boolean(),
23071
+ hasEstimates: z90.boolean(),
22242
23072
  light: DailyControlLightMirror
22243
23073
  }).passthrough();
22244
- var DailyControlProductMirror = z86.object({
22245
- projectId: z86.string().uuid(),
22246
- productName: z86.string().nullable(),
23074
+ var DailyControlProductMirror = z90.object({
23075
+ projectId: z90.string().uuid(),
23076
+ productName: z90.string().nullable(),
22247
23077
  status: DailyControlStatusMirror,
22248
- statusMessage: z86.string().nullable(),
22249
- days: z86.array(DailyControlDayMirror),
23078
+ statusMessage: z90.string().nullable(),
23079
+ days: z90.array(DailyControlDayMirror),
22250
23080
  verdict: DailyControlVerdictMirror.nullable(),
22251
- rationale: z86.string().nullable()
23081
+ rationale: z90.string().nullable()
22252
23082
  }).passthrough();
22253
- var DailyControlResponseMirror = z86.object({
22254
- since: z86.string(),
22255
- until: z86.string(),
22256
- products: z86.array(DailyControlProductMirror),
22257
- archivedProjectSpend: z86.array(z86.unknown())
23083
+ var DailyControlResponseMirror = z90.object({
23084
+ since: z90.string(),
23085
+ until: z90.string(),
23086
+ products: z90.array(DailyControlProductMirror),
23087
+ archivedProjectSpend: z90.array(z90.unknown())
22258
23088
  }).passthrough();
22259
23089
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
22260
23090
  function withWarnings(response) {
@@ -22338,42 +23168,42 @@ function registerDailyControlTools(server, api) {
22338
23168
  __name(registerDailyControlTools, "registerDailyControlTools");
22339
23169
 
22340
23170
  // src/tools/product-control.ts
22341
- import { z as z87 } from "zod";
23171
+ import { z as z91 } from "zod";
22342
23172
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
22343
23173
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
22344
23174
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
22345
23175
  var setProductCostingGuidance = getProductMakerCapabilityModelGuidance("set_product_costing");
22346
23176
  var reportProductCountsGuidance = getProductMakerCapabilityModelGuidance("report_product_counts");
22347
- var DateOnly2 = z87.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23177
+ var DateOnly2 = z91.string().regex(/^\d{4}-\d{2}-\d{2}$/);
22348
23178
  var IMPORT_BATCH_MAX2 = 50;
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."),
23179
+ var ProductControlListInput = z91.object({
23180
+ days: z91.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
22351
23181
  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."),
22352
- shopDomain: z87.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
23182
+ shopDomain: z91.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
22353
23183
  }).strict();
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()
23184
+ var ImportableProductsInput = z91.object({
23185
+ q: z91.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
23186
+ after: z91.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
23187
+ shopDomain: z91.string().min(1).optional()
22358
23188
  }).strict();
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."),
23189
+ var ImportProductControlsInput = z91.object({
23190
+ shopifyProductIds: z91.array(z91.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."),
22361
23191
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
22362
23192
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
22363
- shopDomain: z87.string().min(1)
23193
+ shopDomain: z91.string().min(1)
22364
23194
  }).strict();
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)
23195
+ var SetProductCostingInput = z91.object({
23196
+ shopDomain: z91.string().min(1),
23197
+ shopifyProductId: z91.string().min(1).max(64),
23198
+ targetCountry: z91.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
23199
+ supplierCost: z91.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
23200
+ shippingCost: z91.number().finite().nonnegative(),
23201
+ returnRate: z91.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
23202
+ cancellationRate: z91.number().finite().min(0).lt(1)
22373
23203
  }).strict();
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."),
23204
+ var Count = z91.number().int().min(0).max(1e5).nullable().optional();
23205
+ var ReportProductCountsInput = z91.object({
23206
+ productControlId: z91.string().uuid().describe("El identificador que devuelve get_product_control."),
22377
23207
  date: DateOnly2,
22378
23208
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
22379
23209
  cancelledOrders: Count,