@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/http.js CHANGED
@@ -68,6 +68,23 @@ var VideoPreset = z.enum([
68
68
  ]);
69
69
  var VoiceId = z.string();
70
70
  var _VIDEO_MODEL_SET = new Set(VideoModel.options);
71
+ var BROLL_VIDEO_MODES = new Set(VideoModel.options);
72
+ var PersistedVideoMode = z.enum([
73
+ ...VideoModel.options,
74
+ "avatar_talking",
75
+ "hybrid",
76
+ "sora"
77
+ ]);
78
+ var PersistedVideoModel = z.enum([
79
+ ...VideoModel.options,
80
+ "sora",
81
+ "infinitalk"
82
+ ]);
83
+ var PLAN_VIDEO_MODES = [
84
+ ...VideoModel.options,
85
+ "avatar_talking",
86
+ "hybrid"
87
+ ];
71
88
 
72
89
  // ../../packages/types/src/video-creation.ts
73
90
  import { z as z3 } from "zod";
@@ -1038,40 +1055,206 @@ var VideoTier = z8.preprocess((v) => v === "grok" ? "single_call" : v, z8.enum([
1038
1055
  "single_call"
1039
1056
  ]));
1040
1057
  var DEFAULT_VIDEO_TIER = "single_call";
1058
+ var WritableVideoTier = VideoTier.refine((tier) => tier !== "legacy", {
1059
+ message: "VIDEO_TIER_RETIRED"
1060
+ });
1041
1061
 
