@productmaker/mcp 8.1.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 +1618 -799
  3. package/dist/stdio.js +1602 -783
  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(),
@@ -7269,7 +7449,8 @@ var IMAGE_QA_GATES = [
7269
7449
  "limb",
7270
7450
  "device_panel",
7271
7451
  "critical_feature",
7272
- "cross_section"
7452
+ "cross_section",
7453
+ "usage_fidelity"
7273
7454
  ];
7274
7455
  var ImageQaGate = z36.enum(IMAGE_QA_GATES);
7275
7456
  var ImageQaGateOutcome = z36.enum([
@@ -8315,6 +8496,10 @@ var GEMINI_OMNI_FLAT_USER_PRICE_CENTS = 168;
8315
8496
  // ../../packages/types/src/pricing.ts
8316
8497
  var CREDITS_PER_USD_CENT = 10;
8317
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
+ };
8318
8503
  var KALODATA_USD_CENTS_PER_PROVIDER_CREDIT = 9;
8319
8504
  var KALODATA_PROVIDER_CREDITS_PER_SOURCE_CEILING = 7.5;
8320
8505
  var DEFAULT_PRICING = {
@@ -9273,6 +9458,27 @@ var DEFAULT_PRICING = {
9273
9458
  ourCostCents: 1.88,
9274
9459
  userPriceCents: 3.76
9275
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
+ },
9276
9482
  // Landing commercial-facts extraction (gemini-3.8-flash, ONE text-only call over
9277
9483
  // the seller's offer/context/features). Sized off the image-QA key beside it,
9278
9484
  // which measured 1.88¢ at ~11.1K prompt tokens: this prompt is capped at ~3K in
@@ -10011,6 +10217,24 @@ var DEFAULT_PRICING = {
10011
10217
  ourCostCents: 0.2,
10012
10218
  userPriceCents: 0.4
10013
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
+ },
10014
10238
  // Unit = one reference-grouping pass over the user's product images (0.1241¢).
10015
10239
  "openrouter:product-reference-grouping": {
10016
10240
  ourCostCents: 0.15,
@@ -13528,7 +13752,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13528
13752
  "video"
13529
13753
  ]
13530
13754
  ),
13531
- defineCapability("generate_image_creatives", "eb2c3f6a0d8974ccf33c42f2b4cc9e09918dabf29182acce1418ea2842a01ec3", "credit_consuming", "creative", [
13755
+ defineCapability("generate_image_creatives", "2f1698b623d98645b7c618a17988f3aac30f403a9c3f3dc26eb5bdbd9c6ef23e", "credit_consuming", "creative", [
13532
13756
  "credit_consuming",
13533
13757
  "state_change"
13534
13758
  ], [
@@ -15179,79 +15403,696 @@ var WhatsAppPresentationManifestSchema = z67.object({
15179
15403
  }
15180
15404
  });
15181
15405
 
15182
- // ../../packages/types/src/flight-recorder.ts
15406
+ // ../../packages/types/src/usage-decision.ts
15183
15407
  import { z as z68 } from "zod";
15184
- 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([
15185
16026
  "initial",
15186
16027
  "regeneration",
15187
16028
  "edit",
15188
16029
  "retry"
15189
16030
  ]);
15190
- var FlightRecorderProviderSchema = z68.enum([
16031
+ var FlightRecorderProviderSchema = z72.enum([
15191
16032
  "kie",
15192
16033
  "fal"
15193
16034
  ]);
15194
- var FlightRecorderElementSchema = z68.object({
15195
- name: z68.string().optional(),
15196
- description: z68.string().optional(),
15197
- frontalImageUrl: z68.string().optional(),
15198
- referenceImageUrls: z68.array(z68.string()).optional(),
15199
- videoUrl: z68.string().optional()
15200
- });
15201
- var FlightRecorderDistillationSchema = z68.object({
15202
- 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([
15203
16044
  "female",
15204
16045
  "male",
15205
16046
  "mixed"
15206
- ]).or(z68.string()).optional(),
15207
- voiceId: z68.string().optional(),
15208
- cameraMotion: z68.string().optional()
15209
- }).catchall(z68.unknown());
15210
- var FlightRecorderEntrySchema = z68.object({
15211
- schemaVersion: z68.literal(1).optional(),
15212
- id: z68.string().min(1),
15213
- taskId: z68.string().min(1),
15214
- runId: z68.string().min(1),
15215
- sequence: z68.number().int().nonnegative(),
15216
- timestamp: z68.string().min(1),
15217
- provider: FlightRecorderProviderSchema.or(z68.string()),
15218
- model: z68.string().min(1),
15219
- prompt: z68.string(),
15220
- durationSeconds: z68.number().nonnegative(),
15221
- aspectRatio: z68.string().optional(),
15222
- resolution: z68.string().optional(),
15223
- startImageUrl: z68.string().optional(),
15224
- endImageUrl: z68.string().optional(),
15225
- 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(),
15226
16067
  // Correlation & pipeline metadata
15227
- angleKey: z68.string().optional(),
15228
- sceneIndex: z68.number().int().nonnegative().optional(),
16068
+ angleKey: z72.string().optional(),
16069
+ sceneIndex: z72.number().int().nonnegative().optional(),
15229
16070
  generationType: FlightRecorderGenerationTypeSchema,
15230
- operationId: z68.string().min(1).optional(),
15231
- revisionId: z68.string().min(1).optional(),
15232
- 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),
15233
16074
  // Elements & Distillation
15234
- elements: z68.array(FlightRecorderElementSchema).optional(),
16075
+ elements: z72.array(FlightRecorderElementSchema).optional(),
15235
16076
  distillation: FlightRecorderDistillationSchema.optional(),
15236
16077
  // Raw payload (sanitized of secrets)
15237
- rawPayload: z68.record(z68.unknown())
16078
+ rawPayload: z72.record(z72.unknown())
15238
16079
  });
15239
- var FlightRecorderQuerySchema = z68.object({
15240
- taskId: z68.string().min(1),
15241
- runId: z68.string().optional(),
15242
- sceneIndex: z68.number().int().nonnegative().optional(),
15243
- 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(),
15244
16085
  generationType: FlightRecorderGenerationTypeSchema.optional(),
15245
- cursor: z68.number().int().nonnegative().optional(),
15246
- limit: z68.number().int().positive().optional()
16086
+ cursor: z72.number().int().nonnegative().optional(),
16087
+ limit: z72.number().int().positive().optional()
15247
16088
  });
15248
- var FlightRecorderResponseSchema = z68.object({
15249
- taskId: z68.string().min(1),
15250
- runId: z68.string().min(1),
15251
- 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),
15252
16093
  lastCall: FlightRecorderEntrySchema.nullable(),
15253
- count: z68.number().int().nonnegative(),
15254
- nextCursor: z68.number().int().nonnegative().nullable()
16094
+ count: z72.number().int().nonnegative(),
16095
+ nextCursor: z72.number().int().nonnegative().nullable()
15255
16096
  });
15256
16097
 
15257
16098
  // src/http.ts
@@ -15426,8 +16267,8 @@ async function readResponseText(response, maxBytes) {
15426
16267
  }
15427
16268
  __name(readResponseText, "readResponseText");
15428
16269
  async function readResponseJson(response, maxBytes) {
15429
- const text = await readResponseText(response, maxBytes);
15430
- return JSON.parse(text);
16270
+ const text2 = await readResponseText(response, maxBytes);
16271
+ return JSON.parse(text2);
15431
16272
  }
15432
16273
  __name(readResponseJson, "readResponseJson");
15433
16274
 
@@ -15760,22 +16601,22 @@ import { InsufficientScopeError, InvalidTokenError } from "@modelcontextprotocol
15760
16601
  import { createRemoteJWKSet as createRemoteJWKSet2, jwtVerify as jwtVerify2 } from "jose";
15761
16602
 
15762
16603
  // src/auth/oauth-config.ts
15763
- import { z as z69 } from "zod";
16604
+ import { z as z73 } from "zod";
15764
16605
  var MCP_RESOURCE = new URL("https://mcp.productmaker.app/mcp");
15765
16606
  var MCP_SCOPE = "mcp:access";
15766
16607
  var STATIC_CLIENT_ISSUER = new URL(MCP_RESOURCE.origin);
15767
- var oauthEnvSchema = z69.object({
15768
- MCP_REMOTE_AUTH_MODE: z69.literal("oauth"),
15769
- MCP_AUTH0_ISSUER: z69.string().trim().min(1),
15770
- 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, {
15771
16612
  message: `must equal ${MCP_RESOURCE.href}`
15772
16613
  }),
15773
- MCP_AUTH0_CLIENT_ID: z69.string().trim().min(1),
15774
- MCP_AUTH0_CLIENT_SECRET: z69.string().trim().min(1),
15775
- PM_API_AUDIENCE: z69.string().trim().min(1),
15776
- AUTH0_AUDIENCE: z69.string().trim().min(1),
15777
- MCP_STATIC_CLIENT_ID: z69.string().trim().min(1).optional(),
15778
- 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()
15779
16620
  });
15780
16621
  function formatZodIssues(error) {
15781
16622
  return error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
@@ -16059,7 +16900,7 @@ function badRequest(res, description) {
16059
16900
  __name(badRequest, "badRequest");
16060
16901
  function createOAuthProxyRouter(options) {
16061
16902
  const router = express.Router();
16062
- const stateKey = deriveStateKey(options.staticClient.clientSecret);
16903
+ const stateKey3 = deriveStateKey(options.staticClient.clientSecret);
16063
16904
  const now = options.now ?? (() => Date.now());
16064
16905
  router.get(OAUTH_PROXY_PATHS.authorize, (req, res) => {
16065
16906
  const redirectUri = firstQueryValue(req.query.redirect_uri);
@@ -16088,7 +16929,7 @@ function createOAuthProxyRouter(options) {
16088
16929
  }
16089
16930
  }
16090
16931
  upstream.searchParams.set("redirect_uri", PROXY_CALLBACK_URL);
16091
- upstream.searchParams.set("state", sealState(stateKey, {
16932
+ upstream.searchParams.set("state", sealState(stateKey3, {
16092
16933
  redirectUri,
16093
16934
  ...firstQueryValue(req.query.state) === void 0 ? {} : {
16094
16935
  clientState: firstQueryValue(req.query.state)
@@ -16098,7 +16939,7 @@ function createOAuthProxyRouter(options) {
16098
16939
  });
16099
16940
  router.get(OAUTH_PROXY_PATHS.callback, (req, res) => {
16100
16941
  const sealed = firstQueryValue(req.query.state);
16101
- const opened = sealed === void 0 ? void 0 : openState(stateKey, sealed, now());
16942
+ const opened = sealed === void 0 ? void 0 : openState(stateKey3, sealed, now());
16102
16943
  if (!opened) {
16103
16944
  badRequest(res, "state is missing, tampered with, or expired");
16104
16945
  return;
@@ -16882,7 +17723,7 @@ var ApiClient = class {
16882
17723
  };
16883
17724
 
16884
17725
  // src/index.ts
16885
- var MCP_VERSION = "8.1.0";
17726
+ var MCP_VERSION = "8.2.0";
16886
17727
 
16887
17728
  // src/meta-upload-app.ts
16888
17729
  import { readFileSync } from "fs";
@@ -16954,7 +17795,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
16954
17795
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
16955
17796
 
16956
17797
  // src/tools/tasks.ts
16957
- import { z as z73 } from "zod";
17798
+ import { z as z77 } from "zod";
16958
17799
 
16959
17800
  // src/resolve-image.ts
16960
17801
  import { lookup as dnsLookup } from "dns/promises";
@@ -17515,10 +18356,10 @@ async function resolveMediaRef(ref, opts) {
17515
18356
  __name(resolveMediaRef, "resolveMediaRef");
17516
18357
 
17517
18358
  // src/tools/shared.ts
17518
- import { z as z70 } from "zod";
17519
- 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);
17520
- var Country = z70.string().min(2).max(3);
17521
- 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([
17522
18363
  "auto",
17523
18364
  "classic",
17524
18365
  "pain_solution",
@@ -17527,12 +18368,12 @@ var LandingStrategyEnum = z70.enum([
17527
18368
  "offer_value",
17528
18369
  "lifestyle_identity"
17529
18370
  ]);
17530
- var LandingImageFormatEnum = z70.enum([
18371
+ var LandingImageFormatEnum = z74.enum([
17531
18372
  "9:16",
17532
18373
  "4:5",
17533
18374
  "1:1"
17534
18375
  ]);
17535
- var VideoPresetEnum = z70.enum([
18376
+ var VideoPresetEnum = z74.enum([
17536
18377
  "auto",
17537
18378
  "ugc_dynamic",
17538
18379
  "ugc_how_to",
@@ -17545,21 +18386,21 @@ var VideoPresetEnum = z70.enum([
17545
18386
  "pixar_problem",
17546
18387
  "pixar_sassy"
17547
18388
  ]);
17548
- var VideoStructureEnum = z70.enum([
18389
+ var VideoStructureEnum = z74.enum([
17549
18390
  "single_take",
17550
18391
  "multi_scene"
17551
18392
  ]);
17552
- var VideoQualityEnum = z70.enum([
18393
+ var VideoQualityEnum = z74.enum([
17553
18394
  "economy",
17554
18395
  "medium",
17555
18396
  "pro"
17556
18397
  ]);
17557
- var VideoRouteIdEnum = z70.enum([
18398
+ var VideoRouteIdEnum = z74.enum([
17558
18399
  "single_take",
17559
18400
  "multi_scene",
17560
18401
  "free"
17561
18402
  ]);
17562
- var TaskCreativeVariantVideoPresetEnum = z70.enum([
18403
+ var TaskCreativeVariantVideoPresetEnum = z74.enum([
17563
18404
  "auto",
17564
18405
  "ugc_dynamic",
17565
18406
  "ugc_how_to",
@@ -17576,53 +18417,43 @@ var VIDEO_PRESET_RESOLUTION = {
17576
18417
  auto: null,
17577
18418
  ugc_dynamic: {
17578
18419
  videoStyle: "ai_dynamic",
17579
- narrativeStyle: "review",
17580
- videoModel: "veo"
18420
+ narrativeStyle: "review"
17581
18421
  },
17582
18422
  ugc_how_to: {
17583
18423
  videoStyle: "ai_dynamic",
17584
- narrativeStyle: "ugc_how_to",
17585
- videoModel: "veo"
18424
+ narrativeStyle: "ugc_how_to"
17586
18425
  },
17587
18426
  ugc_unboxing_chaos: {
17588
18427
  videoStyle: "ai_dynamic",
17589
- narrativeStyle: "ugc_unboxing_chaos",
17590
- videoModel: "veo"
18428
+ narrativeStyle: "ugc_unboxing_chaos"
17591
18429
  },
17592
18430
  problem_solution: {
17593
18431
  videoStyle: "ai_dynamic",
17594
- narrativeStyle: "problem_product_cta",
17595
- videoModel: "kling"
18432
+ narrativeStyle: "problem_product_cta"
17596
18433
  },
17597
18434
  pixar_problem: {
17598
18435
  videoStyle: "ai_dynamic",
17599
- narrativeStyle: "animated_problem_pixar",
17600
- videoModel: "kling"
18436
+ narrativeStyle: "animated_problem_pixar"
17601
18437
  },
17602
18438
  pixar_sassy: {
17603
18439
  videoStyle: "ai_dynamic",
17604
- narrativeStyle: "sassy_product_pixar",
17605
- videoModel: "seedance"
18440
+ narrativeStyle: "sassy_product_pixar"
17606
18441
  },
17607
18442
  product_showcase: {
17608
18443
  videoStyle: "product_only",
17609
- narrativeStyle: "product_showcase",
17610
- videoModel: "veo"
18444
+ narrativeStyle: "product_showcase"
17611
18445
  },
17612
18446
  wearable_showcase: {
17613
18447
  videoStyle: "ugc",
17614
- narrativeStyle: "wearable_showcase",
17615
- videoModel: "veo"
18448
+ narrativeStyle: "wearable_showcase"
17616
18449
  },
17617
18450
  cinematic: {
17618
18451
  videoStyle: "product_only",
17619
- narrativeStyle: "cinematic",
17620
- videoModel: "grok"
18452
+ narrativeStyle: "cinematic"
17621
18453
  },
17622
18454
  wild_card: {
17623
18455
  videoStyle: "product_only",
17624
- narrativeStyle: "wild_card",
17625
- videoModel: "grok"
18456
+ narrativeStyle: "wild_card"
17626
18457
  }
17627
18458
  };
17628
18459
  function resolveVideoPreset(preset) {
@@ -17630,7 +18461,7 @@ function resolveVideoPreset(preset) {
17630
18461
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
17631
18462
  }
17632
18463
  __name(resolveVideoPreset, "resolveVideoPreset");
17633
- var VideoTierEnum = z70.enum([
18464
+ var VideoTierEnum = z74.enum([
17634
18465
  "basic"
17635
18466
  ]);
17636
18467
  function resolveVideoTier(_tier) {
@@ -17670,22 +18501,22 @@ function assertSemanticVideoDurationCompatibility(structure, quality, durationSe
17670
18501
  }
17671
18502
  }
17672
18503
  __name(assertSemanticVideoDurationCompatibility, "assertSemanticVideoDurationCompatibility");
17673
- var VideoResolutionEnum = z70.enum([
18504
+ var VideoResolutionEnum = z74.enum([
17674
18505
  "480p",
17675
18506
  "720p"
17676
18507
  ]);
17677
- var CreativeGenderEnum = z70.enum([
18508
+ var CreativeGenderEnum = z74.enum([
17678
18509
  "female",
17679
18510
  "male",
17680
18511
  "mixed"
17681
18512
  ]);
17682
- var VideoStyleEnum = z70.enum([
18513
+ var VideoStyleEnum = z74.enum([
17683
18514
  "ugc",
17684
18515
  "cartoon_3d",
17685
18516
  "product_only",
17686
18517
  "ai_dynamic"
17687
18518
  ]);
17688
- var NarrativeStyleEnum = z70.enum([
18519
+ var NarrativeStyleEnum = z74.enum([
17689
18520
  "review",
17690
18521
  "ugc_how_to",
17691
18522
  "problem_product_cta",
@@ -17703,7 +18534,7 @@ var NarrativeStyleEnum = z70.enum([
17703
18534
  "ugc_demo_review",
17704
18535
  "market"
17705
18536
  ]);
17706
- var PublicNarrativeStyleEnum = z70.enum([
18537
+ var PublicNarrativeStyleEnum = z74.enum([
17707
18538
  "review",
17708
18539
  "ugc_how_to",
17709
18540
  "ugc_unboxing_chaos",
@@ -17716,7 +18547,7 @@ var PublicNarrativeStyleEnum = z70.enum([
17716
18547
  "sassy_product_pixar",
17717
18548
  "market"
17718
18549
  ]);
17719
- var VideoModelEnum = z70.enum([
18550
+ var TaskVideoModelEnum = z74.enum([
17720
18551
  "veo",
17721
18552
  "wan",
17722
18553
  "bytedance",
@@ -17724,29 +18555,29 @@ var VideoModelEnum = z70.enum([
17724
18555
  "grok",
17725
18556
  "kling"
17726
18557
  ]);
17727
- var ProductReferenceUserChoiceEnum = z70.enum([
18558
+ var ProductReferenceUserChoiceEnum = z74.enum([
17728
18559
  "same_product",
17729
18560
  "variants",
17730
18561
  "different_products",
17731
18562
  "combo_distinct"
17732
18563
  ]);
17733
- var ProductReferenceCandidateGroupingEnum = z70.enum([
18564
+ var ProductReferenceCandidateGroupingEnum = z74.enum([
17734
18565
  "same_product_same_variant",
17735
18566
  "same_product_different_variants",
17736
18567
  "different_products",
17737
18568
  "unclear"
17738
18569
  ]);
17739
- var ProductReferenceScopeEnum = z70.enum([
18570
+ var ProductReferenceScopeEnum = z74.enum([
17740
18571
  "base",
17741
18572
  "video_view_pack"
17742
18573
  ]);
17743
- var ProductReferenceResolutionDecisionEnum = z70.enum([
18574
+ var ProductReferenceResolutionDecisionEnum = z74.enum([
17744
18575
  "approve",
17745
18576
  "reject",
17746
18577
  "observed_only",
17747
18578
  "correct_view"
17748
18579
  ]);
17749
- var ProductReferenceRejectionReasonEnum = z70.enum([
18580
+ var ProductReferenceRejectionReasonEnum = z74.enum([
17750
18581
  "replacement_requested",
17751
18582
  "wrong_product_identity",
17752
18583
  "wrong_variant",
@@ -17757,13 +18588,13 @@ var ProductReferenceRejectionReasonEnum = z70.enum([
17757
18588
  "not_a_product_photo",
17758
18589
  "other"
17759
18590
  ]);
17760
- var GapDurationChoiceMirror = z70.object({
17761
- angleIndex: z70.number().int().nonnegative(),
17762
- recommendedSec: z70.union([
17763
- z70.literal(15),
17764
- 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)
17765
18596
  ]),
17766
- estimatedDeltaCredits: z70.number().int().nonnegative().optional()
18597
+ estimatedDeltaCredits: z74.number().int().nonnegative().optional()
17767
18598
  });
17768
18599
  function buildSelectedImageUrlsHash(urls) {
17769
18600
  const input = [
@@ -17773,13 +18604,13 @@ function buildSelectedImageUrlsHash(urls) {
17773
18604
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
17774
18605
  }
17775
18606
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
17776
- var ImageCreativeStyleEnum = z70.enum([
18607
+ var ImageCreativeStyleEnum = z74.enum([
17777
18608
  "studio",
17778
18609
  "floating",
17779
18610
  "ingredients",
17780
18611
  "in_use"
17781
18612
  ]);
17782
- var ImageCreativeArchetypeEnum = z70.enum([
18613
+ var ImageCreativeArchetypeEnum = z74.enum([
17783
18614
  "direct_response_product_ad",
17784
18615
  "hero_outcome",
17785
18616
  "offer_value_prop",
@@ -17788,20 +18619,20 @@ var ImageCreativeArchetypeEnum = z70.enum([
17788
18619
  "problem_solution",
17789
18620
  "lifestyle_identity"
17790
18621
  ]);
17791
- var ImageCreativeVisualTreatmentEnum = z70.enum([
18622
+ var ImageCreativeVisualTreatmentEnum = z74.enum([
17792
18623
  "performance_product_ad",
17793
18624
  "premium_dtc_carousel"
17794
18625
  ]);
17795
- var ImageCreativeAspectRatioEnum = z70.enum([
18626
+ var ImageCreativeAspectRatioEnum = z74.enum([
17796
18627
  "1:1",
17797
18628
  "4:5",
17798
18629
  "9:16",
17799
18630
  "16:9"
17800
18631
  ]);
17801
- var ImageRefSchema = z70.object({
17802
- 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.'),
17803
- 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`.'),
17804
- 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.")
17805
18636
  }).refine((v) => [
17806
18637
  v.url,
17807
18638
  v.path,
@@ -17809,11 +18640,11 @@ var ImageRefSchema = z70.object({
17809
18640
  ].filter(Boolean).length === 1, {
17810
18641
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
17811
18642
  });
17812
- 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) => {
17813
18644
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
17814
18645
  if (assetCount > 0 && assetCount !== images.length) {
17815
18646
  ctx.addIssue({
17816
- code: z70.ZodIssueCode.custom,
18647
+ code: z74.ZodIssueCode.custom,
17817
18648
  message: "all image entries must use assetId, or all must use URL/path sources"
17818
18649
  });
17819
18650
  }
@@ -17881,14 +18712,14 @@ async function submitCreative(api, opts) {
17881
18712
  });
17882
18713
  }
17883
18714
  __name(submitCreative, "submitCreative");
17884
- var ResearchTargetCountryEnum = z70.enum([
18715
+ var ResearchTargetCountryEnum = z74.enum([
17885
18716
  "CO",
17886
18717
  "MX",
17887
18718
  "PE",
17888
18719
  "EC",
17889
18720
  "CL"
17890
18721
  ]);
17891
- var ResearchCategoryEnum = z70.enum([
18722
+ var ResearchCategoryEnum = z74.enum([
17892
18723
  "auto",
17893
18724
  "automotive",
17894
18725
  "kitchen",
@@ -17957,7 +18788,7 @@ var OVERWRITES_EXTERNAL = {
17957
18788
  idempotentHint: false,
17958
18789
  openWorldHint: false
17959
18790
  };
17960
- var DailyControlStatusEnum = z70.enum([
18791
+ var DailyControlStatusEnum = z74.enum([
17961
18792
  "ok",
17962
18793
  "sales_unavailable",
17963
18794
  "timezone_unavailable",
@@ -17970,19 +18801,19 @@ var DailyControlStatusEnum = z70.enum([
17970
18801
  "product_missing",
17971
18802
  "store_unreachable"
17972
18803
  ]);
17973
- var DailyControlLightEnum = z70.enum([
18804
+ var DailyControlLightEnum = z74.enum([
17974
18805
  "green",
17975
18806
  "amber",
17976
18807
  "red",
17977
18808
  "none"
17978
18809
  ]);
17979
- var DailyControlVerdictEnum = z70.enum([
18810
+ var DailyControlVerdictEnum = z74.enum([
17980
18811
  "scale",
17981
18812
  "hold",
17982
18813
  "kill",
17983
18814
  "insufficient_sample"
17984
18815
  ]);
17985
- var DailyControlSourceEnum = z70.enum([
18816
+ var DailyControlSourceEnum = z74.enum([
17986
18817
  "shopify",
17987
18818
  "shopify_settling",
17988
18819
  "user",
@@ -19070,29 +19901,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
19070
19901
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
19071
19902
 
19072
19903
  // src/tools/media-presentation.ts
19073
- import { z as z71 } from "zod";
19074
- 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:");
19075
19906
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
19076
19907
  const hostname = new URL(value).hostname.toLowerCase();
19077
19908
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
19078
19909
  }, "preview URL must be owned by ProductMaker");
19079
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z71.number().int().positive().max(maximum), "positiveIntAtMost");
19080
- var PresentationImageSchema = z71.object({
19081
- 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"),
19082
19913
  url: HttpsPresentationUrlSchema,
19083
- mimeType: z71.enum([
19914
+ mimeType: z75.enum([
19084
19915
  "image/jpeg",
19085
19916
  "image/png"
19086
19917
  ]),
19087
19918
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
19088
19919
  width: positiveIntAtMost(16384),
19089
19920
  height: positiveIntAtMost(16384),
19090
- alt: z71.string().trim().min(1).max(240)
19921
+ alt: z75.string().trim().min(1).max(240)
19091
19922
  }).strict();
19092
19923
  var McpMediaPresentationSchema = PresentationImageSchema;
19093
- var GalleryImageSchema = z71.object({
19924
+ var GalleryImageSchema = z75.object({
19094
19925
  url: ProductMakerPreviewUrlSchema,
19095
- alt: z71.string().trim().min(1).max(240)
19926
+ alt: z75.string().trim().min(1).max(240)
19096
19927
  });
19097
19928
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
19098
19929
  async function imageBlocks(image, transport) {
@@ -19242,10 +20073,10 @@ ${summary}`,
19242
20073
  __name(requirePaidCreativeConfirmation, "requirePaidCreativeConfirmation");
19243
20074
 
19244
20075
  // src/tools/winning-product-image.ts
19245
- import { z as z72 } from "zod";
19246
- var WinnerReferenceInput = z72.object({
19247
- runId: z72.string().uuid(),
19248
- 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)
19249
20080
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
19250
20081
  async function resolveWinnerImages(api, winnerReference, images) {
19251
20082
  if (!winnerReference) return images;
@@ -19282,59 +20113,59 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
19282
20113
  var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
19283
20114
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
19284
20115
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
19285
- var CreateProductTaskInput = z73.object({
20116
+ var CreateProductTaskInput = z77.object({
19286
20117
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
19287
20118
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
19288
- 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."),
19289
- 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."),
19290
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.'),
19291
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.'),
19292
- 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.'),
19293
- 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".'),
19294
- 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.'),
19295
- 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.'),
19296
- 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."),
19297
- 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.'),
19298
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.'),
19299
- durationSeconds: z73.union([
19300
- z73.literal(15),
19301
- z73.literal(30)
20130
+ durationSeconds: z77.union([
20131
+ z77.literal(15),
20132
+ z77.literal(30)
19302
20133
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
19303
- 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."),
19304
- 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."),
19305
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.'),
19306
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.'),
19307
20138
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
19308
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).'),
19309
- 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."),
19310
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.'),
19311
- outputs: z73.array(z73.enum([
20142
+ outputs: z77.array(z77.enum([
19312
20143
  "landing",
19313
20144
  "video",
19314
20145
  "image"
19315
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}`),
19316
- 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."),
19317
- 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."),
19318
- 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."),
19319
- 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."),
19320
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.'),
19321
- 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.'),
19322
- 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."),
19323
- 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."),
19324
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".'),
19325
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".')
19326
20157
  }).strict();
19327
- var CreateServiceVideoInput = z73.object({
19328
- 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."),
19329
- 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.'),
19330
20161
  language: Lang.describe("Idioma del video: es, en o pt."),
19331
- 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.'),
19332
- brandId: z73.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
19333
- 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([
19334
20165
  "automatic",
19335
20166
  "guided"
19336
20167
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
19337
- videoPreset: z73.enum([
20168
+ videoPreset: z77.enum([
19338
20169
  "auto",
19339
20170
  "ugc_dynamic",
19340
20171
  "ugc_how_to",
@@ -19344,128 +20175,128 @@ var CreateServiceVideoInput = z73.object({
19344
20175
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
19345
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.')
19346
20177
  }).strict();
19347
- var GetTaskStatusInput = z73.object({
19348
- taskId: z73.string().min(1),
19349
- 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()
19350
20181
  });
19351
- var ListTasksInput = z73.object({
19352
- limit: z73.number().int().min(1).max(50).optional(),
19353
- offset: z73.number().int().min(0).optional(),
19354
- 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()
19355
20186
  });
19356
20187
  var MCP_REVIEW_LIST_FIELD_MAX = 1500;
19357
20188
  var MCP_REVIEW_FEATURE_ITEM_MAX = 240;
19358
- var EditTaskDraftInput = z73.object({
19359
- taskId: z73.string().min(1),
19360
- angleIndex: z73.number().int().min(0),
19361
- angle: z73.object({
19362
- angle: z73.string().min(1).max(480),
19363
- buyerPersona: z73.string().min(1).max(360),
19364
- actor: z73.string().min(1).max(360).optional(),
19365
- 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."),
19366
- 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([
19367
20198
  "female",
19368
20199
  "male"
19369
20200
  ]).optional(),
19370
- scriptNotes: z73.string().max(2e3).optional()
20201
+ scriptNotes: z77.string().max(2e3).optional()
19371
20202
  })
19372
20203
  });
19373
- var PendingActionPayload = z73.discriminatedUnion("kind", [
19374
- z73.object({
19375
- kind: z73.literal("product_reference_set_approval"),
20204
+ var PendingActionPayload = z77.discriminatedUnion("kind", [
20205
+ z77.object({
20206
+ kind: z77.literal("product_reference_set_approval"),
19376
20207
  scope: ProductReferenceScopeEnum.optional(),
19377
- scopeKey: z73.string().min(1).max(120).optional(),
19378
- scopeSnapshotId: z73.string().uuid().optional(),
19379
- 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(),
19380
20211
  decision: ProductReferenceResolutionDecisionEnum,
19381
20212
  reason: ProductReferenceRejectionReasonEnum.optional(),
19382
- affectedRefKeys: z73.array(z73.string().min(1).max(200)).min(1).optional(),
19383
- affectedPhotoNumbers: z73.array(z73.number().int().positive()).min(1).optional(),
19384
- 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([
19385
20216
  "remove",
19386
20217
  "replace",
19387
20218
  "upload",
19388
20219
  "return_to_selection"
19389
20220
  ]).optional()
19390
20221
  }),
19391
- z73.object({
19392
- kind: z73.literal("product_reference_confirmation"),
19393
- 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."),
19394
20225
  userChoice: ProductReferenceUserChoiceEnum.optional(),
19395
- 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(),
19396
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."),
19397
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."),
19398
- 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.")
19399
20230
  }),
19400
- z73.object({
19401
- kind: z73.literal("angle_review_approval"),
20231
+ z77.object({
20232
+ kind: z77.literal("angle_review_approval"),
19402
20233
  // All edits are optional — empty action body just approves the
19403
20234
  // backend-generated draft as-is. Field shapes mirror the angle-review
19404
20235
  // request contracts in @packages/types/wizard.ts; the handler routes to
19405
20236
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
19406
- customAngle: z73.string().min(1).max(480).optional(),
20237
+ customAngle: z77.string().min(1).max(480).optional(),
19407
20238
  // Keep the shared MCP action within the strictest downstream contract:
19408
20239
  // autopilot/image resume endpoints cap these fields at 1500 characters.
19409
- painPoints: z73.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19410
- 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(),
19411
20242
  // Same policy as the two fields above: the strictest downstream contract
19412
20243
  // wins. The image endpoint caps each feature at 240 while landing/video
19413
20244
  // accept 300, and this single action routes to whichever the task is — so
19414
20245
  // accepting 300 here turns a 250-character feature on an image task into
19415
20246
  // an opaque HTTP 400 after the model already believed it had been saved.
19416
- features: z73.array(z73.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
19417
- 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(),
19418
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.'),
19419
- 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."),
19420
- actorId: z73.string().max(120).nullable().optional(),
19421
- creativeDirection: z73.string().max(2e3).optional(),
19422
- 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."),
19423
- angleEdits: z73.array(z73.object({
19424
- angleNumber: z73.number().int().positive(),
19425
- 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([
19426
20257
  "market",
19427
20258
  "guided"
19428
20259
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
19429
- angle: z73.string().min(1).max(480).optional(),
19430
- 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(),
19431
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.'),
19432
- actor: z73.string().min(1).max(360).optional(),
19433
- actorId: z73.string().max(120).nullable().optional(),
19434
- 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()
19435
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)."),
19436
- gapDurationSeconds: z73.union([
19437
- z73.literal(15),
19438
- z73.literal(30)
20267
+ gapDurationSeconds: z77.union([
20268
+ z77.literal(15),
20269
+ z77.literal(30)
19439
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.")
19440
20271
  }),
19441
- z73.object({
19442
- kind: z73.literal("service_angle_approval"),
19443
- angleId: z73.string().uuid().optional(),
19444
- angleNumber: z73.number().int().positive().optional(),
19445
- content: z73.string().min(1).max(480).optional(),
19446
- creativeDirection: z73.string().min(1).max(1500).optional(),
19447
- 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()
19448
20279
  }),
19449
- z73.object({
19450
- kind: z73.literal("service_script_approval"),
19451
- voiceovers: z73.record(z73.string(), z73.string().min(1).max(600)).optional(),
19452
- visualDirections: z73.record(z73.string(), z73.string().min(1).max(1200)).optional(),
19453
- voiceoversByScene: z73.record(z73.string(), z73.string().min(1).max(600)).optional(),
19454
- 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()
19455
20286
  })
19456
20287
  ]);
19457
- var ResolvePendingActionInput = z73.object({
19458
- taskId: z73.string().min(1),
20288
+ var ResolvePendingActionInput = z77.object({
20289
+ taskId: z77.string().min(1),
19459
20290
  action: PendingActionPayload
19460
20291
  }).strict();
19461
20292
  function resolveVariantConfirmVideoTier(action) {
19462
20293
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
19463
20294
  }
19464
20295
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
19465
- var StatusForResolveSchema = z73.object({
20296
+ var StatusForResolveSchema = z77.object({
19466
20297
  // Metadata used to select the backend resume contract. Older API responses
19467
20298
  // may omit these fields, so the resolver keeps the generic fallback.
19468
- kind: z73.enum([
20299
+ kind: z77.enum([
19469
20300
  "autopilot",
19470
20301
  "video",
19471
20302
  "image",
@@ -19473,18 +20304,18 @@ var StatusForResolveSchema = z73.object({
19473
20304
  "mix",
19474
20305
  "service"
19475
20306
  ]).optional(),
19476
- selectedOutputs: z73.array(z73.enum([
20307
+ selectedOutputs: z77.array(z77.enum([
19477
20308
  "landing",
19478
20309
  "video",
19479
20310
  "image"
19480
20311
  ])).optional(),
19481
- videoAngleCount: z73.number().int().min(1).max(3).optional(),
19482
- ugcFormat: z73.enum([
20312
+ videoAngleCount: z77.number().int().min(1).max(3).optional(),
20313
+ ugcFormat: z77.enum([
19483
20314
  "single_8s",
19484
20315
  "single_15s",
19485
20316
  "double_30s"
19486
20317
  ]).optional(),
19487
- videoStyle: z73.enum([
20318
+ videoStyle: z77.enum([
19488
20319
  "ugc",
19489
20320
  "cartoon_3d",
19490
20321
  "product_only",
@@ -19493,79 +20324,72 @@ var StatusForResolveSchema = z73.object({
19493
20324
  videoStructure: VideoStructureEnum.optional(),
19494
20325
  videoQuality: VideoQualityEnum.optional(),
19495
20326
  videoRouteId: VideoRouteIdEnum.optional(),
19496
- videoModel: z73.enum([
19497
- "veo",
19498
- "wan",
19499
- "bytedance",
19500
- "seedance",
19501
- "grok",
19502
- "kling"
19503
- ]).optional(),
19504
- videoTier: z73.enum([
20327
+ videoModel: TaskVideoModelEnum.optional(),
20328
+ videoTier: z77.enum([
19505
20329
  "legacy",
19506
20330
  "standard",
19507
20331
  "pro",
19508
20332
  "single_call"
19509
20333
  ]).optional(),
19510
- videoResolution: z73.enum([
20334
+ videoResolution: z77.enum([
19511
20335
  "480p",
19512
20336
  "720p"
19513
20337
  ]).optional(),
19514
20338
  narrativeStyle: NarrativeStyleEnum.optional(),
19515
- pauseForVideoScriptReview: z73.boolean().optional(),
19516
- pendingUserAction: z73.object({
19517
- kind: z73.string(),
19518
- candidateGrouping: z73.string().optional(),
19519
- selectedImageUrls: z73.array(z73.string()).optional(),
19520
- 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(),
19521
20345
  // Adaptive reference questions are server-owned. Echo only the evidence
19522
20346
  // identity and the choices shown by the current snapshot; never accept a
19523
20347
  // client-supplied reference set as authorization.
19524
- options: z73.array(ProductReferenceUserChoiceEnum).max(4).optional(),
19525
- mode: z73.enum([
20348
+ options: z77.array(ProductReferenceUserChoiceEnum).max(4).optional(),
20349
+ mode: z77.enum([
19526
20350
  "question",
19527
20351
  "visual_recovery"
19528
20352
  ]).optional(),
19529
20353
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
19530
- canKeepSelection: z73.boolean().optional(),
19531
- decisionKey: z73.string().optional(),
19532
- questionOrdinal: z73.number().int().min(1).max(5).optional(),
19533
- questionCeiling: z73.union([
19534
- z73.literal(3),
19535
- 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)
19536
20360
  ]).optional(),
19537
- referenceEvidenceVersion: z73.number().int().positive().optional(),
19538
- expectedEvidenceHash: z73.string().optional(),
19539
- question: z73.object({
19540
- prompt: z73.string().min(1).max(240),
19541
- helpText: z73.string().min(1).max(300).optional(),
19542
- 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({
19543
20367
  value: ProductReferenceUserChoiceEnum,
19544
- label: z73.string().min(1).max(120),
19545
- 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()
19546
20370
  })).min(2).max(4)
19547
20371
  }).optional(),
19548
20372
  scope: ProductReferenceScopeEnum.optional(),
19549
- scopeKey: z73.string().optional(),
19550
- scopeSnapshotId: z73.string().uuid().optional(),
19551
- scopeHash: z73.string().optional(),
19552
- baseReferenceSetHash: z73.string().optional(),
19553
- 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([
19554
20378
  "preparation",
19555
20379
  "final"
19556
20380
  ]).optional(),
19557
- selectedRefKeys: z73.array(z73.string().min(1).max(200)).optional(),
19558
- allowedDecisions: z73.array(ProductReferenceResolutionDecisionEnum).optional(),
19559
- previews: z73.array(z73.object({
19560
- 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)
19561
20385
  }).passthrough()).optional(),
19562
- customAngleDraft: z73.string().optional(),
19563
- painPointsDraft: z73.string().optional(),
19564
- benefitsDraft: z73.string().optional(),
19565
- featuresDraft: z73.array(z73.string()).optional(),
19566
- angleOptions: z73.array(z73.object({
19567
- index: z73.number().int().nonnegative(),
19568
- 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)
19569
20393
  }).passthrough()).min(1).max(5).optional(),
19570
20394
  // Recommendation consumed only when the caller explicitly sends
19571
20395
  // gapDurationSeconds: 30 in the angle approval action.
@@ -19575,17 +20399,17 @@ var StatusForResolveSchema = z73.object({
19575
20399
  // keys. `actorId` (the saved custom actor the picker stored) was silently
19576
20400
  // dropped here, so the approval handler below could not echo it back on the
19577
20401
  // PATCH — the selection looked accepted and reached no render.
19578
- angles: z73.array(z73.object({
19579
- id: z73.string().uuid(),
19580
- content: z73.string(),
19581
- creativeDirection: z73.string(),
19582
- actor: z73.string(),
19583
- 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()
19584
20408
  }).passthrough()).optional(),
19585
- panels: z73.array(z73.object({
19586
- beatId: z73.string(),
19587
- voiceover: z73.string(),
19588
- visualDirection: z73.string()
20409
+ panels: z77.array(z77.object({
20410
+ beatId: z77.string(),
20411
+ voiceover: z77.string(),
20412
+ visualDirection: z77.string()
19589
20413
  }).passthrough()).optional()
19590
20414
  }).optional()
19591
20415
  }).passthrough();
@@ -20420,7 +21244,7 @@ __name(registerTaskTools, "registerTaskTools");
20420
21244
 
20421
21245
  // src/tools/creatives.ts
20422
21246
  import { randomUUID } from "crypto";
20423
- import { z as z74 } from "zod";
21247
+ import { z as z78 } from "zod";
20424
21248
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
20425
21249
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
20426
21250
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -20430,70 +21254,70 @@ var CreativeRefs = {
20430
21254
  images: ImagesInput,
20431
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.'),
20432
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.'),
20433
- 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.'),
20434
- 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.'),
20435
- 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".'),
20436
- 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."),
20437
- 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.'),
20438
- 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.'),
20439
- isCombo: z74.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
20440
- 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."),
20441
- 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.")
20442
21266
  };
20443
- var VideoPresenter = z74.discriminatedUnion("mode", [
20444
- z74.object({
20445
- mode: z74.literal("none")
21267
+ var VideoPresenter = z78.discriminatedUnion("mode", [
21268
+ z78.object({
21269
+ mode: z78.literal("none")
20446
21270
  }).strict(),
20447
- z74.object({
20448
- mode: z74.literal("saved_actor"),
20449
- 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.")
20450
21274
  }).strict(),
20451
- z74.object({
20452
- mode: z74.literal("described"),
20453
- 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.")
20454
21278
  }).strict()
20455
21279
  ]);
20456
- var VideoCreativeSetup = z74.discriminatedUnion("mode", [
20457
- z74.object({
20458
- 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".')
20459
21283
  }).strict(),
20460
- z74.object({
20461
- mode: z74.literal("guided"),
21284
+ z78.object({
21285
+ mode: z78.literal("guided"),
20462
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.'),
20463
- buyerPersona: z74.string().trim().min(1).max(360),
21287
+ buyerPersona: z78.string().trim().min(1).max(360),
20464
21288
  presenter: VideoPresenter,
20465
- 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.")
20466
21290
  }).strict()
20467
21291
  ]);
20468
- var VideoInput = z74.object({
21292
+ var VideoInput = z78.object({
20469
21293
  images: CreativeRefs.images.optional(),
20470
21294
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20471
- title: z74.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
20472
- 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".'),
20473
21297
  language: CreativeRefs.language,
20474
21298
  country: CreativeRefs.country,
20475
- aspectRatio: z74.enum([
21299
+ aspectRatio: z78.enum([
20476
21300
  "9:16",
20477
21301
  "16:9",
20478
21302
  "Auto"
20479
21303
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
20480
- 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."),
20481
- 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."),
20482
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.'),
20483
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."),
20484
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.'),
20485
21309
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
20486
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.'),
20487
- 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"].'),
20488
21312
  price: CreativeRefs.price,
20489
21313
  offer: CreativeRefs.offer,
20490
21314
  productContext: CreativeRefs.productContext,
20491
21315
  productLabel: CreativeRefs.productLabel,
20492
- 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.'),
20493
- 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.'),
20494
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.'),
20495
21319
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
20496
- 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."),
20497
21321
  brandId: CreativeRefs.brandId
20498
21322
  }).strict();
20499
21323
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -20511,7 +21335,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
20511
21335
  length: 29
20512
21336
  }, (_, index) => index + 2)
20513
21337
  };
20514
- var FreeVideoModelIdEnum = z74.enum([
21338
+ var FreeVideoModelIdEnum = z78.enum([
20515
21339
  "grok-imagine-video-1-5-preview",
20516
21340
  "minimax-h3/reference-to-video",
20517
21341
  "wan/3-0-video",
@@ -20522,70 +21346,65 @@ var FREE_SELECTABLE_MODEL_IDS = [
20522
21346
  "minimax-h3/reference-to-video",
20523
21347
  "wan/3-0-video"
20524
21348
  ];
20525
- var FreeVideoInput = z74.object({
21349
+ var FreeVideoInput = z78.object({
20526
21350
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
20527
- 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."),
20528
21352
  language: CreativeRefs.language,
20529
21353
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
20530
21354
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
20531
21355
  // parsed ONLY so the handler can reject it with a message naming its
20532
21356
  // replacement — dropping it silently would turn a caller's explicit
20533
21357
  // Pro++ pick into a quiet fallback to Wan.
20534
- freeProModel: z74.enum([
21358
+ freeProModel: z78.enum([
20535
21359
  "wan",
20536
21360
  "seedance"
20537
21361
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
20538
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.'),
20539
- 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."),
20540
21364
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
20541
- generateAiMusic: z74.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
20542
- addSubtitles: z74.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
20543
- 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.")
20544
21368
  }).strict();
20545
21369
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
20546
- var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20547
- z74.object({
20548
- mode: z74.literal("automatic")
21370
+ var ImageCreativeSetup = z78.discriminatedUnion("mode", [
21371
+ z78.object({
21372
+ mode: z78.literal("automatic")
20549
21373
  }).strict(),
20550
- z74.object({
20551
- mode: z74.literal("guided"),
20552
- creativeArchetype: z74.union([
21374
+ z78.object({
21375
+ mode: z78.literal("guided"),
21376
+ creativeArchetype: z78.union([
20553
21377
  ImageCreativeArchetypeEnum,
20554
- z74.literal("ai_decides")
21378
+ z78.literal("ai_decides")
20555
21379
  ]),
20556
- visualTreatment: z74.union([
21380
+ visualTreatment: z78.union([
20557
21381
  ImageCreativeVisualTreatmentEnum,
20558
- z74.literal("ai_decides")
21382
+ z78.literal("ai_decides")
20559
21383
  ]),
20560
21384
  aspectRatio: ImageCreativeAspectRatioEnum,
20561
- nVariants: z74.union([
20562
- z74.literal(1),
20563
- z74.literal(2),
20564
- z74.literal(3),
20565
- z74.literal(4),
20566
- z74.literal(6)
20567
- ]),
20568
- imageModel: z74.enum([
20569
- "gpt-image-2-5:1k",
20570
- "gpt-image-2-5:2k",
20571
- "gpt-image-2:1k",
20572
- "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)
20573
21391
  ]),
20574
- 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."),
20575
- generateAdCopy: z74.boolean(),
20576
- competitorScanEnabled: z74.boolean(),
20577
- productContext: z74.string().trim().min(1).max(3e3).nullable(),
20578
- creativeDirection: z74.string().trim().min(1).max(500).nullable(),
20579
- 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.'),
20580
- headline: z74.string().trim().min(1).max(120).nullable(),
20581
- 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()
20582
21401
  }).strict()
20583
21402
  ]).superRefine((setup, context) => {
20584
21403
  if (setup.mode !== "guided") return;
20585
21404
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
20586
21405
  if (needsStyleMix && setup.styleMix === null) {
20587
21406
  context.addIssue({
20588
- code: z74.ZodIssueCode.custom,
21407
+ code: z78.ZodIssueCode.custom,
20589
21408
  path: [
20590
21409
  "styleMix"
20591
21410
  ],
@@ -20594,16 +21413,16 @@ var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20594
21413
  }
20595
21414
  if (!needsStyleMix && setup.styleMix !== null) {
20596
21415
  context.addIssue({
20597
- code: z74.ZodIssueCode.custom,
21416
+ code: z78.ZodIssueCode.custom,
20598
21417
  path: [
20599
21418
  "styleMix"
20600
21419
  ],
20601
21420
  message: "styleMix debe ser null cuando nVariants es 1 o 6."
20602
21421
  });
20603
21422
  }
20604
- 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") {
20605
21424
  context.addIssue({
20606
- code: z74.ZodIssueCode.custom,
21425
+ code: z78.ZodIssueCode.custom,
20607
21426
  path: [
20608
21427
  "aspectRatio"
20609
21428
  ],
@@ -20611,53 +21430,53 @@ var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20611
21430
  });
20612
21431
  }
20613
21432
  });
20614
- var LandingCreativeSetup = z74.discriminatedUnion("mode", [
20615
- z74.object({
20616
- mode: z74.literal("automatic")
21433
+ var LandingCreativeSetup = z78.discriminatedUnion("mode", [
21434
+ z78.object({
21435
+ mode: z78.literal("automatic")
20617
21436
  }).strict(),
20618
- z74.object({
20619
- mode: z74.literal("guided"),
21437
+ z78.object({
21438
+ mode: z78.literal("guided"),
20620
21439
  landingStrategy: LandingStrategyEnum,
20621
21440
  landingImageFormat: LandingImageFormatEnum,
20622
- competitorScanEnabled: z74.boolean(),
20623
- paymentMethods: z74.string().trim().min(1).max(240).nullable(),
20624
- productContext: z74.string().trim().min(1).max(3e3).nullable(),
20625
- creativeDirection: z74.string().trim().min(1).max(500).nullable(),
20626
- headline: z74.string().trim().min(1).max(120).nullable(),
20627
- 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()
20628
21447
  }).strict()
20629
21448
  ]);
20630
- var ImageInput = z74.object({
21449
+ var ImageInput = z78.object({
20631
21450
  images: CreativeRefs.images.optional(),
20632
21451
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20633
- productTitle: z74.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
20634
- 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.'),
20635
21454
  buyerPersona: CreativeRefs.buyerPersona,
20636
21455
  language: CreativeRefs.language,
20637
21456
  country: CreativeRefs.country,
20638
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."),
20639
21458
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
20640
- 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"].'),
20641
21460
  price: CreativeRefs.price,
20642
- 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."),
20643
21462
  compareAtPrice: CreativeRefs.compareAtPrice,
20644
21463
  offer: CreativeRefs.offer,
20645
21464
  productLabel: CreativeRefs.productLabel,
20646
21465
  isCombo: CreativeRefs.isCombo,
20647
21466
  brandId: CreativeRefs.brandId
20648
21467
  });
20649
- var EditImageCreativeInput = z74.object({
20650
- taskId: z74.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
20651
- variantIndex: z74.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
20652
- 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".')
20653
21472
  });
20654
- var LandingInput = z74.object({
21473
+ var LandingInput = z78.object({
20655
21474
  images: CreativeRefs.images.optional(),
20656
21475
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20657
21476
  language: CreativeRefs.language,
20658
21477
  country: CreativeRefs.country,
20659
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."),
20660
- 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.'),
20661
21480
  buyerPersona: CreativeRefs.buyerPersona,
20662
21481
  price: CreativeRefs.price,
20663
21482
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -20676,7 +21495,7 @@ function resolveImageSetup(setup) {
20676
21495
  },
20677
21496
  aspectRatio: setup.aspectRatio,
20678
21497
  nVariants: setup.nVariants,
20679
- imageModel: setup.imageModel,
21498
+ imageModel: canonicalImageModelInput(setup.imageModel),
20680
21499
  ...setup.nVariants === 6 ? {
20681
21500
  styleMix: true
20682
21501
  } : setup.styleMix === null ? {} : {
@@ -20919,10 +21738,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
20919
21738
  __name(registerCreativeTools, "registerCreativeTools");
20920
21739
 
20921
21740
  // src/tools/creative-variants.ts
20922
- import { z as z75 } from "zod";
21741
+ import { z as z79 } from "zod";
20923
21742
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
20924
21743
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
20925
- var LandingSectionKeyEnum = z75.enum([
21744
+ var LandingSectionKeyEnum = z79.enum([
20926
21745
  "problem_hook",
20927
21746
  "problem_cost",
20928
21747
  "solution_mechanism",
@@ -20962,24 +21781,24 @@ var LandingSectionKeyEnum = z75.enum([
20962
21781
  "lifestyle_fit",
20963
21782
  "join_lifestyle"
20964
21783
  ]);
20965
- var CreativeVariantKindEnum = z75.enum([
21784
+ var CreativeVariantKindEnum = z79.enum([
20966
21785
  "video",
20967
21786
  "image",
20968
21787
  "landing"
20969
21788
  ]);
20970
- var EstimateCreativeVariantInputBase = z75.object({
20971
- 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."),
20972
21791
  kind: CreativeVariantKindEnum,
20973
21792
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
20974
21793
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
20975
- 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)."),
20976
21795
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
20977
- 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.")
20978
21797
  }).strict();
20979
21798
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
20980
21799
  if (input.kind === "video" && input.nVariants !== void 0) {
20981
21800
  ctx.addIssue({
20982
- code: z75.ZodIssueCode.custom,
21801
+ code: z79.ZodIssueCode.custom,
20983
21802
  path: [
20984
21803
  "nVariants"
20985
21804
  ],
@@ -20989,7 +21808,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20989
21808
  if (input.kind !== "video") {
20990
21809
  if (input.videoPreset !== void 0) {
20991
21810
  ctx.addIssue({
20992
- code: z75.ZodIssueCode.custom,
21811
+ code: z79.ZodIssueCode.custom,
20993
21812
  path: [
20994
21813
  "videoPreset"
20995
21814
  ],
@@ -20998,7 +21817,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20998
21817
  }
20999
21818
  if (input.videoResolution !== void 0) {
21000
21819
  ctx.addIssue({
21001
- code: z75.ZodIssueCode.custom,
21820
+ code: z79.ZodIssueCode.custom,
21002
21821
  path: [
21003
21822
  "videoResolution"
21004
21823
  ],
@@ -21008,7 +21827,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21008
21827
  }
21009
21828
  if (input.kind !== "image" && input.nVariants !== void 0) {
21010
21829
  ctx.addIssue({
21011
- code: z75.ZodIssueCode.custom,
21830
+ code: z79.ZodIssueCode.custom,
21012
21831
  path: [
21013
21832
  "nVariants"
21014
21833
  ],
@@ -21018,7 +21837,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21018
21837
  if (input.kind !== "landing") {
21019
21838
  if (input.sectionKey !== void 0) {
21020
21839
  ctx.addIssue({
21021
- code: z75.ZodIssueCode.custom,
21840
+ code: z79.ZodIssueCode.custom,
21022
21841
  path: [
21023
21842
  "sectionKey"
21024
21843
  ],
@@ -21027,7 +21846,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21027
21846
  }
21028
21847
  if (input.instructions !== void 0) {
21029
21848
  ctx.addIssue({
21030
- code: z75.ZodIssueCode.custom,
21849
+ code: z79.ZodIssueCode.custom,
21031
21850
  path: [
21032
21851
  "instructions"
21033
21852
  ],
@@ -21036,31 +21855,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
21036
21855
  }
21037
21856
  }
21038
21857
  });
21039
- var CreateCreativeVariantInputBase = z75.object({
21040
- 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."),
21041
21860
  kind: CreativeVariantKindEnum,
21042
- confirm: z75.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
21043
- 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."),
21044
- angle: z75.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
21045
- buyerPersona: z75.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
21046
- scriptNotes: z75.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
21047
- 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."),
21048
21867
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
21049
21868
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
21050
- generateAiMusic: z75.boolean().optional().describe("Opcional para video."),
21051
- 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)."),
21052
21871
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
21053
21872
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
21054
21873
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
21055
21874
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
21056
- styleMix: z75.boolean().optional().describe("Opcional para imagen."),
21875
+ styleMix: z79.boolean().optional().describe("Opcional para imagen."),
21057
21876
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
21058
- 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.")
21059
21878
  }).strict();
21060
21879
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
21061
21880
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
21062
21881
  ctx.addIssue({
21063
- code: z75.ZodIssueCode.custom,
21882
+ code: z79.ZodIssueCode.custom,
21064
21883
  path: [
21065
21884
  "angle"
21066
21885
  ],
@@ -21069,7 +21888,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
21069
21888
  }
21070
21889
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
21071
21890
  ctx.addIssue({
21072
- code: z75.ZodIssueCode.custom,
21891
+ code: z79.ZodIssueCode.custom,
21073
21892
  path: [
21074
21893
  "instructions"
21075
21894
  ],
@@ -21115,7 +21934,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
21115
21934
  for (const field of fieldsByKind[input.kind]) {
21116
21935
  if (input[field] !== void 0) {
21117
21936
  ctx.addIssue({
21118
- code: z75.ZodIssueCode.custom,
21937
+ code: z79.ZodIssueCode.custom,
21119
21938
  path: [
21120
21939
  field
21121
21940
  ],
@@ -21232,32 +22051,32 @@ function registerCreativeVariantTools(server, api) {
21232
22051
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
21233
22052
 
21234
22053
  // src/tools/script-review.ts
21235
- import { z as z76 } from "zod";
22054
+ import { z as z80 } from "zod";
21236
22055
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
21237
22056
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
21238
22057
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
21239
- var GetVideoScriptInput = z76.object({
21240
- taskId: z76.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
21241
- 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.')
21242
22061
  }).strict();
21243
22062
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
21244
22063
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
21245
- var ApproveSceneEdit = z76.object({
21246
- index: z76.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
21247
- 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, {
21248
22067
  message: "dialogue no puede ser s\xF3lo espacios"
21249
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.")
21250
22069
  }).strict();
21251
- var ApproveVideoScriptInput = z76.object({
21252
- taskId: z76.string().min(1).describe("ID de la tarea."),
21253
- 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.'),
21254
- 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.")
21255
22074
  }).strict();
21256
- var RegenerateVideoScriptInput = z76.object({
21257
- taskId: z76.string().min(1).describe("ID de la tarea."),
21258
- 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.'),
21259
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).'),
21260
- narrativeSelection: z76.enum([
22079
+ narrativeSelection: z80.enum([
21261
22080
  "market",
21262
22081
  "guided"
21263
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.")
@@ -21338,14 +22157,14 @@ function registerScriptReviewTools(server, api) {
21338
22157
  __name(registerScriptReviewTools, "registerScriptReviewTools");
21339
22158
 
21340
22159
  // src/tools/connections.ts
21341
- import { z as z77 } from "zod";
22160
+ import { z as z81 } from "zod";
21342
22161
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
21343
22162
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
21344
22163
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
21345
22164
  var listMetaDestinationsGuidance = getProductMakerCapabilityModelGuidance("list_meta_destinations");
21346
22165
  var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list_tiktok_advertisers");
21347
22166
  function registerConnectionTools(server, api) {
21348
- 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 () => {
21349
22168
  try {
21350
22169
  const r = await api.getJson("/v1/shopify/shops");
21351
22170
  return asText(r);
@@ -21353,10 +22172,10 @@ function registerConnectionTools(server, api) {
21353
22172
  throw translateError(e);
21354
22173
  }
21355
22174
  });
21356
- 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({
21357
- shopDomain: z77.string().min(3).max(120),
21358
- query: z77.string().trim().max(120).optional(),
21359
- 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()
21360
22179
  }).shape, READS_EXTERNAL, async ({ shopDomain, query, taskId }) => {
21361
22180
  try {
21362
22181
  const params = new URLSearchParams({
@@ -21370,7 +22189,7 @@ function registerConnectionTools(server, api) {
21370
22189
  throw translateError(e);
21371
22190
  }
21372
22191
  });
21373
- 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 () => {
21374
22193
  try {
21375
22194
  const r = await api.getJson("/v1/facebook/ad-accounts");
21376
22195
  return asText(r);
@@ -21380,7 +22199,7 @@ function registerConnectionTools(server, api) {
21380
22199
  });
21381
22200
  server.registerTool("list_meta_destinations", {
21382
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.",
21383
- inputSchema: z77.object({}).shape,
22202
+ inputSchema: z81.object({}).shape,
21384
22203
  annotations: READS_EXTERNAL,
21385
22204
  _meta: {
21386
22205
  "openai/widgetAccessible": true
@@ -21393,7 +22212,7 @@ function registerConnectionTools(server, api) {
21393
22212
  throw translateError(e);
21394
22213
  }
21395
22214
  });
21396
- 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 () => {
21397
22216
  try {
21398
22217
  const r = await api.getJson("/v1/tiktok/advertisers");
21399
22218
  return asText(r);
@@ -21405,10 +22224,10 @@ function registerConnectionTools(server, api) {
21405
22224
  __name(registerConnectionTools, "registerConnectionTools");
21406
22225
 
21407
22226
  // src/tools/actors.ts
21408
- import { z as z78 } from "zod";
22227
+ import { z as z82 } from "zod";
21409
22228
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
21410
22229
  function registerActorTools(server, api) {
21411
- 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 () => {
21412
22231
  try {
21413
22232
  const rows = await api.getJson("/v1/actors");
21414
22233
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -21429,7 +22248,7 @@ function registerActorTools(server, api) {
21429
22248
  __name(registerActorTools, "registerActorTools");
21430
22249
 
21431
22250
  // src/tools/publish.ts
21432
- import { z as z79 } from "zod";
22251
+ import { z as z83 } from "zod";
21433
22252
 
21434
22253
  // src/tools/stable-uuid.ts
21435
22254
  import { createHash as createHash3 } from "crypto";
@@ -21501,40 +22320,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
21501
22320
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
21502
22321
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
21503
22322
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
21504
- var ShopifyInput = z79.object({
21505
- taskId: z79.string().min(1),
21506
- shopDomain: z79.string().min(1),
22323
+ var ShopifyInput = z83.object({
22324
+ taskId: z83.string().min(1),
22325
+ shopDomain: z83.string().min(1),
21507
22326
  /** Override: number of landing images to include. Default = ALL images the
21508
22327
  * task generated (the MCP fetches /v1/results first to count). Bounded
21509
22328
  * generously here; the backend validates each index against
21510
22329
  * landing.images.length and rejects out-of-range. */
21511
- numLandingImages: z79.number().int().min(1).max(20).optional(),
21512
- 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(),
21513
22332
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
21514
22333
  * When true, the landing renders variant-picker pills; when false, it ships
21515
22334
  * a single-option product page. Defaults to false. */
21516
- showVariantPicker: z79.boolean().optional(),
22335
+ showVariantPicker: z83.boolean().optional(),
21517
22336
  /** Default `auto` updates the product previously published for this task and
21518
22337
  * shop. Use `existing` with targetProductId to choose another product, or
21519
22338
  * `new` only when the user explicitly wants a duplicate/new listing. */
21520
- publicationMode: z79.enum([
22339
+ publicationMode: z83.enum([
21521
22340
  "auto",
21522
22341
  "existing",
21523
22342
  "new"
21524
22343
  ]).optional(),
21525
22344
  /** Shopify product GID, numeric id, or admin product URL. Required when
21526
22345
  * publicationMode is `existing`. */
21527
- targetProductId: z79.string().trim().min(1).max(300).optional(),
22346
+ targetProductId: z83.string().trim().min(1).max(300).optional(),
21528
22347
  /** Add an announcement bar text above add-to-cart (optional). */
21529
- announcementBarEnabled: z79.boolean().optional(),
21530
- 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(),
21531
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."),
21532
- 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.")
21533
22352
  });
21534
22353
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
21535
22354
  if (value.commerceCorrection && value.confirmed !== true) {
21536
22355
  ctx.addIssue({
21537
- code: z79.ZodIssueCode.custom,
22356
+ code: z83.ZodIssueCode.custom,
21538
22357
  path: [
21539
22358
  "confirmed"
21540
22359
  ],
@@ -21543,7 +22362,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
21543
22362
  }
21544
22363
  if (value.announcementBarEnabled && !value.announcementBarText) {
21545
22364
  ctx.addIssue({
21546
- code: z79.ZodIssueCode.custom,
22365
+ code: z83.ZodIssueCode.custom,
21547
22366
  path: [
21548
22367
  "announcementBarText"
21549
22368
  ],
@@ -21552,7 +22371,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
21552
22371
  }
21553
22372
  if (!value.announcementBarEnabled && value.announcementBarText) {
21554
22373
  ctx.addIssue({
21555
- code: z79.ZodIssueCode.custom,
22374
+ code: z83.ZodIssueCode.custom,
21556
22375
  path: [
21557
22376
  "announcementBarText"
21558
22377
  ],
@@ -21566,91 +22385,91 @@ function parseShopifyInput(rawInput) {
21566
22385
  return parsed.data;
21567
22386
  }
21568
22387
  __name(parseShopifyInput, "parseShopifyInput");
21569
- var McpCampaignConfig = z79.object({
22388
+ var McpCampaignConfig = z83.object({
21570
22389
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
21571
22390
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
21572
22391
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
21573
- dailyBudgetUsd: z79.number().positive().optional(),
22392
+ dailyBudgetUsd: z83.number().positive().optional(),
21574
22393
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
21575
22394
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
21576
22395
  * TikTok takes only the first entry. */
21577
- targetCountries: z79.array(CountryIso2Schema).max(1).optional(),
21578
- 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()
21579
22398
  });
21580
22399
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
21581
- var MetaInput = z79.object({
21582
- taskId: z79.string().min(1),
22400
+ var MetaInput = z83.object({
22401
+ taskId: z83.string().min(1),
21583
22402
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
21584
- portfolioId: z79.string().trim().min(1),
22403
+ portfolioId: z83.string().trim().min(1),
21585
22404
  /** Exact Facebook Page selected from `list_meta_destinations`. */
21586
- pageId: z79.string().trim().min(1),
22405
+ pageId: z83.string().trim().min(1),
21587
22406
  adAccountId: McpAdAccountId,
21588
- pixelId: z79.string().min(1).optional(),
21589
- landingUrl: z79.string().url().optional(),
22407
+ pixelId: z83.string().min(1).optional(),
22408
+ landingUrl: z83.string().url().optional(),
21590
22409
  /** Select which angles to publish by 0-based index. Omit to publish all
21591
22410
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
21592
- angleIndexes: z79.array(z79.number().int().nonnegative()).optional(),
22411
+ angleIndexes: z83.array(z83.number().int().nonnegative()).optional(),
21593
22412
  campaignConfig: McpCampaignConfig.optional(),
21594
22413
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
21595
22414
  * uses the auto-generated copy attached to the task. Capped at 500 chars
21596
22415
  * (Meta's primary-text limit). */
21597
- primaryText: z79.string().trim().min(1).max(500).optional(),
22416
+ primaryText: z83.string().trim().min(1).max(500).optional(),
21598
22417
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
21599
22418
  * (wa.me) instead of a landing page. */
21600
- phoneNumber: z79.string().min(8).max(32).optional()
22419
+ phoneNumber: z83.string().min(8).max(32).optional()
21601
22420
  });
21602
- var GroupedTaskSource = z79.object({
21603
- type: z79.literal("task"),
21604
- taskId: z79.string().min(1),
21605
- angleIndex: z79.number().int().min(0).optional(),
21606
- 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([
21607
22426
  "with_subtitles",
21608
22427
  "without_subtitles"
21609
22428
  ]).optional(),
21610
- imageVariantIndex: z79.number().int().min(0).optional()
21611
- });
21612
- var GroupedMediaSource = z79.object({
21613
- type: z79.literal("media"),
21614
- 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."),
21615
- 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".'),
21616
- thumbnailUrl: z79.string().url().optional(),
21617
- 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()
21618
22437
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
21619
22438
  message: "media source needs exactly one of `url` or `path`"
21620
22439
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
21621
22440
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
21622
22441
  });
21623
- var GroupedUploadedAssetSource = z79.object({
21624
- type: z79.literal("asset"),
22442
+ var GroupedUploadedAssetSource = z83.object({
22443
+ type: z83.literal("asset"),
21625
22444
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
21626
- assetId: z79.string().uuid(),
21627
- thumbnailAssetId: z79.string().uuid().optional()
22445
+ assetId: z83.string().uuid(),
22446
+ thumbnailAssetId: z83.string().uuid().optional()
21628
22447
  });
21629
- var GroupedCreative = z79.object({
21630
- type: z79.enum([
22448
+ var GroupedCreative = z83.object({
22449
+ type: z83.enum([
21631
22450
  "image",
21632
22451
  "video"
21633
22452
  ]),
21634
- source: z79.union([
22453
+ source: z83.union([
21635
22454
  GroupedTaskSource,
21636
22455
  GroupedMediaSource,
21637
22456
  GroupedUploadedAssetSource
21638
22457
  ]),
21639
- title: z79.string().max(120).optional(),
21640
- description: z79.string().max(500).optional(),
22458
+ title: z83.string().max(120).optional(),
22459
+ description: z83.string().max(500).optional(),
21641
22460
  cta: MetaCtaType.optional(),
21642
- creativeId: z79.string().min(1).optional()
22461
+ creativeId: z83.string().min(1).optional()
21643
22462
  });
21644
- var GroupedCampaignConfigBase = z79.object({
22463
+ var GroupedCampaignConfigBase = z83.object({
21645
22464
  campaignType: MetaCampaignType.default("sales"),
21646
22465
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
21647
22466
  budgetMode: MetaBudgetMode.optional(),
21648
- campaignDailyBudget: z79.number().int().positive().optional(),
21649
- adSets: z79.array(z79.object({
21650
- tempId: z79.string().min(1).max(80),
21651
- name: z79.string().min(1).max(100),
21652
- dailyBudget: z79.number().int().positive().optional(),
21653
- 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)
21654
22473
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
21655
22474
  /**
21656
22475
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -21658,17 +22477,17 @@ var GroupedCampaignConfigBase = z79.object({
21658
22477
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
21659
22478
  * the API since #849 — unreachable from this tool.
21660
22479
  */
21661
- destination: z79.discriminatedUnion("type", [
21662
- z79.object({
21663
- type: z79.literal("landing"),
21664
- landingUrl: z79.string().url()
22480
+ destination: z83.discriminatedUnion("type", [
22481
+ z83.object({
22482
+ type: z83.literal("landing"),
22483
+ landingUrl: z83.string().url()
21665
22484
  }),
21666
- z79.object({
21667
- type: z79.literal("whatsapp"),
21668
- phoneNumber: z79.string().min(8).max(32)
22485
+ z83.object({
22486
+ type: z83.literal("whatsapp"),
22487
+ phoneNumber: z83.string().min(8).max(32)
21669
22488
  })
21670
22489
  ]),
21671
- saveAsDefault: z79.boolean().default(false),
22490
+ saveAsDefault: z83.boolean().default(false),
21672
22491
  budgetPolicy: MetaBudgetPolicy.optional()
21673
22492
  });
21674
22493
  function resolveBudgetMode(value) {
@@ -21682,7 +22501,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21682
22501
  const budgetMode = resolveBudgetMode(value);
21683
22502
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
21684
22503
  ctx.addIssue({
21685
- code: z79.ZodIssueCode.custom,
22504
+ code: z83.ZodIssueCode.custom,
21686
22505
  path: [
21687
22506
  "campaignDailyBudget"
21688
22507
  ],
@@ -21693,7 +22512,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21693
22512
  value.adSets.forEach((adSet, index) => {
21694
22513
  if (adSet.dailyBudget === void 0) {
21695
22514
  ctx.addIssue({
21696
- code: z79.ZodIssueCode.custom,
22515
+ code: z83.ZodIssueCode.custom,
21697
22516
  path: [
21698
22517
  "adSets",
21699
22518
  index,
@@ -21708,28 +22527,28 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21708
22527
  ...value,
21709
22528
  budgetMode: resolveBudgetMode(value)
21710
22529
  }));
21711
- var PublishCreativesToMetaInputBase = z79.object({
21712
- 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),
21713
22532
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
21714
- portfolioId: z79.string().trim().min(1),
22533
+ portfolioId: z83.string().trim().min(1),
21715
22534
  /** Exact Facebook Page selected from `list_meta_destinations`. */
21716
- pageId: z79.string().trim().min(1),
22535
+ pageId: z83.string().trim().min(1),
21717
22536
  adAccountId: McpAdAccountId,
21718
- pixelId: z79.string().min(1).optional(),
22537
+ pixelId: z83.string().min(1).optional(),
21719
22538
  /** Required unless `campaignConfig.destination` is whatsapp — see the
21720
22539
  * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
21721
- landingUrl: z79.string().url().optional(),
22540
+ landingUrl: z83.string().url().optional(),
21722
22541
  /** ISO-2 code or resolvable country name — mirrors the API contract
21723
22542
  * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
21724
22543
  targetCountry: CountryIso2Schema,
21725
- campaignName: z79.string().trim().min(1).max(100),
22544
+ campaignName: z83.string().trim().min(1).max(100),
21726
22545
  campaignConfig: GroupedCampaignConfig.optional()
21727
22546
  });
21728
22547
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
21729
22548
  const destination = value.campaignConfig?.destination;
21730
22549
  if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
21731
22550
  ctx.addIssue({
21732
- code: z79.ZodIssueCode.custom,
22551
+ code: z83.ZodIssueCode.custom,
21733
22552
  path: [
21734
22553
  "landingUrl"
21735
22554
  ],
@@ -21738,7 +22557,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
21738
22557
  }
21739
22558
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
21740
22559
  ctx.addIssue({
21741
- code: z79.ZodIssueCode.custom,
22560
+ code: z83.ZodIssueCode.custom,
21742
22561
  path: [
21743
22562
  "campaignConfig",
21744
22563
  "destination",
@@ -21757,16 +22576,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
21757
22576
  }
21758
22577
  return value;
21759
22578
  });
21760
- var PresignUploadResponseSchema = z79.object({
21761
- uploadUrl: z79.string().url().refine((value) => {
22579
+ var PresignUploadResponseSchema = z83.object({
22580
+ uploadUrl: z83.string().url().refine((value) => {
21762
22581
  const url = new URL(value);
21763
22582
  return !url.username && !url.password && url.protocol === "https:";
21764
22583
  }, "presigned upload URL must be HTTPS without embedded credentials"),
21765
- publicUrl: z79.string().url().refine((value) => {
22584
+ publicUrl: z83.string().url().refine((value) => {
21766
22585
  const url = new URL(value);
21767
22586
  return !url.username && !url.password;
21768
22587
  }, "public media URL must not contain embedded credentials"),
21769
- stagingAssetId: z79.string().uuid()
22588
+ stagingAssetId: z83.string().uuid()
21770
22589
  });
21771
22590
  async function uploadResolvedMedia(api, media, assetRole) {
21772
22591
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -21791,16 +22610,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
21791
22610
  return uploadResolvedMedia(api, media, assetRole);
21792
22611
  }
21793
22612
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
21794
- var TikTokInput = z79.object({
21795
- taskId: z79.string().min(1),
21796
- advertiserId: z79.string().min(1),
21797
- pixelId: z79.string().min(1).optional(),
21798
- landingUrl: z79.string().url().optional(),
21799
- 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(),
21800
22619
  campaignConfig: McpCampaignConfig.optional(),
21801
22620
  /** Override the ad's description (TikTok's body copy). If omitted,
21802
22621
  * ProductMaker uses the auto-generated copy attached to the task. */
21803
- primaryText: z79.string().trim().min(1).max(500).optional()
22622
+ primaryText: z83.string().trim().min(1).max(500).optional()
21804
22623
  });
21805
22624
  function registerPublishTools(server, api, opts = {}) {
21806
22625
  const transport = opts.transport ?? "http";
@@ -22128,39 +22947,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
22128
22947
 
22129
22948
  // src/tools/meta-upload.ts
22130
22949
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
22131
- import { z as z80 } from "zod";
22950
+ import { z as z84 } from "zod";
22132
22951
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
22133
- var UploadSessionInputBase = z80.object({
22134
- mediaKind: z80.enum([
22952
+ var UploadSessionInputBase = z84.object({
22953
+ mediaKind: z84.enum([
22135
22954
  "image",
22136
22955
  "video",
22137
22956
  "mixed"
22138
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."),
22139
- assetRole: z80.enum([
22958
+ assetRole: z84.enum([
22140
22959
  "media",
22141
22960
  "thumbnail"
22142
22961
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
22143
- uploadPurpose: z80.enum([
22962
+ uploadPurpose: z84.enum([
22144
22963
  "product_reference",
22145
22964
  "creative",
22146
22965
  "generic"
22147
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."),
22148
- 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.")
22149
22968
  });
22150
- var OpenAiFileReference = z80.object({
22151
- 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."),
22152
- file_id: z80.string().min(1),
22153
- mime_type: z80.string().min(1).optional(),
22154
- 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()
22155
22974
  });
22156
22975
  var UploadSessionToolInputShape = {
22157
22976
  ...UploadSessionInputBase.shape,
22158
- 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.")
22159
22978
  };
22160
- var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
22979
+ var UploadSessionToolInput = z84.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
22161
22980
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
22162
22981
  ctx.addIssue({
22163
- code: z80.ZodIssueCode.custom,
22982
+ code: z84.ZodIssueCode.custom,
22164
22983
  path: [
22165
22984
  "mediaKind"
22166
22985
  ],
@@ -22169,7 +22988,7 @@ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine
22169
22988
  }
22170
22989
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
22171
22990
  ctx.addIssue({
22172
- code: z80.ZodIssueCode.custom,
22991
+ code: z84.ZodIssueCode.custom,
22173
22992
  path: [
22174
22993
  "maxFiles"
22175
22994
  ],
@@ -22178,7 +22997,7 @@ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine
22178
22997
  }
22179
22998
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
22180
22999
  ctx.addIssue({
22181
- code: z80.ZodIssueCode.custom,
23000
+ code: z84.ZodIssueCode.custom,
22182
23001
  path: [
22183
23002
  "maxFiles"
22184
23003
  ],
@@ -22186,38 +23005,38 @@ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine
22186
23005
  });
22187
23006
  }
22188
23007
  });
22189
- var UploadSessionResponse = z80.object({
22190
- sessionId: z80.string().uuid(),
22191
- uploadPageUrl: z80.string().url(),
22192
- mediaKind: z80.enum([
23008
+ var UploadSessionResponse = z84.object({
23009
+ sessionId: z84.string().uuid(),
23010
+ uploadPageUrl: z84.string().url(),
23011
+ mediaKind: z84.enum([
22193
23012
  "image",
22194
23013
  "video",
22195
23014
  "mixed"
22196
23015
  ]),
22197
- assetRole: z80.enum([
23016
+ assetRole: z84.enum([
22198
23017
  "media",
22199
23018
  "thumbnail"
22200
23019
  ]),
22201
- maxFiles: z80.number().int().positive(),
22202
- expiresAt: z80.string().datetime()
23020
+ maxFiles: z84.number().int().positive(),
23021
+ expiresAt: z84.string().datetime()
22203
23022
  });
22204
- var UploadStatusInput = z80.object({
22205
- 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.")
22206
23025
  });
22207
- var UniversalUploadStatusResponse = z80.discriminatedUnion("status", [
22208
- z80.object({
22209
- status: z80.literal("pending"),
22210
- 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)
22211
23030
  }),
22212
- z80.object({
22213
- status: z80.literal("uploaded"),
22214
- assets: z80.array(z80.object({
22215
- assetId: z80.string().uuid(),
22216
- 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([
22217
23036
  "image",
22218
23037
  "video"
22219
23038
  ]),
22220
- assetRole: z80.enum([
23039
+ assetRole: z84.enum([
22221
23040
  "media",
22222
23041
  "thumbnail"
22223
23042
  ])
@@ -22225,13 +23044,13 @@ var UniversalUploadStatusResponse = z80.discriminatedUnion("status", [
22225
23044
  })
22226
23045
  ]);
22227
23046
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
22228
- uploadPurpose: z80.enum([
23047
+ uploadPurpose: z84.enum([
22229
23048
  "product_reference",
22230
23049
  "creative",
22231
23050
  "generic"
22232
23051
  ]),
22233
- checkToolName: z80.literal("check_media_upload"),
22234
- resolveEndpoint: z80.string().url()
23052
+ checkToolName: z84.literal("check_media_upload"),
23053
+ resolveEndpoint: z84.string().url()
22235
23054
  });
22236
23055
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
22237
23056
  const url = new URL(uploadPageUrl);
@@ -22322,15 +23141,15 @@ function registerMediaUploadTools(server, api) {
22322
23141
  __name(registerMediaUploadTools, "registerMediaUploadTools");
22323
23142
 
22324
23143
  // src/tools/campaigns.ts
22325
- import { z as z81 } from "zod";
23144
+ import { z as z85 } from "zod";
22326
23145
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
22327
23146
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
22328
- var MetaStatusInput = z81.object({
22329
- 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.")
22330
23149
  });
22331
- var TikTokStatusInput = z81.object({
22332
- campaignId: z81.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
22333
- 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.")
22334
23153
  });
22335
23154
  function registerCampaignTools(server, api) {
22336
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) => {
@@ -22427,10 +23246,10 @@ function renderTikTokStatusMarkdown(r) {
22427
23246
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
22428
23247
 
22429
23248
  // ../../packages/product-economics/src/product-costing.ts
22430
- import { z as z83 } from "zod";
23249
+ import { z as z87 } from "zod";
22431
23250
 
22432
23251
  // ../../packages/product-economics/src/product-costing-countries.ts
22433
- import { z as z82 } from "zod";
23252
+ import { z as z86 } from "zod";
22434
23253
 
22435
23254
  // ../../packages/product-economics/src/product-costing-shipping-references.json
22436
23255
  var product_costing_shipping_references_default = {
@@ -22494,21 +23313,21 @@ var product_costing_shipping_references_default = {
22494
23313
  };
22495
23314
 
22496
23315
  // ../../packages/product-economics/src/product-costing-countries.ts
22497
- var ShippingReferenceSchema = z82.object({
22498
- reference: z82.number().positive(),
22499
- min: z82.number().nonnegative(),
22500
- max: z82.number().positive(),
22501
- updatedAt: z82.string().date(),
22502
- 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([
22503
23322
  "high",
22504
23323
  "medium",
22505
23324
  "medium-low"
22506
23325
  ]),
22507
- 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)
22508
23327
  }).superRefine(({ reference, min, max }, context) => {
22509
23328
  if (min > reference || reference > max) {
22510
23329
  context.addIssue({
22511
- code: z82.ZodIssueCode.custom,
23330
+ code: z86.ZodIssueCode.custom,
22512
23331
  message: "shipping_reference_outside_range",
22513
23332
  path: [
22514
23333
  "reference"
@@ -22516,7 +23335,7 @@ var ShippingReferenceSchema = z82.object({
22516
23335
  });
22517
23336
  }
22518
23337
  });
22519
- 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);
22520
23339
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
22521
23340
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
22522
23341
  "MX",
@@ -22698,18 +23517,18 @@ function getProductCostingCountryName(country) {
22698
23517
  __name(getProductCostingCountryName, "getProductCostingCountryName");
22699
23518
 
22700
23519
  // ../../packages/product-economics/src/product-costing.ts
22701
- var ProductCostingInputSchema = z83.object({
22702
- country: z83.string().refine(isProductCostingCountryCode, "unsupported_country"),
22703
- supplierCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
22704
- shippingCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
22705
- returnRate: z83.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22706
- cancellationRate: z83.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22707
- adsManagerCpa: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
22708
- 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")
22709
23528
  }).superRefine(({ returnRate, cancellationRate }, context) => {
22710
23529
  if (returnRate + cancellationRate >= 1) {
22711
23530
  context.addIssue({
22712
- code: z83.ZodIssueCode.custom,
23531
+ code: z87.ZodIssueCode.custom,
22713
23532
  message: "delivery_rate_positive",
22714
23533
  path: [
22715
23534
  "cancellationRate"
@@ -22806,15 +23625,15 @@ function calculateProductCosting(rawInput) {
22806
23625
  __name(calculateProductCosting, "calculateProductCosting");
22807
23626
 
22808
23627
  // src/tools/product-costing.ts
22809
- import { z as z84 } from "zod";
23628
+ import { z as z88 } from "zod";
22810
23629
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
22811
- var optionalAmount = /* @__PURE__ */ __name((description) => z84.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
22812
- var optionalPercent = /* @__PURE__ */ __name((description) => z84.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
22813
- var ProductCostingToolInput = z84.object({
22814
- 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, {
22815
23634
  message: "Pa\xEDs no soportado por ProductMaker."
22816
23635
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
22817
- 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."),
22818
23637
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
22819
23638
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
22820
23639
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -22973,7 +23792,7 @@ function formatPercent(value) {
22973
23792
  __name(formatPercent, "formatPercent");
22974
23793
 
22975
23794
  // src/tools/product-research.ts
22976
- import { z as z85 } from "zod";
23795
+ import { z as z89 } from "zod";
22977
23796
 
22978
23797
  // src/tools/product-research-idempotency.ts
22979
23798
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -23344,35 +24163,35 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
23344
24163
  ]);
23345
24164
  var POLL_INTERVAL_MS = 5e3;
23346
24165
  var MAX_WAIT_SECONDS = 120;
23347
- var FindInput = z85.object({
24166
+ var FindInput = z89.object({
23348
24167
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
23349
24168
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
23350
- 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.`),
23351
- 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.")
23352
24171
  });
23353
- var GetInput = z85.object({
23354
- 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.")
23355
24174
  });
23356
- var ListInput = z85.object({
23357
- 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)
23358
24177
  });
23359
- function textResult(text) {
24178
+ function textResult(text2) {
23360
24179
  return {
23361
24180
  content: [
23362
24181
  {
23363
24182
  type: "text",
23364
- text
24183
+ text: text2
23365
24184
  }
23366
24185
  ]
23367
24186
  };
23368
24187
  }
23369
24188
  __name(textResult, "textResult");
23370
- function researchResult(run, text) {
24189
+ function researchResult(run, text2) {
23371
24190
  return {
23372
24191
  content: [
23373
24192
  {
23374
24193
  type: "text",
23375
- text
24194
+ text: text2
23376
24195
  }
23377
24196
  ],
23378
24197
  structuredContent: run
@@ -23477,17 +24296,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
23477
24296
  __name(registerProductResearchTools, "registerProductResearchTools");
23478
24297
 
23479
24298
  // src/tools/dropshipping-projects.ts
23480
- import { z as z86 } from "zod";
24299
+ import { z as z90 } from "zod";
23481
24300
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
23482
24301
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
23483
24302
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
23484
- var ProjectId = z86.string().uuid();
23485
- var DropshippingProjectStatus = z86.enum([
24303
+ var ProjectId = z90.string().uuid();
24304
+ var DropshippingProjectStatus = z90.enum([
23486
24305
  "active",
23487
24306
  "completed",
23488
24307
  "archived"
23489
24308
  ]);
23490
- var DropshippingProjectPhase = z86.enum([
24309
+ var DropshippingProjectPhase = z90.enum([
23491
24310
  "research",
23492
24311
  "costing",
23493
24312
  "media",
@@ -23496,21 +24315,21 @@ var DropshippingProjectPhase = z86.enum([
23496
24315
  "advertising",
23497
24316
  "complete"
23498
24317
  ]);
23499
- var DropshippingRewardMilestone = z86.enum([
24318
+ var DropshippingRewardMilestone = z90.enum([
23500
24319
  "product_selected",
23501
24320
  "costing_saved",
23502
24321
  "product_media_ready",
23503
24322
  "creatives_completed",
23504
24323
  "campaign_created"
23505
24324
  ]);
23506
- var TargetCountry = z86.enum([
24325
+ var TargetCountry = z90.enum([
23507
24326
  "CO",
23508
24327
  "MX",
23509
24328
  "PE",
23510
24329
  "EC",
23511
24330
  "CL"
23512
24331
  ]);
23513
- var ResearchCategory = z86.enum([
24332
+ var ResearchCategory = z90.enum([
23514
24333
  "auto",
23515
24334
  "automotive",
23516
24335
  "kitchen",
@@ -23525,7 +24344,7 @@ var ResearchCategory = z86.enum([
23525
24344
  "garden",
23526
24345
  "cleaning"
23527
24346
  ]);
23528
- var HttpUrl3 = z86.string().url().max(2e3).refine((value) => {
24347
+ var HttpUrl3 = z90.string().url().max(2e3).refine((value) => {
23529
24348
  try {
23530
24349
  return [
23531
24350
  "http:",
@@ -23535,45 +24354,45 @@ var HttpUrl3 = z86.string().url().max(2e3).refine((value) => {
23535
24354
  return false;
23536
24355
  }
23537
24356
  }, "URL must use HTTP(S)");
23538
- var ResearchCandidateOrigin = z86.object({
23539
- type: z86.literal("research_candidate"),
24357
+ var ResearchCandidateOrigin = z90.object({
24358
+ type: z90.literal("research_candidate"),
23540
24359
  runId: ProjectId,
23541
- candidateSourceId: z86.string().min(1).max(160)
24360
+ candidateSourceId: z90.string().min(1).max(160)
23542
24361
  });
23543
- var TaskOrigin = z86.object({
23544
- type: z86.literal("task"),
24362
+ var TaskOrigin = z90.object({
24363
+ type: z90.literal("task"),
23545
24364
  taskId: ProjectId
23546
24365
  });
23547
- var ManualOrigin = z86.object({
23548
- type: z86.literal("manual"),
24366
+ var ManualOrigin = z90.object({
24367
+ type: z90.literal("manual"),
23549
24368
  clientRequestId: ProjectId,
23550
- country: z86.string().min(2).max(3).optional()
24369
+ country: z90.string().min(2).max(3).optional()
23551
24370
  });
23552
- var StartProjectInput = z86.object({
23553
- origin: z86.discriminatedUnion("type", [
24371
+ var StartProjectInput = z90.object({
24372
+ origin: z90.discriminatedUnion("type", [
23554
24373
  ResearchCandidateOrigin,
23555
24374
  TaskOrigin,
23556
24375
  ManualOrigin
23557
24376
  ]),
23558
- productName: z86.string().trim().min(1).max(240).optional(),
24377
+ productName: z90.string().trim().min(1).max(240).optional(),
23559
24378
  productUrl: HttpUrl3.optional(),
23560
- country: z86.string().min(2).max(3).optional(),
23561
- 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()
23562
24381
  }).strict();
23563
- var CostProjectInput = z86.object({
24382
+ var CostProjectInput = z90.object({
23564
24383
  projectId: ProjectId,
23565
- version: z86.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
23566
- 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, {
23567
24386
  message: "Pa\xEDs no soportado por ProductMaker."
23568
24387
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
23569
- 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."),
23570
- 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."),
23571
- 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."),
23572
- 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."),
23573
- adsManagerCpa: z86.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
23574
- 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.")
23575
- });
23576
- 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({
23577
24396
  projectId: ProjectId.optional()
23578
24397
  }).strict();
23579
24398
  var NEXT_ACTION_KINDS = [
@@ -23591,29 +24410,29 @@ var NEXT_ACTION_KINDS = [
23591
24410
  "repair_meta_campaign",
23592
24411
  "review_paused_campaign"
23593
24412
  ];
23594
- var DropshippingProjectNextAction = z86.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z86.object({
23595
- kind: z86.literal(kind),
23596
- 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)
23597
24416
  })));
23598
- var CostingInputSchema = z86.object({
23599
- country: z86.string().min(2).max(3),
23600
- supplierCost: z86.number().finite().positive(),
23601
- shippingCost: z86.number().finite().nonnegative(),
23602
- returnRate: z86.number().finite().min(0).lt(1),
23603
- cancellationRate: z86.number().finite().min(0).lt(1),
23604
- adsManagerCpa: z86.number().finite().nonnegative(),
23605
- 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)
23606
24425
  }).superRefine(({ returnRate, cancellationRate }, context) => {
23607
24426
  if (returnRate + cancellationRate >= 1) context.addIssue({
23608
- code: z86.ZodIssueCode.custom,
24427
+ code: z90.ZodIssueCode.custom,
23609
24428
  path: [
23610
24429
  "cancellationRate"
23611
24430
  ]
23612
24431
  });
23613
24432
  });
23614
- var FiniteCostingNumber = z86.number().finite();
23615
- var CostingResultSchema = z86.object({
23616
- 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),
23617
24436
  deliveryRate: FiniteCostingNumber,
23618
24437
  adjustedShippingCost: FiniteCostingNumber,
23619
24438
  adjustedCpa: FiniteCostingNumber,
@@ -23626,45 +24445,45 @@ var CostingResultSchema = z86.object({
23626
24445
  estimatedProfit: FiniteCostingNumber,
23627
24446
  actualMargin: FiniteCostingNumber,
23628
24447
  breakEvenAdsManagerCpa: FiniteCostingNumber,
23629
- wasPriceAutoAdjusted: z86.boolean(),
23630
- profitabilityStatus: z86.literal("healthy")
23631
- });
23632
- var RewardProgressSchema = z86.object({
23633
- campaignKey: z86.literal("dropshipping-launch-v1"),
23634
- totalCredits: z86.number().int().positive(),
23635
- earnedCredits: z86.number().int().nonnegative(),
23636
- 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({
23637
24456
  milestone: DropshippingRewardMilestone,
23638
- credits: z86.number().int().positive(),
23639
- available: z86.boolean().optional(),
23640
- earned: z86.boolean(),
24457
+ credits: z90.number().int().positive(),
24458
+ available: z90.boolean().optional(),
24459
+ earned: z90.boolean(),
23641
24460
  grantId: ProjectId.nullable(),
23642
- grantedAt: z86.string().datetime().nullable()
24461
+ grantedAt: z90.string().datetime().nullable()
23643
24462
  })).length(DropshippingRewardMilestone.options.length)
23644
24463
  });
23645
- var ProjectResponseSchema = z86.object({
24464
+ var ProjectResponseSchema = z90.object({
23646
24465
  id: ProjectId,
23647
24466
  taskId: ProjectId.nullable(),
23648
24467
  status: DropshippingProjectStatus,
23649
- originKey: z86.string().min(1),
24468
+ originKey: z90.string().min(1),
23650
24469
  researchRunId: ProjectId.nullable(),
23651
- candidateSourceId: z86.string().nullable(),
23652
- productName: z86.string().nullable(),
24470
+ candidateSourceId: z90.string().nullable(),
24471
+ productName: z90.string().nullable(),
23653
24472
  productUrl: HttpUrl3.nullable(),
23654
24473
  referenceImageUrl: HttpUrl3.nullable(),
23655
- targetCountry: z86.string().nullable(),
23656
- languageCode: z86.string().nullable(),
23657
- hasReferenceImage: z86.boolean(),
23658
- hasWinnerReferenceImage: z86.boolean(),
24474
+ targetCountry: z90.string().nullable(),
24475
+ languageCode: z90.string().nullable(),
24476
+ hasReferenceImage: z90.boolean(),
24477
+ hasWinnerReferenceImage: z90.boolean(),
23659
24478
  costingInput: CostingInputSchema.nullable(),
23660
24479
  costingResult: CostingResultSchema.nullable(),
23661
- costingVersion: z86.number().int().positive().nullable(),
23662
- version: z86.number().int().positive(),
24480
+ costingVersion: z90.number().int().positive().nullable(),
24481
+ version: z90.number().int().positive(),
23663
24482
  phase: DropshippingProjectPhase,
23664
24483
  nextAction: DropshippingProjectNextAction.nullable(),
23665
24484
  rewards: RewardProgressSchema,
23666
- createdAt: z86.string().datetime(),
23667
- updatedAt: z86.string().datetime()
24485
+ createdAt: z90.string().datetime(),
24486
+ updatedAt: z90.string().datetime()
23668
24487
  }).passthrough();
23669
24488
  var NEXT_ACTION_GUIDANCE = {
23670
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.",
@@ -23782,58 +24601,58 @@ function registerDropshippingProjectTools(server, api) {
23782
24601
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
23783
24602
 
23784
24603
  // src/tools/daily-control.ts
23785
- import { z as z87 } from "zod";
24604
+ import { z as z91 } from "zod";
23786
24605
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
23787
24606
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
23788
24607
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
23789
- var ProviderCampaignIdentifier = z87.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
23790
- var DateOnly = z87.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23791
- 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({
23792
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."),
23793
- days: z87.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23794
- 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.")
23795
24614
  }).strict();
23796
- var LinkCampaignInput = z87.object({
23797
- projectId: z87.string().uuid(),
23798
- provider: z87.enum([
24615
+ var LinkCampaignInput = z91.object({
24616
+ projectId: z91.string().uuid(),
24617
+ provider: z91.enum([
23799
24618
  "meta",
23800
24619
  "tiktok"
23801
24620
  ]),
23802
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."),
23803
24622
  campaignId: ProviderCampaignIdentifier
23804
24623
  }).strict();
23805
- var ReportReturnsInput = z87.object({
23806
- projectId: z87.string().uuid(),
24624
+ var ReportReturnsInput = z91.object({
24625
+ projectId: z91.string().uuid(),
23807
24626
  date: DateOnly,
23808
- returnedOrders: z87.number().int().min(0).max(1e5),
23809
- note: z87.string().trim().max(280).optional()
24627
+ returnedOrders: z91.number().int().min(0).max(1e5),
24628
+ note: z91.string().trim().max(280).optional()
23810
24629
  }).strict();
23811
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z87.string());
23812
- var DailyControlLightMirror = DailyControlLightEnum.or(z87.string());
23813
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z87.string());
23814
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z87.string());
23815
- var DailyControlDayMirror = z87.object({
23816
- date: z87.string(),
23817
- 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(),
23818
24637
  returnedSource: DailyControlSourceMirror,
23819
24638
  cancelledSource: DailyControlSourceMirror,
23820
- hasEstimates: z87.boolean(),
24639
+ hasEstimates: z91.boolean(),
23821
24640
  light: DailyControlLightMirror
23822
24641
  }).passthrough();
23823
- var DailyControlProductMirror = z87.object({
23824
- projectId: z87.string().uuid(),
23825
- productName: z87.string().nullable(),
24642
+ var DailyControlProductMirror = z91.object({
24643
+ projectId: z91.string().uuid(),
24644
+ productName: z91.string().nullable(),
23826
24645
  status: DailyControlStatusMirror,
23827
- statusMessage: z87.string().nullable(),
23828
- days: z87.array(DailyControlDayMirror),
24646
+ statusMessage: z91.string().nullable(),
24647
+ days: z91.array(DailyControlDayMirror),
23829
24648
  verdict: DailyControlVerdictMirror.nullable(),
23830
- rationale: z87.string().nullable()
24649
+ rationale: z91.string().nullable()
23831
24650
  }).passthrough();
23832
- var DailyControlResponseMirror = z87.object({
23833
- since: z87.string(),
23834
- until: z87.string(),
23835
- products: z87.array(DailyControlProductMirror),
23836
- 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())
23837
24656
  }).passthrough();
23838
24657
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
23839
24658
  function withWarnings(response) {
@@ -23917,42 +24736,42 @@ function registerDailyControlTools(server, api) {
23917
24736
  __name(registerDailyControlTools, "registerDailyControlTools");
23918
24737
 
23919
24738
  // src/tools/product-control.ts
23920
- import { z as z88 } from "zod";
24739
+ import { z as z92 } from "zod";
23921
24740
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
23922
24741
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
23923
24742
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
23924
24743
  var setProductCostingGuidance = getProductMakerCapabilityModelGuidance("set_product_costing");
23925
24744
  var reportProductCountsGuidance = getProductMakerCapabilityModelGuidance("report_product_counts");
23926
- var DateOnly2 = z88.string().regex(/^\d{4}-\d{2}-\d{2}$/);
24745
+ var DateOnly2 = z92.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23927
24746
  var IMPORT_BATCH_MAX2 = 50;
23928
- var ProductControlListInput = z88.object({
23929
- 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."),
23930
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."),
23931
- 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.")
23932
24751
  }).strict();
23933
- var ImportableProductsInput = z88.object({
23934
- q: z88.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
23935
- after: z88.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
23936
- 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()
23937
24756
  }).strict();
23938
- var ImportProductControlsInput = z88.object({
23939
- 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."),
23940
24759
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
23941
24760
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
23942
- shopDomain: z88.string().min(1)
24761
+ shopDomain: z92.string().min(1)
23943
24762
  }).strict();
23944
- var SetProductCostingInput = z88.object({
23945
- shopDomain: z88.string().min(1),
23946
- shopifyProductId: z88.string().min(1).max(64),
23947
- targetCountry: z88.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
23948
- supplierCost: z88.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
23949
- shippingCost: z88.number().finite().nonnegative(),
23950
- returnRate: z88.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
23951
- 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)
23952
24771
  }).strict();
23953
- var Count = z88.number().int().min(0).max(1e5).nullable().optional();
23954
- var ReportProductCountsInput = z88.object({
23955
- 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."),
23956
24775
  date: DateOnly2,
23957
24776
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
23958
24777
  cancelledOrders: Count,