1042
- // ../../packages/types/src/image-provider.ts
1043
- var GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K = [
1044
- "4:5",
1045
- "5:4"
1062
+ // ../../packages/types/src/image-models.ts
1063
+ var IMAGE_RESOLUTIONS = [
1064
+ "1k",
1065
+ "2k",
1066
+ "4k"
1046
1067
  ];
1047
- var GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K = [
1048
- "4:5",
1049
- "5:4",
1050
- "27:16",
1051
- "16:27",
1052
- "9:8",
1053
- "8:9"
1068
+ var GPT_IMAGE_2_5_TOKENS = {
1069
+ "1k": "gpt-image-2-5:1k",
1070
+ "2k": "gpt-image-2-5:2k",
1071
+ "4k": "gpt-image-2-5:4k"
1072
+ };
1073
+ var GPT_IMAGE_2_TOKENS = {
1074
+ "1k": "gpt-image-2:1k",
1075
+ "2k": "gpt-image-2:2k",
1076
+ "4k": "gpt-image-2:4k"
1077
+ };
1078
+ var GPT_IMAGE_2_5 = {
1079
+ id: "gpt-image-2.5",
1080
+ status: "active",
1081
+ renderedBy: "gpt-image-2.5",
1082
+ tokens: GPT_IMAGE_2_5_TOKENS,
1083
+ kie: {
1084
+ imageToImage: [
1085
+ "gpt-image-2-5-sunburst-image-to-image",
1086
+ "gpt-image-2-5-flare-image-to-image"
1087
+ ],
1088
+ textToImage: [
1089
+ "gpt-image-2-5-sunburst-text-to-image",
1090
+ "gpt-image-2-5-flare-text-to-image"
1091
+ ],
1092
+ shorthands: [
1093
+ "gpt-image-2-5"
1094
+ ]
1095
+ },
1096
+ fal: {
1097
+ edit: "openai/gpt-image-2.5/sunburst/edit",
1098
+ textToImage: "openai/gpt-image-2.5/sunburst/text-to-image",
1099
+ quality: {
1100
+ "1k": "low",
1101
+ "2k": "medium",
1102
+ "4k": "high"
1103
+ },
1104
+ ourCostCents: {
1105
+ "1k": 1.5,
1106
+ "2k": 6.1,
1107
+ "4k": 17.8
1108
+ }
1109
+ },
1110
+ // Docs KIE de gpt-image-2-5 (sunburst/flare): 27:16, 16:27, 9:8, 8:9 solo 1K;
1111
+ // 4:5 y 5:4 también bloqueados por encima de 1K.
1112
+ ratiosBlockedAbove1k: [
1113
+ "4:5",
1114
+ "5:4",
1115
+ "27:16",
1116
+ "16:27",
1117
+ "9:8",
1118
+ "8:9"
1119
+ ],
1120
+ ledgerSuffix: {
1121
+ "1k": "gpt-image-2",
1122
+ "2k": "gpt-image-2:medium",
1123
+ "4k": "gpt-image-2:high"
1124
+ },
1125
+ falLedgerSuffix: {
1126
+ "1k": "gpt-image-2:1k",
1127
+ "2k": "gpt-image-2:2k",
1128
+ "4k": "gpt-image-2:4k"
1129
+ }
1130
+ };
1131
+ var GPT_IMAGE_2 = {
1132
+ ...GPT_IMAGE_2_5,
1133
+ id: "gpt-image-2",
1134
+ status: "retired",
1135
+ renderedBy: GPT_IMAGE_2_5.id,
1136
+ tokens: GPT_IMAGE_2_TOKENS,
1137
+ kie: {
1138
+ imageToImage: [
1139
+ "gpt-image-2-image-to-image"
1140
+ ],
1141
+ textToImage: [
1142
+ "gpt-image-2-text-to-image"
1143
+ ],
1144
+ shorthands: [
1145
+ "gpt-image-2"
1146
+ ]
1147
+ },
1148
+ ratiosBlockedAbove1k: [
1149
+ "4:5",
1150
+ "5:4"
1151
+ ]
1152
+ };
1153
+ var IMAGE_MODELS = [
1154
+ GPT_IMAGE_2_5,
1155
+ GPT_IMAGE_2
1054
1156
  ];
1055
- function gptImage2SupportsTier(aspectRatio, tier) {
1056
- if (tier === "gpt-image-2:1k" || tier === "gpt-image-2-5:1k") return true;
1057
- if (tier.startsWith("gpt-image-2-5:")) {
1058
- return !GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K.includes(aspectRatio);
1157
+ var ACTIVE_IMAGE_MODEL = GPT_IMAGE_2_5;
1158
+ var IMAGE_WRITE_TOKENS = GPT_IMAGE_2_5_TOKENS;
1159
+ var LEGACY_IMAGE_TOKENS = GPT_IMAGE_2_TOKENS;
1160
+ var PUBLIC_IMAGE_QUALITY_INPUTS = [
1161
+ IMAGE_WRITE_TOKENS["1k"],
1162
+ IMAGE_WRITE_TOKENS["2k"],
1163
+ LEGACY_IMAGE_TOKENS["1k"],
1164
+ LEGACY_IMAGE_TOKENS["2k"],
1165
+ "image:1k",
1166
+ "image:2k"
1167
+ ];
1168
+ function entryById(id) {
1169
+ const found = IMAGE_MODELS.find((entry) => entry.id === id);
1170
+ if (!found) throw new Error(`IMAGE_MODEL_UNKNOWN:${id}`);
1171
+ return found;
1172
+ }
1173
+ __name(entryById, "entryById");
1174
+ function resolveImageToken(raw) {
1175
+ if (typeof raw !== "string") return null;
1176
+ let normalized = raw.trim().toLowerCase();
1177
+ let viaFal = false;
1178
+ if (normalized.startsWith("fal:")) {
1179
+ viaFal = true;
1180
+ normalized = normalized.slice("fal:".length);
1181
+ }
1182
+ for (const resolution of IMAGE_RESOLUTIONS) {
1183
+ if (normalized === `image:${resolution}`) {
1184
+ return {
1185
+ resolution,
1186
+ model: ACTIVE_IMAGE_MODEL,
1187
+ declared: ACTIVE_IMAGE_MODEL,
1188
+ spelling: "intent",
1189
+ viaFal
1190
+ };
1191
+ }
1192
+ }
1193
+ for (const entry of IMAGE_MODELS) {
1194
+ for (const resolution of IMAGE_RESOLUTIONS) {
1195
+ if (entry.tokens[resolution] === normalized) {
1196
+ return {
1197
+ resolution,
1198
+ model: entryById(entry.renderedBy),
1199
+ declared: entry,
1200
+ spelling: entry.status === "active" ? "current" : "retired",
1201
+ viaFal
1202
+ };
1203
+ }
1204
+ }
1059
1205
  }
1060
- return !GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K.includes(aspectRatio);
1206
+ return null;
1207
+ }
1208
+ __name(resolveImageToken, "resolveImageToken");
1209
+ function imageResolutionOf(raw) {
1210
+ const token = resolveImageToken(raw);
1211
+ return token && !token.viaFal ? token.resolution : null;
1212
+ }
1213
+ __name(imageResolutionOf, "imageResolutionOf");
1214
+ function requireKieImageId(ids, index, label) {
1215
+ const id = ids[index];
1216
+ if (!id) throw new Error(`IMAGE_MODEL_NO_KIE_ID:${label}`);
1217
+ return id;
1218
+ }
1219
+ __name(requireKieImageId, "requireKieImageId");
1220
+ var KIE_FLARE_IMAGE_TO_IMAGE_MODEL = requireKieImageId(GPT_IMAGE_2_5.kie.imageToImage, 1, "flare-imageToImage");
1221
+ function canonicalImageModelInput(raw) {
1222
+ if (raw === void 0) return void 0;
1223
+ const token = resolveImageToken(raw);
1224
+ if (!token || token.viaFal || token.spelling !== "intent") return raw;
1225
+ return IMAGE_WRITE_TOKENS[token.resolution];
1226
+ }
1227
+ __name(canonicalImageModelInput, "canonicalImageModelInput");
1228
+ function imageTokenSupportsRatio(aspectRatio, rawToken) {
1229
+ const token = resolveImageToken(rawToken);
1230
+ if (!token) return true;
1231
+ if (token.resolution === "1k") return true;
1232
+ return !token.declared.ratiosBlockedAbove1k.includes(aspectRatio);
1233
+ }
1234
+ __name(imageTokenSupportsRatio, "imageTokenSupportsRatio");
1235
+
1236
+ // ../../packages/types/src/image-provider.ts
1237
+ var GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K = GPT_IMAGE_2.ratiosBlockedAbove1k;
1238
+ var GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K = GPT_IMAGE_2_5.ratiosBlockedAbove1k;
1239
+ function gptImage2SupportsTier(aspectRatio, tier) {
1240
+ return imageTokenSupportsRatio(aspectRatio, tier);
1061
1241
  }
1062
1242
  __name(gptImage2SupportsTier, "gptImage2SupportsTier");
1063
1243
  var IMAGE_TIER_UNSUPPORTED_FOR_RATIO_RULE = "image_tier_unsupported_for_ratio";
1064
1244
  var IMAGE_TIER_LIST = [
1065
- "gpt-image-2-5:1k",
1066
- "gpt-image-2-5:2k",
1067
- "gpt-image-2-5:4k",
1068
- "gpt-image-2:1k",
1069
- "gpt-image-2:2k",
1070
- "gpt-image-2:4k"
1245
+ ...Object.values(IMAGE_WRITE_TOKENS),
1246
+ ...Object.values(LEGACY_IMAGE_TOKENS)
1071
1247
  ];
1248
+ function isImageTier(value) {
1249
+ return IMAGE_TIER_LIST.includes(value);
1250
+ }
1251
+ __name(isImageTier, "isImageTier");
1072
1252
  function parseImageTier(imageModel) {
1073
- const normalized = imageModel.trim().toLowerCase();
1074
- return IMAGE_TIER_LIST.includes(normalized) ? normalized : null;
1253
+ const token = resolveImageToken(imageModel);
1254
+ if (!token || token.viaFal) return null;
1255
+ if (token.spelling === "intent") return IMAGE_WRITE_TOKENS[token.resolution];
1256
+ const declared = token.declared.tokens[token.resolution];
1257
+ return isImageTier(declared) ? declared : null;
1075
1258
  }
1076
1259
  __name(parseImageTier, "parseImageTier");
1077
1260
  function validateImageTierForRatio(aspectRatio, imageModel) {
@@ -3808,7 +3991,7 @@ var IngestOptions = z22.object({
3808
3991
  durationSeconds: FreeVideoOptionsSchema.shape.durationSeconds.optional(),
3809
3992
  addSubtitles: FreeVideoOptionsSchema.shape.addSubtitles.optional(),
3810
3993
  subtitleText: z22.string().transform((value) => value.trim()).pipe(z22.string().max(FREE_VIDEO_SUBTITLE_MAX_CHARS)).optional(),
3811
- videoTier: VideoTier.default(DEFAULT_VIDEO_TIER),
3994
+ videoTier: WritableVideoTier.default(DEFAULT_VIDEO_TIER),
3812
3995
  narrativeStyle: NarrativeStyle.default("review"),
3813
3996
  videoPreset: VideoPreset.optional(),
3814
3997
  multiAngleVideos: z22.boolean().default(false),
@@ -3882,7 +4065,9 @@ var IngestOptions = z22.object({
3882
4065
  aspectRatio: z22.string().optional(),
3883
4066
  brandColors: z22.string().optional(),
3884
4067
  nVariants: z22.number().int().min(1).max(6).optional(),
3885
- imageModel: z22.string().optional(),
4068
+ // O7: `image:Nk` is accepted and stored as the spelling written today
4069
+ // (IMAGE_WRITE_TOKENS); see packages/types/src/image-models.ts.
4070
+ imageModel: z22.string().optional().transform((value) => canonicalImageModelInput(value)),
3886
4071
  styleMix: z22.string().optional(),
3887
4072
  aiDecidesAll: z22.boolean().optional(),
3888
4073
  /** Opt out of the competitor-spy analysis. When false the worker skips
@@ -4001,7 +4186,7 @@ var VideoOptionsOverride = z22.object({
4001
4186
  videoStructure: VideoStructure.optional(),
4002
4187
  videoQuality: VideoQuality.optional(),
4003
4188
  videoModel: VideoModel.optional(),
4004
- videoTier: VideoTier.optional(),
4189
+ videoTier: WritableVideoTier.optional(),
4005
4190
  ugcFormat: VideoFormat.optional(),
4006
4191
  videoStyle: VideoStyle.optional(),
4007
4192
  narrativeStyle: NarrativeStyle.optional(),
@@ -4084,6 +4269,11 @@ var IngestResumePayload = z22.object({
4084
4269
  // "keep what the task has". See angle-management.service.ts resumeAfterAngles.
4085
4270
  videoStyle: VideoStyle.optional(),
4086
4271
  videoModel: VideoModel.default("veo"),
4272
+ // READ schema on purpose, unlike IngestOptions/VideoOptionsOverride: resume
4273
+ // does not write the tier — `resumeAfterAngles` projects the route from the
4274
+ // task's OWN persisted tier and ignores this field. MCP and WhatsApp echo
4275
+ // `status.videoTier`, which is still `legacy` for historical rows; refusing
4276
+ // it made those tasks impossible to resume from both channels.
4087
4277
  videoTier: VideoTier.optional(),
4088
4278
  videoStructure: VideoStructure.optional(),
4089
4279
  videoQuality: VideoQuality.optional(),
@@ -4894,17 +5084,7 @@ var VideoGenerator = z26.object({
4894
5084
  format: VideoFormat.optional(),
4895
5085
  videoStyle: VideoStyle.optional(),
4896
5086
  narrativeStyle: NarrativeStyle.optional(),
4897
- videoMode: z26.enum([
4898
- "veo",
4899
- "wan",
4900
- "bytedance",
4901
- "seedance",
4902
- "grok",
4903
- "kling",
4904
- "avatar_talking",
4905
- "hybrid",
4906
- "sora"
4907
- ]).optional(),
5087
+ videoMode: PersistedVideoMode.optional(),
4908
5088
  videoResolution: VideoResolution.optional(),
4909
5089
  videoStructure: VideoStructure.optional(),
4910
5090
  videoQuality: VideoQuality.optional(),
@@ -6918,7 +7098,10 @@ var ServiceCreativeEstimationOptions = z34.object({
6918
7098
  uploadedVideoDurationSeconds: z34.number().min(0).max(240).optional(),
6919
7099
  /** Quality the panels render at (its registry model sets the per-second
6920
7100
  * price). Absent = economy, the pre-quality service default. */
6921
- videoQuality: VideoQuality.optional()
7101
+ videoQuality: VideoQuality.optional(),
7102
+ /** Semantic resolution the panels render at (H3 maps 480p/720p to its
7103
+ * native 768P/2K). Absent = 480p, the pre-resolution service default. */
7104
+ videoResolution: VideoResolution.optional()
6922
7105
  });
6923
7106
  var ActorGridEstimationOptions = z34.object({}).strict();
6924
7107
  var CostEstimationRequest = z34.discriminatedUnion("type", [
@@ -7266,7 +7449,8 @@ var IMAGE_QA_GATES = [
7266
7449
  "limb",
7267
7450
  "device_panel",
7268
7451
  "critical_feature",
7269
- "cross_section"
7452
+ "cross_section",
7453
+ "usage_fidelity"
7270
7454
  ];
7271
7455
  var ImageQaGate = z36.enum(IMAGE_QA_GATES);
7272
7456
  var ImageQaGateOutcome = z36.enum([
@@ -8312,6 +8496,10 @@ var GEMINI_OMNI_FLAT_USER_PRICE_CENTS = 168;
8312
8496
  // ../../packages/types/src/pricing.ts
8313
8497
  var CREDITS_PER_USD_CENT = 10;
8314
8498
  var CREDITS_PER_DOLLAR = 100 * CREDITS_PER_USD_CENT;
8499
+ var AD_CREATIVE_MODELS = {
8500
+ STANDARD: IMAGE_WRITE_TOKENS["1k"],
8501
+ PREMIUM: IMAGE_WRITE_TOKENS["2k"]
8502
+ };
8315
8503
  var KALODATA_USD_CENTS_PER_PROVIDER_CREDIT = 9;
8316
8504
  var KALODATA_PROVIDER_CREDITS_PER_SOURCE_CEILING = 7.5;
8317
8505
  var DEFAULT_PRICING = {
@@ -9270,6 +9458,27 @@ var DEFAULT_PRICING = {
9270
9458
  ourCostCents: 1.88,
9271
9459
  userPriceCents: 3.76
9272
9460
  },
9461
+ // Usage decider (role `usage-decider`: Gemini 3.8 Flash effort:'high' since
9462
+ // 05f543eae, ≤6 images + seller text, temperature 0 json_object, once per
9463
+ // classic landing, always on). Was 3¢ measured on Claude
9464
+ // Sonnet 5 (spike 2026-09-24, 17 prod tasks). NOT re-measured on Flash — no
9465
+ // local BillingEntry row carries the Flash decider yet — so it is priced as
9466
+ // the product truth (`openrouter:product-truth`, 2.2¢ measured from
9467
+ // OpenRouter usage.cost): same model, same effort, same ≤6-photo input and a
9468
+ // JSON answer of similar size. Refine from usage.cost after the e2e. Fallback
9469
+ // only (OpenRouter's usage.cost is billed when present).
9470
+ "openrouter:usage-decision": {
9471
+ ourCostCents: 2.2,
9472
+ userPriceCents: 4.4
9473
+ },
9474
+ // Usage-fidelity QA judge (records misuse; regen gated separately behind
9475
+ // always on, bounded by USAGE_FIDELITY_MAX_REGENS). Sized off landing-image-qa beside it: same
9476
+ // shape of call (1-2 images, a verdict), so quoted at the same rate until
9477
+ // it has its own BillingEntry volume to re-derive from.
9478
+ "openrouter:usage-fidelity": {
9479
+ ourCostCents: 1.88,
9480
+ userPriceCents: 3.76
9481
+ },
9273
9482
  // Landing commercial-facts extraction (gemini-3.8-flash, ONE text-only call over
9274
9483
  // the seller's offer/context/features). Sized off the image-QA key beside it,
9275
9484
  // which measured 1.88¢ at ~11.1K prompt tokens: this prompt is capped at ~3K in
@@ -10008,6 +10217,24 @@ var DEFAULT_PRICING = {
10008
10217
  ourCostCents: 0.2,
10009
10218
  userPriceCents: 0.4
10010
10219
  },
10220
+ // Product truth (Gemini 3.8 Flash effort:'high', ≤6 photos + all seller text, once per
10221
+ // extract, always on). Plan C spike 2026-09-24: 6 calls, US$0.132 total ⇒
10222
+ // 2.2¢/call measured from OpenRouter usage.cost. Replaces usage spec + functional demo +
10223
+ // product-use sheet (+ landing visual-context-fusion) on the same task. Fallback only.
10224
+ "openrouter:product-truth": {
10225
+ ourCostCents: 2.2,
10226
+ userPriceCents: 4.4
10227
+ },
10228
+ // Landing creative director, «categorías» arm (Gemini 3.8 Flash effort:'high', ≤6 photos +
10229
+ // all seller text + the section plan, once per classic landing behind
10230
+ // LANDING_DIRECTOR_ENABLED). ESTIMATE, not measured: same call shape as the product truth
10231
+ // (2.2¢) with a ~2-3x longer JSON answer (one content spec per section) ⇒ ~4¢. Replaces
10232
+ // the visual brief (4¢) + visual-context fusion (0.4¢) + usage decision (2.2¢) on that
10233
+ // landing. Refine from OpenRouter usage.cost after the e2e. Fallback only.
10234
+ "openrouter:landing-director": {
10235
+ ourCostCents: 4,
10236
+ userPriceCents: 8
10237
+ },
10011
10238
  // Unit = one reference-grouping pass over the user's product images (0.1241¢).
10012
10239
  "openrouter:product-reference-grouping": {
10013
10240
  ourCostCents: 0.15,
@@ -13352,7 +13579,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13352
13579
  "task",
13353
13580
  "product"
13354
13581
  ]),
13355
- defineCapability("create_service_video", "863884c1af5de3e168cbbe825ea3961901c84dae1899ca400f8f7fa01df91c0a", "credit_consuming", "creative", [
13582
+ defineCapability("create_service_video", "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21", "credit_consuming", "creative", [
13356
13583
  "credit_consuming",
13357
13584
  "state_change"
13358
13585
  ], [
@@ -13380,6 +13607,9 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13380
13607
  // MCP-only for now: WhatsApp's service flow keeps the economy default.
13381
13608
  slot("video_quality", false, [
13382
13609
  "videoQuality"
13610
+ ], []),
13611
+ slot("video_resolution", false, [
13612
+ "videoResolution"
13383
13613
  ], [])
13384
13614
  ], [
13385
13615
  "service_context"
@@ -13522,7 +13752,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13522
13752
  "video"
13523
13753
  ]
13524
13754
  ),
13525
- defineCapability("generate_image_creatives", "eb2c3f6a0d8974ccf33c42f2b4cc9e09918dabf29182acce1418ea2842a01ec3", "credit_consuming", "creative", [
13755
+ defineCapability("generate_image_creatives", "2f1698b623d98645b7c618a17988f3aac30f403a9c3f3dc26eb5bdbd9c6ef23e", "credit_consuming", "creative", [
13526
13756
  "credit_consuming",
13527
13757
  "state_change"
13528
13758
  ], [
@@ -15173,79 +15403,696 @@ var WhatsAppPresentationManifestSchema = z67.object({
15173
15403
  }
15174
15404
  });
15175
15405
 
15176
- // ../../packages/types/src/flight-recorder.ts
15406
+ // ../../packages/types/src/usage-decision.ts
15177
15407
  import { z as z68 } from "zod";
15178
- var FlightRecorderGenerationTypeSchema = z68.enum([
15408
+
15409
+ // ../../packages/types/src/text-clamp.ts
15410
+ function clampAtWordBoundary(value, max) {
15411
+ if (typeof value !== "string") return value;
15412
+ if (value.length <= max) return value;
15413
+ const cut = value.slice(0, max);
15414
+ const lastSpace = cut.lastIndexOf(" ");
15415
+ const atWordBoundary = lastSpace > 0 ? cut.slice(0, lastSpace) : cut;
15416
+ return atWordBoundary.replace(/[,;:\s]+$/, "");
15417
+ }
15418
+ __name(clampAtWordBoundary, "clampAtWordBoundary");
15419
+ function clampStringArray(max) {
15420
+ return (value) => {
15421
+ if (!Array.isArray(value)) return value;
15422
+ const nonEmpty = value.filter((item) => typeof item === "string" && item.trim().length > 0);
15423
+ return nonEmpty.slice(0, max);
15424
+ };
15425
+ }
15426
+ __name(clampStringArray, "clampStringArray");
15427
+
15428
+ // ../../packages/types/src/usage-decision.ts
15429
+ var USAGE_SCENE_RULE_MAX_CHARS = 240;
15430
+ var USAGE_DECISION_MAX_REQUIRED_PARTS = 6;
15431
+ var USAGE_DECISION_MAX_ALTERNATE_USES = 4;
15432
+ var USAGE_DECISION_MAX_MISUSE = 5;
15433
+ function clampRule(value) {
15434
+ return clampAtWordBoundary(value, USAGE_SCENE_RULE_MAX_CHARS);
15435
+ }
15436
+ __name(clampRule, "clampRule");
15437
+ var UsageDecisionSchema = z68.object({
15438
+ productIdentity: z68.string().min(1),
15439
+ endUser: z68.object({
15440
+ who: z68.string(),
15441
+ appliedTo: z68.string()
15442
+ }),
15443
+ promise: z68.string().min(1),
15444
+ primaryUse: z68.object({
15445
+ scene: z68.string().min(1),
15446
+ postureAndGrip: z68.string(),
15447
+ contactPoint: z68.string(),
15448
+ requiredParts: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_REQUIRED_PARTS), z68.array(z68.string()).max(USAGE_DECISION_MAX_REQUIRED_PARTS))
15449
+ }),
15450
+ validAlternateUses: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_ALTERNATE_USES), z68.array(z68.string()).max(USAGE_DECISION_MAX_ALTERNATE_USES)),
15451
+ misuse: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_MISUSE), z68.array(z68.string().min(1)).max(USAGE_DECISION_MAX_MISUSE)),
15452
+ useSceneRule: z68.preprocess(clampRule, z68.string().min(1).max(USAGE_SCENE_RULE_MAX_CHARS)),
15453
+ /**
15454
+ * True when the promise can ONLY be shown with the primary use (the pain is bending over and
15455
+ * the product has an extension pole: without the pole there is no promise); false when the
15456
+ * valid alternates sell it equally. Drives whether an alternate use in a use scene is a
15457
+ * failure (`requirePrimary` in the usage judge) and whether the prompts' primary use is
15458
+ * mandatory. Optional and fail-safe: missing (decisions stored before the field) or not a
15459
+ * boolean ⇒ `undefined`, read as false by every caller — never a rejected decision.
15460
+ */
15461
+ primaryRequired: z68.boolean().optional().catch(void 0),
15462
+ confidence: z68.number().min(0).max(1),
15463
+ modelId: z68.string(),
15464
+ decidedAt: z68.string()
15465
+ });
15466
+
15467
+ // ../../packages/types/src/product-truth.ts
15468
+ import { z as z70 } from "zod";
15469
+
15470
+ // ../../packages/types/src/lenient-zod.ts
15471
+ import { z as z69 } from "zod";
15472
+ function trimAndClamp(value, max) {
15473
+ if (typeof value !== "string") return value;
15474
+ return clampAtWordBoundary(value.replace(/\s+/g, " ").trim(), max);
15475
+ }
15476
+ __name(trimAndClamp, "trimAndClamp");
15477
+ function lenientText(max) {
15478
+ return z69.preprocess((v) => trimAndClamp(v, max), z69.string().min(1).max(max));
15479
+ }
15480
+ __name(lenientText, "lenientText");
15481
+ function lenientOptionalText(max) {
15482
+ return z69.preprocess((v) => {
15483
+ if (typeof v !== "string") return void 0;
15484
+ const clamped = trimAndClamp(v, max);
15485
+ return typeof clamped === "string" && clamped.length > 0 ? clamped : void 0;
15486
+ }, z69.string().max(max).optional());
15487
+ }
15488
+ __name(lenientOptionalText, "lenientOptionalText");
15489
+ function lenientTextList(maxItems, maxChars) {
15490
+ return z69.preprocess((v) => {
15491
+ if (!Array.isArray(v)) return [];
15492
+ return v.map((item) => trimAndClamp(item, maxChars)).filter((item) => typeof item === "string" && item.length > 0).slice(0, maxItems);
15493
+ }, z69.array(z69.string().min(1).max(maxChars)).max(maxItems));
15494
+ }
15495
+ __name(lenientTextList, "lenientTextList");
15496
+ function lenientList(item, maxItems) {
15497
+ return z69.preprocess((v) => {
15498
+ if (!Array.isArray(v)) return [];
15499
+ return v.filter((entry) => item.safeParse(entry).success).slice(0, maxItems);
15500
+ }, z69.array(item).max(maxItems));
15501
+ }
15502
+ __name(lenientList, "lenientList");
15503
+
15504
+ // ../../packages/types/src/product-truth.ts
15505
+ var PRODUCT_TRUTH_SCHEMA_VERSION = 1;
15506
+ var PRODUCT_TRUTH_CAPS = {
15507
+ whatItIs: 160,
15508
+ deliveryForm: 120,
15509
+ distinctiveMarks: 6,
15510
+ distinctiveMarkChars: 160,
15511
+ parts: 12,
15512
+ partNameChars: 80,
15513
+ criticalFeatures: 6,
15514
+ connections: 6,
15515
+ connectionChars: 80,
15516
+ states: 4,
15517
+ stateKeyChars: 60,
15518
+ stateLabelChars: 80,
15519
+ partsPresent: 10,
15520
+ orientationInUseChars: 200,
15521
+ appliedToChars: 120,
15522
+ environmentChars: 120,
15523
+ summaryChars: 200,
15524
+ sceneChars: 300,
15525
+ postureAndGripChars: 160,
15526
+ contactPointChars: 120,
15527
+ steps: 8,
15528
+ stepNameChars: 120,
15529
+ stepInstructionChars: 300,
15530
+ visibleEffectChars: 200,
15531
+ beforeStateChars: 200,
15532
+ requiredProps: 8,
15533
+ requiredPropChars: 120,
15534
+ alternates: 3,
15535
+ misuse: 5,
15536
+ misuseChars: 200,
15537
+ mustShowFeatures: 5,
15538
+ mustShowFeatureChars: 100,
15539
+ safety: 5,
15540
+ safetyChars: 200,
15541
+ forbiddenClaims: 8,
15542
+ unsupportedClaims: 5,
15543
+ claimChars: 200,
15544
+ visualSummaryEnChars: 400
15545
+ };
15546
+ var PRODUCT_TRUTH_END_USER_AGE_BANDS = [
15547
+ "baby",
15548
+ "child",
15549
+ "teen",
15550
+ "adult",
15551
+ "any"
15552
+ ];
15553
+ var PRODUCT_TRUTH_END_USER_GENDERS = [
15554
+ "female",
15555
+ "male",
15556
+ "any"
15557
+ ];
15558
+ var PRODUCT_TRUTH_UNKNOWN_REASONS = [
15559
+ "model_unsure",
15560
+ "no_signal",
15561
+ "invalid_response",
15562
+ "provider_error"
15563
+ ];
15564
+ var text = lenientText;
15565
+ var optionalText = lenientOptionalText;
15566
+ var textList = lenientTextList;
15567
+ function toProductTruthStateKey(value) {
15568
+ if (typeof value !== "string") return void 0;
15569
+ const slug = value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, PRODUCT_TRUTH_CAPS.stateKeyChars);
15570
+ return slug.length > 0 ? slug : void 0;
15571
+ }
15572
+ __name(toProductTruthStateKey, "toProductTruthStateKey");
15573
+ var stateKey = z70.preprocess(toProductTruthStateKey, z70.string().min(1).max(PRODUCT_TRUTH_CAPS.stateKeyChars));
15574
+ var optionalStateKey = z70.preprocess(toProductTruthStateKey, z70.string().min(1).max(PRODUCT_TRUTH_CAPS.stateKeyChars).optional());
15575
+ var AGE_BAND_ALIASES = {
15576
+ baby: "baby",
15577
+ babies: "baby",
15578
+ infant: "baby",
15579
+ infants: "baby",
15580
+ toddler: "child",
15581
+ child: "child",
15582
+ children: "child",
15583
+ kid: "child",
15584
+ kids: "child",
15585
+ teen: "teen",
15586
+ teens: "teen",
15587
+ teenager: "teen",
15588
+ teenagers: "teen",
15589
+ adult: "adult",
15590
+ adults: "adult",
15591
+ any: "any",
15592
+ all: "any",
15593
+ "all ages": "any"
15594
+ };
15595
+ var GENDER_ALIASES = {
15596
+ female: "female",
15597
+ woman: "female",
15598
+ women: "female",
15599
+ girl: "female",
15600
+ male: "male",
15601
+ man: "male",
15602
+ men: "male",
15603
+ boy: "male",
15604
+ any: "any",
15605
+ unisex: "any",
15606
+ both: "any",
15607
+ all: "any"
15608
+ };
15609
+ function matchAlias(raw, aliases) {
15610
+ if (typeof raw !== "string") return void 0;
15611
+ const text2 = raw.trim().toLowerCase();
15612
+ const exact = aliases[text2];
15613
+ if (exact) return exact;
15614
+ const words = new Set(text2.split(/[^a-z]+/).filter(Boolean));
15615
+ for (const [alias, value] of Object.entries(aliases)) {
15616
+ if (words.has(alias)) return value;
15617
+ }
15618
+ return void 0;
15619
+ }
15620
+ __name(matchAlias, "matchAlias");
15621
+ function normalizeEndUser(value) {
15622
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
15623
+ const v = value;
15624
+ const age = matchAlias(v.ageBand, AGE_BAND_ALIASES);
15625
+ const gender = matchAlias(v.gender, GENDER_ALIASES);
15626
+ if (!age || !gender || typeof v.usedByBuyer !== "boolean") return void 0;
15627
+ return {
15628
+ ageBand: age,
15629
+ gender,
15630
+ usedByBuyer: v.usedByBuyer
15631
+ };
15632
+ }
15633
+ __name(normalizeEndUser, "normalizeEndUser");
15634
+ var ProductTruthEndUserSchema = z70.object({
15635
+ ageBand: z70.enum(PRODUCT_TRUTH_END_USER_AGE_BANDS),
15636
+ gender: z70.enum(PRODUCT_TRUTH_END_USER_GENDERS),
15637
+ usedByBuyer: z70.boolean()
15638
+ });
15639
+ var MATERIAL_HINTS = ProductMorphology.shape.materialHints.unwrap().element.options;
15640
+ var DEMO_TYPES = FunctionalDemonstration.shape.demoType;
15641
+ var PartSchema = z70.object({
15642
+ name: text(PRODUCT_TRUTH_CAPS.partNameChars),
15643
+ kind: z70.enum([
15644
+ "rigid",
15645
+ "flexible",
15646
+ "joint"
15647
+ ]).catch("rigid"),
15648
+ count: z70.number().int().min(1).max(20).catch(1)
15649
+ });
15650
+ var CriticalFeatureSchema = z70.object({
15651
+ name: text(60),
15652
+ importance: text(120),
15653
+ antiPattern: optionalText(80),
15654
+ expectedCount: z70.number().int().min(1).max(20).optional().catch(void 0)
15655
+ });
15656
+ var ConnectionSchema = z70.object({
15657
+ part: text(PRODUCT_TRUTH_CAPS.connectionChars),
15658
+ attachesTo: text(PRODUCT_TRUTH_CAPS.connectionChars),
15659
+ where: optionalText(PRODUCT_TRUTH_CAPS.connectionChars)
15660
+ });
15661
+ var StateSchema = z70.object({
15662
+ key: stateKey,
15663
+ label: optionalText(PRODUCT_TRUTH_CAPS.stateLabelChars),
15664
+ partsPresent: textList(PRODUCT_TRUTH_CAPS.partsPresent, PRODUCT_TRUTH_CAPS.partNameChars),
15665
+ orientationInUse: text(PRODUCT_TRUTH_CAPS.orientationInUseChars),
15666
+ naturalOrientation: ProductNaturalOrientation.optional().catch(void 0)
15667
+ });
15668
+ var StepSchema = z70.object({
15669
+ name: text(PRODUCT_TRUTH_CAPS.stepNameChars),
15670
+ instruction: text(PRODUCT_TRUTH_CAPS.stepInstructionChars),
15671
+ kind: z70.enum([
15672
+ "setup",
15673
+ "use",
15674
+ "finish"
15675
+ ]).catch("use")
15676
+ });
15677
+ var AlternateSchema = z70.object({
15678
+ summary: text(PRODUCT_TRUTH_CAPS.summaryChars),
15679
+ stateKey: optionalStateKey,
15680
+ advertisedBySeller: z70.boolean().catch(false)
15681
+ });
15682
+ var DemoSchema = z70.object({
15683
+ demoType: DEMO_TYPES.nullable().catch(null),
15684
+ mustShowFeatures: textList(PRODUCT_TRUTH_CAPS.mustShowFeatures, PRODUCT_TRUTH_CAPS.mustShowFeatureChars),
15685
+ importance: z70.enum([
15686
+ "critical",
15687
+ "important",
15688
+ "nice_to_have"
15689
+ ]).catch("important")
15690
+ });
15691
+ var objectOrEmpty = /* @__PURE__ */ __name((v) => v && typeof v === "object" && !Array.isArray(v) ? v : {}, "objectOrEmpty");
15692
+ var ProductTruthBody = z70.object({
15693
+ identity: z70.object({
15694
+ whatItIs: text(PRODUCT_TRUTH_CAPS.whatItIs),
15695
+ deliveryForm: optionalText(PRODUCT_TRUTH_CAPS.deliveryForm),
15696
+ distinctiveMarks: textList(PRODUCT_TRUTH_CAPS.distinctiveMarks, PRODUCT_TRUTH_CAPS.distinctiveMarkChars)
15697
+ }),
15698
+ morphology: z70.preprocess(objectOrEmpty, z70.object({
15699
+ shape: ProductGeometryShape.optional().catch(void 0),
15700
+ crossSection: ProductCrossSection.optional().catch(void 0),
15701
+ cornerProfile: ProductCornerProfile.optional().catch(void 0),
15702
+ silhouetteWidthToHeightRatio: z70.number().min(0.05).max(20).optional().catch(void 0),
15703
+ parts: lenientList(PartSchema, PRODUCT_TRUTH_CAPS.parts),
15704
+ criticalFeatures: lenientList(CriticalFeatureSchema, PRODUCT_TRUTH_CAPS.criticalFeatures),
15705
+ shapeLockLevel: z70.enum([
15706
+ "strict",
15707
+ "moderate",
15708
+ "relaxed"
15709
+ ]).optional().catch(void 0),
15710
+ materialHints: z70.preprocess((v) => Array.isArray(v) ? [
15711
+ ...new Set(v.filter((m) => MATERIAL_HINTS.includes(m)))
15712
+ ].slice(0, 3) : [], z70.array(z70.enum(MATERIAL_HINTS)).max(3))
15713
+ })),
15714
+ assembly: z70.object({
15715
+ connections: lenientList(ConnectionSchema, PRODUCT_TRUTH_CAPS.connections),
15716
+ states: z70.preprocess((v) => {
15717
+ if (!Array.isArray(v)) return v;
15718
+ const seen = /* @__PURE__ */ new Set();
15719
+ return v.filter((entry) => {
15720
+ const parsed = StateSchema.safeParse(entry);
15721
+ if (!parsed.success || seen.has(parsed.data.key)) return false;
15722
+ seen.add(parsed.data.key);
15723
+ return true;
15724
+ }).slice(0, PRODUCT_TRUTH_CAPS.states);
15725
+ }, z70.array(StateSchema).min(1).max(PRODUCT_TRUTH_CAPS.states)),
15726
+ defaultStateKey: optionalStateKey
15727
+ }),
15728
+ use: z70.object({
15729
+ endUser: z70.preprocess(normalizeEndUser, ProductTruthEndUserSchema.optional()).catch(void 0),
15730
+ appliedTo: optionalText(PRODUCT_TRUTH_CAPS.appliedToChars),
15731
+ environment: optionalText(PRODUCT_TRUTH_CAPS.environmentChars),
15732
+ primary: z70.object({
15733
+ summary: text(PRODUCT_TRUTH_CAPS.summaryChars),
15734
+ scene: text(PRODUCT_TRUTH_CAPS.sceneChars),
15735
+ postureAndGrip: optionalText(PRODUCT_TRUTH_CAPS.postureAndGripChars),
15736
+ contactPoint: optionalText(PRODUCT_TRUTH_CAPS.contactPointChars),
15737
+ stateKey: optionalStateKey,
15738
+ 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)),
15739
+ visibleEffect: optionalText(PRODUCT_TRUTH_CAPS.visibleEffectChars),
15740
+ beforeState: optionalText(PRODUCT_TRUTH_CAPS.beforeStateChars),
15741
+ requiredProps: textList(PRODUCT_TRUTH_CAPS.requiredProps, PRODUCT_TRUTH_CAPS.requiredPropChars)
15742
+ }),
15743
+ alternates: lenientList(AlternateSchema, PRODUCT_TRUTH_CAPS.alternates),
15744
+ misuse: textList(PRODUCT_TRUTH_CAPS.misuse, PRODUCT_TRUTH_CAPS.misuseChars),
15745
+ demo: z70.preprocess(objectOrEmpty, DemoSchema),
15746
+ safety: textList(PRODUCT_TRUTH_CAPS.safety, PRODUCT_TRUTH_CAPS.safetyChars)
15747
+ }),
15748
+ claims: z70.preprocess(objectOrEmpty, z70.object({
15749
+ forbidden: textList(PRODUCT_TRUTH_CAPS.forbiddenClaims, PRODUCT_TRUTH_CAPS.claimChars),
15750
+ unsupported: textList(PRODUCT_TRUTH_CAPS.unsupportedClaims, PRODUCT_TRUTH_CAPS.claimChars)
15751
+ })),
15752
+ visualSummaryEn: optionalText(PRODUCT_TRUTH_CAPS.visualSummaryEnChars),
15753
+ evidence: z70.preprocess(objectOrEmpty, z70.object({
15754
+ photoIndexForState: z70.preprocess((v) => {
15755
+ const out = {};
15756
+ if (!v || typeof v !== "object" || Array.isArray(v)) return out;
15757
+ for (const [rawKey, rawIndexes] of Object.entries(v)) {
15758
+ const key = toProductTruthStateKey(rawKey);
15759
+ if (!key || !Array.isArray(rawIndexes)) continue;
15760
+ out[key] = rawIndexes.filter((i) => typeof i === "number" && Number.isInteger(i) && i >= 0 && i < 20);
15761
+ }
15762
+ return out;
15763
+ }, z70.record(z70.array(z70.number().int().min(0).max(19))))
15764
+ })),
15765
+ confidence: z70.preprocess((v) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : 0, z70.number().min(0).max(1))
15766
+ });
15767
+ function resolveStateRefs(body) {
15768
+ const keys = new Set(body.assembly.states.map((s) => s.key));
15769
+ const firstKey = body.assembly.states[0]?.key ?? "";
15770
+ const defaultStateKey = body.assembly.defaultStateKey && keys.has(body.assembly.defaultStateKey) ? body.assembly.defaultStateKey : firstKey;
15771
+ const primaryKey = body.use.primary.stateKey && keys.has(body.use.primary.stateKey) ? body.use.primary.stateKey : defaultStateKey;
15772
+ const photoIndexForState = Object.fromEntries(Object.entries(body.evidence.photoIndexForState).filter(([key]) => keys.has(key)));
15773
+ return {
15774
+ ...body,
15775
+ assembly: {
15776
+ ...body.assembly,
15777
+ defaultStateKey
15778
+ },
15779
+ use: {
15780
+ ...body.use,
15781
+ primary: {
15782
+ ...body.use.primary,
15783
+ stateKey: primaryKey
15784
+ },
15785
+ alternates: body.use.alternates.map((alt) => ({
15786
+ ...alt,
15787
+ stateKey: alt.stateKey && keys.has(alt.stateKey) ? alt.stateKey : defaultStateKey
15788
+ }))
15789
+ },
15790
+ evidence: {
15791
+ ...body.evidence,
15792
+ photoIndexForState
15793
+ }
15794
+ };
15795
+ }
15796
+ __name(resolveStateRefs, "resolveStateRefs");
15797
+ var ProductTruthModelResponseSchema = ProductTruthBody.transform(resolveStateRefs);
15798
+ var provenance = {
15799
+ schemaVersion: z70.literal(PRODUCT_TRUTH_SCHEMA_VERSION),
15800
+ modelId: z70.string().min(1),
15801
+ derivedAt: z70.string().min(1),
15802
+ /** Hash of (image keys + seller text + features): a reader that sees a different current
15803
+ * fingerprint treats the truth as absent. See `computeProductTruthFingerprint` in packages/ai. */
15804
+ sourceFingerprint: z70.string().min(1),
15805
+ /** The seller upload KEYS (deduped, sorted) the fingerprint was computed over. Stored so a
15806
+ * reader can recompute the CURRENT fingerprint from today's seller text + features without
15807
+ * knowing the extract job's inputs (plan Global Constraint "Invalidez"). */
15808
+ sourceImageKeys: z70.array(z70.string().min(1)).max(20).optional()
15809
+ };
15810
+ var ProductTruthKnownSchema = ProductTruthBody.extend({
15811
+ ...provenance,
15812
+ known: z70.literal(true)
15813
+ }).transform(resolveStateRefs);
15814
+ var ProductTruthUnknownSchema = z70.object({
15815
+ schemaVersion: z70.literal(PRODUCT_TRUTH_SCHEMA_VERSION),
15816
+ known: z70.literal(false),
15817
+ unknownReason: z70.enum(PRODUCT_TRUTH_UNKNOWN_REASONS),
15818
+ modelId: z70.string().optional(),
15819
+ derivedAt: z70.string().min(1),
15820
+ sourceFingerprint: z70.string().min(1),
15821
+ sourceImageKeys: z70.array(z70.string().min(1)).max(20).optional()
15822
+ });
15823
+ var ProductTruthSchema = z70.union([
15824
+ ProductTruthKnownSchema,
15825
+ ProductTruthUnknownSchema
15826
+ ]);
15827
+
15828
+ // ../../packages/types/src/landing-director.ts
15829
+ import { z as z71 } from "zod";
15830
+ var LANDING_DIRECTOR_SCHEMA_VERSION = 1;
15831
+ var LANDING_DIRECTOR_ARM = "categories";
15832
+ var LANDING_DIRECTOR_CAPS = {
15833
+ productIdentity: 200,
15834
+ parts: 8,
15835
+ partName: 40,
15836
+ promise: 200,
15837
+ endUserWho: 80,
15838
+ endUserAppliedTo: 80,
15839
+ forbiddenClaims: 10,
15840
+ claimChars: 80,
15841
+ misuse: 5,
15842
+ misuseChars: 120,
15843
+ assembledStates: 3,
15844
+ statePartsMax: 6,
15845
+ orientation: 160,
15846
+ handling: 140,
15847
+ primaryScene: 200,
15848
+ postureAndGrip: 140,
15849
+ contactPoint: 100,
15850
+ alternates: 3,
15851
+ alternateChars: 120,
15852
+ ambiguities: 4,
15853
+ ambiguityChars: 160,
15854
+ sectionKeyChars: 40,
15855
+ personWho: 80,
15856
+ personPosture: 120,
15857
+ personGrip: 120,
15858
+ scene: 450,
15859
+ panels: 4,
15860
+ panelScene: 200,
15861
+ panelCaption: 60,
15862
+ /** Rendered text: an item over its cap is DROPPED, never cut. The headline cap is 80, not
15863
+ * the design's 70: a dropped headline costs the whole director headline, and 7-10 Spanish
15864
+ * words routinely run 70-80 chars. */
15865
+ headline: 80,
15866
+ subheadline: 90,
15867
+ labels: 3,
15868
+ labelChars: 40,
15869
+ captions: 3,
15870
+ captionChars: 60,
15871
+ props: 4,
15872
+ propChars: 40,
15873
+ mustNotShow: 5,
15874
+ mustNotShowChars: 80
15875
+ };
15876
+ var STATE_KEY_PATTERN = /^[a-z][a-z_]{1,23}$/;
15877
+ function toLandingDirectorStateKey(value) {
15878
+ if (typeof value !== "string") return void 0;
15879
+ const slug = value.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 24).replace(/_+$/g, "");
15880
+ return STATE_KEY_PATTERN.test(slug) ? slug : void 0;
15881
+ }
15882
+ __name(toLandingDirectorStateKey, "toLandingDirectorStateKey");
15883
+ var stateKey2 = z71.preprocess(toLandingDirectorStateKey, z71.string().regex(STATE_KEY_PATTERN));
15884
+ function renderedOptionalText(max) {
15885
+ return z71.preprocess((v) => {
15886
+ if (typeof v !== "string") return void 0;
15887
+ const trimmed = v.replace(/\s+/g, " ").trim();
15888
+ return trimmed.length > 0 && trimmed.length <= max ? trimmed : void 0;
15889
+ }, z71.string().min(1).max(max).optional());
15890
+ }
15891
+ __name(renderedOptionalText, "renderedOptionalText");
15892
+ function renderedTextList(maxItems, maxChars) {
15893
+ return z71.preprocess((v) => {
15894
+ if (!Array.isArray(v)) return [];
15895
+ return v.map((item) => typeof item === "string" ? item.replace(/\s+/g, " ").trim() : "").filter((item) => item.length > 0 && item.length <= maxChars).slice(0, maxItems);
15896
+ }, z71.array(z71.string().min(1).max(maxChars)).max(maxItems));
15897
+ }
15898
+ __name(renderedTextList, "renderedTextList");
15899
+ var C = LANDING_DIRECTOR_CAPS;
15900
+ var PartSchema2 = z71.object({
15901
+ name: lenientText(C.partName),
15902
+ critical: z71.boolean().catch(false)
15903
+ });
15904
+ var AssembledStateSchema = z71.object({
15905
+ key: stateKey2,
15906
+ parts: lenientTextList(C.statePartsMax, C.partName),
15907
+ orientation: lenientText(C.orientation),
15908
+ handling: lenientOptionalText(C.handling)
15909
+ });
15910
+ var END_USER_GENDERS = [
15911
+ "female",
15912
+ "male",
15913
+ "any"
15914
+ ];
15915
+ var END_USER_AGE_BANDS = [
15916
+ "child",
15917
+ "teen",
15918
+ "adult",
15919
+ "senior",
15920
+ "any"
15921
+ ];
15922
+ var EndUserSchema = z71.object({
15923
+ who: lenientText(C.endUserWho),
15924
+ appliedTo: lenientOptionalText(C.endUserAppliedTo),
15925
+ gender: z71.enum(END_USER_GENDERS).catch("any"),
15926
+ ageBand: z71.enum(END_USER_AGE_BANDS).catch("any")
15927
+ });
15928
+ var LandingDirectorGlobalSchema = z71.object({
15929
+ productIdentity: lenientText(C.productIdentity),
15930
+ parts: lenientList(PartSchema2, C.parts),
15931
+ promise: lenientText(C.promise),
15932
+ endUser: EndUserSchema,
15933
+ forbiddenClaims: lenientTextList(C.forbiddenClaims, C.claimChars),
15934
+ misuse: lenientTextList(C.misuse, C.misuseChars),
15935
+ assembledStates: z71.preprocess((v) => {
15936
+ if (!Array.isArray(v)) return v;
15937
+ const seen = /* @__PURE__ */ new Set();
15938
+ return v.filter((entry) => {
15939
+ const parsed = AssembledStateSchema.safeParse(entry);
15940
+ if (!parsed.success || seen.has(parsed.data.key)) return false;
15941
+ seen.add(parsed.data.key);
15942
+ return true;
15943
+ }).slice(0, C.assembledStates);
15944
+ }, z71.array(AssembledStateSchema).min(1).max(C.assembledStates)),
15945
+ primaryUse: z71.object({
15946
+ assembledState: stateKey2,
15947
+ scene: lenientText(C.primaryScene),
15948
+ postureAndGrip: lenientText(C.postureAndGrip),
15949
+ contactPoint: lenientOptionalText(C.contactPoint)
15950
+ }),
15951
+ primaryRequired: z71.boolean().catch(false),
15952
+ validAlternateUses: lenientTextList(C.alternates, C.alternateChars),
15953
+ ambiguities: lenientTextList(C.ambiguities, C.ambiguityChars)
15954
+ });
15955
+ var LANDING_DIRECTOR_BODY_PARTS = [
15956
+ "hands",
15957
+ "face",
15958
+ "torso",
15959
+ "legs",
15960
+ "feet",
15961
+ "full_body"
15962
+ ];
15963
+ var PersonSchema = z71.object({
15964
+ who: lenientText(C.personWho),
15965
+ posture: lenientText(C.personPosture),
15966
+ grip: lenientOptionalText(C.personGrip),
15967
+ bodyPartsVisible: z71.preprocess((v) => Array.isArray(v) ? [
15968
+ ...new Set(v.filter((part) => LANDING_DIRECTOR_BODY_PARTS.includes(part)))
15969
+ ] : [], z71.array(z71.enum(LANDING_DIRECTOR_BODY_PARTS)))
15970
+ });
15971
+ var LandingDirectorTextSchema = z71.object({
15972
+ headline: renderedOptionalText(C.headline),
15973
+ subheadline: renderedOptionalText(C.subheadline),
15974
+ labels: renderedTextList(C.labels, C.labelChars),
15975
+ captions: renderedTextList(C.captions, C.captionChars)
15976
+ });
15977
+ var PanelSchema = z71.object({
15978
+ scene: lenientText(C.panelScene),
15979
+ caption: renderedOptionalText(C.panelCaption)
15980
+ });
15981
+ var PRODUCT_IN_FRAME_VALUES = [
15982
+ "none",
15983
+ "packshot",
15984
+ "in_use"
15985
+ ];
15986
+ var LandingDirectorSectionSchema = z71.object({
15987
+ sectionKey: z71.string().trim().min(1).max(C.sectionKeyChars),
15988
+ /** Present only in the «director» arm. Kept as a flag so the «categorías» validation can
15989
+ * invalidate the section (design §2.3) instead of silently dropping the model's choice. */
15990
+ hasComposition: z71.boolean().default(false),
15991
+ productInFrame: z71.enum(PRODUCT_IN_FRAME_VALUES),
15992
+ assembledState: z71.preprocess((v) => v === null || v === void 0 ? null : toLandingDirectorStateKey(v), z71.string().regex(STATE_KEY_PATTERN).nullable()),
15993
+ usesPrimary: z71.boolean().catch(false),
15994
+ person: z71.preprocess((v) => v === void 0 ? null : v, PersonSchema.nullable()),
15995
+ scene: lenientText(C.scene),
15996
+ panels: lenientList(PanelSchema, C.panels),
15997
+ textToRender: z71.preprocess((v) => v && typeof v === "object" && !Array.isArray(v) ? v : {}, LandingDirectorTextSchema),
15998
+ props: lenientTextList(C.props, C.propChars),
15999
+ mustNotShow: lenientTextList(C.mustNotShow, C.mustNotShowChars)
16000
+ });
16001
+ var LandingDirectorOutputSchema = z71.object({
16002
+ version: z71.literal(LANDING_DIRECTOR_SCHEMA_VERSION),
16003
+ confidence: z71.number().min(0).max(1),
16004
+ global: LandingDirectorGlobalSchema,
16005
+ sections: z71.array(LandingDirectorSectionSchema)
16006
+ });
16007
+ var StoredLandingDirectorSchema = z71.object({
16008
+ version: z71.literal(LANDING_DIRECTOR_SCHEMA_VERSION),
16009
+ arm: z71.literal(LANDING_DIRECTOR_ARM),
16010
+ modelId: z71.string().min(1),
16011
+ generatedAt: z71.string().min(1),
16012
+ confidence: z71.number().min(0).max(1),
16013
+ /** The plan the answer was validated against (sectionKey, or the role on classic). */
16014
+ planSectionKeys: z71.array(z71.string().min(1)),
16015
+ output: LandingDirectorOutputSchema,
16016
+ /** Sections that fell back to the category composition, and why. */
16017
+ fallbackSections: z71.array(z71.object({
16018
+ sectionKey: z71.string().min(1),
16019
+ reason: z71.string().min(1)
16020
+ }))
16021
+ });
16022
+
16023
+ // ../../packages/types/src/flight-recorder.ts
16024
+ import { z as z72 } from "zod";
16025
+ var FlightRecorderGenerationTypeSchema = z72.enum([
15179
16026
  "initial",
15180
16027
  "regeneration",
15181
16028
  "edit",
15182
16029
  "retry"
15183
16030
  ]);
15184
- var FlightRecorderProviderSchema = z68.enum([
16031
+ var FlightRecorderProviderSchema = z72.enum([
15185
16032
  "kie",
15186
16033
  "fal"
15187
16034
  ]);
15188
- var FlightRecorderElementSchema = z68.object({
15189
- name: z68.string().optional(),
15190
- description: z68.string().optional(),
15191
- frontalImageUrl: z68.string().optional(),
15192
- referenceImageUrls: z68.array(z68.string()).optional(),
15193
- videoUrl: z68.string().optional()
15194
- });
15195
- var FlightRecorderDistillationSchema = z68.object({
15196
- actorGender: z68.enum([
16035
+ var FlightRecorderElementSchema = z72.object({
16036
+ name: z72.string().optional(),
16037
+ description: z72.string().optional(),
16038
+ frontalImageUrl: z72.string().optional(),
16039
+ referenceImageUrls: z72.array(z72.string()).optional(),
16040
+ videoUrl: z72.string().optional()
16041
+ });
16042
+ var FlightRecorderDistillationSchema = z72.object({
16043
+ actorGender: z72.enum([
15197
16044
  "female",
15198
16045
  "male",
15199
16046
  "mixed"
15200
- ]).or(z68.string()).optional(),
15201
- voiceId: z68.string().optional(),
15202
- cameraMotion: z68.string().optional()
15203
- }).catchall(z68.unknown());
15204
- var FlightRecorderEntrySchema = z68.object({
15205
- schemaVersion: z68.literal(1).optional(),
15206
- id: z68.string().min(1),
15207
- taskId: z68.string().min(1),
15208
- runId: z68.string().min(1),
15209
- sequence: z68.number().int().nonnegative(),
15210
- timestamp: z68.string().min(1),
15211
- provider: FlightRecorderProviderSchema.or(z68.string()),
15212
- model: z68.string().min(1),
15213
- prompt: z68.string(),
15214
- durationSeconds: z68.number().nonnegative(),
15215
- aspectRatio: z68.string().optional(),
15216
- resolution: z68.string().optional(),
15217
- startImageUrl: z68.string().optional(),
15218
- endImageUrl: z68.string().optional(),
15219
- generateAudio: z68.boolean().optional(),
16047
+ ]).or(z72.string()).optional(),
16048
+ voiceId: z72.string().optional(),
16049
+ cameraMotion: z72.string().optional()
16050
+ }).catchall(z72.unknown());
16051
+ var FlightRecorderEntrySchema = z72.object({
16052
+ schemaVersion: z72.literal(1).optional(),
16053
+ id: z72.string().min(1),
16054
+ taskId: z72.string().min(1),
16055
+ runId: z72.string().min(1),
16056
+ sequence: z72.number().int().nonnegative(),
16057
+ timestamp: z72.string().min(1),
16058
+ provider: FlightRecorderProviderSchema.or(z72.string()),
16059
+ model: z72.string().min(1),
16060
+ prompt: z72.string(),
16061
+ durationSeconds: z72.number().nonnegative(),
16062
+ aspectRatio: z72.string().optional(),
16063
+ resolution: z72.string().optional(),
16064
+ startImageUrl: z72.string().optional(),
16065
+ endImageUrl: z72.string().optional(),
16066
+ generateAudio: z72.boolean().optional(),
15220
16067
  // Correlation & pipeline metadata
15221
- angleKey: z68.string().optional(),
15222
- sceneIndex: z68.number().int().nonnegative().optional(),
16068
+ angleKey: z72.string().optional(),
16069
+ sceneIndex: z72.number().int().nonnegative().optional(),
15223
16070
  generationType: FlightRecorderGenerationTypeSchema,
15224
- operationId: z68.string().min(1).optional(),
15225
- revisionId: z68.string().min(1).optional(),
15226
- attemptNumber: z68.number().int().nonnegative().default(1),
16071
+ operationId: z72.string().min(1).optional(),
16072
+ revisionId: z72.string().min(1).optional(),
16073
+ attemptNumber: z72.number().int().nonnegative().default(1),
15227
16074
  // Elements & Distillation
15228
- elements: z68.array(FlightRecorderElementSchema).optional(),
16075
+ elements: z72.array(FlightRecorderElementSchema).optional(),
15229
16076
  distillation: FlightRecorderDistillationSchema.optional(),
15230
16077
  // Raw payload (sanitized of secrets)
15231
- rawPayload: z68.record(z68.unknown())
16078
+ rawPayload: z72.record(z72.unknown())
15232
16079
  });
15233
- var FlightRecorderQuerySchema = z68.object({
15234
- taskId: z68.string().min(1),
15235
- runId: z68.string().optional(),
15236
- sceneIndex: z68.number().int().nonnegative().optional(),
15237
- angleKey: z68.string().optional(),
16080
+ var FlightRecorderQuerySchema = z72.object({
16081
+ taskId: z72.string().min(1),
16082
+ runId: z72.string().optional(),
16083
+ sceneIndex: z72.number().int().nonnegative().optional(),
16084
+ angleKey: z72.string().optional(),
15238
16085
  generationType: FlightRecorderGenerationTypeSchema.optional(),
15239
- cursor: z68.number().int().nonnegative().optional(),
15240
- limit: z68.number().int().positive().optional()
16086
+ cursor: z72.number().int().nonnegative().optional(),
16087
+ limit: z72.number().int().positive().optional()
15241
16088
  });
15242
- var FlightRecorderResponseSchema = z68.object({
15243
- taskId: z68.string().min(1),
15244
- runId: z68.string().min(1),
15245
- entries: z68.array(FlightRecorderEntrySchema),
16089
+ var FlightRecorderResponseSchema = z72.object({
16090
+ taskId: z72.string().min(1),
16091
+ runId: z72.string().min(1),
16092
+ entries: z72.array(FlightRecorderEntrySchema),
15246
16093
  lastCall: FlightRecorderEntrySchema.nullable(),
15247
- count: z68.number().int().nonnegative(),
15248
- nextCursor: z68.number().int().nonnegative().nullable()
16094
+ count: z72.number().int().nonnegative(),
16095
+ nextCursor: z72.number().int().nonnegative().nullable()
15249
16096
  });
15250
16097
 
15251
16098
  // src/http.ts
@@ -15420,8 +16267,8 @@ async function readResponseText(response, maxBytes) {
15420
16267
  }
15421
16268
  __name(readResponseText, "readResponseText");
15422
16269
  async function readResponseJson(response, maxBytes) {
15423
- const text = await readResponseText(response, maxBytes);
15424
- return JSON.parse(text);
16270
+ const text2 = await readResponseText(response, maxBytes);
16271
+ return JSON.parse(text2);
15425
16272
  }
15426
16273
  __name(readResponseJson, "readResponseJson");
15427
16274
 
@@ -15754,22 +16601,22 @@ import { InsufficientScopeError, InvalidTokenError } from "@modelcontextprotocol
15754
16601
  import { createRemoteJWKSet as createRemoteJWKSet2, jwtVerify as jwtVerify2 } from "jose";
15755
16602
 
15756
16603
  // src/auth/oauth-config.ts
15757
- import { z as z69 } from "zod";
16604
+ import { z as z73 } from "zod";
15758
16605
  var MCP_RESOURCE = new URL("https://mcp.productmaker.app/mcp");
15759
16606
  var MCP_SCOPE = "mcp:access";
15760
16607
  var STATIC_CLIENT_ISSUER = new URL(MCP_RESOURCE.origin);
15761
- var oauthEnvSchema = z69.object({
15762
- MCP_REMOTE_AUTH_MODE: z69.literal("oauth"),
15763
- MCP_AUTH0_ISSUER: z69.string().trim().min(1),
15764
- MCP_AUTH0_AUDIENCE: z69.string().trim().refine((value) => value === MCP_RESOURCE.href, {
16608
+ var oauthEnvSchema = z73.object({
16609
+ MCP_REMOTE_AUTH_MODE: z73.literal("oauth"),
16610
+ MCP_AUTH0_ISSUER: z73.string().trim().min(1),
16611
+ MCP_AUTH0_AUDIENCE: z73.string().trim().refine((value) => value === MCP_RESOURCE.href, {
15765
16612
  message: `must equal ${MCP_RESOURCE.href}`
15766
16613
  }),
15767
- MCP_AUTH0_CLIENT_ID: z69.string().trim().min(1),
15768
- MCP_AUTH0_CLIENT_SECRET: z69.string().trim().min(1),
15769
- PM_API_AUDIENCE: z69.string().trim().min(1),
15770
- AUTH0_AUDIENCE: z69.string().trim().min(1),
15771
- MCP_STATIC_CLIENT_ID: z69.string().trim().min(1).optional(),
15772
- MCP_STATIC_CLIENT_SECRET: z69.string().trim().min(1).optional()
16614
+ MCP_AUTH0_CLIENT_ID: z73.string().trim().min(1),
16615
+ MCP_AUTH0_CLIENT_SECRET: z73.string().trim().min(1),
16616
+ PM_API_AUDIENCE: z73.string().trim().min(1),
16617
+ AUTH0_AUDIENCE: z73.string().trim().min(1),
16618
+ MCP_STATIC_CLIENT_ID: z73.string().trim().min(1).optional(),
16619
+ MCP_STATIC_CLIENT_SECRET: z73.string().trim().min(1).optional()
15773
16620
  });
15774
16621
  function formatZodIssues(error) {
15775
16622
  return error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
@@ -16053,7 +16900,7 @@ function badRequest(res, description) {
16053
16900
  __name(badRequest, "badRequest");
16054
16901
  function createOAuthProxyRouter(options) {
16055
16902
  const router = express.Router();
16056
- const stateKey = deriveStateKey(options.staticClient.clientSecret);
16903
+ const stateKey3 = deriveStateKey(options.staticClient.clientSecret);
16057
16904
  const now = options.now ?? (() => Date.now());
16058
16905
  router.get(OAUTH_PROXY_PATHS.authorize, (req, res) => {
16059
16906
  const redirectUri = firstQueryValue(req.query.redirect_uri);
@@ -16082,7 +16929,7 @@ function createOAuthProxyRouter(options) {
16082
16929
  }
16083
16930
  }
16084
16931
  upstream.searchParams.set("redirect_uri", PROXY_CALLBACK_URL);
16085
- upstream.searchParams.set("state", sealState(stateKey, {
16932
+ upstream.searchParams.set("state", sealState(stateKey3, {
16086
16933
  redirectUri,
16087
16934
  ...firstQueryValue(req.query.state) === void 0 ? {} : {
16088
16935
  clientState: firstQueryValue(req.query.state)
@@ -16092,7 +16939,7 @@ function createOAuthProxyRouter(options) {
16092
16939
  });
16093
16940
  router.get(OAUTH_PROXY_PATHS.callback, (req, res) => {
16094
16941
  const sealed = firstQueryValue(req.query.state);
16095
- const opened = sealed === void 0 ? void 0 : openState(stateKey, sealed, now());
16942
+ const opened = sealed === void 0 ? void 0 : openState(stateKey3, sealed, now());
16096
16943
  if (!opened) {
16097
16944
  badRequest(res, "state is missing, tampered with, or expired");
16098
16945
  return;
@@ -16876,7 +17723,7 @@ var ApiClient = class {
16876
17723
  };
16877
17724
 
16878
17725
  // src/index.ts
16879
- var MCP_VERSION = "8.0.0";
17726
+ var MCP_VERSION = "8.2.0";
16880
17727
 
16881
17728
  // src/meta-upload-app.ts
16882
17729
  import { readFileSync } from "fs";
@@ -16948,7 +17795,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
16948
17795
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
16949
17796
 
16950
17797
  // src/tools/tasks.ts
16951
- import { z as z73 } from "zod";
17798
+ import { z as z77 } from "zod";
16952
17799
 
16953
17800
  // src/resolve-image.ts
16954
17801
  import { lookup as dnsLookup } from "dns/promises";
@@ -17509,10 +18356,10 @@ async function resolveMediaRef(ref, opts) {
17509
18356
  __name(resolveMediaRef, "resolveMediaRef");
17510
18357
 
17511
18358
  // src/tools/shared.ts
17512
- import { z as z70 } from "zod";
17513
- var Lang = z70.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);
17514
- var Country = z70.string().min(2).max(3);
17515
- var LandingStrategyEnum = z70.enum([
18359
+ import { z as z74 } from "zod";
18360
+ var Lang = z74.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);
18361
+ var Country = z74.string().min(2).max(3);
18362
+ var LandingStrategyEnum = z74.enum([
17516
18363
  "auto",
17517
18364
  "classic",
17518
18365
  "pain_solution",
@@ -17521,12 +18368,12 @@ var LandingStrategyEnum = z70.enum([
17521
18368
  "offer_value",
17522
18369
  "lifestyle_identity"
17523
18370
  ]);
17524
- var LandingImageFormatEnum = z70.enum([
18371
+ var LandingImageFormatEnum = z74.enum([
17525
18372
  "9:16",
17526
18373
  "4:5",
17527
18374
  "1:1"
17528
18375
  ]);
17529
- var VideoPresetEnum = z70.enum([
18376
+ var VideoPresetEnum = z74.enum([
17530
18377
  "auto",
17531
18378
  "ugc_dynamic",
17532
18379
  "ugc_how_to",
@@ -17539,21 +18386,21 @@ var VideoPresetEnum = z70.enum([
17539
18386
  "pixar_problem",
17540
18387
  "pixar_sassy"
17541
18388
  ]);
17542
- var VideoStructureEnum = z70.enum([
18389
+ var VideoStructureEnum = z74.enum([
17543
18390
  "single_take",
17544
18391
  "multi_scene"
17545
18392
  ]);
17546
- var VideoQualityEnum = z70.enum([
18393
+ var VideoQualityEnum = z74.enum([
17547
18394
  "economy",
17548
18395
  "medium",
17549
18396
  "pro"
17550
18397
  ]);
17551
- var VideoRouteIdEnum = z70.enum([
18398
+ var VideoRouteIdEnum = z74.enum([
17552
18399
  "single_take",
17553
18400
  "multi_scene",
17554
18401
  "free"
17555
18402
  ]);
17556
- var TaskCreativeVariantVideoPresetEnum = z70.enum([
18403
+ var TaskCreativeVariantVideoPresetEnum = z74.enum([
17557
18404
  "auto",
17558
18405
  "ugc_dynamic",
17559
18406
  "ugc_how_to",
@@ -17570,53 +18417,43 @@ var VIDEO_PRESET_RESOLUTION = {
17570
18417
  auto: null,
17571
18418
  ugc_dynamic: {
17572
18419
  videoStyle: "ai_dynamic",
17573
- narrativeStyle: "review",
17574
- videoModel: "veo"
18420
+ narrativeStyle: "review"
17575
18421
  },
17576
18422
  ugc_how_to: {
17577
18423
  videoStyle: "ai_dynamic",
17578
- narrativeStyle: "ugc_how_to",
17579
- videoModel: "veo"
18424
+ narrativeStyle: "ugc_how_to"
17580
18425
  },
17581
18426
  ugc_unboxing_chaos: {
17582
18427
  videoStyle: "ai_dynamic",
17583
- narrativeStyle: "ugc_unboxing_chaos",
17584
- videoModel: "veo"
18428
+ narrativeStyle: "ugc_unboxing_chaos"
17585
18429
  },
17586
18430
  problem_solution: {
17587
18431
  videoStyle: "ai_dynamic",
17588
- narrativeStyle: "problem_product_cta",
17589
- videoModel: "kling"
18432
+ narrativeStyle: "problem_product_cta"
17590
18433
  },
17591
18434
  pixar_problem: {
17592
18435
  videoStyle: "ai_dynamic",
17593
- narrativeStyle: "animated_problem_pixar",
17594
- videoModel: "kling"
18436
+ narrativeStyle: "animated_problem_pixar"
17595
18437
  },
17596
18438
  pixar_sassy: {
17597
18439
  videoStyle: "ai_dynamic",
17598
- narrativeStyle: "sassy_product_pixar",
17599
- videoModel: "seedance"
18440
+ narrativeStyle: "sassy_product_pixar"
17600
18441
  },
17601
18442
  product_showcase: {
17602
18443
  videoStyle: "product_only",
17603
- narrativeStyle: "product_showcase",
17604
- videoModel: "veo"
18444
+ narrativeStyle: "product_showcase"
17605
18445
  },
17606
18446
  wearable_showcase: {
17607
18447
  videoStyle: "ugc",
17608
- narrativeStyle: "wearable_showcase",
17609
- videoModel: "veo"
18448
+ narrativeStyle: "wearable_showcase"
17610
18449
  },
17611
18450
  cinematic: {
17612
18451
  videoStyle: "product_only",
17613
- narrativeStyle: "cinematic",
17614
- videoModel: "grok"
18452
+ narrativeStyle: "cinematic"
17615
18453
  },
17616
18454
  wild_card: {
17617
18455
  videoStyle: "product_only",
17618
- narrativeStyle: "wild_card",
17619
- videoModel: "grok"
18456
+ narrativeStyle: "wild_card"
17620
18457
  }
17621
18458
  };
17622
18459
  function resolveVideoPreset(preset) {
@@ -17624,7 +18461,7 @@ function resolveVideoPreset(preset) {
17624
18461
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
17625
18462
  }
17626
18463
  __name(resolveVideoPreset, "resolveVideoPreset");
17627
- var VideoTierEnum = z70.enum([
18464
+ var VideoTierEnum = z74.enum([
17628
18465
  "basic"
17629
18466
  ]);
17630
18467
  function resolveVideoTier(_tier) {
@@ -17664,22 +18501,22 @@ function assertSemanticVideoDurationCompatibility(structure, quality, durationSe
17664
18501
  }
17665
18502
  }
17666
18503
  __name(assertSemanticVideoDurationCompatibility, "assertSemanticVideoDurationCompatibility");
17667
- var VideoResolutionEnum = z70.enum([
18504
+ var VideoResolutionEnum = z74.enum([
17668
18505
  "480p",
17669
18506
  "720p"
17670
18507
  ]);
17671
- var CreativeGenderEnum = z70.enum([
18508
+ var CreativeGenderEnum = z74.enum([
17672
18509
  "female",
17673
18510
  "male",
17674
18511
  "mixed"
17675
18512
  ]);
17676
- var VideoStyleEnum = z70.enum([
18513
+ var VideoStyleEnum = z74.enum([
17677
18514
  "ugc",
17678
18515
  "cartoon_3d",
17679
18516
  "product_only",
17680
18517
  "ai_dynamic"
17681
18518
  ]);
17682
- var NarrativeStyleEnum = z70.enum([
18519
+ var NarrativeStyleEnum = z74.enum([
17683
18520
  "review",
17684
18521
  "ugc_how_to",
17685
18522
  "problem_product_cta",
@@ -17697,7 +18534,7 @@ var NarrativeStyleEnum = z70.enum([
17697
18534
  "ugc_demo_review",
17698
18535
  "market"
17699
18536
  ]);
17700
- var PublicNarrativeStyleEnum = z70.enum([
18537
+ var PublicNarrativeStyleEnum = z74.enum([
17701
18538
  "review",
17702
18539
  "ugc_how_to",
17703
18540
  "ugc_unboxing_chaos",
@@ -17710,7 +18547,7 @@ var PublicNarrativeStyleEnum = z70.enum([
17710
18547
  "sassy_product_pixar",
17711
18548
  "market"
17712
18549
  ]);
17713
- var VideoModelEnum = z70.enum([
18550
+ var TaskVideoModelEnum = z74.enum([
17714
18551
  "veo",
17715
18552
  "wan",
17716
18553
  "bytedance",
@@ -17718,29 +18555,29 @@ var VideoModelEnum = z70.enum([
17718
18555
  "grok",
17719
18556
  "kling"
17720
18557
  ]);
17721
- var ProductReferenceUserChoiceEnum = z70.enum([
18558
+ var ProductReferenceUserChoiceEnum = z74.enum([
17722
18559
  "same_product",
17723
18560
  "variants",
17724
18561
  "different_products",
17725
18562
  "combo_distinct"
17726
18563
  ]);
17727
- var ProductReferenceCandidateGroupingEnum = z70.enum([
18564
+ var ProductReferenceCandidateGroupingEnum = z74.enum([
17728
18565
  "same_product_same_variant",
17729
18566
  "same_product_different_variants",
17730
18567
  "different_products",
17731
18568
  "unclear"
17732
18569
  ]);
17733
- var ProductReferenceScopeEnum = z70.enum([
18570
+ var ProductReferenceScopeEnum = z74.enum([
17734
18571
  "base",
17735
18572
  "video_view_pack"
17736
18573
  ]);
17737
- var ProductReferenceResolutionDecisionEnum = z70.enum([
18574
+ var ProductReferenceResolutionDecisionEnum = z74.enum([
17738
18575
  "approve",
17739
18576
  "reject",
17740
18577
  "observed_only",
17741
18578
  "correct_view"
17742
18579
  ]);
17743
- var ProductReferenceRejectionReasonEnum = z70.enum([
18580
+ var ProductReferenceRejectionReasonEnum = z74.enum([
17744
18581
  "replacement_requested",
17745
18582
  "wrong_product_identity",
17746
18583
  "wrong_variant",
@@ -17751,13 +18588,13 @@ var ProductReferenceRejectionReasonEnum = z70.enum([
17751
18588
  "not_a_product_photo",
17752
18589
  "other"
17753
18590
  ]);
17754
- var GapDurationChoiceMirror = z70.object({
17755
- angleIndex: z70.number().int().nonnegative(),
17756
- recommendedSec: z70.union([
17757
- z70.literal(15),
17758
- z70.literal(30)
18591
+ var GapDurationChoiceMirror = z74.object({
18592
+ angleIndex: z74.number().int().nonnegative(),
18593
+ recommendedSec: z74.union([
18594
+ z74.literal(15),
18595
+ z74.literal(30)
17759
18596
  ]),
17760
- estimatedDeltaCredits: z70.number().int().nonnegative().optional()
18597
+ estimatedDeltaCredits: z74.number().int().nonnegative().optional()
17761
18598
  });
17762
18599
  function buildSelectedImageUrlsHash(urls) {
17763
18600
  const input = [
@@ -17767,13 +18604,13 @@ function buildSelectedImageUrlsHash(urls) {
17767
18604
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
17768
18605
  }
17769
18606
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
17770
- var ImageCreativeStyleEnum = z70.enum([
18607
+ var ImageCreativeStyleEnum = z74.enum([
17771
18608
  "studio",
17772
18609
  "floating",
17773
18610
  "ingredients",
17774
18611
  "in_use"
17775
18612
  ]);
17776
- var ImageCreativeArchetypeEnum = z70.enum([
18613
+ var ImageCreativeArchetypeEnum = z74.enum([
17777
18614
  "direct_response_product_ad",
17778
18615
  "hero_outcome",
17779
18616
  "offer_value_prop",
@@ -17782,20 +18619,20 @@ var ImageCreativeArchetypeEnum = z70.enum([
17782
18619
  "problem_solution",
17783
18620
  "lifestyle_identity"
17784
18621
  ]);
17785
- var ImageCreativeVisualTreatmentEnum = z70.enum([
18622
+ var ImageCreativeVisualTreatmentEnum = z74.enum([
17786
18623
  "performance_product_ad",
17787
18624
  "premium_dtc_carousel"
17788
18625
  ]);
17789
- var ImageCreativeAspectRatioEnum = z70.enum([
18626
+ var ImageCreativeAspectRatioEnum = z74.enum([
17790
18627
  "1:1",
17791
18628
  "4:5",
17792
18629
  "9:16",
17793
18630
  "16:9"
17794
18631
  ]);
17795
- var ImageRefSchema = z70.object({
17796
- url: z70.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.'),
17797
- path: z70.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`.'),
17798
- assetId: z70.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.")
18632
+ var ImageRefSchema = z74.object({
18633
+ url: z74.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.'),
18634
+ path: z74.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`.'),
18635
+ assetId: z74.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.")
17799
18636
  }).refine((v) => [
17800
18637
  v.url,
17801
18638
  v.path,
@@ -17803,11 +18640,11 @@ var ImageRefSchema = z70.object({
17803
18640
  ].filter(Boolean).length === 1, {
17804
18641
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
17805
18642
  });
17806
- var ImagesInput = z70.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
18643
+ var ImagesInput = z74.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
17807
18644
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
17808
18645
  if (assetCount > 0 && assetCount !== images.length) {
17809
18646
  ctx.addIssue({
17810
- code: z70.ZodIssueCode.custom,
18647
+ code: z74.ZodIssueCode.custom,
17811
18648
  message: "all image entries must use assetId, or all must use URL/path sources"
17812
18649
  });
17813
18650
  }
@@ -17875,14 +18712,14 @@ async function submitCreative(api, opts) {
17875
18712
  });
17876
18713
  }
17877
18714
  __name(submitCreative, "submitCreative");
17878
- var ResearchTargetCountryEnum = z70.enum([
18715
+ var ResearchTargetCountryEnum = z74.enum([
17879
18716
  "CO",
17880
18717
  "MX",
17881
18718
  "PE",
17882
18719
  "EC",
17883
18720
  "CL"
17884
18721
  ]);
17885
- var ResearchCategoryEnum = z70.enum([
18722
+ var ResearchCategoryEnum = z74.enum([
17886
18723
  "auto",
17887
18724
  "automotive",
17888
18725
  "kitchen",
@@ -17951,7 +18788,7 @@ var OVERWRITES_EXTERNAL = {
17951
18788
  idempotentHint: false,
17952
18789
  openWorldHint: false
17953
18790
  };
17954
- var DailyControlStatusEnum = z70.enum([
18791
+ var DailyControlStatusEnum = z74.enum([
17955
18792
  "ok",
17956
18793
  "sales_unavailable",
17957
18794
  "timezone_unavailable",
@@ -17964,19 +18801,19 @@ var DailyControlStatusEnum = z70.enum([
17964
18801
  "product_missing",
17965
18802
  "store_unreachable"
17966
18803
  ]);
17967
- var DailyControlLightEnum = z70.enum([
18804
+ var DailyControlLightEnum = z74.enum([
17968
18805
  "green",
17969
18806
  "amber",
17970
18807
  "red",
17971
18808
  "none"
17972
18809
  ]);
17973
- var DailyControlVerdictEnum = z70.enum([
18810
+ var DailyControlVerdictEnum = z74.enum([
17974
18811
  "scale",
17975
18812
  "hold",
17976
18813
  "kill",
17977
18814
  "insufficient_sample"
17978
18815
  ]);
17979
- var DailyControlSourceEnum = z70.enum([
18816
+ var DailyControlSourceEnum = z74.enum([
17980
18817
  "shopify",
17981
18818
  "shopify_settling",
17982
18819
  "user",
@@ -19064,29 +19901,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
19064
19901
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
19065
19902
 
19066
19903
  // src/tools/media-presentation.ts
19067
- import { z as z71 } from "zod";
19068
- var HttpsPresentationUrlSchema = z71.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
19904
+ import { z as z75 } from "zod";
19905
+ var HttpsPresentationUrlSchema = z75.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
19069
19906
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
19070
19907
  const hostname = new URL(value).hostname.toLowerCase();
19071
19908
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
19072
19909
  }, "preview URL must be owned by ProductMaker");
19073
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z71.number().int().positive().max(maximum), "positiveIntAtMost");
19074
- var PresentationImageSchema = z71.object({
19075
- kind: z71.literal("image"),
19910
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z75.number().int().positive().max(maximum), "positiveIntAtMost");
19911
+ var PresentationImageSchema = z75.object({
19912
+ kind: z75.literal("image"),
19076
19913
  url: HttpsPresentationUrlSchema,
19077
- mimeType: z71.enum([
19914
+ mimeType: z75.enum([
19078
19915
  "image/jpeg",
19079
19916
  "image/png"
19080
19917
  ]),
19081
19918
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
19082
19919
  width: positiveIntAtMost(16384),
19083
19920
  height: positiveIntAtMost(16384),
19084
- alt: z71.string().trim().min(1).max(240)
19921
+ alt: z75.string().trim().min(1).max(240)
19085
19922
  }).strict();
19086
19923
  var McpMediaPresentationSchema = PresentationImageSchema;
19087
- var GalleryImageSchema = z71.object({
19924
+ var GalleryImageSchema = z75.object({
19088
19925
  url: ProductMakerPreviewUrlSchema,
19089
- alt: z71.string().trim().min(1).max(240)
19926
+ alt: z75.string().trim().min(1).max(240)
19090
19927
  });
19091
19928
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
19092
19929
  async function imageBlocks(image, transport) {
@@ -19236,10 +20073,10 @@ ${summary}`,
19236
20073
  __name(requirePaidCreativeConfirmation, "requirePaidCreativeConfirmation");
19237
20074
 
19238
20075
  // src/tools/winning-product-image.ts
19239
- import { z as z72 } from "zod";
19240
- var WinnerReferenceInput = z72.object({
19241
- runId: z72.string().uuid(),
19242
- candidateSourceId: z72.string().trim().min(1).max(160)
20076
+ import { z as z76 } from "zod";
20077
+ var WinnerReferenceInput = z76.object({
20078
+ runId: z76.string().uuid(),
20079
+ candidateSourceId: z76.string().trim().min(1).max(160)
19243
20080
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
19244
20081
  async function resolveWinnerImages(api, winnerReference, images) {
19245
20082
  if (!winnerReference) return images;
@@ -19276,189 +20113,190 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
19276
20113
  var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
19277
20114
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
19278
20115
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
19279
- var CreateProductTaskInput = z73.object({
20116
+ var CreateProductTaskInput = z77.object({
19280
20117
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
19281
20118
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
19282
- projectId: z73.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
19283
- productUrl: z73.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."),
20119
+ projectId: z77.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
20120
+ productUrl: z77.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."),
19284
20121
  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.'),
19285
20122
  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.'),
19286
- price: z73.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.'),
19287
- compareAtPrice: z73.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".'),
19288
- offer: z73.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.'),
19289
- paymentMethods: z73.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.'),
19290
- 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."),
19291
- productLabel: z73.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.'),
20123
+ price: z77.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.'),
20124
+ compareAtPrice: z77.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".'),
20125
+ offer: z77.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.'),
20126
+ paymentMethods: z77.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.'),
20127
+ 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."),
20128
+ productLabel: z77.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.'),
19292
20129
  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.'),
19293
- durationSeconds: z73.union([
19294
- z73.literal(15),
19295
- z73.literal(30)
20130
+ durationSeconds: z77.union([
20131
+ z77.literal(15),
20132
+ z77.literal(30)
19296
20133
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
19297
- pauseForAngleReview: z73.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."),
19298
- aiDecidesAll: z73.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."),
20134
+ pauseForAngleReview: z77.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."),
20135
+ aiDecidesAll: z77.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."),
19299
20136
  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.'),
19300
20137
  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.'),
19301
20138
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
19302
20139
  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).'),
19303
- videoAngleCount: z73.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."),
20140
+ videoAngleCount: z77.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."),
19304
20141
  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.'),
19305
- outputs: z73.array(z73.enum([
20142
+ outputs: z77.array(z77.enum([
19306
20143
  "landing",
19307
20144
  "video",
19308
20145
  "image"
19309
20146
  ])).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}`),
19310
- 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). 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."),
19311
- replicateWinnerWhenFound: z73.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."),
19312
- 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 los outputs generados."),
19313
- actorId: z73.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."),
20147
+ 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). 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."),
20148
+ replicateWinnerWhenFound: z77.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."),
20149
+ 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 los outputs generados."),
20150
+ actorId: z77.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."),
19314
20151
  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.'),
19315
- creativeDirection: z73.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.'),
19316
- headline: z73.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."),
19317
- subheadline: z73.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."),
20152
+ creativeDirection: z77.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.'),
20153
+ headline: z77.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."),
20154
+ subheadline: z77.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."),
19318
20155
  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".'),
19319
20156
  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".')
19320
20157
  }).strict();
19321
- var CreateServiceVideoInput = z73.object({
19322
- landingUrl: z73.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
19323
- additionalContext: z73.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
20158
+ var CreateServiceVideoInput = z77.object({
20159
+ landingUrl: z77.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
20160
+ additionalContext: z77.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
19324
20161
  language: Lang.describe("Idioma del video: es, en o pt."),
19325
- voiceId: z73.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.'),
19326
- brandId: z73.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
19327
- reviewMode: z73.enum([
20162
+ voiceId: z77.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.'),
20163
+ brandId: z77.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
20164
+ reviewMode: z77.enum([
19328
20165
  "automatic",
19329
20166
  "guided"
19330
20167
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
19331
- videoPreset: z73.enum([
20168
+ videoPreset: z77.enum([
19332
20169
  "auto",
19333
20170
  "ugc_dynamic",
19334
20171
  "ugc_how_to",
19335
20172
  "cinematic",
19336
20173
  "wild_card"
19337
20174
  ]).default("auto"),
19338
- videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.')
20175
+ videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
20176
+ 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.')
19339
20177
  }).strict();
19340
- var GetTaskStatusInput = z73.object({
19341
- taskId: z73.string().min(1),
19342
- waitSeconds: z73.number().int().min(0).max(120).optional()
20178
+ var GetTaskStatusInput = z77.object({
20179
+ taskId: z77.string().min(1),
20180
+ waitSeconds: z77.number().int().min(0).max(120).optional()
19343
20181
  });
19344
- var ListTasksInput = z73.object({
19345
- limit: z73.number().int().min(1).max(50).optional(),
19346
- offset: z73.number().int().min(0).optional(),
19347
- search: z73.string().optional()
20182
+ var ListTasksInput = z77.object({
20183
+ limit: z77.number().int().min(1).max(50).optional(),
20184
+ offset: z77.number().int().min(0).optional(),
20185
+ search: z77.string().optional()
19348
20186
  });
19349
20187
  var MCP_REVIEW_LIST_FIELD_MAX = 1500;
19350
20188
  var MCP_REVIEW_FEATURE_ITEM_MAX = 240;
19351
- var EditTaskDraftInput = z73.object({
19352
- taskId: z73.string().min(1),
19353
- angleIndex: z73.number().int().min(0),
19354
- angle: z73.object({
19355
- angle: z73.string().min(1).max(480),
19356
- buyerPersona: z73.string().min(1).max(360),
19357
- actor: z73.string().min(1).max(360).optional(),
19358
- actorId: z73.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."),
19359
- gender: z73.enum([
20189
+ var EditTaskDraftInput = z77.object({
20190
+ taskId: z77.string().min(1),
20191
+ angleIndex: z77.number().int().min(0),
20192
+ angle: z77.object({
20193
+ angle: z77.string().min(1).max(480),
20194
+ buyerPersona: z77.string().min(1).max(360),
20195
+ actor: z77.string().min(1).max(360).optional(),
20196
+ actorId: z77.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."),
20197
+ gender: z77.enum([
19360
20198
  "female",
19361
20199
  "male"
19362
20200
  ]).optional(),
19363
- scriptNotes: z73.string().max(2e3).optional()
20201
+ scriptNotes: z77.string().max(2e3).optional()
19364
20202
  })
19365
20203
  });
19366
- var PendingActionPayload = z73.discriminatedUnion("kind", [
19367
- z73.object({
19368
- kind: z73.literal("product_reference_set_approval"),
20204
+ var PendingActionPayload = z77.discriminatedUnion("kind", [
20205
+ z77.object({
20206
+ kind: z77.literal("product_reference_set_approval"),
19369
20207
  scope: ProductReferenceScopeEnum.optional(),
19370
- scopeKey: z73.string().min(1).max(120).optional(),
19371
- scopeSnapshotId: z73.string().uuid().optional(),
19372
- expectedScopeHash: z73.string().min(1).max(128).optional(),
20208
+ scopeKey: z77.string().min(1).max(120).optional(),
20209
+ scopeSnapshotId: z77.string().uuid().optional(),
20210
+ expectedScopeHash: z77.string().min(1).max(128).optional(),
19373
20211
  decision: ProductReferenceResolutionDecisionEnum,
19374
20212
  reason: ProductReferenceRejectionReasonEnum.optional(),
19375
- affectedRefKeys: z73.array(z73.string().min(1).max(200)).min(1).optional(),
19376
- affectedPhotoNumbers: z73.array(z73.number().int().positive()).min(1).optional(),
19377
- recoveryAction: z73.enum([
20213
+ affectedRefKeys: z77.array(z77.string().min(1).max(200)).min(1).optional(),
20214
+ affectedPhotoNumbers: z77.array(z77.number().int().positive()).min(1).optional(),
20215
+ recoveryAction: z77.enum([
19378
20216
  "remove",
19379
20217
  "replace",
19380
20218
  "upload",
19381
20219
  "return_to_selection"
19382
20220
  ]).optional()
19383
20221
  }),
19384
- z73.object({
19385
- kind: z73.literal("product_reference_confirmation"),
19386
- selectedPhotoNumbers: z73.array(z73.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."),
20222
+ z77.object({
20223
+ kind: z77.literal("product_reference_confirmation"),
20224
+ selectedPhotoNumbers: z77.array(z77.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."),
19387
20225
  userChoice: ProductReferenceUserChoiceEnum.optional(),
19388
- confirmedProductNames: z73.array(z73.string().min(1).max(120)).min(2).max(8).optional(),
20226
+ confirmedProductNames: z77.array(z77.string().min(1).max(120)).min(2).max(8).optional(),
19389
20227
  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."),
19390
20228
  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."),
19391
- useMultiSceneShowcase: z73.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
20229
+ useMultiSceneShowcase: z77.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
19392
20230
  }),
19393
- z73.object({
19394
- kind: z73.literal("angle_review_approval"),
20231
+ z77.object({
20232
+ kind: z77.literal("angle_review_approval"),
19395
20233
  // All edits are optional — empty action body just approves the
19396
20234
  // backend-generated draft as-is. Field shapes mirror the angle-review
19397
20235
  // request contracts in @packages/types/wizard.ts; the handler routes to
19398
20236
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
19399
- customAngle: z73.string().min(1).max(480).optional(),
20237
+ customAngle: z77.string().min(1).max(480).optional(),
19400
20238
  // Keep the shared MCP action within the strictest downstream contract:
19401
20239
  // autopilot/image resume endpoints cap these fields at 1500 characters.
19402
- painPoints: z73.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19403
- benefits: z73.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
20240
+ painPoints: z77.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
20241
+ benefits: z77.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19404
20242
  // Same policy as the two fields above: the strictest downstream contract
19405
20243
  // wins. The image endpoint caps each feature at 240 while landing/video
19406
20244
  // accept 300, and this single action routes to whichever the task is — so
19407
20245
  // accepting 300 here turns a 250-character feature on an image task into
19408
20246
  // an opaque HTTP 400 after the model already believed it had been saved.
19409
- features: z73.array(z73.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
19410
- buyerPersona: z73.string().min(1).max(360).optional(),
20247
+ features: z77.array(z77.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
20248
+ buyerPersona: z77.string().min(1).max(360).optional(),
19411
20249
  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.'),
19412
- actor: z73.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."),
19413
- actorId: z73.string().max(120).nullable().optional(),
19414
- creativeDirection: z73.string().max(2e3).optional(),
19415
- selectedAngleNumbers: z73.array(z73.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."),
19416
- angleEdits: z73.array(z73.object({
19417
- angleNumber: z73.number().int().positive(),
19418
- narrativeSelection: z73.enum([
20250
+ actor: z77.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."),
20251
+ actorId: z77.string().max(120).nullable().optional(),
20252
+ creativeDirection: z77.string().max(2e3).optional(),
20253
+ selectedAngleNumbers: z77.array(z77.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."),
20254
+ angleEdits: z77.array(z77.object({
20255
+ angleNumber: z77.number().int().positive(),
20256
+ narrativeSelection: z77.enum([
19419
20257
  "market",
19420
20258
  "guided"
19421
20259
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
19422
- angle: z73.string().min(1).max(480).optional(),
19423
- buyerPersona: z73.string().min(1).max(360).optional(),
20260
+ angle: z77.string().min(1).max(480).optional(),
20261
+ buyerPersona: z77.string().min(1).max(360).optional(),
19424
20262
  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.'),
19425
- actor: z73.string().min(1).max(360).optional(),
19426
- actorId: z73.string().max(120).nullable().optional(),
19427
- creativeDirection: z73.string().max(2e3).optional()
20263
+ actor: z77.string().min(1).max(360).optional(),
20264
+ actorId: z77.string().max(120).nullable().optional(),
20265
+ creativeDirection: z77.string().max(2e3).optional()
19428
20266
  }).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)."),
19429
- gapDurationSeconds: z73.union([
19430
- z73.literal(15),
19431
- z73.literal(30)
20267
+ gapDurationSeconds: z77.union([
20268
+ z77.literal(15),
20269
+ z77.literal(30)
19432
20270
  ]).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.")
19433
20271
  }),
19434
- z73.object({
19435
- kind: z73.literal("service_angle_approval"),
19436
- angleId: z73.string().uuid().optional(),
19437
- angleNumber: z73.number().int().positive().optional(),
19438
- content: z73.string().min(1).max(480).optional(),
19439
- creativeDirection: z73.string().min(1).max(1500).optional(),
19440
- actor: z73.string().min(1).max(360).optional()
20272
+ z77.object({
20273
+ kind: z77.literal("service_angle_approval"),
20274
+ angleId: z77.string().uuid().optional(),
20275
+ angleNumber: z77.number().int().positive().optional(),
20276
+ content: z77.string().min(1).max(480).optional(),
20277
+ creativeDirection: z77.string().min(1).max(1500).optional(),
20278
+ actor: z77.string().min(1).max(360).optional()
19441
20279
  }),
19442
- z73.object({
19443
- kind: z73.literal("service_script_approval"),
19444
- voiceovers: z73.record(z73.string(), z73.string().min(1).max(600)).optional(),
19445
- visualDirections: z73.record(z73.string(), z73.string().min(1).max(1200)).optional(),
19446
- voiceoversByScene: z73.record(z73.string(), z73.string().min(1).max(600)).optional(),
19447
- visualDirectionsByScene: z73.record(z73.string(), z73.string().min(1).max(1200)).optional()
20280
+ z77.object({
20281
+ kind: z77.literal("service_script_approval"),
20282
+ voiceovers: z77.record(z77.string(), z77.string().min(1).max(600)).optional(),
20283
+ visualDirections: z77.record(z77.string(), z77.string().min(1).max(1200)).optional(),
20284
+ voiceoversByScene: z77.record(z77.string(), z77.string().min(1).max(600)).optional(),
20285
+ visualDirectionsByScene: z77.record(z77.string(), z77.string().min(1).max(1200)).optional()
19448
20286
  })
19449
20287
  ]);
19450
- var ResolvePendingActionInput = z73.object({
19451
- taskId: z73.string().min(1),
20288
+ var ResolvePendingActionInput = z77.object({
20289
+ taskId: z77.string().min(1),
19452
20290
  action: PendingActionPayload
19453
20291
  }).strict();
19454
20292
  function resolveVariantConfirmVideoTier(action) {
19455
20293
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
19456
20294
  }
19457
20295
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
19458
- var StatusForResolveSchema = z73.object({
20296
+ var StatusForResolveSchema = z77.object({
19459
20297
  // Metadata used to select the backend resume contract. Older API responses
19460
20298
  // may omit these fields, so the resolver keeps the generic fallback.
19461
- kind: z73.enum([
20299
+ kind: z77.enum([
19462
20300
  "autopilot",
19463
20301
  "video",
19464
20302
  "image",
@@ -19466,18 +20304,18 @@ var StatusForResolveSchema = z73.object({
19466
20304
  "mix",
19467
20305
  "service"
19468
20306
  ]).optional(),
19469
- selectedOutputs: z73.array(z73.enum([
20307
+ selectedOutputs: z77.array(z77.enum([
19470
20308
  "landing",
19471
20309
  "video",
19472
20310
  "image"
19473
20311
  ])).optional(),
19474
- videoAngleCount: z73.number().int().min(1).max(3).optional(),
19475
- ugcFormat: z73.enum([
20312
+ videoAngleCount: z77.number().int().min(1).max(3).optional(),
20313
+ ugcFormat: z77.enum([
19476
20314
  "single_8s",
19477
20315
  "single_15s",
19478
20316
  "double_30s"
19479
20317
  ]).optional(),
19480
- videoStyle: z73.enum([
20318
+ videoStyle: z77.enum([
19481
20319
  "ugc",
19482
20320
  "cartoon_3d",
19483
20321
  "product_only",
@@ -19486,79 +20324,72 @@ var StatusForResolveSchema = z73.object({
19486
20324
  videoStructure: VideoStructureEnum.optional(),
19487
20325
  videoQuality: VideoQualityEnum.optional(),
19488
20326
  videoRouteId: VideoRouteIdEnum.optional(),
19489
- videoModel: z73.enum([
19490
- "veo",
19491
- "wan",
19492
- "bytedance",
19493
- "seedance",
19494
- "grok",
19495
- "kling"
19496
- ]).optional(),
19497
- videoTier: z73.enum([
20327
+ videoModel: TaskVideoModelEnum.optional(),
20328
+ videoTier: z77.enum([
19498
20329
  "legacy",
19499
20330
  "standard",
19500
20331
  "pro",
19501
20332
  "single_call"
19502
20333
  ]).optional(),
19503
- videoResolution: z73.enum([
20334
+ videoResolution: z77.enum([
19504
20335
  "480p",
19505
20336
  "720p"
19506
20337
  ]).optional(),
19507
20338
  narrativeStyle: NarrativeStyleEnum.optional(),
19508
- pauseForVideoScriptReview: z73.boolean().optional(),
19509
- pendingUserAction: z73.object({
19510
- kind: z73.string(),
19511
- candidateGrouping: z73.string().optional(),
19512
- selectedImageUrls: z73.array(z73.string()).optional(),
19513
- proposedProductNames: z73.array(z73.string()).optional(),
20339
+ pauseForVideoScriptReview: z77.boolean().optional(),
20340
+ pendingUserAction: z77.object({
20341
+ kind: z77.string(),
20342
+ candidateGrouping: z77.string().optional(),
20343
+ selectedImageUrls: z77.array(z77.string()).optional(),
20344
+ proposedProductNames: z77.array(z77.string()).optional(),
19514
20345
  // Adaptive reference questions are server-owned. Echo only the evidence
19515
20346
  // identity and the choices shown by the current snapshot; never accept a
19516
20347
  // client-supplied reference set as authorization.
19517
- options: z73.array(ProductReferenceUserChoiceEnum).max(4).optional(),
19518
- mode: z73.enum([
20348
+ options: z77.array(ProductReferenceUserChoiceEnum).max(4).optional(),
20349
+ mode: z77.enum([
19519
20350
  "question",
19520
20351
  "visual_recovery"
19521
20352
  ]).optional(),
19522
20353
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
19523
- canKeepSelection: z73.boolean().optional(),
19524
- decisionKey: z73.string().optional(),
19525
- questionOrdinal: z73.number().int().min(1).max(5).optional(),
19526
- questionCeiling: z73.union([
19527
- z73.literal(3),
19528
- z73.literal(5)
20354
+ canKeepSelection: z77.boolean().optional(),
20355
+ decisionKey: z77.string().optional(),
20356
+ questionOrdinal: z77.number().int().min(1).max(5).optional(),
20357
+ questionCeiling: z77.union([
20358
+ z77.literal(3),
20359
+ z77.literal(5)
19529
20360
  ]).optional(),
19530
- referenceEvidenceVersion: z73.number().int().positive().optional(),
19531
- expectedEvidenceHash: z73.string().optional(),
19532
- question: z73.object({
19533
- prompt: z73.string().min(1).max(240),
19534
- helpText: z73.string().min(1).max(300).optional(),
19535
- options: z73.array(z73.object({
20361
+ referenceEvidenceVersion: z77.number().int().positive().optional(),
20362
+ expectedEvidenceHash: z77.string().optional(),
20363
+ question: z77.object({
20364
+ prompt: z77.string().min(1).max(240),
20365
+ helpText: z77.string().min(1).max(300).optional(),
20366
+ options: z77.array(z77.object({
19536
20367
  value: ProductReferenceUserChoiceEnum,
19537
- label: z73.string().min(1).max(120),
19538
- description: z73.string().min(1).max(240).optional()
20368
+ label: z77.string().min(1).max(120),
20369
+ description: z77.string().min(1).max(240).optional()
19539
20370
  })).min(2).max(4)
19540
20371
  }).optional(),
19541
20372
  scope: ProductReferenceScopeEnum.optional(),
19542
- scopeKey: z73.string().optional(),
19543
- scopeSnapshotId: z73.string().uuid().optional(),
19544
- scopeHash: z73.string().optional(),
19545
- baseReferenceSetHash: z73.string().optional(),
19546
- phase: z73.enum([
20373
+ scopeKey: z77.string().optional(),
20374
+ scopeSnapshotId: z77.string().uuid().optional(),
20375
+ scopeHash: z77.string().optional(),
20376
+ baseReferenceSetHash: z77.string().optional(),
20377
+ phase: z77.enum([
19547
20378
  "preparation",
19548
20379
  "final"
19549
20380
  ]).optional(),
19550
- selectedRefKeys: z73.array(z73.string().min(1).max(200)).optional(),
19551
- allowedDecisions: z73.array(ProductReferenceResolutionDecisionEnum).optional(),
19552
- previews: z73.array(z73.object({
19553
- refKey: z73.string().min(1).max(200)
20381
+ selectedRefKeys: z77.array(z77.string().min(1).max(200)).optional(),
20382
+ allowedDecisions: z77.array(ProductReferenceResolutionDecisionEnum).optional(),
20383
+ previews: z77.array(z77.object({
20384
+ refKey: z77.string().min(1).max(200)
19554
20385
  }).passthrough()).optional(),
19555
- customAngleDraft: z73.string().optional(),
19556
- painPointsDraft: z73.string().optional(),
19557
- benefitsDraft: z73.string().optional(),
19558
- featuresDraft: z73.array(z73.string()).optional(),
19559
- angleOptions: z73.array(z73.object({
19560
- index: z73.number().int().nonnegative(),
19561
- angle: z73.string().min(1)
20386
+ customAngleDraft: z77.string().optional(),
20387
+ painPointsDraft: z77.string().optional(),
20388
+ benefitsDraft: z77.string().optional(),
20389
+ featuresDraft: z77.array(z77.string()).optional(),
20390
+ angleOptions: z77.array(z77.object({
20391
+ index: z77.number().int().nonnegative(),
20392
+ angle: z77.string().min(1)
19562
20393
  }).passthrough()).min(1).max(5).optional(),
19563
20394
  // Recommendation consumed only when the caller explicitly sends
19564
20395
  // gapDurationSeconds: 30 in the angle approval action.
@@ -19568,17 +20399,17 @@ var StatusForResolveSchema = z73.object({
19568
20399
  // keys. `actorId` (the saved custom actor the picker stored) was silently
19569
20400
  // dropped here, so the approval handler below could not echo it back on the
19570
20401
  // PATCH — the selection looked accepted and reached no render.
19571
- angles: z73.array(z73.object({
19572
- id: z73.string().uuid(),
19573
- content: z73.string(),
19574
- creativeDirection: z73.string(),
19575
- actor: z73.string(),
19576
- actorId: z73.string().nullable().optional()
20402
+ angles: z77.array(z77.object({
20403
+ id: z77.string().uuid(),
20404
+ content: z77.string(),
20405
+ creativeDirection: z77.string(),
20406
+ actor: z77.string(),
20407
+ actorId: z77.string().nullable().optional()
19577
20408
  }).passthrough()).optional(),
19578
- panels: z73.array(z73.object({
19579
- beatId: z73.string(),
19580
- voiceover: z73.string(),
19581
- visualDirection: z73.string()
20409
+ panels: z77.array(z77.object({
20410
+ beatId: z77.string(),
20411
+ voiceover: z77.string(),
20412
+ visualDirection: z77.string()
19582
20413
  }).passthrough()).optional()
19583
20414
  }).optional()
19584
20415
  }).passthrough();
@@ -19792,6 +20623,9 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
19792
20623
  });
19793
20624
  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) => {
19794
20625
  try {
20626
+ if (input.videoQuality === "medium" && input.videoResolution === "720p") {
20627
+ 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".');
20628
+ }
19795
20629
  await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
19796
20630
  const created = await api.postJson("/v2/ingest", {
19797
20631
  taskType: "service",
@@ -19805,6 +20639,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
19805
20639
  } : {},
19806
20640
  videoPreset: input.videoPreset,
19807
20641
  videoQuality: input.videoQuality,
20642
+ videoResolution: input.videoResolution,
19808
20643
  reviewMode: input.reviewMode,
19809
20644
  ...input.brandId ? {
19810
20645
  brandId: input.brandId
@@ -20409,7 +21244,7 @@ __name(registerTaskTools, "registerTaskTools");
20409
21244
 
20410
21245
  // src/tools/creatives.ts
20411
21246
  import { randomUUID } from "crypto";
20412
- import { z as z74 } from "zod";
21247
+ import { z as z78 } from "zod";
20413
21248
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
20414
21249
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
20415
21250
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -20419,70 +21254,70 @@ var CreativeRefs = {
20419
21254
  images: ImagesInput,
20420
21255
  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.'),
20421
21256
  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.'),
20422
- price: z74.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.'),
20423
- offer: z74.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.'),
20424
- compareAtPrice: z74.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
20425
- productContext: z74.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."),
20426
- productLabel: z74.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.'),
20427
- buyerPersona: z74.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.'),
20428
- isCombo: z74.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
20429
- competitorScanEnabled: z74.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."),
20430
- brandId: z74.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.")
21257
+ price: z78.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.'),
21258
+ offer: z78.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.'),
21259
+ compareAtPrice: z78.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
21260
+ productContext: z78.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."),
21261
+ productLabel: z78.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.'),
21262
+ buyerPersona: z78.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.'),
21263
+ isCombo: z78.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
21264
+ competitorScanEnabled: z78.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."),
21265
+ brandId: z78.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.")
20431
21266
  };
20432
- var VideoPresenter = z74.discriminatedUnion("mode", [
20433
- z74.object({
20434
- mode: z74.literal("none")
21267
+ var VideoPresenter = z78.discriminatedUnion("mode", [
21268
+ z78.object({
21269
+ mode: z78.literal("none")
20435
21270
  }).strict(),
20436
- z74.object({
20437
- mode: z74.literal("saved_actor"),
20438
- actorId: z74.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
21271
+ z78.object({
21272
+ mode: z78.literal("saved_actor"),
21273
+ actorId: z78.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
20439
21274
  }).strict(),
20440
- z74.object({
20441
- mode: z74.literal("described"),
20442
- description: z74.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
21275
+ z78.object({
21276
+ mode: z78.literal("described"),
21277
+ description: z78.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
20443
21278
  }).strict()
20444
21279
  ]);
20445
- var VideoCreativeSetup = z74.discriminatedUnion("mode", [
20446
- z74.object({
20447
- mode: z74.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
21280
+ var VideoCreativeSetup = z78.discriminatedUnion("mode", [
21281
+ z78.object({
21282
+ mode: z78.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
20448
21283
  }).strict(),
20449
- z74.object({
20450
- mode: z74.literal("guided"),
21284
+ z78.object({
21285
+ mode: z78.literal("guided"),
20451
21286
  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.'),
20452
- buyerPersona: z74.string().trim().min(1).max(360),
21287
+ buyerPersona: z78.string().trim().min(1).max(360),
20453
21288
  presenter: VideoPresenter,
20454
- creativeDirection: z74.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
21289
+ creativeDirection: z78.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
20455
21290
  }).strict()
20456
21291
  ]);
20457
- var VideoInput = z74.object({
21292
+ var VideoInput = z78.object({
20458
21293
  images: CreativeRefs.images.optional(),
20459
21294
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20460
- title: z74.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
20461
- primaryAngle: z74.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".'),
21295
+ title: z78.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
21296
+ primaryAngle: z78.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".'),
20462
21297
  language: CreativeRefs.language,
20463
21298
  country: CreativeRefs.country,
20464
- aspectRatio: z74.enum([
21299
+ aspectRatio: z78.enum([
20465
21300
  "9:16",
20466
21301
  "16:9",
20467
21302
  "Auto"
20468
21303
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
20469
- durationSeconds: z74.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."),
20470
- videoAngleCount: z74.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."),
21304
+ durationSeconds: z78.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."),
21305
+ videoAngleCount: z78.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."),
20471
21306
  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.'),
20472
21307
  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."),
20473
21308
  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.'),
20474
21309
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
20475
21310
  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.'),
20476
- features: z74.array(z74.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
21311
+ features: z78.array(z78.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
20477
21312
  price: CreativeRefs.price,
20478
21313
  offer: CreativeRefs.offer,
20479
21314
  productContext: CreativeRefs.productContext,
20480
21315
  productLabel: CreativeRefs.productLabel,
20481
- cta: z74.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.'),
20482
- scriptNotes: z74.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.'),
21316
+ cta: z78.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.'),
21317
+ scriptNotes: z78.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.'),
20483
21318
  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.'),
20484
21319
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
20485
- replicateWinnerWhenFound: z74.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."),
21320
+ replicateWinnerWhenFound: z78.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."),
20486
21321
  brandId: CreativeRefs.brandId
20487
21322
  }).strict();
20488
21323
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -20500,7 +21335,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
20500
21335
  length: 29
20501
21336
  }, (_, index) => index + 2)
20502
21337
  };
20503
- var FreeVideoModelIdEnum = z74.enum([
21338
+ var FreeVideoModelIdEnum = z78.enum([
20504
21339
  "grok-imagine-video-1-5-preview",
20505
21340
  "minimax-h3/reference-to-video",
20506
21341
  "wan/3-0-video",
@@ -20511,70 +21346,65 @@ var FREE_SELECTABLE_MODEL_IDS = [
20511
21346
  "minimax-h3/reference-to-video",
20512
21347
  "wan/3-0-video"
20513
21348
  ];
20514
- var FreeVideoInput = z74.object({
21349
+ var FreeVideoInput = z78.object({
20515
21350
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
20516
- rawPrompt: z74.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."),
21351
+ rawPrompt: z78.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."),
20517
21352
  language: CreativeRefs.language,
20518
21353
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
20519
21354
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
20520
21355
  // parsed ONLY so the handler can reject it with a message naming its
20521
21356
  // replacement — dropping it silently would turn a caller's explicit
20522
21357
  // Pro++ pick into a quiet fallback to Wan.
20523
- freeProModel: z74.enum([
21358
+ freeProModel: z78.enum([
20524
21359
  "wan",
20525
21360
  "seedance"
20526
21361
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
20527
21362
  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.'),
20528
- durationSeconds: z74.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."),
21363
+ durationSeconds: z78.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."),
20529
21364
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
20530
- generateAiMusic: z74.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
20531
- addSubtitles: z74.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
20532
- idempotencyKey: z74.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.")
21365
+ generateAiMusic: z78.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
21366
+ addSubtitles: z78.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
21367
+ idempotencyKey: z78.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.")
20533
21368
  }).strict();
20534
21369
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
20535
- var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20536
- z74.object({
20537
- mode: z74.literal("automatic")
21370
+ var ImageCreativeSetup = z78.discriminatedUnion("mode", [
21371
+ z78.object({
21372
+ mode: z78.literal("automatic")
20538
21373
  }).strict(),
20539
- z74.object({
20540
- mode: z74.literal("guided"),
20541
- creativeArchetype: z74.union([
21374
+ z78.object({
21375
+ mode: z78.literal("guided"),
21376
+ creativeArchetype: z78.union([
20542
21377
  ImageCreativeArchetypeEnum,
20543
- z74.literal("ai_decides")
21378
+ z78.literal("ai_decides")
20544
21379
  ]),
20545
- visualTreatment: z74.union([
21380
+ visualTreatment: z78.union([
20546
21381
  ImageCreativeVisualTreatmentEnum,
20547
- z74.literal("ai_decides")
21382
+ z78.literal("ai_decides")
20548
21383
  ]),
20549
21384
  aspectRatio: ImageCreativeAspectRatioEnum,
20550
- nVariants: z74.union([
20551
- z74.literal(1),
20552
- z74.literal(2),
20553
- z74.literal(3),
20554
- z74.literal(4),
20555
- z74.literal(6)
20556
- ]),
20557
- imageModel: z74.enum([
20558
- "gpt-image-2-5:1k",
20559
- "gpt-image-2-5:2k",
20560
- "gpt-image-2:1k",
20561
- "gpt-image-2:2k"
21385
+ nVariants: z78.union([
21386
+ z78.literal(1),
21387
+ z78.literal(2),
21388
+ z78.literal(3),
21389
+ z78.literal(4),
21390
+ z78.literal(6)
20562
21391
  ]),
20563
- styleMix: z74.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
20564
- generateAdCopy: z74.boolean(),
20565
- competitorScanEnabled: z74.boolean(),
20566
- productContext: z74.string().trim().min(1).max(3e3).nullable(),
20567
- creativeDirection: z74.string().trim().min(1).max(500).nullable(),
20568
- brandColors: z74.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.'),
20569
- headline: z74.string().trim().min(1).max(120).nullable(),
20570
- subheadline: z74.string().trim().min(1).max(160).nullable()
21392
+ imageModel: z78.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.'),
21393
+ styleMix: z78.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
21394
+ generateAdCopy: z78.boolean(),
21395
+ competitorScanEnabled: z78.boolean(),
21396
+ productContext: z78.string().trim().min(1).max(3e3).nullable(),
21397
+ creativeDirection: z78.string().trim().min(1).max(500).nullable(),
21398
+ brandColors: z78.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.'),
21399
+ headline: z78.string().trim().min(1).max(120).nullable(),
21400
+ subheadline: z78.string().trim().min(1).max(160).nullable()
20571
21401
  }).strict()
20572
21402
  ]).superRefine((setup, context) => {
20573
21403
  if (setup.mode !== "guided") return;
20574
21404
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
20575
21405
  if (needsStyleMix && setup.styleMix === null) {
20576
21406
  context.addIssue({
20577
- code: z74.ZodIssueCode.custom,
21407
+ code: z78.ZodIssueCode.custom,
20578
21408
  path: [
20579
21409
  "styleMix"
20580
21410
  ],
@@ -20583,16 +21413,16 @@ var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20583
21413
  }
20584
21414
  if (!needsStyleMix && setup.styleMix !== null) {
20585
21415
  context.addIssue({
20586
- code: z74.ZodIssueCode.custom,
21416
+ code: z78.ZodIssueCode.custom,
20587
21417
  path: [
20588
21418
  "styleMix"
20589
21419
  ],
20590
21420
  message: "styleMix debe ser null cuando nVariants es 1 o 6."
20591
21421
  });
20592
21422
  }
20593
- if ((setup.imageModel === "gpt-image-2:2k" || setup.imageModel === "gpt-image-2-5:2k") && setup.aspectRatio === "4:5") {
21423
+ if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
20594
21424
  context.addIssue({
20595
- code: z74.ZodIssueCode.custom,
21425
+ code: z78.ZodIssueCode.custom,
20596
21426
  path: [
20597
21427
  "aspectRatio"
20598
21428
  ],
@@ -20600,53 +21430,53 @@ var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20600
21430
  });
20601
21431
  }
20602
21432
  });
20603
- var LandingCreativeSetup = z74.discriminatedUnion("mode", [
20604
- z74.object({
20605
- mode: z74.literal("automatic")
21433
+ var LandingCreativeSetup = z78.discriminatedUnion("mode", [
21434
+ z78.object({
21435
+ mode: z78.literal("automatic")
20606
21436
  }).strict(),
20607
- z74.object({
20608
- mode: z74.literal("guided"),
21437
+ z78.object({
21438
+ mode: z78.literal("guided"),
20609
21439
  landingStrategy: LandingStrategyEnum,
20610
21440
  landingImageFormat: LandingImageFormatEnum,
20611
- competitorScanEnabled: z74.boolean(),
20612
- paymentMethods: z74.string().trim().min(1).max(240).nullable(),
20613
- productContext: z74.string().trim().min(1).max(3e3).nullable(),
20614
- creativeDirection: z74.string().trim().min(1).max(500).nullable(),
20615
- headline: z74.string().trim().min(1).max(120).nullable(),
20616
- subheadline: z74.string().trim().min(1).max(160).nullable()
21441
+ competitorScanEnabled: z78.boolean(),
21442
+ paymentMethods: z78.string().trim().min(1).max(240).nullable(),
21443
+ productContext: z78.string().trim().min(1).max(3e3).nullable(),
21444
+ creativeDirection: z78.string().trim().min(1).max(500).nullable(),
21445
+ headline: z78.string().trim().min(1).max(120).nullable(),
21446
+ subheadline: z78.string().trim().min(1).max(160).nullable()
20617
21447
  }).strict()
20618
21448
  ]);
20619
- var ImageInput = z74.object({
21449
+ var ImageInput = z78.object({
20620
21450
  images: CreativeRefs.images.optional(),
20621
21451
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20622
- productTitle: z74.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
20623
- primaryAngle: z74.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.'),
21452
+ productTitle: z78.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
21453
+ primaryAngle: z78.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.'),
20624
21454
  buyerPersona: CreativeRefs.buyerPersona,
20625
21455
  language: CreativeRefs.language,
20626
21456
  country: CreativeRefs.country,
20627
21457
  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."),
20628
21458
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
20629
- features: z74.array(z74.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
21459
+ features: z78.array(z78.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
20630
21460
  price: CreativeRefs.price,
20631
- omitPrice: z74.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."),
21461
+ omitPrice: z78.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."),
20632
21462
  compareAtPrice: CreativeRefs.compareAtPrice,
20633
21463
  offer: CreativeRefs.offer,
20634
21464
  productLabel: CreativeRefs.productLabel,
20635
21465
  isCombo: CreativeRefs.isCombo,
20636
21466
  brandId: CreativeRefs.brandId
20637
21467
  });
20638
- var EditImageCreativeInput = z74.object({
20639
- taskId: z74.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
20640
- variantIndex: z74.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
20641
- instruction: z74.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".')
21468
+ var EditImageCreativeInput = z78.object({
21469
+ taskId: z78.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
21470
+ variantIndex: z78.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
21471
+ instruction: z78.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".')
20642
21472
  });
20643
- var LandingInput = z74.object({
21473
+ var LandingInput = z78.object({
20644
21474
  images: CreativeRefs.images.optional(),
20645
21475
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20646
21476
  language: CreativeRefs.language,
20647
21477
  country: CreativeRefs.country,
20648
21478
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
20649
- salesAngle: z74.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.'),
21479
+ salesAngle: z78.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.'),
20650
21480
  buyerPersona: CreativeRefs.buyerPersona,
20651
21481
  price: CreativeRefs.price,
20652
21482
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -20665,7 +21495,7 @@ function resolveImageSetup(setup) {
20665
21495
  },
20666
21496
  aspectRatio: setup.aspectRatio,
20667
21497
  nVariants: setup.nVariants,
20668
- imageModel: setup.imageModel,
21498
+ imageModel: canonicalImageModelInput(setup.imageModel),
20669
21499
  ...setup.nVariants === 6 ? {
20670
21500
  styleMix: true
20671
21501
  } : setup.styleMix === null ? {} : {
@@ -20908,10 +21738,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
20908
21738
  __name(registerCreativeTools, "registerCreativeTools");
20909
21739
 
20910
21740
  // src/tools/creative-variants.ts
20911
- import { z as z75 } from "zod";
21741
+ import { z as z79 } from "zod";
20912
21742
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
20913
21743
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
20914
- var LandingSectionKeyEnum = z75.enum([
21744
+ var LandingSectionKeyEnum = z79.enum([
20915
21745
  "problem_hook",
20916
21746
  "problem_cost",
20917
21747
  "solution_mechanism",
@@ -20951,24 +21781,24 @@ var LandingSectionKeyEnum = z75.enum([
20951
21781
  "lifestyle_fit",
20952
21782
  "join_lifestyle"
20953
21783
  ]);
20954
- var CreativeVariantKindEnum = z75.enum([
21784
+ var CreativeVariantKindEnum = z79.enum([
20955
21785
  "video",
20956
21786
  "image",
20957
21787
  "landing"
20958
21788
  ]);
20959
- var EstimateCreativeVariantInputBase = z75.object({
20960
- sourceTaskId: z75.string().uuid().describe("ID de la tarea original completada."),
21789
+ var EstimateCreativeVariantInputBase = z79.object({
21790
+ sourceTaskId: z79.string().uuid().describe("ID de la tarea original completada."),
20961
21791
  kind: CreativeVariantKindEnum,
20962
21792
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
20963
21793
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
20964
- nVariants: z75.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
21794
+ nVariants: z79.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
20965
21795
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
20966
- instructions: z75.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.")
21796
+ instructions: z79.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.")
20967
21797
  }).strict();
20968
21798
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
20969
21799
  if (input.kind === "video" && input.nVariants !== void 0) {
20970
21800
  ctx.addIssue({
20971
- code: z75.ZodIssueCode.custom,
21801
+ code: z79.ZodIssueCode.custom,
20972
21802
  path: [
20973
21803
  "nVariants"
20974
21804
  ],
@@ -20978,7 +21808,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20978
21808
  if (input.kind !== "video") {
20979
21809
  if (input.videoPreset !== void 0) {
20980
21810
  ctx.addIssue({
20981
- code: z75.ZodIssueCode.custom,
21811
+ code: z79.ZodIssueCode.custom,
20982
21812
  path: [
20983
21813
  "videoPreset"
20984
21814
  ],
@@ -20987,7 +21817,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20987
21817
  }
20988
21818
  if (input.videoResolution !== void 0) {
20989
21819
  ctx.addIssue({
20990
- code: z75.ZodIssueCode.custom,
21820
+ code: z79.ZodIssueCode.custom,
20991
21821
  path: [
20992
21822
  "videoResolution"
20993
21823
  ],
@@ -20997,7 +21827,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20997
21827
  }
20998
21828
  if (input.kind !== "image" && input.nVariants !== void 0) {
20999
21829
  ctx.addIssue({
21000
- code: z75.ZodIssueCode.custom,
21830
+ code: z79.ZodIssueCode.custom,
21001
21831
  path: [
21002
21832
  "nVariants"
21003
21833
  ],
@@ -21007,7 +21837,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21007
21837
  if (input.kind !== "landing") {
21008
21838
  if (input.sectionKey !== void 0) {
21009
21839
  ctx.addIssue({
21010
- code: z75.ZodIssueCode.custom,
21840
+ code: z79.ZodIssueCode.custom,
21011
21841
  path: [
21012
21842
  "sectionKey"
21013
21843
  ],
@@ -21016,7 +21846,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21016
21846
  }
21017
21847
  if (input.instructions !== void 0) {
21018
21848
  ctx.addIssue({
21019
- code: z75.ZodIssueCode.custom,
21849
+ code: z79.ZodIssueCode.custom,
21020
21850
  path: [
21021
21851
  "instructions"
21022
21852
  ],
@@ -21025,31 +21855,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21025
21855
  }
21026
21856
  }
21027
21857
  });
21028
- var CreateCreativeVariantInputBase = z75.object({
21029
- sourceTaskId: z75.string().uuid().describe("ID de la tarea original completada."),
21858
+ var CreateCreativeVariantInputBase = z79.object({
21859
+ sourceTaskId: z79.string().uuid().describe("ID de la tarea original completada."),
21030
21860
  kind: CreativeVariantKindEnum,
21031
- confirm: z75.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
21032
- clientRequestId: z75.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."),
21033
- angle: z75.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
21034
- buyerPersona: z75.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
21035
- scriptNotes: z75.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
21036
- creativeDirection: z75.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
21861
+ confirm: z79.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
21862
+ clientRequestId: z79.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."),
21863
+ angle: z79.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
21864
+ buyerPersona: z79.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
21865
+ scriptNotes: z79.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
21866
+ creativeDirection: z79.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
21037
21867
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
21038
21868
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
21039
- generateAiMusic: z75.boolean().optional().describe("Opcional para video."),
21040
- nVariants: z75.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
21869
+ generateAiMusic: z79.boolean().optional().describe("Opcional para video."),
21870
+ nVariants: z79.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
21041
21871
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
21042
21872
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
21043
21873
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
21044
21874
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
21045
- styleMix: z75.boolean().optional().describe("Opcional para imagen."),
21875
+ styleMix: z79.boolean().optional().describe("Opcional para imagen."),
21046
21876
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
21047
- instructions: z75.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.")
21877
+ instructions: z79.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.")
21048
21878
  }).strict();
21049
21879
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
21050
21880
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
21051
21881
  ctx.addIssue({
21052
- code: z75.ZodIssueCode.custom,
21882
+ code: z79.ZodIssueCode.custom,
21053
21883
  path: [
21054
21884
  "angle"
21055
21885
  ],
@@ -21058,7 +21888,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
21058
21888
  }
21059
21889
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
21060
21890
  ctx.addIssue({
21061
- code: z75.ZodIssueCode.custom,
21891
+ code: z79.ZodIssueCode.custom,
21062
21892
  path: [
21063
21893
  "instructions"
21064
21894
  ],
@@ -21104,7 +21934,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
21104
21934
  for (const field of fieldsByKind[input.kind]) {
21105
21935
  if (input[field] !== void 0) {
21106
21936
  ctx.addIssue({
21107
- code: z75.ZodIssueCode.custom,
21937
+ code: z79.ZodIssueCode.custom,
21108
21938
  path: [
21109
21939
  field
21110
21940
  ],
@@ -21221,32 +22051,32 @@ function registerCreativeVariantTools(server, api) {
21221
22051
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
21222
22052
 
21223
22053
  // src/tools/script-review.ts
21224
- import { z as z76 } from "zod";
22054
+ import { z as z80 } from "zod";
21225
22055
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
21226
22056
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
21227
22057
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
21228
- var GetVideoScriptInput = z76.object({
21229
- taskId: z76.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
21230
- angleKey: z76.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.')
22058
+ var GetVideoScriptInput = z80.object({
22059
+ taskId: z80.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
22060
+ angleKey: z80.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.')
21231
22061
  }).strict();
21232
22062
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
21233
22063
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
21234
- var ApproveSceneEdit = z76.object({
21235
- index: z76.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
21236
- dialogue: z76.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
22064
+ var ApproveSceneEdit = z80.object({
22065
+ index: z80.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
22066
+ dialogue: z80.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
21237
22067
  message: "dialogue no puede ser s\xF3lo espacios"
21238
22068
  }).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.")
21239
22069
  }).strict();
21240
- var ApproveVideoScriptInput = z76.object({
21241
- taskId: z76.string().min(1).describe("ID de la tarea."),
21242
- angleKey: z76.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.'),
21243
- scenes: z76.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.")
22070
+ var ApproveVideoScriptInput = z80.object({
22071
+ taskId: z80.string().min(1).describe("ID de la tarea."),
22072
+ angleKey: z80.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.'),
22073
+ scenes: z80.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.")
21244
22074
  }).strict();
21245
- var RegenerateVideoScriptInput = z76.object({
21246
- taskId: z76.string().min(1).describe("ID de la tarea."),
21247
- angleKey: z76.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.'),
22075
+ var RegenerateVideoScriptInput = z80.object({
22076
+ taskId: z80.string().min(1).describe("ID de la tarea."),
22077
+ angleKey: z80.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.'),
21248
22078
  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).'),
21249
- narrativeSelection: z76.enum([
22079
+ narrativeSelection: z80.enum([
21250
22080
  "market",
21251
22081
  "guided"
21252
22082
  ]).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.")
@@ -21327,14 +22157,14 @@ function registerScriptReviewTools(server, api) {
21327
22157
  __name(registerScriptReviewTools, "registerScriptReviewTools");
21328
22158
 
21329
22159
  // src/tools/connections.ts
21330
- import { z as z77 } from "zod";
22160
+ import { z as z81 } from "zod";
21331
22161
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
21332
22162
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
21333
22163
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
21334
22164
  var listMetaDestinationsGuidance = getProductMakerCapabilityModelGuidance("list_meta_destinations");
21335
22165
  var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list_tiktok_advertisers");
21336
22166
  function registerConnectionTools(server, api) {
21337
- 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.", z77.object({}).shape, READS_INTERNAL, async () => {
22167
+ 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.", z81.object({}).shape, READS_INTERNAL, async () => {
21338
22168
  try {
21339
22169
  const r = await api.getJson("/v1/shopify/shops");
21340
22170
  return asText(r);
@@ -21342,10 +22172,10 @@ function registerConnectionTools(server, api) {
21342
22172
  throw translateError(e);
21343
22173
  }
21344
22174
  });
21345
- 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.', z77.object({
21346
- shopDomain: z77.string().min(3).max(120),
21347
- query: z77.string().trim().max(120).optional(),
21348
- taskId: z77.string().uuid().optional()
22175
+ 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.', z81.object({
22176
+ shopDomain: z81.string().min(3).max(120),
22177
+ query: z81.string().trim().max(120).optional(),
22178
+ taskId: z81.string().uuid().optional()
21349
22179
  }).shape, READS_EXTERNAL, async ({ shopDomain, query, taskId }) => {
21350
22180
  try {
21351
22181
  const params = new URLSearchParams({
@@ -21359,7 +22189,7 @@ function registerConnectionTools(server, api) {
21359
22189
  throw translateError(e);
21360
22190
  }
21361
22191
  });
21362
- 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.", z77.object({}).shape, READS_EXTERNAL, async () => {
22192
+ 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.", z81.object({}).shape, READS_EXTERNAL, async () => {
21363
22193
  try {
21364
22194
  const r = await api.getJson("/v1/facebook/ad-accounts");
21365
22195
  return asText(r);
@@ -21369,7 +22199,7 @@ function registerConnectionTools(server, api) {
21369
22199
  });
21370
22200
  server.registerTool("list_meta_destinations", {
21371
22201
  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.",
21372
- inputSchema: z77.object({}).shape,
22202
+ inputSchema: z81.object({}).shape,
21373
22203
  annotations: READS_EXTERNAL,
21374
22204
  _meta: {
21375
22205
  "openai/widgetAccessible": true
@@ -21382,7 +22212,7 @@ function registerConnectionTools(server, api) {
21382
22212
  throw translateError(e);
21383
22213
  }
21384
22214
  });
21385
- server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z77.object({}).shape, READS_EXTERNAL, async () => {
22215
+ server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z81.object({}).shape, READS_EXTERNAL, async () => {
21386
22216
  try {
21387
22217
  const r = await api.getJson("/v1/tiktok/advertisers");
21388
22218
  return asText(r);
@@ -21394,10 +22224,10 @@ function registerConnectionTools(server, api) {
21394
22224
  __name(registerConnectionTools, "registerConnectionTools");
21395
22225
 
21396
22226
  // src/tools/actors.ts
21397
- import { z as z78 } from "zod";
22227
+ import { z as z82 } from "zod";
21398
22228
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
21399
22229
  function registerActorTools(server, api) {
21400
- 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.", z78.object({}).shape, READS_INTERNAL, async () => {
22230
+ 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.", z82.object({}).shape, READS_INTERNAL, async () => {
21401
22231
  try {
21402
22232
  const rows = await api.getJson("/v1/actors");
21403
22233
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -21418,7 +22248,7 @@ function registerActorTools(server, api) {
21418
22248
  __name(registerActorTools, "registerActorTools");
21419
22249
 
21420
22250
  // src/tools/publish.ts
21421
- import { z as z79 } from "zod";
22251
+ import { z as z83 } from "zod";
21422
22252
 
21423
22253
  // src/tools/stable-uuid.ts
21424
22254
  import { createHash as createHash3 } from "crypto";
@@ -21490,40 +22320,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
21490
22320
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
21491
22321
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
21492
22322
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
21493
- var ShopifyInput = z79.object({
21494
- taskId: z79.string().min(1),
21495
- shopDomain: z79.string().min(1),
22323
+ var ShopifyInput = z83.object({
22324
+ taskId: z83.string().min(1),
22325
+ shopDomain: z83.string().min(1),
21496
22326
  /** Override: number of landing images to include. Default = ALL images the
21497
22327
  * task generated (the MCP fetches /v1/results first to count). Bounded
21498
22328
  * generously here; the backend validates each index against
21499
22329
  * landing.images.length and rejects out-of-range. */
21500
- numLandingImages: z79.number().int().min(1).max(20).optional(),
21501
- variantIndex: z79.number().int().min(0).optional(),
22330
+ numLandingImages: z83.number().int().min(1).max(20).optional(),
22331
+ variantIndex: z83.number().int().min(0).optional(),
21502
22332
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
21503
22333
  * When true, the landing renders variant-picker pills; when false, it ships
21504
22334
  * a single-option product page. Defaults to false. */
21505
- showVariantPicker: z79.boolean().optional(),
22335
+ showVariantPicker: z83.boolean().optional(),
21506
22336
  /** Default `auto` updates the product previously published for this task and
21507
22337
  * shop. Use `existing` with targetProductId to choose another product, or
21508
22338
  * `new` only when the user explicitly wants a duplicate/new listing. */
21509
- publicationMode: z79.enum([
22339
+ publicationMode: z83.enum([
21510
22340
  "auto",
21511
22341
  "existing",
21512
22342
  "new"
21513
22343
  ]).optional(),
21514
22344
  /** Shopify product GID, numeric id, or admin product URL. Required when
21515
22345
  * publicationMode is `existing`. */
21516
- targetProductId: z79.string().trim().min(1).max(300).optional(),
22346
+ targetProductId: z83.string().trim().min(1).max(300).optional(),
21517
22347
  /** Add an announcement bar text above add-to-cart (optional). */
21518
- announcementBarEnabled: z79.boolean().optional(),
21519
- announcementBarText: z79.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
22348
+ announcementBarEnabled: z83.boolean().optional(),
22349
+ announcementBarText: z83.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
21520
22350
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
21521
- confirmed: z79.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
22351
+ confirmed: z83.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
21522
22352
  });
21523
22353
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
21524
22354
  if (value.commerceCorrection && value.confirmed !== true) {
21525
22355
  ctx.addIssue({
21526
- code: z79.ZodIssueCode.custom,
22356
+ code: z83.ZodIssueCode.custom,
21527
22357
  path: [
21528
22358
  "confirmed"
21529
22359
  ],
@@ -21532,7 +22362,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
21532
22362
  }
21533
22363
  if (value.announcementBarEnabled && !value.announcementBarText) {
21534
22364
  ctx.addIssue({
21535
- code: z79.ZodIssueCode.custom,
22365
+ code: z83.ZodIssueCode.custom,
21536
22366
  path: [
21537
22367
  "announcementBarText"
21538
22368
  ],
@@ -21541,7 +22371,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
21541
22371
  }
21542
22372
  if (!value.announcementBarEnabled && value.announcementBarText) {
21543
22373
  ctx.addIssue({
21544
- code: z79.ZodIssueCode.custom,
22374
+ code: z83.ZodIssueCode.custom,
21545
22375
  path: [
21546
22376
  "announcementBarText"
21547
22377
  ],
@@ -21555,91 +22385,91 @@ function parseShopifyInput(rawInput) {
21555
22385
  return parsed.data;
21556
22386
  }
21557
22387
  __name(parseShopifyInput, "parseShopifyInput");
21558
- var McpCampaignConfig = z79.object({
22388
+ var McpCampaignConfig = z83.object({
21559
22389
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
21560
22390
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
21561
22391
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
21562
- dailyBudgetUsd: z79.number().positive().optional(),
22392
+ dailyBudgetUsd: z83.number().positive().optional(),
21563
22393
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
21564
22394
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
21565
22395
  * TikTok takes only the first entry. */
21566
- targetCountries: z79.array(CountryIso2Schema).max(1).optional(),
21567
- campaignName: z79.string().trim().min(1).max(100).optional()
22396
+ targetCountries: z83.array(CountryIso2Schema).max(1).optional(),
22397
+ campaignName: z83.string().trim().min(1).max(100).optional()
21568
22398
  });
21569
22399
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
21570
- var MetaInput = z79.object({
21571
- taskId: z79.string().min(1),
22400
+ var MetaInput = z83.object({
22401
+ taskId: z83.string().min(1),
21572
22402
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
21573
- portfolioId: z79.string().trim().min(1),
22403
+ portfolioId: z83.string().trim().min(1),
21574
22404
  /** Exact Facebook Page selected from `list_meta_destinations`. */
21575
- pageId: z79.string().trim().min(1),
22405
+ pageId: z83.string().trim().min(1),
21576
22406
  adAccountId: McpAdAccountId,
21577
- pixelId: z79.string().min(1).optional(),
21578
- landingUrl: z79.string().url().optional(),
22407
+ pixelId: z83.string().min(1).optional(),
22408
+ landingUrl: z83.string().url().optional(),
21579
22409
  /** Select which angles to publish by 0-based index. Omit to publish all
21580
22410
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
21581
- angleIndexes: z79.array(z79.number().int().nonnegative()).optional(),
22411
+ angleIndexes: z83.array(z83.number().int().nonnegative()).optional(),
21582
22412
  campaignConfig: McpCampaignConfig.optional(),
21583
22413
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
21584
22414
  * uses the auto-generated copy attached to the task. Capped at 500 chars
21585
22415
  * (Meta's primary-text limit). */
21586
- primaryText: z79.string().trim().min(1).max(500).optional(),
22416
+ primaryText: z83.string().trim().min(1).max(500).optional(),
21587
22417
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
21588
22418
  * (wa.me) instead of a landing page. */
21589
- phoneNumber: z79.string().min(8).max(32).optional()
22419
+ phoneNumber: z83.string().min(8).max(32).optional()
21590
22420
  });
21591
- var GroupedTaskSource = z79.object({
21592
- type: z79.literal("task"),
21593
- taskId: z79.string().min(1),
21594
- angleIndex: z79.number().int().min(0).optional(),
21595
- videoVariant: z79.enum([
22421
+ var GroupedTaskSource = z83.object({
22422
+ type: z83.literal("task"),
22423
+ taskId: z83.string().min(1),
22424
+ angleIndex: z83.number().int().min(0).optional(),
22425
+ videoVariant: z83.enum([
21596
22426
  "with_subtitles",
21597
22427
  "without_subtitles"
21598
22428
  ]).optional(),
21599
- imageVariantIndex: z79.number().int().min(0).optional()
21600
- });
21601
- var GroupedMediaSource = z79.object({
21602
- type: z79.literal("media"),
21603
- url: z79.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
21604
- path: z79.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".'),
21605
- thumbnailUrl: z79.string().url().optional(),
21606
- thumbnailPath: z79.string().min(1).optional()
22429
+ imageVariantIndex: z83.number().int().min(0).optional()
22430
+ });
22431
+ var GroupedMediaSource = z83.object({
22432
+ type: z83.literal("media"),
22433
+ url: z83.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
22434
+ path: z83.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".'),
22435
+ thumbnailUrl: z83.string().url().optional(),
22436
+ thumbnailPath: z83.string().min(1).optional()
21607
22437
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
21608
22438
  message: "media source needs exactly one of `url` or `path`"
21609
22439
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
21610
22440
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
21611
22441
  });
21612
- var GroupedUploadedAssetSource = z79.object({
21613
- type: z79.literal("asset"),
22442
+ var GroupedUploadedAssetSource = z83.object({
22443
+ type: z83.literal("asset"),
21614
22444
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
21615
- assetId: z79.string().uuid(),
21616
- thumbnailAssetId: z79.string().uuid().optional()
22445
+ assetId: z83.string().uuid(),
22446
+ thumbnailAssetId: z83.string().uuid().optional()
21617
22447
  });
21618
- var GroupedCreative = z79.object({
21619
- type: z79.enum([
22448
+ var GroupedCreative = z83.object({
22449
+ type: z83.enum([
21620
22450
  "image",
21621
22451
  "video"
21622
22452
  ]),
21623
- source: z79.union([
22453
+ source: z83.union([
21624
22454
  GroupedTaskSource,
21625
22455
  GroupedMediaSource,
21626
22456
  GroupedUploadedAssetSource
21627
22457
  ]),
21628
- title: z79.string().max(120).optional(),
21629
- description: z79.string().max(500).optional(),
22458
+ title: z83.string().max(120).optional(),
22459
+ description: z83.string().max(500).optional(),
21630
22460
  cta: MetaCtaType.optional(),
21631
- creativeId: z79.string().min(1).optional()
22461
+ creativeId: z83.string().min(1).optional()
21632
22462
  });
21633
- var GroupedCampaignConfigBase = z79.object({
22463
+ var GroupedCampaignConfigBase = z83.object({
21634
22464
  campaignType: MetaCampaignType.default("sales"),
21635
22465
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
21636
22466
  budgetMode: MetaBudgetMode.optional(),
21637
- campaignDailyBudget: z79.number().int().positive().optional(),
21638
- adSets: z79.array(z79.object({
21639
- tempId: z79.string().min(1).max(80),
21640
- name: z79.string().min(1).max(100),
21641
- dailyBudget: z79.number().int().positive().optional(),
21642
- creativeIds: z79.array(z79.string().min(1)).min(1)
22467
+ campaignDailyBudget: z83.number().int().positive().optional(),
22468
+ adSets: z83.array(z83.object({
22469
+ tempId: z83.string().min(1).max(80),
22470
+ name: z83.string().min(1).max(100),
22471
+ dailyBudget: z83.number().int().positive().optional(),
22472
+ creativeIds: z83.array(z83.string().min(1)).min(1)
21643
22473
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
21644
22474
  /**
21645
22475
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -21647,17 +22477,17 @@ var GroupedCampaignConfigBase = z79.object({
21647
22477
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
21648
22478
  * the API since #849 — unreachable from this tool.
21649
22479
  */
21650
- destination: z79.discriminatedUnion("type", [
21651
- z79.object({
21652
- type: z79.literal("landing"),
21653
- landingUrl: z79.string().url()
22480
+ destination: z83.discriminatedUnion("type", [
22481
+ z83.object({
22482
+ type: z83.literal("landing"),
22483
+ landingUrl: z83.string().url()
21654
22484
  }),
21655
- z79.object({
21656
- type: z79.literal("whatsapp"),
21657
- phoneNumber: z79.string().min(8).max(32)
22485
+ z83.object({
22486
+ type: z83.literal("whatsapp"),
22487
+ phoneNumber: z83.string().min(8).max(32)
21658
22488
  })
21659
22489
  ]),
21660
- saveAsDefault: z79.boolean().default(false),
22490
+ saveAsDefault: z83.boolean().default(false),
21661
22491
  budgetPolicy: MetaBudgetPolicy.optional()
21662
22492
  });
21663
22493
  function resolveBudgetMode(value) {
@@ -21671,7 +22501,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21671
22501
  const budgetMode = resolveBudgetMode(value);
21672
22502
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
21673
22503
  ctx.addIssue({
21674
- code: z79.ZodIssueCode.custom,
22504
+ code: z83.ZodIssueCode.custom,
21675
22505
  path: [
21676
22506
  "campaignDailyBudget"
21677
22507
  ],
@@ -21682,7 +22512,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21682
22512
  value.adSets.forEach((adSet, index) => {
21683
22513
  if (adSet.dailyBudget === void 0) {
21684
22514
  ctx.addIssue({
21685
- code: z79.ZodIssueCode.custom,
22515
+ code: z83.ZodIssueCode.custom,
21686
22516
  path: [
21687
22517
  "adSets",
21688
22518
  index,
@@ -21697,28 +22527,28 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21697
22527
  ...value,
21698
22528
  budgetMode: resolveBudgetMode(value)
21699
22529
  }));
21700
- var PublishCreativesToMetaInputBase = z79.object({
21701
- creatives: z79.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
22530
+ var PublishCreativesToMetaInputBase = z83.object({
22531
+ creatives: z83.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
21702
22532
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
21703
- portfolioId: z79.string().trim().min(1),
22533
+ portfolioId: z83.string().trim().min(1),
21704
22534
  /** Exact Facebook Page selected from `list_meta_destinations`. */
21705
- pageId: z79.string().trim().min(1),
22535
+ pageId: z83.string().trim().min(1),
21706
22536
  adAccountId: McpAdAccountId,
21707
- pixelId: z79.string().min(1).optional(),
22537
+ pixelId: z83.string().min(1).optional(),
21708
22538
  /** Required unless `campaignConfig.destination` is whatsapp — see the
21709
22539
  * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
21710
- landingUrl: z79.string().url().optional(),
22540
+ landingUrl: z83.string().url().optional(),
21711
22541
  /** ISO-2 code or resolvable country name — mirrors the API contract
21712
22542
  * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
21713
22543
  targetCountry: CountryIso2Schema,
21714
- campaignName: z79.string().trim().min(1).max(100),
22544
+ campaignName: z83.string().trim().min(1).max(100),
21715
22545
  campaignConfig: GroupedCampaignConfig.optional()
21716
22546
  });
21717
22547
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
21718
22548
  const destination = value.campaignConfig?.destination;
21719
22549
  if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
21720
22550
  ctx.addIssue({
21721
- code: z79.ZodIssueCode.custom,
22551
+ code: z83.ZodIssueCode.custom,
21722
22552
  path: [
21723
22553
  "landingUrl"
21724
22554
  ],
@@ -21727,7 +22557,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
21727
22557
  }
21728
22558
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
21729
22559
  ctx.addIssue({
21730
- code: z79.ZodIssueCode.custom,
22560
+ code: z83.ZodIssueCode.custom,
21731
22561
  path: [
21732
22562
  "campaignConfig",
21733
22563
  "destination",
@@ -21746,16 +22576,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
21746
22576
  }
21747
22577
  return value;
21748
22578
  });
21749
- var PresignUploadResponseSchema = z79.object({
21750
- uploadUrl: z79.string().url().refine((value) => {
22579
+ var PresignUploadResponseSchema = z83.object({
22580
+ uploadUrl: z83.string().url().refine((value) => {
21751
22581
  const url = new URL(value);
21752
22582
  return !url.username && !url.password && url.protocol === "https:";
21753
22583
  }, "presigned upload URL must be HTTPS without embedded credentials"),
21754
- publicUrl: z79.string().url().refine((value) => {
22584
+ publicUrl: z83.string().url().refine((value) => {
21755
22585
  const url = new URL(value);
21756
22586
  return !url.username && !url.password;
21757
22587
  }, "public media URL must not contain embedded credentials"),
21758
- stagingAssetId: z79.string().uuid()
22588
+ stagingAssetId: z83.string().uuid()
21759
22589
  });
21760
22590
  async function uploadResolvedMedia(api, media, assetRole) {
21761
22591
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -21780,16 +22610,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
21780
22610
  return uploadResolvedMedia(api, media, assetRole);
21781
22611
  }
21782
22612
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
21783
- var TikTokInput = z79.object({
21784
- taskId: z79.string().min(1),
21785
- advertiserId: z79.string().min(1),
21786
- pixelId: z79.string().min(1).optional(),
21787
- landingUrl: z79.string().url().optional(),
21788
- angleIndexes: z79.array(z79.number().int().nonnegative()).optional(),
22613
+ var TikTokInput = z83.object({
22614
+ taskId: z83.string().min(1),
22615
+ advertiserId: z83.string().min(1),
22616
+ pixelId: z83.string().min(1).optional(),
22617
+ landingUrl: z83.string().url().optional(),
22618
+ angleIndexes: z83.array(z83.number().int().nonnegative()).optional(),
21789
22619
  campaignConfig: McpCampaignConfig.optional(),
21790
22620
  /** Override the ad's description (TikTok's body copy). If omitted,
21791
22621
  * ProductMaker uses the auto-generated copy attached to the task. */
21792
- primaryText: z79.string().trim().min(1).max(500).optional()
22622
+ primaryText: z83.string().trim().min(1).max(500).optional()
21793
22623
  });
21794
22624
  function registerPublishTools(server, api, opts = {}) {
21795
22625
  const transport = opts.transport ?? "http";
@@ -22117,39 +22947,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
22117
22947
 
22118
22948
  // src/tools/meta-upload.ts
22119
22949
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
22120
- import { z as z80 } from "zod";
22950
+ import { z as z84 } from "zod";
22121
22951
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
22122
- var UploadSessionInputBase = z80.object({
22123
- mediaKind: z80.enum([
22952
+ var UploadSessionInputBase = z84.object({
22953
+ mediaKind: z84.enum([
22124
22954
  "image",
22125
22955
  "video",
22126
22956
  "mixed"
22127
22957
  ]).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."),
22128
- assetRole: z80.enum([
22958
+ assetRole: z84.enum([
22129
22959
  "media",
22130
22960
  "thumbnail"
22131
22961
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
22132
- uploadPurpose: z80.enum([
22962
+ uploadPurpose: z84.enum([
22133
22963
  "product_reference",
22134
22964
  "creative",
22135
22965
  "generic"
22136
22966
  ]).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."),
22137
- maxFiles: z80.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
22967
+ maxFiles: z84.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
22138
22968
  });
22139
- var OpenAiFileReference = z80.object({
22140
- download_url: z80.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."),
22141
- file_id: z80.string().min(1),
22142
- mime_type: z80.string().min(1).optional(),
22143
- file_name: z80.string().min(1).optional()
22969
+ var OpenAiFileReference = z84.object({
22970
+ download_url: z84.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."),
22971
+ file_id: z84.string().min(1),
22972
+ mime_type: z84.string().min(1).optional(),
22973
+ file_name: z84.string().min(1).optional()
22144
22974
  });
22145
22975
  var UploadSessionToolInputShape = {
22146
22976
  ...UploadSessionInputBase.shape,
22147
- files: z80.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.")
22977
+ files: z84.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.")
22148
22978
  };
22149
- var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
22979
+ var UploadSessionToolInput = z84.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
22150
22980
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
22151
22981
  ctx.addIssue({
22152
- code: z80.ZodIssueCode.custom,
22982
+ code: z84.ZodIssueCode.custom,
22153
22983
  path: [
22154
22984
  "mediaKind"
22155
22985
  ],
@@ -22158,7 +22988,7 @@ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine
22158
22988
  }
22159
22989
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
22160
22990
  ctx.addIssue({
22161
- code: z80.ZodIssueCode.custom,
22991
+ code: z84.ZodIssueCode.custom,
22162
22992
  path: [
22163
22993
  "maxFiles"
22164
22994
  ],
@@ -22167,7 +22997,7 @@ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine
22167
22997
  }
22168
22998
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
22169
22999
  ctx.addIssue({
22170
- code: z80.ZodIssueCode.custom,
23000
+ code: z84.ZodIssueCode.custom,
22171
23001
  path: [
22172
23002
  "maxFiles"
22173
23003
  ],
@@ -22175,38 +23005,38 @@ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine
22175
23005
  });
22176
23006
  }
22177
23007
  });
22178
- var UploadSessionResponse = z80.object({
22179
- sessionId: z80.string().uuid(),
22180
- uploadPageUrl: z80.string().url(),
22181
- mediaKind: z80.enum([
23008
+ var UploadSessionResponse = z84.object({
23009
+ sessionId: z84.string().uuid(),
23010
+ uploadPageUrl: z84.string().url(),
23011
+ mediaKind: z84.enum([
22182
23012
  "image",
22183
23013
  "video",
22184
23014
  "mixed"
22185
23015
  ]),
22186
- assetRole: z80.enum([
23016
+ assetRole: z84.enum([
22187
23017
  "media",
22188
23018
  "thumbnail"
22189
23019
  ]),
22190
- maxFiles: z80.number().int().positive(),
22191
- expiresAt: z80.string().datetime()
23020
+ maxFiles: z84.number().int().positive(),
23021
+ expiresAt: z84.string().datetime()
22192
23022
  });
22193
- var UploadStatusInput = z80.object({
22194
- sessionId: z80.string().uuid().describe("The sessionId returned by request_media_upload.")
23023
+ var UploadStatusInput = z84.object({
23024
+ sessionId: z84.string().uuid().describe("The sessionId returned by request_media_upload.")
22195
23025
  });
22196
- var UniversalUploadStatusResponse = z80.discriminatedUnion("status", [
22197
- z80.object({
22198
- status: z80.literal("pending"),
22199
- assets: z80.array(z80.never()).length(0)
23026
+ var UniversalUploadStatusResponse = z84.discriminatedUnion("status", [
23027
+ z84.object({
23028
+ status: z84.literal("pending"),
23029
+ assets: z84.array(z84.never()).length(0)
22200
23030
  }),
22201
- z80.object({
22202
- status: z80.literal("uploaded"),
22203
- assets: z80.array(z80.object({
22204
- assetId: z80.string().uuid(),
22205
- mediaKind: z80.enum([
23031
+ z84.object({
23032
+ status: z84.literal("uploaded"),
23033
+ assets: z84.array(z84.object({
23034
+ assetId: z84.string().uuid(),
23035
+ mediaKind: z84.enum([
22206
23036
  "image",
22207
23037
  "video"
22208
23038
  ]),
22209
- assetRole: z80.enum([
23039
+ assetRole: z84.enum([
22210
23040
  "media",
22211
23041
  "thumbnail"
22212
23042
  ])
@@ -22214,13 +23044,13 @@ var UniversalUploadStatusResponse = z80.discriminatedUnion("status", [
22214
23044
  })
22215
23045
  ]);
22216
23046
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
22217
- uploadPurpose: z80.enum([
23047
+ uploadPurpose: z84.enum([
22218
23048
  "product_reference",
22219
23049
  "creative",
22220
23050
  "generic"
22221
23051
  ]),
22222
- checkToolName: z80.literal("check_media_upload"),
22223
- resolveEndpoint: z80.string().url()
23052
+ checkToolName: z84.literal("check_media_upload"),
23053
+ resolveEndpoint: z84.string().url()
22224
23054
  });
22225
23055
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
22226
23056
  const url = new URL(uploadPageUrl);
@@ -22311,15 +23141,15 @@ function registerMediaUploadTools(server, api) {
22311
23141
  __name(registerMediaUploadTools, "registerMediaUploadTools");
22312
23142
 
22313
23143
  // src/tools/campaigns.ts
22314
- import { z as z81 } from "zod";
23144
+ import { z as z85 } from "zod";
22315
23145
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
22316
23146
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
22317
- var MetaStatusInput = z81.object({
22318
- campaignId: z81.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
23147
+ var MetaStatusInput = z85.object({
23148
+ campaignId: z85.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
22319
23149
  });
22320
- var TikTokStatusInput = z81.object({
22321
- campaignId: z81.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
22322
- advertiserId: z81.string().min(1).describe("The same advertiserId used to publish the campaign.")
23150
+ var TikTokStatusInput = z85.object({
23151
+ campaignId: z85.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
23152
+ advertiserId: z85.string().min(1).describe("The same advertiserId used to publish the campaign.")
22323
23153
  });
22324
23154
  function registerCampaignTools(server, api) {
22325
23155
  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) => {
@@ -22416,10 +23246,10 @@ function renderTikTokStatusMarkdown(r) {
22416
23246
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
22417
23247
 
22418
23248
  // ../../packages/product-economics/src/product-costing.ts
22419
- import { z as z83 } from "zod";
23249
+ import { z as z87 } from "zod";
22420
23250
 
22421
23251
  // ../../packages/product-economics/src/product-costing-countries.ts
22422
- import { z as z82 } from "zod";
23252
+ import { z as z86 } from "zod";
22423
23253
 
22424
23254
  // ../../packages/product-economics/src/product-costing-shipping-references.json
22425
23255
  var product_costing_shipping_references_default = {
@@ -22483,21 +23313,21 @@ var product_costing_shipping_references_default = {
22483
23313
  };
22484
23314
 
22485
23315
  // ../../packages/product-economics/src/product-costing-countries.ts
22486
- var ShippingReferenceSchema = z82.object({
22487
- reference: z82.number().positive(),
22488
- min: z82.number().nonnegative(),
22489
- max: z82.number().positive(),
22490
- updatedAt: z82.string().date(),
22491
- confidence: z82.enum([
23316
+ var ShippingReferenceSchema = z86.object({
23317
+ reference: z86.number().positive(),
23318
+ min: z86.number().nonnegative(),
23319
+ max: z86.number().positive(),
23320
+ updatedAt: z86.string().date(),
23321
+ confidence: z86.enum([
22492
23322
  "high",
22493
23323
  "medium",
22494
23324
  "medium-low"
22495
23325
  ]),
22496
- sources: z82.array(z82.string().url().startsWith("https://")).min(1).max(3)
23326
+ sources: z86.array(z86.string().url().startsWith("https://")).min(1).max(3)
22497
23327
  }).superRefine(({ reference, min, max }, context) => {
22498
23328
  if (min > reference || reference > max) {
22499
23329
  context.addIssue({
22500
- code: z82.ZodIssueCode.custom,
23330
+ code: z86.ZodIssueCode.custom,
22501
23331
  message: "shipping_reference_outside_range",
22502
23332
  path: [
22503
23333
  "reference"
@@ -22505,7 +23335,7 @@ var ShippingReferenceSchema = z82.object({
22505
23335
  });
22506
23336
  }
22507
23337
  });
22508
- var SHIPPING_REFERENCES = z82.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
23338
+ var SHIPPING_REFERENCES = z86.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
22509
23339
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
22510
23340
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
22511
23341
  "MX",
@@ -22687,18 +23517,18 @@ function getProductCostingCountryName(country) {
22687
23517
  __name(getProductCostingCountryName, "getProductCostingCountryName");
22688
23518
 
22689
23519
  // ../../packages/product-economics/src/product-costing.ts
22690
- var ProductCostingInputSchema = z83.object({
22691
- country: z83.string().refine(isProductCostingCountryCode, "unsupported_country"),
22692
- supplierCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
22693
- shippingCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
22694
- returnRate: z83.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22695
- cancellationRate: z83.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22696
- adsManagerCpa: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
22697
- desiredMargin: z83.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
23520
+ var ProductCostingInputSchema = z87.object({
23521
+ country: z87.string().refine(isProductCostingCountryCode, "unsupported_country"),
23522
+ supplierCost: z87.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
23523
+ shippingCost: z87.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
23524
+ returnRate: z87.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
23525
+ cancellationRate: z87.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
23526
+ adsManagerCpa: z87.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
23527
+ desiredMargin: z87.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
22698
23528
  }).superRefine(({ returnRate, cancellationRate }, context) => {
22699
23529
  if (returnRate + cancellationRate >= 1) {
22700
23530
  context.addIssue({
22701
- code: z83.ZodIssueCode.custom,
23531
+ code: z87.ZodIssueCode.custom,
22702
23532
  message: "delivery_rate_positive",
22703
23533
  path: [
22704
23534
  "cancellationRate"
@@ -22795,15 +23625,15 @@ function calculateProductCosting(rawInput) {
22795
23625
  __name(calculateProductCosting, "calculateProductCosting");
22796
23626
 
22797
23627
  // src/tools/product-costing.ts
22798
- import { z as z84 } from "zod";
23628
+ import { z as z88 } from "zod";
22799
23629
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
22800
- var optionalAmount = /* @__PURE__ */ __name((description) => z84.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
22801
- var optionalPercent = /* @__PURE__ */ __name((description) => z84.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
22802
- var ProductCostingToolInput = z84.object({
22803
- country: z84.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
23630
+ var optionalAmount = /* @__PURE__ */ __name((description) => z88.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
23631
+ var optionalPercent = /* @__PURE__ */ __name((description) => z88.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
23632
+ var ProductCostingToolInput = z88.object({
23633
+ country: z88.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
22804
23634
  message: "Pa\xEDs no soportado por ProductMaker."
22805
23635
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
22806
- supplierCost: z84.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."),
23636
+ supplierCost: z88.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."),
22807
23637
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
22808
23638
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
22809
23639
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -22962,7 +23792,7 @@ function formatPercent(value) {
22962
23792
  __name(formatPercent, "formatPercent");
22963
23793
 
22964
23794
  // src/tools/product-research.ts
22965
- import { z as z85 } from "zod";
23795
+ import { z as z89 } from "zod";
22966
23796
 
22967
23797
  // src/tools/product-research-idempotency.ts
22968
23798
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -23333,35 +24163,35 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
23333
24163
  ]);
23334
24164
  var POLL_INTERVAL_MS = 5e3;
23335
24165
  var MAX_WAIT_SECONDS = 120;
23336
- var FindInput = z85.object({
24166
+ var FindInput = z89.object({
23337
24167
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
23338
24168
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
23339
- confirmed: z85.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
23340
- waitSeconds: z85.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
24169
+ confirmed: z89.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
24170
+ waitSeconds: z89.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
23341
24171
  });
23342
- var GetInput = z85.object({
23343
- runId: z85.string().uuid().describe("ID del run devuelto por find_winning_products.")
24172
+ var GetInput = z89.object({
24173
+ runId: z89.string().uuid().describe("ID del run devuelto por find_winning_products.")
23344
24174
  });
23345
- var ListInput = z85.object({
23346
- limit: z85.number().int().min(1).max(20).default(10)
24175
+ var ListInput = z89.object({
24176
+ limit: z89.number().int().min(1).max(20).default(10)
23347
24177
  });
23348
- function textResult(text) {
24178
+ function textResult(text2) {
23349
24179
  return {
23350
24180
  content: [
23351
24181
  {
23352
24182
  type: "text",
23353
- text
24183
+ text: text2
23354
24184
  }
23355
24185
  ]
23356
24186
  };
23357
24187
  }
23358
24188
  __name(textResult, "textResult");
23359
- function researchResult(run, text) {
24189
+ function researchResult(run, text2) {
23360
24190
  return {
23361
24191
  content: [
23362
24192
  {
23363
24193
  type: "text",
23364
- text
24194
+ text: text2
23365
24195
  }
23366
24196
  ],
23367
24197
  structuredContent: run
@@ -23466,17 +24296,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
23466
24296
  __name(registerProductResearchTools, "registerProductResearchTools");
23467
24297
 
23468
24298
  // src/tools/dropshipping-projects.ts
23469
- import { z as z86 } from "zod";
24299
+ import { z as z90 } from "zod";
23470
24300
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
23471
24301
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
23472
24302
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
23473
- var ProjectId = z86.string().uuid();
23474
- var DropshippingProjectStatus = z86.enum([
24303
+ var ProjectId = z90.string().uuid();
24304
+ var DropshippingProjectStatus = z90.enum([
23475
24305
  "active",
23476
24306
  "completed",
23477
24307
  "archived"
23478
24308
  ]);
23479
- var DropshippingProjectPhase = z86.enum([
24309
+ var DropshippingProjectPhase = z90.enum([
23480
24310
  "research",
23481
24311
  "costing",
23482
24312
  "media",
@@ -23485,21 +24315,21 @@ var DropshippingProjectPhase = z86.enum([
23485
24315
  "advertising",
23486
24316
  "complete"
23487
24317
  ]);
23488
- var DropshippingRewardMilestone = z86.enum([
24318
+ var DropshippingRewardMilestone = z90.enum([
23489
24319
  "product_selected",
23490
24320
  "costing_saved",
23491
24321
  "product_media_ready",
23492
24322
  "creatives_completed",
23493
24323
  "campaign_created"
23494
24324
  ]);
23495
- var TargetCountry = z86.enum([
24325
+ var TargetCountry = z90.enum([
23496
24326
  "CO",
23497
24327
  "MX",
23498
24328
  "PE",
23499
24329
  "EC",
23500
24330
  "CL"
23501
24331
  ]);
23502
- var ResearchCategory = z86.enum([
24332
+ var ResearchCategory = z90.enum([
23503
24333
  "auto",
23504
24334
  "automotive",
23505
24335
  "kitchen",
@@ -23514,7 +24344,7 @@ var ResearchCategory = z86.enum([
23514
24344
  "garden",
23515
24345
  "cleaning"
23516
24346
  ]);
23517
- var HttpUrl3 = z86.string().url().max(2e3).refine((value) => {
24347
+ var HttpUrl3 = z90.string().url().max(2e3).refine((value) => {
23518
24348
  try {
23519
24349
  return [
23520
24350
  "http:",
@@ -23524,45 +24354,45 @@ var HttpUrl3 = z86.string().url().max(2e3).refine((value) => {
23524
24354
  return false;
23525
24355
  }
23526
24356
  }, "URL must use HTTP(S)");
23527
- var ResearchCandidateOrigin = z86.object({
23528
- type: z86.literal("research_candidate"),
24357
+ var ResearchCandidateOrigin = z90.object({
24358
+ type: z90.literal("research_candidate"),
23529
24359
  runId: ProjectId,
23530
- candidateSourceId: z86.string().min(1).max(160)
24360
+ candidateSourceId: z90.string().min(1).max(160)
23531
24361
  });
23532
- var TaskOrigin = z86.object({
23533
- type: z86.literal("task"),
24362
+ var TaskOrigin = z90.object({
24363
+ type: z90.literal("task"),
23534
24364
  taskId: ProjectId
23535
24365
  });
23536
- var ManualOrigin = z86.object({
23537
- type: z86.literal("manual"),
24366
+ var ManualOrigin = z90.object({
24367
+ type: z90.literal("manual"),
23538
24368
  clientRequestId: ProjectId,
23539
- country: z86.string().min(2).max(3).optional()
24369
+ country: z90.string().min(2).max(3).optional()
23540
24370
  });
23541
- var StartProjectInput = z86.object({
23542
- origin: z86.discriminatedUnion("type", [
24371
+ var StartProjectInput = z90.object({
24372
+ origin: z90.discriminatedUnion("type", [
23543
24373
  ResearchCandidateOrigin,
23544
24374
  TaskOrigin,
23545
24375
  ManualOrigin
23546
24376
  ]),
23547
- productName: z86.string().trim().min(1).max(240).optional(),
24377
+ productName: z90.string().trim().min(1).max(240).optional(),
23548
24378
  productUrl: HttpUrl3.optional(),
23549
- country: z86.string().min(2).max(3).optional(),
23550
- languageCode: z86.string().min(2).max(16).optional()
24379
+ country: z90.string().min(2).max(3).optional(),
24380
+ languageCode: z90.string().min(2).max(16).optional()
23551
24381
  }).strict();
23552
- var CostProjectInput = z86.object({
24382
+ var CostProjectInput = z90.object({
23553
24383
  projectId: ProjectId,
23554
- version: z86.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
23555
- country: z86.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
24384
+ version: z90.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
24385
+ country: z90.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
23556
24386
  message: "Pa\xEDs no soportado por ProductMaker."
23557
24387
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
23558
- supplierCost: z86.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."),
23559
- shippingCost: z86.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
23560
- returnRate: z86.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."),
23561
- cancellationRate: z86.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."),
23562
- adsManagerCpa: z86.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
23563
- desiredMargin: z86.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
23564
- });
23565
- var GuideInput = z86.object({
24388
+ supplierCost: z90.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."),
24389
+ shippingCost: z90.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
24390
+ returnRate: z90.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."),
24391
+ cancellationRate: z90.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."),
24392
+ adsManagerCpa: z90.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
24393
+ desiredMargin: z90.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
24394
+ });
24395
+ var GuideInput = z90.object({
23566
24396
  projectId: ProjectId.optional()
23567
24397
  }).strict();
23568
24398
  var NEXT_ACTION_KINDS = [
@@ -23580,29 +24410,29 @@ var NEXT_ACTION_KINDS = [
23580
24410
  "repair_meta_campaign",
23581
24411
  "review_paused_campaign"
23582
24412
  ];
23583
- var DropshippingProjectNextAction = z86.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z86.object({
23584
- kind: z86.literal(kind),
23585
- href: z86.string().min(1)
24413
+ var DropshippingProjectNextAction = z90.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z90.object({
24414
+ kind: z90.literal(kind),
24415
+ href: z90.string().min(1)
23586
24416
  })));
23587
- var CostingInputSchema = z86.object({
23588
- country: z86.string().min(2).max(3),
23589
- supplierCost: z86.number().finite().positive(),
23590
- shippingCost: z86.number().finite().nonnegative(),
23591
- returnRate: z86.number().finite().min(0).lt(1),
23592
- cancellationRate: z86.number().finite().min(0).lt(1),
23593
- adsManagerCpa: z86.number().finite().nonnegative(),
23594
- desiredMargin: z86.number().finite().min(0).lt(1)
24417
+ var CostingInputSchema = z90.object({
24418
+ country: z90.string().min(2).max(3),
24419
+ supplierCost: z90.number().finite().positive(),
24420
+ shippingCost: z90.number().finite().nonnegative(),
24421
+ returnRate: z90.number().finite().min(0).lt(1),
24422
+ cancellationRate: z90.number().finite().min(0).lt(1),
24423
+ adsManagerCpa: z90.number().finite().nonnegative(),
24424
+ desiredMargin: z90.number().finite().min(0).lt(1)
23595
24425
  }).superRefine(({ returnRate, cancellationRate }, context) => {
23596
24426
  if (returnRate + cancellationRate >= 1) context.addIssue({
23597
- code: z86.ZodIssueCode.custom,
24427
+ code: z90.ZodIssueCode.custom,
23598
24428
  path: [
23599
24429
  "cancellationRate"
23600
24430
  ]
23601
24431
  });
23602
24432
  });
23603
- var FiniteCostingNumber = z86.number().finite();
23604
- var CostingResultSchema = z86.object({
23605
- country: z86.string().min(2).max(3),
24433
+ var FiniteCostingNumber = z90.number().finite();
24434
+ var CostingResultSchema = z90.object({
24435
+ country: z90.string().min(2).max(3),
23606
24436
  deliveryRate: FiniteCostingNumber,
23607
24437
  adjustedShippingCost: FiniteCostingNumber,
23608
24438
  adjustedCpa: FiniteCostingNumber,
@@ -23615,45 +24445,45 @@ var CostingResultSchema = z86.object({
23615
24445
  estimatedProfit: FiniteCostingNumber,
23616
24446
  actualMargin: FiniteCostingNumber,
23617
24447
  breakEvenAdsManagerCpa: FiniteCostingNumber,
23618
- wasPriceAutoAdjusted: z86.boolean(),
23619
- profitabilityStatus: z86.literal("healthy")
23620
- });
23621
- var RewardProgressSchema = z86.object({
23622
- campaignKey: z86.literal("dropshipping-launch-v1"),
23623
- totalCredits: z86.number().int().positive(),
23624
- earnedCredits: z86.number().int().nonnegative(),
23625
- milestones: z86.array(z86.object({
24448
+ wasPriceAutoAdjusted: z90.boolean(),
24449
+ profitabilityStatus: z90.literal("healthy")
24450
+ });
24451
+ var RewardProgressSchema = z90.object({
24452
+ campaignKey: z90.literal("dropshipping-launch-v1"),
24453
+ totalCredits: z90.number().int().positive(),
24454
+ earnedCredits: z90.number().int().nonnegative(),
24455
+ milestones: z90.array(z90.object({
23626
24456
  milestone: DropshippingRewardMilestone,
23627
- credits: z86.number().int().positive(),
23628
- available: z86.boolean().optional(),
23629
- earned: z86.boolean(),
24457
+ credits: z90.number().int().positive(),
24458
+ available: z90.boolean().optional(),
24459
+ earned: z90.boolean(),
23630
24460
  grantId: ProjectId.nullable(),
23631
- grantedAt: z86.string().datetime().nullable()
24461
+ grantedAt: z90.string().datetime().nullable()
23632
24462
  })).length(DropshippingRewardMilestone.options.length)
23633
24463
  });
23634
- var ProjectResponseSchema = z86.object({
24464
+ var ProjectResponseSchema = z90.object({
23635
24465
  id: ProjectId,
23636
24466
  taskId: ProjectId.nullable(),
23637
24467
  status: DropshippingProjectStatus,
23638
- originKey: z86.string().min(1),
24468
+ originKey: z90.string().min(1),
23639
24469
  researchRunId: ProjectId.nullable(),
23640
- candidateSourceId: z86.string().nullable(),
23641
- productName: z86.string().nullable(),
24470
+ candidateSourceId: z90.string().nullable(),
24471
+ productName: z90.string().nullable(),
23642
24472
  productUrl: HttpUrl3.nullable(),
23643
24473
  referenceImageUrl: HttpUrl3.nullable(),
23644
- targetCountry: z86.string().nullable(),
23645
- languageCode: z86.string().nullable(),
23646
- hasReferenceImage: z86.boolean(),
23647
- hasWinnerReferenceImage: z86.boolean(),
24474
+ targetCountry: z90.string().nullable(),
24475
+ languageCode: z90.string().nullable(),
24476
+ hasReferenceImage: z90.boolean(),
24477
+ hasWinnerReferenceImage: z90.boolean(),
23648
24478
  costingInput: CostingInputSchema.nullable(),
23649
24479
  costingResult: CostingResultSchema.nullable(),
23650
- costingVersion: z86.number().int().positive().nullable(),
23651
- version: z86.number().int().positive(),
24480
+ costingVersion: z90.number().int().positive().nullable(),
24481
+ version: z90.number().int().positive(),
23652
24482
  phase: DropshippingProjectPhase,
23653
24483
  nextAction: DropshippingProjectNextAction.nullable(),
23654
24484
  rewards: RewardProgressSchema,
23655
- createdAt: z86.string().datetime(),
23656
- updatedAt: z86.string().datetime()
24485
+ createdAt: z90.string().datetime(),
24486
+ updatedAt: z90.string().datetime()
23657
24487
  }).passthrough();
23658
24488
  var NEXT_ACTION_GUIDANCE = {
23659
24489
  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.",
@@ -23771,58 +24601,58 @@ function registerDropshippingProjectTools(server, api) {
23771
24601
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
23772
24602
 
23773
24603
  // src/tools/daily-control.ts
23774
- import { z as z87 } from "zod";
24604
+ import { z as z91 } from "zod";
23775
24605
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
23776
24606
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
23777
24607
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
23778
- var ProviderCampaignIdentifier = z87.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
23779
- var DateOnly = z87.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23780
- var DailyControlInput = z87.object({
24608
+ var ProviderCampaignIdentifier = z91.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
24609
+ var DateOnly = z91.string().regex(/^\d{4}-\d{2}-\d{2}$/);
24610
+ var DailyControlInput = z91.object({
23781
24611
  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."),
23782
- days: z87.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23783
- projectId: z87.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
24612
+ days: z91.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
24613
+ projectId: z91.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
23784
24614
  }).strict();
23785
- var LinkCampaignInput = z87.object({
23786
- projectId: z87.string().uuid(),
23787
- provider: z87.enum([
24615
+ var LinkCampaignInput = z91.object({
24616
+ projectId: z91.string().uuid(),
24617
+ provider: z91.enum([
23788
24618
  "meta",
23789
24619
  "tiktok"
23790
24620
  ]),
23791
24621
  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."),
23792
24622
  campaignId: ProviderCampaignIdentifier
23793
24623
  }).strict();
23794
- var ReportReturnsInput = z87.object({
23795
- projectId: z87.string().uuid(),
24624
+ var ReportReturnsInput = z91.object({
24625
+ projectId: z91.string().uuid(),
23796
24626
  date: DateOnly,
23797
- returnedOrders: z87.number().int().min(0).max(1e5),
23798
- note: z87.string().trim().max(280).optional()
24627
+ returnedOrders: z91.number().int().min(0).max(1e5),
24628
+ note: z91.string().trim().max(280).optional()
23799
24629
  }).strict();
23800
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z87.string());
23801
- var DailyControlLightMirror = DailyControlLightEnum.or(z87.string());
23802
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z87.string());
23803
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z87.string());
23804
- var DailyControlDayMirror = z87.object({
23805
- date: z87.string(),
23806
- returnedOrders: z87.number(),
24630
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z91.string());
24631
+ var DailyControlLightMirror = DailyControlLightEnum.or(z91.string());
24632
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z91.string());
24633
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z91.string());
24634
+ var DailyControlDayMirror = z91.object({
24635
+ date: z91.string(),
24636
+ returnedOrders: z91.number(),
23807
24637
  returnedSource: DailyControlSourceMirror,
23808
24638
  cancelledSource: DailyControlSourceMirror,
23809
- hasEstimates: z87.boolean(),
24639
+ hasEstimates: z91.boolean(),
23810
24640
  light: DailyControlLightMirror
23811
24641
  }).passthrough();
23812
- var DailyControlProductMirror = z87.object({
23813
- projectId: z87.string().uuid(),
23814
- productName: z87.string().nullable(),
24642
+ var DailyControlProductMirror = z91.object({
24643
+ projectId: z91.string().uuid(),
24644
+ productName: z91.string().nullable(),
23815
24645
  status: DailyControlStatusMirror,
23816
- statusMessage: z87.string().nullable(),
23817
- days: z87.array(DailyControlDayMirror),
24646
+ statusMessage: z91.string().nullable(),
24647
+ days: z91.array(DailyControlDayMirror),
23818
24648
  verdict: DailyControlVerdictMirror.nullable(),
23819
- rationale: z87.string().nullable()
24649
+ rationale: z91.string().nullable()
23820
24650
  }).passthrough();
23821
- var DailyControlResponseMirror = z87.object({
23822
- since: z87.string(),
23823
- until: z87.string(),
23824
- products: z87.array(DailyControlProductMirror),
23825
- archivedProjectSpend: z87.array(z87.unknown())
24651
+ var DailyControlResponseMirror = z91.object({
24652
+ since: z91.string(),
24653
+ until: z91.string(),
24654
+ products: z91.array(DailyControlProductMirror),
24655
+ archivedProjectSpend: z91.array(z91.unknown())
23826
24656
  }).passthrough();
23827
24657
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
23828
24658
  function withWarnings(response) {
@@ -23906,42 +24736,42 @@ function registerDailyControlTools(server, api) {
23906
24736
  __name(registerDailyControlTools, "registerDailyControlTools");
23907
24737
 
23908
24738
  // src/tools/product-control.ts
23909
- import { z as z88 } from "zod";
24739
+ import { z as z92 } from "zod";
23910
24740
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
23911
24741
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
23912
24742
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
23913
24743
  var setProductCostingGuidance = getProductMakerCapabilityModelGuidance("set_product_costing");
23914
24744
  var reportProductCountsGuidance = getProductMakerCapabilityModelGuidance("report_product_counts");
23915
- var DateOnly2 = z88.string().regex(/^\d{4}-\d{2}-\d{2}$/);
24745
+ var DateOnly2 = z92.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23916
24746
  var IMPORT_BATCH_MAX2 = 50;
23917
- var ProductControlListInput = z88.object({
23918
- days: z88.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
24747
+ var ProductControlListInput = z92.object({
24748
+ days: z92.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23919
24749
  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."),
23920
- shopDomain: z88.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
24750
+ shopDomain: z92.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
23921
24751
  }).strict();
23922
- var ImportableProductsInput = z88.object({
23923
- q: z88.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
23924
- after: z88.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
23925
- shopDomain: z88.string().min(1).optional()
24752
+ var ImportableProductsInput = z92.object({
24753
+ q: z92.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
24754
+ after: z92.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
24755
+ shopDomain: z92.string().min(1).optional()
23926
24756
  }).strict();
23927
- var ImportProductControlsInput = z88.object({
23928
- shopifyProductIds: z88.array(z88.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."),
24757
+ var ImportProductControlsInput = z92.object({
24758
+ shopifyProductIds: z92.array(z92.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."),
23929
24759
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
23930
24760
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
23931
- shopDomain: z88.string().min(1)
24761
+ shopDomain: z92.string().min(1)
23932
24762
  }).strict();
23933
- var SetProductCostingInput = z88.object({
23934
- shopDomain: z88.string().min(1),
23935
- shopifyProductId: z88.string().min(1).max(64),
23936
- targetCountry: z88.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
23937
- supplierCost: z88.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
23938
- shippingCost: z88.number().finite().nonnegative(),
23939
- returnRate: z88.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
23940
- cancellationRate: z88.number().finite().min(0).lt(1)
24763
+ var SetProductCostingInput = z92.object({
24764
+ shopDomain: z92.string().min(1),
24765
+ shopifyProductId: z92.string().min(1).max(64),
24766
+ targetCountry: z92.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
24767
+ supplierCost: z92.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
24768
+ shippingCost: z92.number().finite().nonnegative(),
24769
+ returnRate: z92.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
24770
+ cancellationRate: z92.number().finite().min(0).lt(1)
23941
24771
  }).strict();
23942
- var Count = z88.number().int().min(0).max(1e5).nullable().optional();
23943
- var ReportProductCountsInput = z88.object({
23944
- productControlId: z88.string().uuid().describe("El identificador que devuelve get_product_control."),
24772
+ var Count = z92.number().int().min(0).max(1e5).nullable().optional();
24773
+ var ReportProductCountsInput = z92.object({
24774
+ productControlId: z92.string().uuid().describe("El identificador que devuelve get_product_control."),
23945
24775
  date: DateOnly2,
23946
24776
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
23947
24777
  cancelledOrders: Count,