@productmaker/mcp 7.1.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/http.js +864 -684
  2. package/dist/stdio.js +853 -673
  3. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -1475,9 +1475,23 @@ var LandingSectionPlanSchema = z11.array(LandingSectionPlanEntrySchema).superRef
1475
1475
 
1476
1476
  // ../../packages/types/src/landing.ts
1477
1477
  var LandingImageReadable = z12.object({
1478
+ /**
1479
+ * Display position in the AGGREGATED gallery (parent images + every `done`
1480
+ * variant's images, concatenated). Recalculated on every read from
1481
+ * `creativeVariants` order (createdAt asc), so it DRIFTS for a given image
1482
+ * when a sibling variant finishes out of creation order — it is NOT a
1483
+ * stable identity. Use `sourceIndex` for that.
1484
+ */
1478
1485
  index: z12.number().int().min(1).max(20),
1479
1486
  /** Child task that owns this image when variants are rendered alongside the root task. */
1480
1487
  variantTaskId: z12.string().uuid().optional(),
1488
+ /**
1489
+ * The image's own `indexNum` within its OWN task (root or variant) — set
1490
+ * once at render time and never recomputed. Unlike `index`, this is stable
1491
+ * across reads and is the correct key for identity/selection tracking.
1492
+ * Optional only for legacy rows persisted before this field existed.
1493
+ */
1494
+ sourceIndex: z12.number().int().min(1).optional(),
1481
1495
  role: LandingRoleLegacy,
1482
1496
  /** Strategy-specific display identity; absent on legacy tasks. */
1483
1497
  sectionKey: LandingSectionKeySchema.optional(),
@@ -3595,11 +3609,12 @@ var FreeformLandingConfigSchema = z21.object({
3595
3609
  showVariantPicker: z21.boolean().optional(),
3596
3610
  /**
3597
3611
  * Suppress the native Shopify buy form (the `BUY_FORM_MARKER` block). The page
3598
- * CTAs already carry `data-cl-buy-trigger` → they open the ReleaseIt COD popup,
3599
- * so on ReleaseIt-only stores the native add-to-cart form is a redundant second
3600
- * buy path (it rendered as a bare "price + Comprar" block). When true the
3601
- * assembler omits the marker entirely. Undefined/false = keep the native form
3602
- * (backward compatible with already-assembled configs).
3612
+ * CTAs already carry `data-cl-buy-trigger` → they open the installed COD
3613
+ * provider's popup (Releasit or EasySell), so on COD-provider stores the
3614
+ * native add-to-cart form is a redundant second buy path (it rendered as a
3615
+ * bare "price + Comprar" block). When true the assembler omits the marker
3616
+ * entirely. Undefined/false = keep the native form (backward compatible with
3617
+ * already-assembled configs).
3603
3618
  */
3604
3619
  hideNativeBuyForm: z21.boolean().optional()
3605
3620
  });
@@ -5102,6 +5117,7 @@ var SelectedLandingImage = z28.object({
5102
5117
  /** 0-based index of the selected variant (from img.notes JSON array) */
5103
5118
  variantIndex: z28.number().int().nonnegative()
5104
5119
  });
5120
+ var SHOPIFY_MAX_LANDING_IMAGES = 20;
5105
5121
  var ShopifyPublicationMode = z28.enum([
5106
5122
  "auto",
5107
5123
  "existing",
@@ -5116,9 +5132,9 @@ var ShopifyPublishRequest = z28.object({
5116
5132
  * Landing images to include in the Shopify page with their selected variants.
5117
5133
  * Required (≥1) for CLASSIC image landings — the classic publish branch enforces
5118
5134
  * that itself. CODE landings have no images and send an empty array, so the schema
5119
- * allows empty; max 10 (one per landing section).
5135
+ * allows empty; at most SHOPIFY_MAX_LANDING_IMAGES.
5120
5136
  */
5121
- selectedLandingImages: z28.array(SelectedLandingImage).max(10).default([]),
5137
+ selectedLandingImages: z28.array(SelectedLandingImage).max(SHOPIFY_MAX_LANDING_IMAGES).default([]),
5122
5138
  /** Show variant picker pills in the landing when the product has multiple variants. */
5123
5139
  showVariantPicker: z28.boolean().optional(),
5124
5140
  /**
@@ -5304,7 +5320,13 @@ var ShopifyPublishErrorResponse = z28.discriminatedUnion("code", [
5304
5320
  "SHOPIFY_PUBLISH_FAILED",
5305
5321
  "SHOPIFY_NO_PUBLISHED_THEME",
5306
5322
  "SHOPIFY_THEME_STRUCTURE_UNSUPPORTED",
5307
- "SHOPIFY_PUBLISH_CONTEXT_CHANGED"
5323
+ "SHOPIFY_PUBLISH_CONTEXT_CHANGED",
5324
+ /**
5325
+ * A publish failure we understand (Shopify did not keep the offer's
5326
+ * variants, another app rewrote the product, landing too large).
5327
+ * `message` carries the seller's next step; never a 500.
5328
+ */
5329
+ "SHOPIFY_PUBLISH_VERIFICATION_FAILED"
5308
5330
  ]),
5309
5331
  message: z28.string().optional(),
5310
5332
  authUrl: z28.string().url().optional(),
@@ -5314,13 +5336,31 @@ var ShopifyPublishErrorResponse = z28.discriminatedUnion("code", [
5314
5336
  z28.object({
5315
5337
  code: z28.literal("SHOPIFY_PUBLISH_INPUT_REQUIRED"),
5316
5338
  message: z28.string().optional(),
5317
- recovery: PublishPreparationSchema.options[1]
5339
+ recovery: PublishPreparationSchema.options[1],
5340
+ /**
5341
+ * Present when this answers a confirmed correction: the seller already
5342
+ * submitted the form and these issue codes are WHY it was refused. Every
5343
+ * surface must say so instead of re-opening the same form mute (C1).
5344
+ */
5345
+ correctionRejected: z28.literal(true).optional(),
5346
+ rejectedIssueCodes: z28.array(PublishRecoveryCodeSchema).max(6).optional()
5318
5347
  }),
5319
5348
  z28.object({
5320
5349
  code: z28.literal("SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR"),
5321
5350
  action: z28.literal("open_editor"),
5322
5351
  message: z28.string().optional()
5323
5352
  }),
5353
+ z28.object({
5354
+ /**
5355
+ * The seller confirmed exactly what we suggested and the offer still
5356
+ * cannot publish: another pass of the recovery form cannot converge, so
5357
+ * the only exit is the landing editor. `message` names the reason.
5358
+ */
5359
+ code: z28.literal("SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED"),
5360
+ action: z28.literal("open_editor"),
5361
+ message: z28.string().optional(),
5362
+ commerceCorrectionSaved: z28.literal(true).optional()
5363
+ }),
5324
5364
  z28.object({
5325
5365
  /**
5326
5366
  * The chosen existing product cannot express the confirmed offer's
@@ -5362,6 +5402,17 @@ var CodeLandingThemeSetupResponse = z28.discriminatedUnion("status", [
5362
5402
  themeEditorDeepLink: z28.string().url(),
5363
5403
  shopDomain: z28.string()
5364
5404
  }),
5405
+ z28.object({
5406
+ /**
5407
+ * The block is missing and the store has NO products yet. Shopify's theme
5408
+ * editor cannot add an app block to a product template with nothing to
5409
+ * preview (it answers "there is a problem with the app block"), so there
5410
+ * is deliberately no deep link: the seller publishes first, and the
5411
+ * publish response carries the link aimed at the product it created.
5412
+ */
5413
+ status: z28.literal("setup_after_publish"),
5414
+ shopDomain: z28.string()
5415
+ }),
5365
5416
  z28.object({
5366
5417
  /** Not a code-landing task — the gate does not apply. */
5367
5418
  status: z28.literal("not_applicable"),
@@ -6864,7 +6915,10 @@ var ChatParseEstimationOptions = z34.object({}).strict();
6864
6915
  var CodeLandingEditEstimationOptions = z34.object({}).strict();
6865
6916
  var ServiceCreativeEstimationOptions = z34.object({
6866
6917
  mediaAssetCount: z34.number().int().min(0).max(8).optional(),
6867
- uploadedVideoDurationSeconds: z34.number().min(0).max(240).optional()
6918
+ uploadedVideoDurationSeconds: z34.number().min(0).max(240).optional(),
6919
+ /** Quality the panels render at (its registry model sets the per-second
6920
+ * price). Absent = economy, the pre-quality service default. */
6921
+ videoQuality: VideoQuality.optional()
6868
6922
  });
6869
6923
  var ActorGridEstimationOptions = z34.object({}).strict();
6870
6924
  var CostEstimationRequest = z34.discriminatedUnion("type", [
@@ -7229,7 +7283,13 @@ var ImageQaGateEntry = z36.object({
7229
7283
  "passed",
7230
7284
  "failed",
7231
7285
  "unavailable"
7232
- ]).optional()
7286
+ ]).optional(),
7287
+ // Paid edit QA telemetry (plan t2-j9): whether the edit could be checked at all,
7288
+ // whether a previous image was actually available to compare against, and the
7289
+ // measured pixel-delta between the two images.
7290
+ requestedEditVerifiable: z36.boolean().optional(),
7291
+ previousImageUsed: z36.boolean().optional(),
7292
+ editPixelDelta: z36.number().min(0).max(1).optional()
7233
7293
  }).passthrough();
7234
7294
  var ImageQaAssessmentState = z36.enum([
7235
7295
  "approved",
@@ -7628,7 +7688,18 @@ var KIE_SUBMIT_IMAGE_TASK_TARGETS = [
7628
7688
  "rapid_master_anchor",
7629
7689
  "clean_product_image",
7630
7690
  "single_call_anchor",
7631
- "product_view_reference"
7691
+ "product_view_reference",
7692
+ // Generated service-video presenter (text-to-image portrait). Task-owned, so
7693
+ // it lives here and not beside `actor_candidate`; it mirrors that target's
7694
+ // model, resolution and recovery policy. The fan-in resumes the service init
7695
+ // (`dispatchServiceActor`, refKey prefix `service_actor:`).
7696
+ "service_actor",
7697
+ // First frame of a generated service B-roll panel: image-to-image from the
7698
+ // service photo the planner cited, cleaned of overlaid text/graphics and
7699
+ // fitted to the shot. Mirrors `rapid_panel`'s model tier and recovery
7700
+ // policy. The same fan-in waits for the whole expected image set
7701
+ // (`dispatchServiceActor`, refKey prefix `service_broll_anchor:`).
7702
+ "service_broll_anchor"
7632
7703
  ];
7633
7704
  var ACTOR_CANDIDATE_TARGET = "actor_candidate";
7634
7705
  var ANY_KIE_SUBMIT_IMAGE_TARGETS = [
@@ -9550,6 +9621,12 @@ var DEFAULT_PRICING = {
9550
9621
  ourCostCents: 0.01,
9551
9622
  userPriceCents: 0.02
9552
9623
  },
9624
+ // Service reels harvested from the business's own public profile (per second,
9625
+ // same Whisper-1 rate). Separate action so the ledger names the source.
9626
+ "openai:service-social-transcribe": {
9627
+ ourCostCents: 0.01,
9628
+ userPriceCents: 0.02
9629
+ },
9553
9630
  // User-uploaded service reference/competitor analysis (per second, same Whisper-1 rate).
9554
9631
  // This is a separate action because its ledger entries identify the analysis source.
9555
9632
  "openai:service-reference-transcribe": {
@@ -10689,6 +10766,11 @@ var DECLARATION = DELIVERY_FAMILIES.map((family) => [
10689
10766
  ])
10690
10767
  ]);
10691
10768
 
10769
+ // ../../packages/types/src/seller-prohibitions.ts
10770
+ var MARKER = String.raw`(?:no|nunca|jam[aá]s|prohibido|evita[r]?)(?:\s*:)?\s`;
10771
+ var PROHIBITION_AT_START = new RegExp(String.raw`^(?:[-•*]\s*)?(${MARKER}[\s\S]*)$`, "iu");
10772
+ var PROHIBITION_AFTER_LABEL = new RegExp(String.raw`^(?:[-•*]\s*)?[^:.!?\n]{1,40}:\s*(${MARKER}[\s\S]*)$`, "iu");
10773
+
10692
10774
  // ../../packages/types/src/task-type.ts
10693
10775
  import { z as z50 } from "zod";
10694
10776
  var TaskTypeSchema = z50.enum([
@@ -13270,7 +13352,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13270
13352
  "task",
13271
13353
  "product"
13272
13354
  ]),
13273
- defineCapability("create_service_video", "40551b8c5d430a494e94bc40a91f265327a2ff5f68e97160559f5219d74d8786", "credit_consuming", "creative", [
13355
+ defineCapability("create_service_video", "863884c1af5de3e168cbbe825ea3961901c84dae1899ca400f8f7fa01df91c0a", "credit_consuming", "creative", [
13274
13356
  "credit_consuming",
13275
13357
  "state_change"
13276
13358
  ], [
@@ -13294,7 +13376,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
13294
13376
  ]),
13295
13377
  slot("video_preset", false, [
13296
13378
  "videoPreset"
13297
- ])
13379
+ ]),
13380
+ // MCP-only for now: WhatsApp's service flow keeps the economy default.
13381
+ slot("video_quality", false, [
13382
+ "videoQuality"
13383
+ ], [])
13298
13384
  ], [
13299
13385
  "service_context"
13300
13386
  ], [
@@ -15087,6 +15173,81 @@ var WhatsAppPresentationManifestSchema = z67.object({
15087
15173
  }
15088
15174
  });
15089
15175
 
15176
+ // ../../packages/types/src/flight-recorder.ts
15177
+ import { z as z68 } from "zod";
15178
+ var FlightRecorderGenerationTypeSchema = z68.enum([
15179
+ "initial",
15180
+ "regeneration",
15181
+ "edit",
15182
+ "retry"
15183
+ ]);
15184
+ var FlightRecorderProviderSchema = z68.enum([
15185
+ "kie",
15186
+ "fal"
15187
+ ]);
15188
+ var FlightRecorderElementSchema = z68.object({
15189
+ name: z68.string().optional(),
15190
+ description: z68.string().optional(),
15191
+ frontalImageUrl: z68.string().optional(),
15192
+ referenceImageUrls: z68.array(z68.string()).optional(),
15193
+ videoUrl: z68.string().optional()
15194
+ });
15195
+ var FlightRecorderDistillationSchema = z68.object({
15196
+ actorGender: z68.enum([
15197
+ "female",
15198
+ "male",
15199
+ "mixed"
15200
+ ]).or(z68.string()).optional(),
15201
+ voiceId: z68.string().optional(),
15202
+ cameraMotion: z68.string().optional()
15203
+ }).catchall(z68.unknown());
15204
+ var FlightRecorderEntrySchema = z68.object({
15205
+ schemaVersion: z68.literal(1).optional(),
15206
+ id: z68.string().min(1),
15207
+ taskId: z68.string().min(1),
15208
+ runId: z68.string().min(1),
15209
+ sequence: z68.number().int().nonnegative(),
15210
+ timestamp: z68.string().min(1),
15211
+ provider: FlightRecorderProviderSchema.or(z68.string()),
15212
+ model: z68.string().min(1),
15213
+ prompt: z68.string(),
15214
+ durationSeconds: z68.number().nonnegative(),
15215
+ aspectRatio: z68.string().optional(),
15216
+ resolution: z68.string().optional(),
15217
+ startImageUrl: z68.string().optional(),
15218
+ endImageUrl: z68.string().optional(),
15219
+ generateAudio: z68.boolean().optional(),
15220
+ // Correlation & pipeline metadata
15221
+ angleKey: z68.string().optional(),
15222
+ sceneIndex: z68.number().int().nonnegative().optional(),
15223
+ generationType: FlightRecorderGenerationTypeSchema,
15224
+ operationId: z68.string().min(1).optional(),
15225
+ revisionId: z68.string().min(1).optional(),
15226
+ attemptNumber: z68.number().int().nonnegative().default(1),
15227
+ // Elements & Distillation
15228
+ elements: z68.array(FlightRecorderElementSchema).optional(),
15229
+ distillation: FlightRecorderDistillationSchema.optional(),
15230
+ // Raw payload (sanitized of secrets)
15231
+ rawPayload: z68.record(z68.unknown())
15232
+ });
15233
+ var FlightRecorderQuerySchema = z68.object({
15234
+ taskId: z68.string().min(1),
15235
+ runId: z68.string().optional(),
15236
+ sceneIndex: z68.number().int().nonnegative().optional(),
15237
+ angleKey: z68.string().optional(),
15238
+ generationType: FlightRecorderGenerationTypeSchema.optional(),
15239
+ cursor: z68.number().int().nonnegative().optional(),
15240
+ limit: z68.number().int().positive().optional()
15241
+ });
15242
+ var FlightRecorderResponseSchema = z68.object({
15243
+ taskId: z68.string().min(1),
15244
+ runId: z68.string().min(1),
15245
+ entries: z68.array(FlightRecorderEntrySchema),
15246
+ lastCall: FlightRecorderEntrySchema.nullable(),
15247
+ count: z68.number().int().nonnegative(),
15248
+ nextCursor: z68.number().int().nonnegative().nullable()
15249
+ });
15250
+
15090
15251
  // src/http.ts
15091
15252
  import express4 from "express";
15092
15253
  import rateLimit2 from "express-rate-limit";
@@ -15593,22 +15754,22 @@ import { InsufficientScopeError, InvalidTokenError } from "@modelcontextprotocol
15593
15754
  import { createRemoteJWKSet as createRemoteJWKSet2, jwtVerify as jwtVerify2 } from "jose";
15594
15755
 
15595
15756
  // src/auth/oauth-config.ts
15596
- import { z as z68 } from "zod";
15757
+ import { z as z69 } from "zod";
15597
15758
  var MCP_RESOURCE = new URL("https://mcp.productmaker.app/mcp");
15598
15759
  var MCP_SCOPE = "mcp:access";
15599
15760
  var STATIC_CLIENT_ISSUER = new URL(MCP_RESOURCE.origin);
15600
- var oauthEnvSchema = z68.object({
15601
- MCP_REMOTE_AUTH_MODE: z68.literal("oauth"),
15602
- MCP_AUTH0_ISSUER: z68.string().trim().min(1),
15603
- MCP_AUTH0_AUDIENCE: z68.string().trim().refine((value) => value === MCP_RESOURCE.href, {
15761
+ var oauthEnvSchema = z69.object({
15762
+ MCP_REMOTE_AUTH_MODE: z69.literal("oauth"),
15763
+ MCP_AUTH0_ISSUER: z69.string().trim().min(1),
15764
+ MCP_AUTH0_AUDIENCE: z69.string().trim().refine((value) => value === MCP_RESOURCE.href, {
15604
15765
  message: `must equal ${MCP_RESOURCE.href}`
15605
15766
  }),
15606
- MCP_AUTH0_CLIENT_ID: z68.string().trim().min(1),
15607
- MCP_AUTH0_CLIENT_SECRET: z68.string().trim().min(1),
15608
- PM_API_AUDIENCE: z68.string().trim().min(1),
15609
- AUTH0_AUDIENCE: z68.string().trim().min(1),
15610
- MCP_STATIC_CLIENT_ID: z68.string().trim().min(1).optional(),
15611
- MCP_STATIC_CLIENT_SECRET: z68.string().trim().min(1).optional()
15767
+ MCP_AUTH0_CLIENT_ID: z69.string().trim().min(1),
15768
+ MCP_AUTH0_CLIENT_SECRET: z69.string().trim().min(1),
15769
+ PM_API_AUDIENCE: z69.string().trim().min(1),
15770
+ AUTH0_AUDIENCE: z69.string().trim().min(1),
15771
+ MCP_STATIC_CLIENT_ID: z69.string().trim().min(1).optional(),
15772
+ MCP_STATIC_CLIENT_SECRET: z69.string().trim().min(1).optional()
15612
15773
  });
15613
15774
  function formatZodIssues(error) {
15614
15775
  return error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
@@ -16715,7 +16876,7 @@ var ApiClient = class {
16715
16876
  };
16716
16877
 
16717
16878
  // src/index.ts
16718
- var MCP_VERSION = "7.1.0";
16879
+ var MCP_VERSION = "7.3.0";
16719
16880
 
16720
16881
  // src/meta-upload-app.ts
16721
16882
  import { readFileSync } from "fs";
@@ -16787,7 +16948,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
16787
16948
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
16788
16949
 
16789
16950
  // src/tools/tasks.ts
16790
- import { z as z72 } from "zod";
16951
+ import { z as z73 } from "zod";
16791
16952
 
16792
16953
  // src/resolve-image.ts
16793
16954
  import { lookup as dnsLookup } from "dns/promises";
@@ -17348,10 +17509,10 @@ async function resolveMediaRef(ref, opts) {
17348
17509
  __name(resolveMediaRef, "resolveMediaRef");
17349
17510
 
17350
17511
  // src/tools/shared.ts
17351
- import { z as z69 } from "zod";
17352
- var Lang = z69.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
17353
- var Country = z69.string().min(2).max(3);
17354
- var LandingStrategyEnum = z69.enum([
17512
+ import { z as z70 } from "zod";
17513
+ var Lang = z70.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
17514
+ var Country = z70.string().min(2).max(3);
17515
+ var LandingStrategyEnum = z70.enum([
17355
17516
  "auto",
17356
17517
  "classic",
17357
17518
  "pain_solution",
@@ -17360,12 +17521,12 @@ var LandingStrategyEnum = z69.enum([
17360
17521
  "offer_value",
17361
17522
  "lifestyle_identity"
17362
17523
  ]);
17363
- var LandingImageFormatEnum = z69.enum([
17524
+ var LandingImageFormatEnum = z70.enum([
17364
17525
  "9:16",
17365
17526
  "4:5",
17366
17527
  "1:1"
17367
17528
  ]);
17368
- var VideoPresetEnum = z69.enum([
17529
+ var VideoPresetEnum = z70.enum([
17369
17530
  "auto",
17370
17531
  "ugc_dynamic",
17371
17532
  "ugc_how_to",
@@ -17378,21 +17539,21 @@ var VideoPresetEnum = z69.enum([
17378
17539
  "pixar_problem",
17379
17540
  "pixar_sassy"
17380
17541
  ]);
17381
- var VideoStructureEnum = z69.enum([
17542
+ var VideoStructureEnum = z70.enum([
17382
17543
  "single_take",
17383
17544
  "multi_scene"
17384
17545
  ]);
17385
- var VideoQualityEnum = z69.enum([
17546
+ var VideoQualityEnum = z70.enum([
17386
17547
  "economy",
17387
17548
  "medium",
17388
17549
  "pro"
17389
17550
  ]);
17390
- var VideoRouteIdEnum = z69.enum([
17551
+ var VideoRouteIdEnum = z70.enum([
17391
17552
  "single_take",
17392
17553
  "multi_scene",
17393
17554
  "free"
17394
17555
  ]);
17395
- var TaskCreativeVariantVideoPresetEnum = z69.enum([
17556
+ var TaskCreativeVariantVideoPresetEnum = z70.enum([
17396
17557
  "auto",
17397
17558
  "ugc_dynamic",
17398
17559
  "ugc_how_to",
@@ -17463,7 +17624,7 @@ function resolveVideoPreset(preset) {
17463
17624
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
17464
17625
  }
17465
17626
  __name(resolveVideoPreset, "resolveVideoPreset");
17466
- var VideoTierEnum = z69.enum([
17627
+ var VideoTierEnum = z70.enum([
17467
17628
  "basic"
17468
17629
  ]);
17469
17630
  function resolveVideoTier(_tier) {
@@ -17503,22 +17664,22 @@ function assertSemanticVideoDurationCompatibility(structure, quality, durationSe
17503
17664
  }
17504
17665
  }
17505
17666
  __name(assertSemanticVideoDurationCompatibility, "assertSemanticVideoDurationCompatibility");
17506
- var VideoResolutionEnum = z69.enum([
17667
+ var VideoResolutionEnum = z70.enum([
17507
17668
  "480p",
17508
17669
  "720p"
17509
17670
  ]);
17510
- var CreativeGenderEnum = z69.enum([
17671
+ var CreativeGenderEnum = z70.enum([
17511
17672
  "female",
17512
17673
  "male",
17513
17674
  "mixed"
17514
17675
  ]);
17515
- var VideoStyleEnum = z69.enum([
17676
+ var VideoStyleEnum = z70.enum([
17516
17677
  "ugc",
17517
17678
  "cartoon_3d",
17518
17679
  "product_only",
17519
17680
  "ai_dynamic"
17520
17681
  ]);
17521
- var NarrativeStyleEnum = z69.enum([
17682
+ var NarrativeStyleEnum = z70.enum([
17522
17683
  "review",
17523
17684
  "ugc_how_to",
17524
17685
  "problem_product_cta",
@@ -17536,7 +17697,7 @@ var NarrativeStyleEnum = z69.enum([
17536
17697
  "ugc_demo_review",
17537
17698
  "market"
17538
17699
  ]);
17539
- var PublicNarrativeStyleEnum = z69.enum([
17700
+ var PublicNarrativeStyleEnum = z70.enum([
17540
17701
  "review",
17541
17702
  "ugc_how_to",
17542
17703
  "ugc_unboxing_chaos",
@@ -17549,7 +17710,7 @@ var PublicNarrativeStyleEnum = z69.enum([
17549
17710
  "sassy_product_pixar",
17550
17711
  "market"
17551
17712
  ]);
17552
- var VideoModelEnum = z69.enum([
17713
+ var VideoModelEnum = z70.enum([
17553
17714
  "veo",
17554
17715
  "wan",
17555
17716
  "bytedance",
@@ -17557,29 +17718,29 @@ var VideoModelEnum = z69.enum([
17557
17718
  "grok",
17558
17719
  "kling"
17559
17720
  ]);
17560
- var ProductReferenceUserChoiceEnum = z69.enum([
17721
+ var ProductReferenceUserChoiceEnum = z70.enum([
17561
17722
  "same_product",
17562
17723
  "variants",
17563
17724
  "different_products",
17564
17725
  "combo_distinct"
17565
17726
  ]);
17566
- var ProductReferenceCandidateGroupingEnum = z69.enum([
17727
+ var ProductReferenceCandidateGroupingEnum = z70.enum([
17567
17728
  "same_product_same_variant",
17568
17729
  "same_product_different_variants",
17569
17730
  "different_products",
17570
17731
  "unclear"
17571
17732
  ]);
17572
- var ProductReferenceScopeEnum = z69.enum([
17733
+ var ProductReferenceScopeEnum = z70.enum([
17573
17734
  "base",
17574
17735
  "video_view_pack"
17575
17736
  ]);
17576
- var ProductReferenceResolutionDecisionEnum = z69.enum([
17737
+ var ProductReferenceResolutionDecisionEnum = z70.enum([
17577
17738
  "approve",
17578
17739
  "reject",
17579
17740
  "observed_only",
17580
17741
  "correct_view"
17581
17742
  ]);
17582
- var ProductReferenceRejectionReasonEnum = z69.enum([
17743
+ var ProductReferenceRejectionReasonEnum = z70.enum([
17583
17744
  "replacement_requested",
17584
17745
  "wrong_product_identity",
17585
17746
  "wrong_variant",
@@ -17590,13 +17751,13 @@ var ProductReferenceRejectionReasonEnum = z69.enum([
17590
17751
  "not_a_product_photo",
17591
17752
  "other"
17592
17753
  ]);
17593
- var GapDurationChoiceMirror = z69.object({
17594
- angleIndex: z69.number().int().nonnegative(),
17595
- recommendedSec: z69.union([
17596
- z69.literal(15),
17597
- z69.literal(30)
17754
+ var GapDurationChoiceMirror = z70.object({
17755
+ angleIndex: z70.number().int().nonnegative(),
17756
+ recommendedSec: z70.union([
17757
+ z70.literal(15),
17758
+ z70.literal(30)
17598
17759
  ]),
17599
- estimatedDeltaCredits: z69.number().int().nonnegative().optional()
17760
+ estimatedDeltaCredits: z70.number().int().nonnegative().optional()
17600
17761
  });
17601
17762
  function buildSelectedImageUrlsHash(urls) {
17602
17763
  const input = [
@@ -17606,13 +17767,13 @@ function buildSelectedImageUrlsHash(urls) {
17606
17767
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
17607
17768
  }
17608
17769
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
17609
- var ImageCreativeStyleEnum = z69.enum([
17770
+ var ImageCreativeStyleEnum = z70.enum([
17610
17771
  "studio",
17611
17772
  "floating",
17612
17773
  "ingredients",
17613
17774
  "in_use"
17614
17775
  ]);
17615
- var ImageCreativeArchetypeEnum = z69.enum([
17776
+ var ImageCreativeArchetypeEnum = z70.enum([
17616
17777
  "direct_response_product_ad",
17617
17778
  "hero_outcome",
17618
17779
  "offer_value_prop",
@@ -17621,20 +17782,20 @@ var ImageCreativeArchetypeEnum = z69.enum([
17621
17782
  "problem_solution",
17622
17783
  "lifestyle_identity"
17623
17784
  ]);
17624
- var ImageCreativeVisualTreatmentEnum = z69.enum([
17785
+ var ImageCreativeVisualTreatmentEnum = z70.enum([
17625
17786
  "performance_product_ad",
17626
17787
  "premium_dtc_carousel"
17627
17788
  ]);
17628
- var ImageCreativeAspectRatioEnum = z69.enum([
17789
+ var ImageCreativeAspectRatioEnum = z70.enum([
17629
17790
  "1:1",
17630
17791
  "4:5",
17631
17792
  "9:16",
17632
17793
  "16:9"
17633
17794
  ]);
17634
- var ImageRefSchema = z69.object({
17635
- url: z69.string().url().optional().describe('URL p\xFAblica HTTPS de la foto. Ej: una URL de Shopify CDN, Cloudinary, Imgur. \xDAsala cuando el usuario te diga "est\xE1 en X.com/foto.jpg" o cuando la foto ya est\xE9 hospedada.'),
17636
- path: z69.string().min(1).optional().describe('Ruta del archivo en el computador del usuario. Ej: "/Users/maria/Desktop/foto.jpg", "~/Pictures/camiseta.png", "C:\\Users\\Maria\\Desktop\\foto.jpg". El MCP local la lee del disco y la sube. SOLO funciona cuando el MCP corre local (stdio). NO funciona en mcp.productmaker.app (HTTP) \u2014 ah\xED usa `url`.'),
17637
- assetId: z69.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
17795
+ var ImageRefSchema = z70.object({
17796
+ url: z70.string().url().optional().describe('URL p\xFAblica HTTPS de la foto. Ej: una URL de Shopify CDN, Cloudinary, Imgur. \xDAsala cuando el usuario te diga "est\xE1 en X.com/foto.jpg" o cuando la foto ya est\xE9 hospedada.'),
17797
+ path: z70.string().min(1).optional().describe('Ruta del archivo en el computador del usuario. Ej: "/Users/maria/Desktop/foto.jpg", "~/Pictures/camiseta.png", "C:\\Users\\Maria\\Desktop\\foto.jpg". El MCP local la lee del disco y la sube. SOLO funciona cuando el MCP corre local (stdio). NO funciona en mcp.productmaker.app (HTTP) \u2014 ah\xED usa `url`.'),
17798
+ assetId: z70.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
17638
17799
  }).refine((v) => [
17639
17800
  v.url,
17640
17801
  v.path,
@@ -17642,11 +17803,11 @@ var ImageRefSchema = z69.object({
17642
17803
  ].filter(Boolean).length === 1, {
17643
17804
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
17644
17805
  });
17645
- var ImagesInput = z69.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
17806
+ var ImagesInput = z70.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
17646
17807
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
17647
17808
  if (assetCount > 0 && assetCount !== images.length) {
17648
17809
  ctx.addIssue({
17649
- code: z69.ZodIssueCode.custom,
17810
+ code: z70.ZodIssueCode.custom,
17650
17811
  message: "all image entries must use assetId, or all must use URL/path sources"
17651
17812
  });
17652
17813
  }
@@ -17714,14 +17875,14 @@ async function submitCreative(api, opts) {
17714
17875
  });
17715
17876
  }
17716
17877
  __name(submitCreative, "submitCreative");
17717
- var ResearchTargetCountryEnum = z69.enum([
17878
+ var ResearchTargetCountryEnum = z70.enum([
17718
17879
  "CO",
17719
17880
  "MX",
17720
17881
  "PE",
17721
17882
  "EC",
17722
17883
  "CL"
17723
17884
  ]);
17724
- var ResearchCategoryEnum = z69.enum([
17885
+ var ResearchCategoryEnum = z70.enum([
17725
17886
  "auto",
17726
17887
  "automotive",
17727
17888
  "kitchen",
@@ -17772,7 +17933,7 @@ var OVERWRITES_EXTERNAL = {
17772
17933
  idempotentHint: false,
17773
17934
  openWorldHint: true
17774
17935
  };
17775
- var DailyControlStatusEnum = z69.enum([
17936
+ var DailyControlStatusEnum = z70.enum([
17776
17937
  "ok",
17777
17938
  "sales_unavailable",
17778
17939
  "timezone_unavailable",
@@ -17785,19 +17946,19 @@ var DailyControlStatusEnum = z69.enum([
17785
17946
  "product_missing",
17786
17947
  "store_unreachable"
17787
17948
  ]);
17788
- var DailyControlLightEnum = z69.enum([
17949
+ var DailyControlLightEnum = z70.enum([
17789
17950
  "green",
17790
17951
  "amber",
17791
17952
  "red",
17792
17953
  "none"
17793
17954
  ]);
17794
- var DailyControlVerdictEnum = z69.enum([
17955
+ var DailyControlVerdictEnum = z70.enum([
17795
17956
  "scale",
17796
17957
  "hold",
17797
17958
  "kill",
17798
17959
  "insufficient_sample"
17799
17960
  ]);
17800
- var DailyControlSourceEnum = z69.enum([
17961
+ var DailyControlSourceEnum = z70.enum([
17801
17962
  "shopify",
17802
17963
  "shopify_settling",
17803
17964
  "user",
@@ -17869,6 +18030,8 @@ var McpErrorCode = {
17869
18030
  SHOPIFY_PUBLISH_INPUT_REQUIRED: "SHOPIFY_PUBLISH_INPUT_REQUIRED",
17870
18031
  SHOPIFY_PUBLISH_CONTEXT_CHANGED: "SHOPIFY_PUBLISH_CONTEXT_CHANGED",
17871
18032
  SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR: "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR",
18033
+ SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED: "SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED",
18034
+ SHOPIFY_PUBLISH_VERIFICATION_FAILED: "SHOPIFY_PUBLISH_VERIFICATION_FAILED",
17872
18035
  SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE: "SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE",
17873
18036
  SHOPIFY_THEME_SETUP_REQUIRED: "SHOPIFY_THEME_SETUP_REQUIRED",
17874
18037
  // Meta / Facebook Ads
@@ -17941,6 +18104,8 @@ var CODE_MESSAGES = {
17941
18104
  SHOPIFY_PUBLISH_INPUT_REQUIRED: "Review every recovery issue with the seller. Ask for missing prices and confirm the exact currency, unit price and pack totals before resending commerceCorrection with confirmed:true. Never invent amounts, convert currency or remove an offer.",
17942
18105
  SHOPIFY_PUBLISH_CONTEXT_CHANGED: "The publication context changed. Reopen the task in ProductMaker, review the current store, product and landing revision, and obtain fresh confirmation. Do not reuse this correction.",
17943
18106
  SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR: "Open the landing editor in ProductMaker to reconcile the visible offer with checkout prices. The correction was not saved; do not retry it automatically or regenerate the landing without approval.",
18107
+ SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED: "The seller confirmed exactly the suggested values and the offer still cannot publish \u2014 resending the same correction will loop. Read the error's reason to the user and send them to the landing editor in ProductMaker to adjust the offer, then publish again. Do not resend commerceCorrection.",
18108
+ SHOPIFY_PUBLISH_VERIFICATION_FAILED: "Shopify did not keep what the publish wrote (offer variants, template or inventory), or the landing is too large. Read the error's reason to the user; retry the publish once, and if it repeats follow the step in the reason (map packs to existing variants, check apps that edit products, or trim the landing in the editor).",
17944
18109
  SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE: "The selected Shopify product cannot carry the confirmed offer (missing quantity options/prices) or no longer exists. Read the error's message to the user, then retry with publicationMode:'new' to create a fresh product, or ask the user to pick a different existing product.",
17945
18110
  SHOPIFY_THEME_SETUP_REQUIRED: "The store's Shopify theme is missing the ProductMaker 'Code Landing' app block \u2014 publishing now would create a product whose page renders blank. Send the user the themeEditorDeepLink (in error data) to open the Shopify theme editor, have them confirm the Code Landing block is added and press Save, then retry publishing. This is a one-time step per store; nothing was published.",
17946
18111
  SHOPIFY_NO_PUBLISHED_THEME: "The Shopify store has no published theme, so there is nowhere to place the landing. Ask the user to publish a theme (Online Store > Themes > Publish) and retry.",
@@ -18136,6 +18301,8 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
18136
18301
  McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED,
18137
18302
  McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED,
18138
18303
  McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR,
18304
+ McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED,
18305
+ McpErrorCode.SHOPIFY_PUBLISH_VERIFICATION_FAILED,
18139
18306
  McpErrorCode.SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE,
18140
18307
  McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED,
18141
18308
  McpErrorCode.TIKTOK_NOT_CONNECTED,
@@ -18163,6 +18330,8 @@ var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
18163
18330
  McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED,
18164
18331
  McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED,
18165
18332
  McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR,
18333
+ McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED,
18334
+ McpErrorCode.SHOPIFY_PUBLISH_VERIFICATION_FAILED,
18166
18335
  McpErrorCode.SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE,
18167
18336
  McpErrorCode.SHOPIFY_NOT_CONNECTED,
18168
18337
  McpErrorCode.SHOPIFY_TOKEN_EXPIRED,
@@ -18286,13 +18455,20 @@ function translateError(err) {
18286
18455
  }
18287
18456
  if (err instanceof ApiHttpError) {
18288
18457
  const body = isRecord2(err.body) ? err.body : {};
18289
- if (body.code === McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR || body.code === McpErrorCode.SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE || body.code === McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_FAILED) {
18458
+ if (body.code === McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_VERIFICATION_FAILED || body.code === McpErrorCode.SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE || body.code === McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_FAILED) {
18290
18459
  const parsed = ShopifyPublishErrorResponse.safeParse(body);
18291
18460
  if (!parsed.success) return mcp(McpErrorCode.INTERNAL, resolveMessage(McpErrorCode.INTERNAL, void 0));
18292
18461
  const details = parsed.data;
18293
18462
  const extra = {};
18294
- if (details.code === "SHOPIFY_PUBLISH_INPUT_REQUIRED") extra.recovery = details.recovery;
18295
- if (details.code === "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR") extra.action = details.action;
18463
+ if (details.code === "SHOPIFY_PUBLISH_INPUT_REQUIRED") {
18464
+ extra.recovery = details.recovery;
18465
+ if (details.correctionRejected) {
18466
+ extra.correctionRejected = true;
18467
+ if (details.rejectedIssueCodes) extra.rejectedIssueCodes = details.rejectedIssueCodes;
18468
+ }
18469
+ }
18470
+ if (details.code === "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR" || details.code === "SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED") extra.action = details.action;
18471
+ if ((details.code === "SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED" || details.code === "SHOPIFY_PUBLISH_VERIFICATION_FAILED" || details.code === "SHOPIFY_PUBLISH_INPUT_REQUIRED" && details.correctionRejected) && details.message) extra.reason = details.message.slice(0, 500);
18296
18472
  if (details.code === "SHOPIFY_THEME_SETUP_REQUIRED") extra.themeEditorDeepLink = details.themeEditorDeepLink;
18297
18473
  const saved = "commerceCorrectionSaved" in details && details.commerceCorrectionSaved === true;
18298
18474
  if (saved) extra.commerceCorrectionSaved = true;
@@ -18870,29 +19046,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
18870
19046
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
18871
19047
 
18872
19048
  // src/tools/media-presentation.ts
18873
- import { z as z70 } from "zod";
18874
- var HttpsPresentationUrlSchema = z70.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
19049
+ import { z as z71 } from "zod";
19050
+ var HttpsPresentationUrlSchema = z71.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
18875
19051
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
18876
19052
  const hostname = new URL(value).hostname.toLowerCase();
18877
19053
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
18878
19054
  }, "preview URL must be owned by ProductMaker");
18879
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z70.number().int().positive().max(maximum), "positiveIntAtMost");
18880
- var PresentationImageSchema = z70.object({
18881
- kind: z70.literal("image"),
19055
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z71.number().int().positive().max(maximum), "positiveIntAtMost");
19056
+ var PresentationImageSchema = z71.object({
19057
+ kind: z71.literal("image"),
18882
19058
  url: HttpsPresentationUrlSchema,
18883
- mimeType: z70.enum([
19059
+ mimeType: z71.enum([
18884
19060
  "image/jpeg",
18885
19061
  "image/png"
18886
19062
  ]),
18887
19063
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
18888
19064
  width: positiveIntAtMost(16384),
18889
19065
  height: positiveIntAtMost(16384),
18890
- alt: z70.string().trim().min(1).max(240)
19066
+ alt: z71.string().trim().min(1).max(240)
18891
19067
  }).strict();
18892
19068
  var McpMediaPresentationSchema = PresentationImageSchema;
18893
- var GalleryImageSchema = z70.object({
19069
+ var GalleryImageSchema = z71.object({
18894
19070
  url: ProductMakerPreviewUrlSchema,
18895
- alt: z70.string().trim().min(1).max(240)
19071
+ alt: z71.string().trim().min(1).max(240)
18896
19072
  });
18897
19073
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
18898
19074
  async function imageBlocks(image, transport) {
@@ -19042,10 +19218,10 @@ ${summary}`,
19042
19218
  __name(requirePaidCreativeConfirmation, "requirePaidCreativeConfirmation");
19043
19219
 
19044
19220
  // src/tools/winning-product-image.ts
19045
- import { z as z71 } from "zod";
19046
- var WinnerReferenceInput = z71.object({
19047
- runId: z71.string().uuid(),
19048
- candidateSourceId: z71.string().trim().min(1).max(160)
19221
+ import { z as z72 } from "zod";
19222
+ var WinnerReferenceInput = z72.object({
19223
+ runId: z72.string().uuid(),
19224
+ candidateSourceId: z72.string().trim().min(1).max(160)
19049
19225
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
19050
19226
  async function resolveWinnerImages(api, winnerReference, images) {
19051
19227
  if (!winnerReference) return images;
@@ -19082,188 +19258,189 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
19082
19258
  var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
19083
19259
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
19084
19260
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
19085
- var CreateProductTaskInput = z72.object({
19261
+ var CreateProductTaskInput = z73.object({
19086
19262
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
19087
19263
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
19088
- projectId: z72.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
19089
- productUrl: z72.string().url().optional().describe("Opcional. URL de la p\xE1gina del producto (Shopify, AliExpress, Amazon, etc.) para enriquecer el contexto. Si se omite, la IA infiere todo desde la imagen."),
19264
+ 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."),
19265
+ 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."),
19090
19266
  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.'),
19091
19267
  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.'),
19092
- price: z72.string().min(1).max(120).optional().describe('Precio que se mostrar\xE1 en la landing y video. Formato libre \u2014 ej. "$89.900", "USD 29.99", "MXN 599". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si te dice "t\xFA elige", om\xEDtelo y el backend sugiere uno.'),
19093
- compareAtPrice: z72.string().min(1).max(120).optional().describe('Opcional. Precio anterior para comunicar un descuento real en landing e im\xE1genes. Ej. "$129.000" cuando price="$89.900".'),
19094
- offer: z72.string().min(1).max(240).optional().describe('Oferta o promoci\xF3n a destacar. Ej. "2x1", "Env\xEDo gratis hoy", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si te dice "t\xFA elige", om\xEDtelo.'),
19095
- paymentMethods: z72.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago que puede mostrar la landing. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
19096
- productContext: z72.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
19097
- productLabel: z72.string().trim().max(80).optional().describe('Opcional. Qu\xE9 es el producto, en pocas palabras (ej. "quita pelusas para ropa"). Es AUTORITATIVO: si lo env\xEDas, la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA detecta el producto desde la imagen.'),
19268
+ 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.'),
19269
+ 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".'),
19270
+ 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.'),
19271
+ 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.'),
19272
+ 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."),
19273
+ 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.'),
19098
19274
  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.'),
19099
- durationSeconds: z72.union([
19100
- z72.literal(15),
19101
- z72.literal(30)
19275
+ durationSeconds: z73.union([
19276
+ z73.literal(15),
19277
+ z73.literal(30)
19102
19278
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
19103
- pauseForAngleReview: z72.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
19104
- aiDecidesAll: z72.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
19279
+ 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."),
19280
+ 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."),
19105
19281
  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.'),
19106
19282
  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.'),
19107
19283
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
19108
19284
  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).'),
19109
- videoAngleCount: z72.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
19285
+ 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."),
19110
19286
  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.'),
19111
- outputs: z72.array(z72.enum([
19287
+ outputs: z73.array(z73.enum([
19112
19288
  "landing",
19113
19289
  "video",
19114
19290
  "image"
19115
19291
  ])).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}`),
19116
- competitorScanEnabled: z72.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico. Omitir no autoriza el estudio profundo."),
19117
- replicateWinnerWhenFound: z72.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
19118
- brandId: z72.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer los outputs generados."),
19119
- actorId: z72.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
19292
+ 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."),
19293
+ 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."),
19294
+ 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."),
19295
+ 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."),
19120
19296
  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.'),
19121
- creativeDirection: z72.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo) que aplica a los outputs de IMAGEN y LANDING (no al video \u2014 el estilo/ambiente del video se dirige con scriptNotes). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Ej. "amarillo y azul, minimalista". M\xE1x 500 caracteres.'),
19122
- headline: z72.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar. Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. Se aplica a las IM\xC1GENES y a la portada de la landing de esta task (el video no lo usa; para el video usa scriptNotes). \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
19123
- subheadline: z72.string().max(160).optional().describe("Opcional. Subt\xEDtulo EXACTO a renderizar, misma regla que headline. Independiente: puedes fijar solo el subt\xEDtulo. M\xE1x 160 caracteres."),
19297
+ 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.'),
19298
+ 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."),
19299
+ 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."),
19124
19300
  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".'),
19125
19301
  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".')
19126
19302
  }).strict();
19127
- var CreateServiceVideoInput = z72.object({
19128
- landingUrl: z72.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
19129
- additionalContext: z72.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
19303
+ var CreateServiceVideoInput = z73.object({
19304
+ 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."),
19305
+ 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.'),
19130
19306
  language: Lang.describe("Idioma del video: es, en o pt."),
19131
- voiceId: z72.string().trim().min(1).optional().describe('Opcional. Voz de ElevenLabs para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador o env\xEDa un ID concreto de la lista de voces de la web.'),
19132
- brandId: z72.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
19133
- reviewMode: z72.enum([
19307
+ 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.'),
19308
+ brandId: z73.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
19309
+ reviewMode: z73.enum([
19134
19310
  "automatic",
19135
19311
  "guided"
19136
19312
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
19137
- videoPreset: z72.enum([
19313
+ videoPreset: z73.enum([
19138
19314
  "auto",
19139
19315
  "ugc_dynamic",
19140
19316
  "ugc_how_to",
19141
19317
  "cinematic",
19142
19318
  "wild_card"
19143
- ]).default("auto")
19319
+ ]).default("auto"),
19320
+ videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.')
19144
19321
  }).strict();
19145
- var GetTaskStatusInput = z72.object({
19146
- taskId: z72.string().min(1),
19147
- waitSeconds: z72.number().int().min(0).max(120).optional()
19322
+ var GetTaskStatusInput = z73.object({
19323
+ taskId: z73.string().min(1),
19324
+ waitSeconds: z73.number().int().min(0).max(120).optional()
19148
19325
  });
19149
- var ListTasksInput = z72.object({
19150
- limit: z72.number().int().min(1).max(50).optional(),
19151
- offset: z72.number().int().min(0).optional(),
19152
- search: z72.string().optional()
19326
+ var ListTasksInput = z73.object({
19327
+ limit: z73.number().int().min(1).max(50).optional(),
19328
+ offset: z73.number().int().min(0).optional(),
19329
+ search: z73.string().optional()
19153
19330
  });
19154
19331
  var MCP_REVIEW_LIST_FIELD_MAX = 1500;
19155
19332
  var MCP_REVIEW_FEATURE_ITEM_MAX = 240;
19156
- var EditTaskDraftInput = z72.object({
19157
- taskId: z72.string().min(1),
19158
- angleIndex: z72.number().int().min(0),
19159
- angle: z72.object({
19160
- angle: z72.string().min(1).max(480),
19161
- buyerPersona: z72.string().min(1).max(360),
19162
- actor: z72.string().min(1).max(360).optional(),
19163
- actorId: z72.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
19164
- gender: z72.enum([
19333
+ var EditTaskDraftInput = z73.object({
19334
+ taskId: z73.string().min(1),
19335
+ angleIndex: z73.number().int().min(0),
19336
+ angle: z73.object({
19337
+ angle: z73.string().min(1).max(480),
19338
+ buyerPersona: z73.string().min(1).max(360),
19339
+ actor: z73.string().min(1).max(360).optional(),
19340
+ 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."),
19341
+ gender: z73.enum([
19165
19342
  "female",
19166
19343
  "male"
19167
19344
  ]).optional(),
19168
- scriptNotes: z72.string().max(2e3).optional()
19345
+ scriptNotes: z73.string().max(2e3).optional()
19169
19346
  })
19170
19347
  });
19171
- var PendingActionPayload = z72.discriminatedUnion("kind", [
19172
- z72.object({
19173
- kind: z72.literal("product_reference_set_approval"),
19348
+ var PendingActionPayload = z73.discriminatedUnion("kind", [
19349
+ z73.object({
19350
+ kind: z73.literal("product_reference_set_approval"),
19174
19351
  scope: ProductReferenceScopeEnum.optional(),
19175
- scopeKey: z72.string().min(1).max(120).optional(),
19176
- scopeSnapshotId: z72.string().uuid().optional(),
19177
- expectedScopeHash: z72.string().min(1).max(128).optional(),
19352
+ scopeKey: z73.string().min(1).max(120).optional(),
19353
+ scopeSnapshotId: z73.string().uuid().optional(),
19354
+ expectedScopeHash: z73.string().min(1).max(128).optional(),
19178
19355
  decision: ProductReferenceResolutionDecisionEnum,
19179
19356
  reason: ProductReferenceRejectionReasonEnum.optional(),
19180
- affectedRefKeys: z72.array(z72.string().min(1).max(200)).min(1).optional(),
19181
- affectedPhotoNumbers: z72.array(z72.number().int().positive()).min(1).optional(),
19182
- recoveryAction: z72.enum([
19357
+ affectedRefKeys: z73.array(z73.string().min(1).max(200)).min(1).optional(),
19358
+ affectedPhotoNumbers: z73.array(z73.number().int().positive()).min(1).optional(),
19359
+ recoveryAction: z73.enum([
19183
19360
  "remove",
19184
19361
  "replace",
19185
19362
  "upload",
19186
19363
  "return_to_selection"
19187
19364
  ]).optional()
19188
19365
  }),
19189
- z72.object({
19190
- kind: z72.literal("product_reference_confirmation"),
19191
- selectedPhotoNumbers: z72.array(z72.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
19366
+ z73.object({
19367
+ kind: z73.literal("product_reference_confirmation"),
19368
+ 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."),
19192
19369
  userChoice: ProductReferenceUserChoiceEnum.optional(),
19193
- confirmedProductNames: z72.array(z72.string().min(1).max(120)).min(2).max(8).optional(),
19370
+ confirmedProductNames: z73.array(z73.string().min(1).max(120)).min(2).max(8).optional(),
19194
19371
  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."),
19195
19372
  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."),
19196
- useMultiSceneShowcase: z72.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
19373
+ useMultiSceneShowcase: z73.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
19197
19374
  }),
19198
- z72.object({
19199
- kind: z72.literal("angle_review_approval"),
19375
+ z73.object({
19376
+ kind: z73.literal("angle_review_approval"),
19200
19377
  // All edits are optional — empty action body just approves the
19201
19378
  // backend-generated draft as-is. Field shapes mirror the angle-review
19202
19379
  // request contracts in @packages/types/wizard.ts; the handler routes to
19203
19380
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
19204
- customAngle: z72.string().min(1).max(480).optional(),
19381
+ customAngle: z73.string().min(1).max(480).optional(),
19205
19382
  // Keep the shared MCP action within the strictest downstream contract:
19206
19383
  // autopilot/image resume endpoints cap these fields at 1500 characters.
19207
- painPoints: z72.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19208
- benefits: z72.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19384
+ painPoints: z73.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19385
+ benefits: z73.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
19209
19386
  // Same policy as the two fields above: the strictest downstream contract
19210
19387
  // wins. The image endpoint caps each feature at 240 while landing/video
19211
19388
  // accept 300, and this single action routes to whichever the task is — so
19212
19389
  // accepting 300 here turns a 250-character feature on an image task into
19213
19390
  // an opaque HTTP 400 after the model already believed it had been saved.
19214
- features: z72.array(z72.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
19215
- buyerPersona: z72.string().min(1).max(360).optional(),
19391
+ features: z73.array(z73.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
19392
+ buyerPersona: z73.string().min(1).max(360).optional(),
19216
19393
  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.'),
19217
- actor: z72.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
19218
- actorId: z72.string().max(120).nullable().optional(),
19219
- creativeDirection: z72.string().max(2e3).optional(),
19220
- selectedAngleNumbers: z72.array(z72.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
19221
- angleEdits: z72.array(z72.object({
19222
- angleNumber: z72.number().int().positive(),
19223
- narrativeSelection: z72.enum([
19394
+ 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."),
19395
+ actorId: z73.string().max(120).nullable().optional(),
19396
+ creativeDirection: z73.string().max(2e3).optional(),
19397
+ 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."),
19398
+ angleEdits: z73.array(z73.object({
19399
+ angleNumber: z73.number().int().positive(),
19400
+ narrativeSelection: z73.enum([
19224
19401
  "market",
19225
19402
  "guided"
19226
19403
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
19227
- angle: z72.string().min(1).max(480).optional(),
19228
- buyerPersona: z72.string().min(1).max(360).optional(),
19404
+ angle: z73.string().min(1).max(480).optional(),
19405
+ buyerPersona: z73.string().min(1).max(360).optional(),
19229
19406
  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.'),
19230
- actor: z72.string().min(1).max(360).optional(),
19231
- actorId: z72.string().max(120).nullable().optional(),
19232
- creativeDirection: z72.string().max(2e3).optional()
19407
+ actor: z73.string().min(1).max(360).optional(),
19408
+ actorId: z73.string().max(120).nullable().optional(),
19409
+ creativeDirection: z73.string().max(2e3).optional()
19233
19410
  }).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)."),
19234
- gapDurationSeconds: z72.union([
19235
- z72.literal(15),
19236
- z72.literal(30)
19411
+ gapDurationSeconds: z73.union([
19412
+ z73.literal(15),
19413
+ z73.literal(30)
19237
19414
  ]).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.")
19238
19415
  }),
19239
- z72.object({
19240
- kind: z72.literal("service_angle_approval"),
19241
- angleId: z72.string().uuid().optional(),
19242
- angleNumber: z72.number().int().positive().optional(),
19243
- content: z72.string().min(1).max(480).optional(),
19244
- creativeDirection: z72.string().min(1).max(1500).optional(),
19245
- actor: z72.string().min(1).max(360).optional()
19416
+ z73.object({
19417
+ kind: z73.literal("service_angle_approval"),
19418
+ angleId: z73.string().uuid().optional(),
19419
+ angleNumber: z73.number().int().positive().optional(),
19420
+ content: z73.string().min(1).max(480).optional(),
19421
+ creativeDirection: z73.string().min(1).max(1500).optional(),
19422
+ actor: z73.string().min(1).max(360).optional()
19246
19423
  }),
19247
- z72.object({
19248
- kind: z72.literal("service_script_approval"),
19249
- voiceovers: z72.record(z72.string(), z72.string().min(1).max(600)).optional(),
19250
- visualDirections: z72.record(z72.string(), z72.string().min(1).max(1200)).optional(),
19251
- voiceoversByScene: z72.record(z72.string(), z72.string().min(1).max(600)).optional(),
19252
- visualDirectionsByScene: z72.record(z72.string(), z72.string().min(1).max(1200)).optional()
19424
+ z73.object({
19425
+ kind: z73.literal("service_script_approval"),
19426
+ voiceovers: z73.record(z73.string(), z73.string().min(1).max(600)).optional(),
19427
+ visualDirections: z73.record(z73.string(), z73.string().min(1).max(1200)).optional(),
19428
+ voiceoversByScene: z73.record(z73.string(), z73.string().min(1).max(600)).optional(),
19429
+ visualDirectionsByScene: z73.record(z73.string(), z73.string().min(1).max(1200)).optional()
19253
19430
  })
19254
19431
  ]);
19255
- var ResolvePendingActionInput = z72.object({
19256
- taskId: z72.string().min(1),
19432
+ var ResolvePendingActionInput = z73.object({
19433
+ taskId: z73.string().min(1),
19257
19434
  action: PendingActionPayload
19258
19435
  }).strict();
19259
19436
  function resolveVariantConfirmVideoTier(action) {
19260
19437
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
19261
19438
  }
19262
19439
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
19263
- var StatusForResolveSchema = z72.object({
19440
+ var StatusForResolveSchema = z73.object({
19264
19441
  // Metadata used to select the backend resume contract. Older API responses
19265
19442
  // may omit these fields, so the resolver keeps the generic fallback.
19266
- kind: z72.enum([
19443
+ kind: z73.enum([
19267
19444
  "autopilot",
19268
19445
  "video",
19269
19446
  "image",
@@ -19271,18 +19448,18 @@ var StatusForResolveSchema = z72.object({
19271
19448
  "mix",
19272
19449
  "service"
19273
19450
  ]).optional(),
19274
- selectedOutputs: z72.array(z72.enum([
19451
+ selectedOutputs: z73.array(z73.enum([
19275
19452
  "landing",
19276
19453
  "video",
19277
19454
  "image"
19278
19455
  ])).optional(),
19279
- videoAngleCount: z72.number().int().min(1).max(3).optional(),
19280
- ugcFormat: z72.enum([
19456
+ videoAngleCount: z73.number().int().min(1).max(3).optional(),
19457
+ ugcFormat: z73.enum([
19281
19458
  "single_8s",
19282
19459
  "single_15s",
19283
19460
  "double_30s"
19284
19461
  ]).optional(),
19285
- videoStyle: z72.enum([
19462
+ videoStyle: z73.enum([
19286
19463
  "ugc",
19287
19464
  "cartoon_3d",
19288
19465
  "product_only",
@@ -19291,7 +19468,7 @@ var StatusForResolveSchema = z72.object({
19291
19468
  videoStructure: VideoStructureEnum.optional(),
19292
19469
  videoQuality: VideoQualityEnum.optional(),
19293
19470
  videoRouteId: VideoRouteIdEnum.optional(),
19294
- videoModel: z72.enum([
19471
+ videoModel: z73.enum([
19295
19472
  "veo",
19296
19473
  "wan",
19297
19474
  "bytedance",
@@ -19299,71 +19476,71 @@ var StatusForResolveSchema = z72.object({
19299
19476
  "grok",
19300
19477
  "kling"
19301
19478
  ]).optional(),
19302
- videoTier: z72.enum([
19479
+ videoTier: z73.enum([
19303
19480
  "legacy",
19304
19481
  "standard",
19305
19482
  "pro",
19306
19483
  "single_call"
19307
19484
  ]).optional(),
19308
- videoResolution: z72.enum([
19485
+ videoResolution: z73.enum([
19309
19486
  "480p",
19310
19487
  "720p"
19311
19488
  ]).optional(),
19312
19489
  narrativeStyle: NarrativeStyleEnum.optional(),
19313
- pauseForVideoScriptReview: z72.boolean().optional(),
19314
- pendingUserAction: z72.object({
19315
- kind: z72.string(),
19316
- candidateGrouping: z72.string().optional(),
19317
- selectedImageUrls: z72.array(z72.string()).optional(),
19318
- proposedProductNames: z72.array(z72.string()).optional(),
19490
+ pauseForVideoScriptReview: z73.boolean().optional(),
19491
+ pendingUserAction: z73.object({
19492
+ kind: z73.string(),
19493
+ candidateGrouping: z73.string().optional(),
19494
+ selectedImageUrls: z73.array(z73.string()).optional(),
19495
+ proposedProductNames: z73.array(z73.string()).optional(),
19319
19496
  // Adaptive reference questions are server-owned. Echo only the evidence
19320
19497
  // identity and the choices shown by the current snapshot; never accept a
19321
19498
  // client-supplied reference set as authorization.
19322
- options: z72.array(ProductReferenceUserChoiceEnum).max(4).optional(),
19323
- mode: z72.enum([
19499
+ options: z73.array(ProductReferenceUserChoiceEnum).max(4).optional(),
19500
+ mode: z73.enum([
19324
19501
  "question",
19325
19502
  "visual_recovery"
19326
19503
  ]).optional(),
19327
19504
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
19328
- canKeepSelection: z72.boolean().optional(),
19329
- decisionKey: z72.string().optional(),
19330
- questionOrdinal: z72.number().int().min(1).max(5).optional(),
19331
- questionCeiling: z72.union([
19332
- z72.literal(3),
19333
- z72.literal(5)
19505
+ canKeepSelection: z73.boolean().optional(),
19506
+ decisionKey: z73.string().optional(),
19507
+ questionOrdinal: z73.number().int().min(1).max(5).optional(),
19508
+ questionCeiling: z73.union([
19509
+ z73.literal(3),
19510
+ z73.literal(5)
19334
19511
  ]).optional(),
19335
- referenceEvidenceVersion: z72.number().int().positive().optional(),
19336
- expectedEvidenceHash: z72.string().optional(),
19337
- question: z72.object({
19338
- prompt: z72.string().min(1).max(240),
19339
- helpText: z72.string().min(1).max(300).optional(),
19340
- options: z72.array(z72.object({
19512
+ referenceEvidenceVersion: z73.number().int().positive().optional(),
19513
+ expectedEvidenceHash: z73.string().optional(),
19514
+ question: z73.object({
19515
+ prompt: z73.string().min(1).max(240),
19516
+ helpText: z73.string().min(1).max(300).optional(),
19517
+ options: z73.array(z73.object({
19341
19518
  value: ProductReferenceUserChoiceEnum,
19342
- label: z72.string().min(1).max(120),
19343
- description: z72.string().min(1).max(240).optional()
19519
+ label: z73.string().min(1).max(120),
19520
+ description: z73.string().min(1).max(240).optional()
19344
19521
  })).min(2).max(4)
19345
19522
  }).optional(),
19346
19523
  scope: ProductReferenceScopeEnum.optional(),
19347
- scopeKey: z72.string().optional(),
19348
- scopeSnapshotId: z72.string().uuid().optional(),
19349
- scopeHash: z72.string().optional(),
19350
- baseReferenceSetHash: z72.string().optional(),
19351
- phase: z72.enum([
19524
+ scopeKey: z73.string().optional(),
19525
+ scopeSnapshotId: z73.string().uuid().optional(),
19526
+ scopeHash: z73.string().optional(),
19527
+ baseReferenceSetHash: z73.string().optional(),
19528
+ phase: z73.enum([
19352
19529
  "preparation",
19353
19530
  "final"
19354
19531
  ]).optional(),
19355
- selectedRefKeys: z72.array(z72.string().min(1).max(200)).optional(),
19356
- allowedDecisions: z72.array(ProductReferenceResolutionDecisionEnum).optional(),
19357
- previews: z72.array(z72.object({
19358
- refKey: z72.string().min(1).max(200)
19532
+ selectedRefKeys: z73.array(z73.string().min(1).max(200)).optional(),
19533
+ allowedDecisions: z73.array(ProductReferenceResolutionDecisionEnum).optional(),
19534
+ previews: z73.array(z73.object({
19535
+ refKey: z73.string().min(1).max(200)
19359
19536
  }).passthrough()).optional(),
19360
- customAngleDraft: z72.string().optional(),
19361
- painPointsDraft: z72.string().optional(),
19362
- benefitsDraft: z72.string().optional(),
19363
- featuresDraft: z72.array(z72.string()).optional(),
19364
- angleOptions: z72.array(z72.object({
19365
- index: z72.number().int().nonnegative(),
19366
- angle: z72.string().min(1)
19537
+ customAngleDraft: z73.string().optional(),
19538
+ painPointsDraft: z73.string().optional(),
19539
+ benefitsDraft: z73.string().optional(),
19540
+ featuresDraft: z73.array(z73.string()).optional(),
19541
+ angleOptions: z73.array(z73.object({
19542
+ index: z73.number().int().nonnegative(),
19543
+ angle: z73.string().min(1)
19367
19544
  }).passthrough()).min(1).max(5).optional(),
19368
19545
  // Recommendation consumed only when the caller explicitly sends
19369
19546
  // gapDurationSeconds: 30 in the angle approval action.
@@ -19373,17 +19550,17 @@ var StatusForResolveSchema = z72.object({
19373
19550
  // keys. `actorId` (the saved custom actor the picker stored) was silently
19374
19551
  // dropped here, so the approval handler below could not echo it back on the
19375
19552
  // PATCH — the selection looked accepted and reached no render.
19376
- angles: z72.array(z72.object({
19377
- id: z72.string().uuid(),
19378
- content: z72.string(),
19379
- creativeDirection: z72.string(),
19380
- actor: z72.string(),
19381
- actorId: z72.string().nullable().optional()
19553
+ angles: z73.array(z73.object({
19554
+ id: z73.string().uuid(),
19555
+ content: z73.string(),
19556
+ creativeDirection: z73.string(),
19557
+ actor: z73.string(),
19558
+ actorId: z73.string().nullable().optional()
19382
19559
  }).passthrough()).optional(),
19383
- panels: z72.array(z72.object({
19384
- beatId: z72.string(),
19385
- voiceover: z72.string(),
19386
- visualDirection: z72.string()
19560
+ panels: z73.array(z73.object({
19561
+ beatId: z73.string(),
19562
+ voiceover: z73.string(),
19563
+ visualDirection: z73.string()
19387
19564
  }).passthrough()).optional()
19388
19565
  }).optional()
19389
19566
  }).passthrough();
@@ -19609,6 +19786,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
19609
19786
  voiceId: input.voiceId
19610
19787
  } : {},
19611
19788
  videoPreset: input.videoPreset,
19789
+ videoQuality: input.videoQuality,
19612
19790
  reviewMode: input.reviewMode,
19613
19791
  ...input.brandId ? {
19614
19792
  brandId: input.brandId
@@ -20213,7 +20391,7 @@ __name(registerTaskTools, "registerTaskTools");
20213
20391
 
20214
20392
  // src/tools/creatives.ts
20215
20393
  import { randomUUID } from "crypto";
20216
- import { z as z73 } from "zod";
20394
+ import { z as z74 } from "zod";
20217
20395
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
20218
20396
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
20219
20397
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -20223,70 +20401,70 @@ var CreativeRefs = {
20223
20401
  images: ImagesInput,
20224
20402
  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.'),
20225
20403
  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.'),
20226
- price: z73.string().min(1).max(120).optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
20227
- offer: z73.string().min(1).max(240).optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
20228
- compareAtPrice: z73.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
20229
- 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."),
20230
- productLabel: z73.string().trim().max(80).optional().describe('Opcional. Nombre o tipo del producto en pocas palabras (ej. "collar de oro", "quita pelusas para ropa"). Es AUTORITATIVO: la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA lo detecta desde la imagen. NO salta la extracci\xF3n.'),
20231
- buyerPersona: z73.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
20232
- isCombo: z73.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
20233
- competitorScanEnabled: z73.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico. Omitir no autoriza el estudio profundo."),
20234
- brandId: z73.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer el creativo.")
20404
+ 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.'),
20405
+ 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.'),
20406
+ 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".'),
20407
+ 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."),
20408
+ 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.'),
20409
+ 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.'),
20410
+ isCombo: z74.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
20411
+ 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."),
20412
+ 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.")
20235
20413
  };
20236
- var VideoPresenter = z73.discriminatedUnion("mode", [
20237
- z73.object({
20238
- mode: z73.literal("none")
20414
+ var VideoPresenter = z74.discriminatedUnion("mode", [
20415
+ z74.object({
20416
+ mode: z74.literal("none")
20239
20417
  }).strict(),
20240
- z73.object({
20241
- mode: z73.literal("saved_actor"),
20242
- actorId: z73.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
20418
+ z74.object({
20419
+ mode: z74.literal("saved_actor"),
20420
+ actorId: z74.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
20243
20421
  }).strict(),
20244
- z73.object({
20245
- mode: z73.literal("described"),
20246
- description: z73.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
20422
+ z74.object({
20423
+ mode: z74.literal("described"),
20424
+ description: z74.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
20247
20425
  }).strict()
20248
20426
  ]);
20249
- var VideoCreativeSetup = z73.discriminatedUnion("mode", [
20250
- z73.object({
20251
- mode: z73.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
20427
+ var VideoCreativeSetup = z74.discriminatedUnion("mode", [
20428
+ z74.object({
20429
+ mode: z74.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
20252
20430
  }).strict(),
20253
- z73.object({
20254
- mode: z73.literal("guided"),
20431
+ z74.object({
20432
+ mode: z74.literal("guided"),
20255
20433
  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.'),
20256
- buyerPersona: z73.string().trim().min(1).max(360),
20434
+ buyerPersona: z74.string().trim().min(1).max(360),
20257
20435
  presenter: VideoPresenter,
20258
- creativeDirection: z73.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
20436
+ 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.")
20259
20437
  }).strict()
20260
20438
  ]);
20261
- var VideoInput = z73.object({
20439
+ var VideoInput = z74.object({
20262
20440
  images: CreativeRefs.images.optional(),
20263
20441
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20264
- title: z73.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
20265
- primaryAngle: z73.string().min(1).describe('\xC1ngulo de venta principal (frase del beneficio). Ej. "Reduce arrugas en 14 d\xEDas" o "Para quienes odian las cremas grasosas".'),
20442
+ title: z74.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
20443
+ 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".'),
20266
20444
  language: CreativeRefs.language,
20267
20445
  country: CreativeRefs.country,
20268
- aspectRatio: z73.enum([
20446
+ aspectRatio: z74.enum([
20269
20447
  "9:16",
20270
20448
  "16:9",
20271
20449
  "Auto"
20272
20450
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
20273
- durationSeconds: z73.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
20274
- videoAngleCount: z73.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
20451
+ 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."),
20452
+ 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."),
20275
20453
  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.'),
20276
20454
  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."),
20277
20455
  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.'),
20278
20456
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
20279
20457
  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.'),
20280
- features: z73.array(z73.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
20458
+ 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"].'),
20281
20459
  price: CreativeRefs.price,
20282
20460
  offer: CreativeRefs.offer,
20283
20461
  productContext: CreativeRefs.productContext,
20284
20462
  productLabel: CreativeRefs.productLabel,
20285
- cta: z73.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
20286
- scriptNotes: z73.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
20463
+ 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.'),
20464
+ 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.'),
20287
20465
  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.'),
20288
20466
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
20289
- replicateWinnerWhenFound: z73.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
20467
+ 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."),
20290
20468
  brandId: CreativeRefs.brandId
20291
20469
  }).strict();
20292
20470
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -20304,7 +20482,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
20304
20482
  length: 29
20305
20483
  }, (_, index) => index + 2)
20306
20484
  };
20307
- var FreeVideoModelIdEnum = z73.enum([
20485
+ var FreeVideoModelIdEnum = z74.enum([
20308
20486
  "grok-imagine-video-1-5-preview",
20309
20487
  "minimax-h3/reference-to-video",
20310
20488
  "wan/3-0-video",
@@ -20315,70 +20493,70 @@ var FREE_SELECTABLE_MODEL_IDS = [
20315
20493
  "minimax-h3/reference-to-video",
20316
20494
  "wan/3-0-video"
20317
20495
  ];
20318
- var FreeVideoInput = z73.object({
20496
+ var FreeVideoInput = z74.object({
20319
20497
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
20320
- rawPrompt: z73.string().trim().min(1).max(2e3).describe("Prompt o guion exacto del video. Si activas subt\xEDtulos, este mismo texto se usa como guion de subt\xEDtulos."),
20498
+ 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."),
20321
20499
  language: CreativeRefs.language,
20322
20500
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
20323
20501
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
20324
20502
  // parsed ONLY so the handler can reject it with a message naming its
20325
20503
  // replacement — dropping it silently would turn a caller's explicit
20326
20504
  // Pro++ pick into a quiet fallback to Wan.
20327
- freeProModel: z73.enum([
20505
+ freeProModel: z74.enum([
20328
20506
  "wan",
20329
20507
  "seedance"
20330
20508
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
20331
20509
  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.'),
20332
- durationSeconds: z73.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
20510
+ 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."),
20333
20511
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
20334
- generateAiMusic: z73.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
20335
- addSubtitles: z73.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
20336
- idempotencyKey: z73.string().uuid().optional().describe("Opcional. UUID para reintentar exactamente esta misma solicitud sin crear ni cobrar otro video. Reutiliza el mismo valor si el cliente no recibi\xF3 la respuesta.")
20512
+ generateAiMusic: z74.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
20513
+ addSubtitles: z74.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
20514
+ 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.")
20337
20515
  }).strict();
20338
20516
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
20339
- var ImageCreativeSetup = z73.discriminatedUnion("mode", [
20340
- z73.object({
20341
- mode: z73.literal("automatic")
20517
+ var ImageCreativeSetup = z74.discriminatedUnion("mode", [
20518
+ z74.object({
20519
+ mode: z74.literal("automatic")
20342
20520
  }).strict(),
20343
- z73.object({
20344
- mode: z73.literal("guided"),
20345
- creativeArchetype: z73.union([
20521
+ z74.object({
20522
+ mode: z74.literal("guided"),
20523
+ creativeArchetype: z74.union([
20346
20524
  ImageCreativeArchetypeEnum,
20347
- z73.literal("ai_decides")
20525
+ z74.literal("ai_decides")
20348
20526
  ]),
20349
- visualTreatment: z73.union([
20527
+ visualTreatment: z74.union([
20350
20528
  ImageCreativeVisualTreatmentEnum,
20351
- z73.literal("ai_decides")
20529
+ z74.literal("ai_decides")
20352
20530
  ]),
20353
20531
  aspectRatio: ImageCreativeAspectRatioEnum,
20354
- nVariants: z73.union([
20355
- z73.literal(1),
20356
- z73.literal(2),
20357
- z73.literal(3),
20358
- z73.literal(4),
20359
- z73.literal(6)
20532
+ nVariants: z74.union([
20533
+ z74.literal(1),
20534
+ z74.literal(2),
20535
+ z74.literal(3),
20536
+ z74.literal(4),
20537
+ z74.literal(6)
20360
20538
  ]),
20361
- imageModel: z73.enum([
20539
+ imageModel: z74.enum([
20362
20540
  "gpt-image-2-5:1k",
20363
20541
  "gpt-image-2-5:2k",
20364
20542
  "gpt-image-2:1k",
20365
20543
  "gpt-image-2:2k"
20366
20544
  ]),
20367
- styleMix: z73.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
20368
- generateAdCopy: z73.boolean(),
20369
- competitorScanEnabled: z73.boolean(),
20370
- productContext: z73.string().trim().min(1).max(3e3).nullable(),
20371
- creativeDirection: z73.string().trim().min(1).max(500).nullable(),
20372
- brandColors: z73.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
20373
- headline: z73.string().trim().min(1).max(120).nullable(),
20374
- subheadline: z73.string().trim().min(1).max(160).nullable()
20545
+ 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."),
20546
+ generateAdCopy: z74.boolean(),
20547
+ competitorScanEnabled: z74.boolean(),
20548
+ productContext: z74.string().trim().min(1).max(3e3).nullable(),
20549
+ creativeDirection: z74.string().trim().min(1).max(500).nullable(),
20550
+ 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.'),
20551
+ headline: z74.string().trim().min(1).max(120).nullable(),
20552
+ subheadline: z74.string().trim().min(1).max(160).nullable()
20375
20553
  }).strict()
20376
20554
  ]).superRefine((setup, context) => {
20377
20555
  if (setup.mode !== "guided") return;
20378
20556
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
20379
20557
  if (needsStyleMix && setup.styleMix === null) {
20380
20558
  context.addIssue({
20381
- code: z73.ZodIssueCode.custom,
20559
+ code: z74.ZodIssueCode.custom,
20382
20560
  path: [
20383
20561
  "styleMix"
20384
20562
  ],
@@ -20387,7 +20565,7 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
20387
20565
  }
20388
20566
  if (!needsStyleMix && setup.styleMix !== null) {
20389
20567
  context.addIssue({
20390
- code: z73.ZodIssueCode.custom,
20568
+ code: z74.ZodIssueCode.custom,
20391
20569
  path: [
20392
20570
  "styleMix"
20393
20571
  ],
@@ -20396,7 +20574,7 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
20396
20574
  }
20397
20575
  if ((setup.imageModel === "gpt-image-2:2k" || setup.imageModel === "gpt-image-2-5:2k") && setup.aspectRatio === "4:5") {
20398
20576
  context.addIssue({
20399
- code: z73.ZodIssueCode.custom,
20577
+ code: z74.ZodIssueCode.custom,
20400
20578
  path: [
20401
20579
  "aspectRatio"
20402
20580
  ],
@@ -20404,53 +20582,53 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
20404
20582
  });
20405
20583
  }
20406
20584
  });
20407
- var LandingCreativeSetup = z73.discriminatedUnion("mode", [
20408
- z73.object({
20409
- mode: z73.literal("automatic")
20585
+ var LandingCreativeSetup = z74.discriminatedUnion("mode", [
20586
+ z74.object({
20587
+ mode: z74.literal("automatic")
20410
20588
  }).strict(),
20411
- z73.object({
20412
- mode: z73.literal("guided"),
20589
+ z74.object({
20590
+ mode: z74.literal("guided"),
20413
20591
  landingStrategy: LandingStrategyEnum,
20414
20592
  landingImageFormat: LandingImageFormatEnum,
20415
- competitorScanEnabled: z73.boolean(),
20416
- paymentMethods: z73.string().trim().min(1).max(240).nullable(),
20417
- productContext: z73.string().trim().min(1).max(3e3).nullable(),
20418
- creativeDirection: z73.string().trim().min(1).max(500).nullable(),
20419
- headline: z73.string().trim().min(1).max(120).nullable(),
20420
- subheadline: z73.string().trim().min(1).max(160).nullable()
20593
+ competitorScanEnabled: z74.boolean(),
20594
+ paymentMethods: z74.string().trim().min(1).max(240).nullable(),
20595
+ productContext: z74.string().trim().min(1).max(3e3).nullable(),
20596
+ creativeDirection: z74.string().trim().min(1).max(500).nullable(),
20597
+ headline: z74.string().trim().min(1).max(120).nullable(),
20598
+ subheadline: z74.string().trim().min(1).max(160).nullable()
20421
20599
  }).strict()
20422
20600
  ]);
20423
- var ImageInput = z73.object({
20601
+ var ImageInput = z74.object({
20424
20602
  images: CreativeRefs.images.optional(),
20425
20603
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20426
- productTitle: z73.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
20427
- primaryAngle: z73.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
20604
+ productTitle: z74.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
20605
+ 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.'),
20428
20606
  buyerPersona: CreativeRefs.buyerPersona,
20429
20607
  language: CreativeRefs.language,
20430
20608
  country: CreativeRefs.country,
20431
20609
  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."),
20432
20610
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
20433
- features: z73.array(z73.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
20611
+ features: z74.array(z74.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
20434
20612
  price: CreativeRefs.price,
20435
- omitPrice: z73.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
20613
+ 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."),
20436
20614
  compareAtPrice: CreativeRefs.compareAtPrice,
20437
20615
  offer: CreativeRefs.offer,
20438
20616
  productLabel: CreativeRefs.productLabel,
20439
20617
  isCombo: CreativeRefs.isCombo,
20440
20618
  brandId: CreativeRefs.brandId
20441
20619
  });
20442
- var EditImageCreativeInput = z73.object({
20443
- taskId: z73.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
20444
- variantIndex: z73.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
20445
- instruction: z73.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
20620
+ var EditImageCreativeInput = z74.object({
20621
+ taskId: z74.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
20622
+ variantIndex: z74.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
20623
+ 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".')
20446
20624
  });
20447
- var LandingInput = z73.object({
20625
+ var LandingInput = z74.object({
20448
20626
  images: CreativeRefs.images.optional(),
20449
20627
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
20450
20628
  language: CreativeRefs.language,
20451
20629
  country: CreativeRefs.country,
20452
20630
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
20453
- salesAngle: z73.string().optional().describe('Opcional. \xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas". Si se omite, la IA lo deduce de la imagen.'),
20631
+ 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.'),
20454
20632
  buyerPersona: CreativeRefs.buyerPersona,
20455
20633
  price: CreativeRefs.price,
20456
20634
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -20712,10 +20890,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
20712
20890
  __name(registerCreativeTools, "registerCreativeTools");
20713
20891
 
20714
20892
  // src/tools/creative-variants.ts
20715
- import { z as z74 } from "zod";
20893
+ import { z as z75 } from "zod";
20716
20894
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
20717
20895
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
20718
- var LandingSectionKeyEnum = z74.enum([
20896
+ var LandingSectionKeyEnum = z75.enum([
20719
20897
  "problem_hook",
20720
20898
  "problem_cost",
20721
20899
  "solution_mechanism",
@@ -20755,24 +20933,24 @@ var LandingSectionKeyEnum = z74.enum([
20755
20933
  "lifestyle_fit",
20756
20934
  "join_lifestyle"
20757
20935
  ]);
20758
- var CreativeVariantKindEnum = z74.enum([
20936
+ var CreativeVariantKindEnum = z75.enum([
20759
20937
  "video",
20760
20938
  "image",
20761
20939
  "landing"
20762
20940
  ]);
20763
- var EstimateCreativeVariantInputBase = z74.object({
20764
- sourceTaskId: z74.string().uuid().describe("ID de la tarea original completada."),
20941
+ var EstimateCreativeVariantInputBase = z75.object({
20942
+ sourceTaskId: z75.string().uuid().describe("ID de la tarea original completada."),
20765
20943
  kind: CreativeVariantKindEnum,
20766
20944
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
20767
20945
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
20768
- nVariants: z74.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
20946
+ nVariants: z75.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
20769
20947
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
20770
- instructions: z74.string().trim().min(1).max(2e3).optional().describe("Opcional para landing. Si se env\xEDa sin sectionKey, el estimado suma la clasificaci\xF3n pagada con IA.")
20948
+ 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.")
20771
20949
  }).strict();
20772
20950
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
20773
20951
  if (input.kind === "video" && input.nVariants !== void 0) {
20774
20952
  ctx.addIssue({
20775
- code: z74.ZodIssueCode.custom,
20953
+ code: z75.ZodIssueCode.custom,
20776
20954
  path: [
20777
20955
  "nVariants"
20778
20956
  ],
@@ -20782,7 +20960,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20782
20960
  if (input.kind !== "video") {
20783
20961
  if (input.videoPreset !== void 0) {
20784
20962
  ctx.addIssue({
20785
- code: z74.ZodIssueCode.custom,
20963
+ code: z75.ZodIssueCode.custom,
20786
20964
  path: [
20787
20965
  "videoPreset"
20788
20966
  ],
@@ -20791,7 +20969,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20791
20969
  }
20792
20970
  if (input.videoResolution !== void 0) {
20793
20971
  ctx.addIssue({
20794
- code: z74.ZodIssueCode.custom,
20972
+ code: z75.ZodIssueCode.custom,
20795
20973
  path: [
20796
20974
  "videoResolution"
20797
20975
  ],
@@ -20801,7 +20979,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20801
20979
  }
20802
20980
  if (input.kind !== "image" && input.nVariants !== void 0) {
20803
20981
  ctx.addIssue({
20804
- code: z74.ZodIssueCode.custom,
20982
+ code: z75.ZodIssueCode.custom,
20805
20983
  path: [
20806
20984
  "nVariants"
20807
20985
  ],
@@ -20811,7 +20989,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20811
20989
  if (input.kind !== "landing") {
20812
20990
  if (input.sectionKey !== void 0) {
20813
20991
  ctx.addIssue({
20814
- code: z74.ZodIssueCode.custom,
20992
+ code: z75.ZodIssueCode.custom,
20815
20993
  path: [
20816
20994
  "sectionKey"
20817
20995
  ],
@@ -20820,7 +20998,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20820
20998
  }
20821
20999
  if (input.instructions !== void 0) {
20822
21000
  ctx.addIssue({
20823
- code: z74.ZodIssueCode.custom,
21001
+ code: z75.ZodIssueCode.custom,
20824
21002
  path: [
20825
21003
  "instructions"
20826
21004
  ],
@@ -20829,31 +21007,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
20829
21007
  }
20830
21008
  }
20831
21009
  });
20832
- var CreateCreativeVariantInputBase = z74.object({
20833
- sourceTaskId: z74.string().uuid().describe("ID de la tarea original completada."),
21010
+ var CreateCreativeVariantInputBase = z75.object({
21011
+ sourceTaskId: z75.string().uuid().describe("ID de la tarea original completada."),
20834
21012
  kind: CreativeVariantKindEnum,
20835
- confirm: z74.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
20836
- clientRequestId: z74.string().uuid().describe("UUID estable y obligatorio para esta intenci\xF3n. Reutil\xEDzalo ante timeouts o transporte ambiguo. Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n y un UUID nuevo."),
20837
- angle: z74.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
20838
- buyerPersona: z74.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
20839
- scriptNotes: z74.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
20840
- creativeDirection: z74.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
21013
+ confirm: z75.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
21014
+ 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."),
21015
+ angle: z75.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
21016
+ buyerPersona: z75.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
21017
+ scriptNotes: z75.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
21018
+ creativeDirection: z75.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
20841
21019
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
20842
21020
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
20843
- generateAiMusic: z74.boolean().optional().describe("Opcional para video."),
20844
- nVariants: z74.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
21021
+ generateAiMusic: z75.boolean().optional().describe("Opcional para video."),
21022
+ nVariants: z75.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
20845
21023
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
20846
21024
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
20847
21025
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
20848
21026
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
20849
- styleMix: z74.boolean().optional().describe("Opcional para imagen."),
21027
+ styleMix: z75.boolean().optional().describe("Opcional para imagen."),
20850
21028
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
20851
- instructions: z74.string().trim().min(1).max(2e3).optional().describe("Solicitud libre para una nueva secci\xF3n de landing. La IA la clasifica si no env\xEDas sectionKey.")
21029
+ 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.")
20852
21030
  }).strict();
20853
21031
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
20854
21032
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
20855
21033
  ctx.addIssue({
20856
- code: z74.ZodIssueCode.custom,
21034
+ code: z75.ZodIssueCode.custom,
20857
21035
  path: [
20858
21036
  "angle"
20859
21037
  ],
@@ -20862,7 +21040,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
20862
21040
  }
20863
21041
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
20864
21042
  ctx.addIssue({
20865
- code: z74.ZodIssueCode.custom,
21043
+ code: z75.ZodIssueCode.custom,
20866
21044
  path: [
20867
21045
  "instructions"
20868
21046
  ],
@@ -20908,7 +21086,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
20908
21086
  for (const field of fieldsByKind[input.kind]) {
20909
21087
  if (input[field] !== void 0) {
20910
21088
  ctx.addIssue({
20911
- code: z74.ZodIssueCode.custom,
21089
+ code: z75.ZodIssueCode.custom,
20912
21090
  path: [
20913
21091
  field
20914
21092
  ],
@@ -21025,32 +21203,32 @@ function registerCreativeVariantTools(server, api) {
21025
21203
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
21026
21204
 
21027
21205
  // src/tools/script-review.ts
21028
- import { z as z75 } from "zod";
21206
+ import { z as z76 } from "zod";
21029
21207
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
21030
21208
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
21031
21209
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
21032
- var GetVideoScriptInput = z75.object({
21033
- taskId: z75.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
21034
- angleKey: z75.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
21210
+ var GetVideoScriptInput = z76.object({
21211
+ taskId: z76.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
21212
+ 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.')
21035
21213
  }).strict();
21036
21214
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
21037
21215
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
21038
- var ApproveSceneEdit = z75.object({
21039
- index: z75.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
21040
- dialogue: z75.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
21216
+ var ApproveSceneEdit = z76.object({
21217
+ index: z76.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
21218
+ dialogue: z76.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
21041
21219
  message: "dialogue no puede ser s\xF3lo espacios"
21042
21220
  }).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.")
21043
21221
  }).strict();
21044
- var ApproveVideoScriptInput = z75.object({
21045
- taskId: z75.string().min(1).describe("ID de la tarea."),
21046
- angleKey: z75.string().trim().min(1).max(120).optional().describe('Mismo angleKey usado en get_video_script. REQUERIDO en multi-angle (si se omite el backend resuelve a "angle_0" literal). En single-angle puede omitirse.'),
21047
- scenes: z75.array(ApproveSceneEdit).min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_SCENES2).describe("Escenas con los di\xE1logos finales. El backend mergea por `index` \u2014 las escenas NO incluidas conservan el di\xE1logo original. Debe haber entre 1 y 50 entradas. Para cada entrada que mandes con un dialogue distinto del original, el backend valida minWords \u2264 words \u2264 maxWords y rechaza con 400 si te sales del rango.")
21222
+ var ApproveVideoScriptInput = z76.object({
21223
+ taskId: z76.string().min(1).describe("ID de la tarea."),
21224
+ 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.'),
21225
+ 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.")
21048
21226
  }).strict();
21049
- var RegenerateVideoScriptInput = z75.object({
21050
- taskId: z75.string().min(1).describe("ID de la tarea."),
21051
- angleKey: z75.string().min(1).describe('Clave del \xE1ngulo a regenerar. Single-angle: pasa "angle_0". Multi-angle: el mismo que devuelve get_video_script. NO se puede omitir \u2014 el backend lo exige siempre.'),
21227
+ var RegenerateVideoScriptInput = z76.object({
21228
+ taskId: z76.string().min(1).describe("ID de la tarea."),
21229
+ 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.'),
21052
21230
  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).'),
21053
- narrativeSelection: z75.enum([
21231
+ narrativeSelection: z76.enum([
21054
21232
  "market",
21055
21233
  "guided"
21056
21234
  ]).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.")
@@ -21131,14 +21309,14 @@ function registerScriptReviewTools(server, api) {
21131
21309
  __name(registerScriptReviewTools, "registerScriptReviewTools");
21132
21310
 
21133
21311
  // src/tools/connections.ts
21134
- import { z as z76 } from "zod";
21312
+ import { z as z77 } from "zod";
21135
21313
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
21136
21314
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
21137
21315
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
21138
21316
  var listMetaDestinationsGuidance = getProductMakerCapabilityModelGuidance("list_meta_destinations");
21139
21317
  var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list_tiktok_advertisers");
21140
21318
  function registerConnectionTools(server, api) {
21141
- server.tool("list_shopify_shops", listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z76.object({}).shape, READS_INTERNAL, async () => {
21319
+ 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 () => {
21142
21320
  try {
21143
21321
  const r = await api.getJson("/v1/shopify/shops");
21144
21322
  return asText(r);
@@ -21146,10 +21324,10 @@ function registerConnectionTools(server, api) {
21146
21324
  throw translateError(e);
21147
21325
  }
21148
21326
  });
21149
- server.tool("list_shopify_products", listShopifyProductsGuidance.summary + ' Usa el `id` devuelto junto con `publicationMode="existing"` en `publish_to_shopify`. Si `taskId` se proporciona, la respuesta tambi\xE9n indica el producto publicado actualmente para esa tarea y tienda. No modifica Shopify.', z76.object({
21150
- shopDomain: z76.string().min(3).max(120),
21151
- query: z76.string().trim().max(120).optional(),
21152
- taskId: z76.string().uuid().optional()
21327
+ 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({
21328
+ shopDomain: z77.string().min(3).max(120),
21329
+ query: z77.string().trim().max(120).optional(),
21330
+ taskId: z77.string().uuid().optional()
21153
21331
  }).shape, READS_EXTERNAL, async ({ shopDomain, query, taskId }) => {
21154
21332
  try {
21155
21333
  const params = new URLSearchParams({
@@ -21163,7 +21341,7 @@ function registerConnectionTools(server, api) {
21163
21341
  throw translateError(e);
21164
21342
  }
21165
21343
  });
21166
- server.tool("list_meta_ad_accounts", listMetaAdAccountsGuidance.summary + " Para publicar, prefiere `list_meta_destinations`, que tambi\xE9n devuelve el portfolio y las p\xE1ginas disponibles. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.", z76.object({}).shape, READS_EXTERNAL, async () => {
21344
+ 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 () => {
21167
21345
  try {
21168
21346
  const r = await api.getJson("/v1/facebook/ad-accounts");
21169
21347
  return asText(r);
@@ -21173,7 +21351,7 @@ function registerConnectionTools(server, api) {
21173
21351
  });
21174
21352
  server.registerTool("list_meta_destinations", {
21175
21353
  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.",
21176
- inputSchema: z76.object({}).shape,
21354
+ inputSchema: z77.object({}).shape,
21177
21355
  annotations: READS_EXTERNAL,
21178
21356
  _meta: {
21179
21357
  "openai/widgetAccessible": true
@@ -21186,7 +21364,7 @@ function registerConnectionTools(server, api) {
21186
21364
  throw translateError(e);
21187
21365
  }
21188
21366
  });
21189
- server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z76.object({}).shape, READS_EXTERNAL, async () => {
21367
+ 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 () => {
21190
21368
  try {
21191
21369
  const r = await api.getJson("/v1/tiktok/advertisers");
21192
21370
  return asText(r);
@@ -21198,10 +21376,10 @@ function registerConnectionTools(server, api) {
21198
21376
  __name(registerConnectionTools, "registerConnectionTools");
21199
21377
 
21200
21378
  // src/tools/actors.ts
21201
- import { z as z77 } from "zod";
21379
+ import { z as z78 } from "zod";
21202
21380
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
21203
21381
  function registerActorTools(server, api) {
21204
- server.tool("list_actors", listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.", z77.object({}).shape, READS_INTERNAL, async () => {
21382
+ 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 () => {
21205
21383
  try {
21206
21384
  const rows = await api.getJson("/v1/actors");
21207
21385
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -21222,7 +21400,7 @@ function registerActorTools(server, api) {
21222
21400
  __name(registerActorTools, "registerActorTools");
21223
21401
 
21224
21402
  // src/tools/publish.ts
21225
- import { z as z78 } from "zod";
21403
+ import { z as z79 } from "zod";
21226
21404
 
21227
21405
  // src/tools/stable-uuid.ts
21228
21406
  import { createHash as createHash3 } from "crypto";
@@ -21294,40 +21472,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
21294
21472
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
21295
21473
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
21296
21474
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
21297
- var ShopifyInput = z78.object({
21298
- taskId: z78.string().min(1),
21299
- shopDomain: z78.string().min(1),
21475
+ var ShopifyInput = z79.object({
21476
+ taskId: z79.string().min(1),
21477
+ shopDomain: z79.string().min(1),
21300
21478
  /** Override: number of landing images to include. Default = ALL images the
21301
21479
  * task generated (the MCP fetches /v1/results first to count). Bounded
21302
21480
  * generously here; the backend validates each index against
21303
21481
  * landing.images.length and rejects out-of-range. */
21304
- numLandingImages: z78.number().int().min(1).max(20).optional(),
21305
- variantIndex: z78.number().int().min(0).optional(),
21482
+ numLandingImages: z79.number().int().min(1).max(20).optional(),
21483
+ variantIndex: z79.number().int().min(0).optional(),
21306
21484
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
21307
21485
  * When true, the landing renders variant-picker pills; when false, it ships
21308
21486
  * a single-option product page. Defaults to false. */
21309
- showVariantPicker: z78.boolean().optional(),
21487
+ showVariantPicker: z79.boolean().optional(),
21310
21488
  /** Default `auto` updates the product previously published for this task and
21311
21489
  * shop. Use `existing` with targetProductId to choose another product, or
21312
21490
  * `new` only when the user explicitly wants a duplicate/new listing. */
21313
- publicationMode: z78.enum([
21491
+ publicationMode: z79.enum([
21314
21492
  "auto",
21315
21493
  "existing",
21316
21494
  "new"
21317
21495
  ]).optional(),
21318
21496
  /** Shopify product GID, numeric id, or admin product URL. Required when
21319
21497
  * publicationMode is `existing`. */
21320
- targetProductId: z78.string().trim().min(1).max(300).optional(),
21498
+ targetProductId: z79.string().trim().min(1).max(300).optional(),
21321
21499
  /** Add an announcement bar text above add-to-cart (optional). */
21322
- announcementBarEnabled: z78.boolean().optional(),
21323
- announcementBarText: z78.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
21500
+ announcementBarEnabled: z79.boolean().optional(),
21501
+ announcementBarText: z79.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
21324
21502
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
21325
- confirmed: z78.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
21503
+ confirmed: z79.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
21326
21504
  });
21327
21505
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
21328
21506
  if (value.commerceCorrection && value.confirmed !== true) {
21329
21507
  ctx.addIssue({
21330
- code: z78.ZodIssueCode.custom,
21508
+ code: z79.ZodIssueCode.custom,
21331
21509
  path: [
21332
21510
  "confirmed"
21333
21511
  ],
@@ -21336,7 +21514,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
21336
21514
  }
21337
21515
  if (value.announcementBarEnabled && !value.announcementBarText) {
21338
21516
  ctx.addIssue({
21339
- code: z78.ZodIssueCode.custom,
21517
+ code: z79.ZodIssueCode.custom,
21340
21518
  path: [
21341
21519
  "announcementBarText"
21342
21520
  ],
@@ -21345,7 +21523,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
21345
21523
  }
21346
21524
  if (!value.announcementBarEnabled && value.announcementBarText) {
21347
21525
  ctx.addIssue({
21348
- code: z78.ZodIssueCode.custom,
21526
+ code: z79.ZodIssueCode.custom,
21349
21527
  path: [
21350
21528
  "announcementBarText"
21351
21529
  ],
@@ -21359,91 +21537,91 @@ function parseShopifyInput(rawInput) {
21359
21537
  return parsed.data;
21360
21538
  }
21361
21539
  __name(parseShopifyInput, "parseShopifyInput");
21362
- var McpCampaignConfig = z78.object({
21540
+ var McpCampaignConfig = z79.object({
21363
21541
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
21364
21542
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
21365
21543
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
21366
- dailyBudgetUsd: z78.number().positive().optional(),
21544
+ dailyBudgetUsd: z79.number().positive().optional(),
21367
21545
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
21368
21546
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
21369
21547
  * TikTok takes only the first entry. */
21370
- targetCountries: z78.array(CountryIso2Schema).max(1).optional(),
21371
- campaignName: z78.string().trim().min(1).max(100).optional()
21548
+ targetCountries: z79.array(CountryIso2Schema).max(1).optional(),
21549
+ campaignName: z79.string().trim().min(1).max(100).optional()
21372
21550
  });
21373
21551
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
21374
- var MetaInput = z78.object({
21375
- taskId: z78.string().min(1),
21552
+ var MetaInput = z79.object({
21553
+ taskId: z79.string().min(1),
21376
21554
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
21377
- portfolioId: z78.string().trim().min(1),
21555
+ portfolioId: z79.string().trim().min(1),
21378
21556
  /** Exact Facebook Page selected from `list_meta_destinations`. */
21379
- pageId: z78.string().trim().min(1),
21557
+ pageId: z79.string().trim().min(1),
21380
21558
  adAccountId: McpAdAccountId,
21381
- pixelId: z78.string().min(1).optional(),
21382
- landingUrl: z78.string().url().optional(),
21559
+ pixelId: z79.string().min(1).optional(),
21560
+ landingUrl: z79.string().url().optional(),
21383
21561
  /** Select which angles to publish by 0-based index. Omit to publish all
21384
21562
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
21385
- angleIndexes: z78.array(z78.number().int().nonnegative()).optional(),
21563
+ angleIndexes: z79.array(z79.number().int().nonnegative()).optional(),
21386
21564
  campaignConfig: McpCampaignConfig.optional(),
21387
21565
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
21388
21566
  * uses the auto-generated copy attached to the task. Capped at 500 chars
21389
21567
  * (Meta's primary-text limit). */
21390
- primaryText: z78.string().trim().min(1).max(500).optional(),
21568
+ primaryText: z79.string().trim().min(1).max(500).optional(),
21391
21569
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
21392
21570
  * (wa.me) instead of a landing page. */
21393
- phoneNumber: z78.string().min(8).max(32).optional()
21571
+ phoneNumber: z79.string().min(8).max(32).optional()
21394
21572
  });
21395
- var GroupedTaskSource = z78.object({
21396
- type: z78.literal("task"),
21397
- taskId: z78.string().min(1),
21398
- angleIndex: z78.number().int().min(0).optional(),
21399
- videoVariant: z78.enum([
21573
+ var GroupedTaskSource = z79.object({
21574
+ type: z79.literal("task"),
21575
+ taskId: z79.string().min(1),
21576
+ angleIndex: z79.number().int().min(0).optional(),
21577
+ videoVariant: z79.enum([
21400
21578
  "with_subtitles",
21401
21579
  "without_subtitles"
21402
21580
  ]).optional(),
21403
- imageVariantIndex: z78.number().int().min(0).optional()
21404
- });
21405
- var GroupedMediaSource = z78.object({
21406
- type: z78.literal("media"),
21407
- url: z78.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
21408
- path: z78.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
21409
- thumbnailUrl: z78.string().url().optional(),
21410
- thumbnailPath: z78.string().min(1).optional()
21581
+ imageVariantIndex: z79.number().int().min(0).optional()
21582
+ });
21583
+ var GroupedMediaSource = z79.object({
21584
+ type: z79.literal("media"),
21585
+ 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."),
21586
+ 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".'),
21587
+ thumbnailUrl: z79.string().url().optional(),
21588
+ thumbnailPath: z79.string().min(1).optional()
21411
21589
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
21412
21590
  message: "media source needs exactly one of `url` or `path`"
21413
21591
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
21414
21592
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
21415
21593
  });
21416
- var GroupedUploadedAssetSource = z78.object({
21417
- type: z78.literal("asset"),
21594
+ var GroupedUploadedAssetSource = z79.object({
21595
+ type: z79.literal("asset"),
21418
21596
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
21419
- assetId: z78.string().uuid(),
21420
- thumbnailAssetId: z78.string().uuid().optional()
21597
+ assetId: z79.string().uuid(),
21598
+ thumbnailAssetId: z79.string().uuid().optional()
21421
21599
  });
21422
- var GroupedCreative = z78.object({
21423
- type: z78.enum([
21600
+ var GroupedCreative = z79.object({
21601
+ type: z79.enum([
21424
21602
  "image",
21425
21603
  "video"
21426
21604
  ]),
21427
- source: z78.union([
21605
+ source: z79.union([
21428
21606
  GroupedTaskSource,
21429
21607
  GroupedMediaSource,
21430
21608
  GroupedUploadedAssetSource
21431
21609
  ]),
21432
- title: z78.string().max(120).optional(),
21433
- description: z78.string().max(500).optional(),
21610
+ title: z79.string().max(120).optional(),
21611
+ description: z79.string().max(500).optional(),
21434
21612
  cta: MetaCtaType.optional(),
21435
- creativeId: z78.string().min(1).optional()
21613
+ creativeId: z79.string().min(1).optional()
21436
21614
  });
21437
- var GroupedCampaignConfigBase = z78.object({
21615
+ var GroupedCampaignConfigBase = z79.object({
21438
21616
  campaignType: MetaCampaignType.default("sales"),
21439
21617
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
21440
21618
  budgetMode: MetaBudgetMode.optional(),
21441
- campaignDailyBudget: z78.number().int().positive().optional(),
21442
- adSets: z78.array(z78.object({
21443
- tempId: z78.string().min(1).max(80),
21444
- name: z78.string().min(1).max(100),
21445
- dailyBudget: z78.number().int().positive().optional(),
21446
- creativeIds: z78.array(z78.string().min(1)).min(1)
21619
+ campaignDailyBudget: z79.number().int().positive().optional(),
21620
+ adSets: z79.array(z79.object({
21621
+ tempId: z79.string().min(1).max(80),
21622
+ name: z79.string().min(1).max(100),
21623
+ dailyBudget: z79.number().int().positive().optional(),
21624
+ creativeIds: z79.array(z79.string().min(1)).min(1)
21447
21625
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
21448
21626
  /**
21449
21627
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -21451,17 +21629,17 @@ var GroupedCampaignConfigBase = z78.object({
21451
21629
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
21452
21630
  * the API since #849 — unreachable from this tool.
21453
21631
  */
21454
- destination: z78.discriminatedUnion("type", [
21455
- z78.object({
21456
- type: z78.literal("landing"),
21457
- landingUrl: z78.string().url()
21632
+ destination: z79.discriminatedUnion("type", [
21633
+ z79.object({
21634
+ type: z79.literal("landing"),
21635
+ landingUrl: z79.string().url()
21458
21636
  }),
21459
- z78.object({
21460
- type: z78.literal("whatsapp"),
21461
- phoneNumber: z78.string().min(8).max(32)
21637
+ z79.object({
21638
+ type: z79.literal("whatsapp"),
21639
+ phoneNumber: z79.string().min(8).max(32)
21462
21640
  })
21463
21641
  ]),
21464
- saveAsDefault: z78.boolean().default(false),
21642
+ saveAsDefault: z79.boolean().default(false),
21465
21643
  budgetPolicy: MetaBudgetPolicy.optional()
21466
21644
  });
21467
21645
  function resolveBudgetMode(value) {
@@ -21475,7 +21653,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21475
21653
  const budgetMode = resolveBudgetMode(value);
21476
21654
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
21477
21655
  ctx.addIssue({
21478
- code: z78.ZodIssueCode.custom,
21656
+ code: z79.ZodIssueCode.custom,
21479
21657
  path: [
21480
21658
  "campaignDailyBudget"
21481
21659
  ],
@@ -21486,7 +21664,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21486
21664
  value.adSets.forEach((adSet, index) => {
21487
21665
  if (adSet.dailyBudget === void 0) {
21488
21666
  ctx.addIssue({
21489
- code: z78.ZodIssueCode.custom,
21667
+ code: z79.ZodIssueCode.custom,
21490
21668
  path: [
21491
21669
  "adSets",
21492
21670
  index,
@@ -21501,28 +21679,28 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
21501
21679
  ...value,
21502
21680
  budgetMode: resolveBudgetMode(value)
21503
21681
  }));
21504
- var PublishCreativesToMetaInputBase = z78.object({
21505
- creatives: z78.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
21682
+ var PublishCreativesToMetaInputBase = z79.object({
21683
+ creatives: z79.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
21506
21684
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
21507
- portfolioId: z78.string().trim().min(1),
21685
+ portfolioId: z79.string().trim().min(1),
21508
21686
  /** Exact Facebook Page selected from `list_meta_destinations`. */
21509
- pageId: z78.string().trim().min(1),
21687
+ pageId: z79.string().trim().min(1),
21510
21688
  adAccountId: McpAdAccountId,
21511
- pixelId: z78.string().min(1).optional(),
21689
+ pixelId: z79.string().min(1).optional(),
21512
21690
  /** Required unless `campaignConfig.destination` is whatsapp — see the
21513
21691
  * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
21514
- landingUrl: z78.string().url().optional(),
21692
+ landingUrl: z79.string().url().optional(),
21515
21693
  /** ISO-2 code or resolvable country name — mirrors the API contract
21516
21694
  * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
21517
21695
  targetCountry: CountryIso2Schema,
21518
- campaignName: z78.string().trim().min(1).max(100),
21696
+ campaignName: z79.string().trim().min(1).max(100),
21519
21697
  campaignConfig: GroupedCampaignConfig.optional()
21520
21698
  });
21521
21699
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
21522
21700
  const destination = value.campaignConfig?.destination;
21523
21701
  if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
21524
21702
  ctx.addIssue({
21525
- code: z78.ZodIssueCode.custom,
21703
+ code: z79.ZodIssueCode.custom,
21526
21704
  path: [
21527
21705
  "landingUrl"
21528
21706
  ],
@@ -21531,7 +21709,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
21531
21709
  }
21532
21710
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
21533
21711
  ctx.addIssue({
21534
- code: z78.ZodIssueCode.custom,
21712
+ code: z79.ZodIssueCode.custom,
21535
21713
  path: [
21536
21714
  "campaignConfig",
21537
21715
  "destination",
@@ -21550,16 +21728,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
21550
21728
  }
21551
21729
  return value;
21552
21730
  });
21553
- var PresignUploadResponseSchema = z78.object({
21554
- uploadUrl: z78.string().url().refine((value) => {
21731
+ var PresignUploadResponseSchema = z79.object({
21732
+ uploadUrl: z79.string().url().refine((value) => {
21555
21733
  const url = new URL(value);
21556
21734
  return !url.username && !url.password && url.protocol === "https:";
21557
21735
  }, "presigned upload URL must be HTTPS without embedded credentials"),
21558
- publicUrl: z78.string().url().refine((value) => {
21736
+ publicUrl: z79.string().url().refine((value) => {
21559
21737
  const url = new URL(value);
21560
21738
  return !url.username && !url.password;
21561
21739
  }, "public media URL must not contain embedded credentials"),
21562
- stagingAssetId: z78.string().uuid()
21740
+ stagingAssetId: z79.string().uuid()
21563
21741
  });
21564
21742
  async function uploadResolvedMedia(api, media, assetRole) {
21565
21743
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -21584,20 +21762,20 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
21584
21762
  return uploadResolvedMedia(api, media, assetRole);
21585
21763
  }
21586
21764
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
21587
- var TikTokInput = z78.object({
21588
- taskId: z78.string().min(1),
21589
- advertiserId: z78.string().min(1),
21590
- pixelId: z78.string().min(1).optional(),
21591
- landingUrl: z78.string().url().optional(),
21592
- angleIndexes: z78.array(z78.number().int().nonnegative()).optional(),
21765
+ var TikTokInput = z79.object({
21766
+ taskId: z79.string().min(1),
21767
+ advertiserId: z79.string().min(1),
21768
+ pixelId: z79.string().min(1).optional(),
21769
+ landingUrl: z79.string().url().optional(),
21770
+ angleIndexes: z79.array(z79.number().int().nonnegative()).optional(),
21593
21771
  campaignConfig: McpCampaignConfig.optional(),
21594
21772
  /** Override the ad's description (TikTok's body copy). If omitted,
21595
21773
  * ProductMaker uses the auto-generated copy attached to the task. */
21596
- primaryText: z78.string().trim().min(1).max(500).optional()
21774
+ primaryText: z79.string().trim().min(1).max(500).optional()
21597
21775
  });
21598
21776
  function registerPublishTools(server, api, opts = {}) {
21599
21777
  const transport = opts.transport ?? "http";
21600
- server.tool("publish_to_shopify", publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Un contexto obsoleto requiere volver a revisar; open_editor requiere el editor de ProductMaker. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.", ShopifyInput.shape, OVERWRITES_EXTERNAL, async (input, extra) => {
21778
+ server.tool("publish_to_shopify", publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.", ShopifyInput.shape, OVERWRITES_EXTERNAL, async (input, extra) => {
21601
21779
  try {
21602
21780
  const parsed = parseShopifyInput(input);
21603
21781
  if (parsed.publicationMode === "existing" && !parsed.targetProductId) {
@@ -21614,7 +21792,7 @@ function registerPublishTools(server, api, opts = {}) {
21614
21792
  const variantIndex = parsed.variantIndex ?? 0;
21615
21793
  const availableImages = await fetchLandingImageCount(api, parsed.taskId);
21616
21794
  const effectiveAvailable = availableImages > 0 ? availableImages : 3;
21617
- const numImages = Math.min(parsed.numLandingImages ?? effectiveAvailable, effectiveAvailable);
21795
+ const numImages = Math.min(parsed.numLandingImages ?? effectiveAvailable, effectiveAvailable, SHOPIFY_MAX_LANDING_IMAGES);
21618
21796
  const selectedLandingImages = Array.from({
21619
21797
  length: numImages
21620
21798
  }, (_, i) => ({
@@ -21645,6 +21823,8 @@ function registerPublishTools(server, api, opts = {}) {
21645
21823
  "SHOPIFY_PUBLISH_INPUT_REQUIRED",
21646
21824
  "SHOPIFY_PUBLISH_CONTEXT_CHANGED",
21647
21825
  "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR",
21826
+ "SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED",
21827
+ "SHOPIFY_PUBLISH_VERIFICATION_FAILED",
21648
21828
  "SHOPIFY_PUBLISH_TARGET_INCOMPATIBLE",
21649
21829
  "SHOPIFY_THEME_SETUP_REQUIRED",
21650
21830
  "SHOPIFY_PUBLISH_FAILED"
@@ -21919,39 +22099,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
21919
22099
 
21920
22100
  // src/tools/meta-upload.ts
21921
22101
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
21922
- import { z as z79 } from "zod";
22102
+ import { z as z80 } from "zod";
21923
22103
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
21924
- var UploadSessionInputBase = z79.object({
21925
- mediaKind: z79.enum([
22104
+ var UploadSessionInputBase = z80.object({
22105
+ mediaKind: z80.enum([
21926
22106
  "image",
21927
22107
  "video",
21928
22108
  "mixed"
21929
22109
  ]).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."),
21930
- assetRole: z79.enum([
22110
+ assetRole: z80.enum([
21931
22111
  "media",
21932
22112
  "thumbnail"
21933
22113
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
21934
- uploadPurpose: z79.enum([
22114
+ uploadPurpose: z80.enum([
21935
22115
  "product_reference",
21936
22116
  "creative",
21937
22117
  "generic"
21938
22118
  ]).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."),
21939
- maxFiles: z79.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
22119
+ maxFiles: z80.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
21940
22120
  });
21941
- var OpenAiFileReference = z79.object({
21942
- download_url: z79.string().url().optional().describe("Optional host-provided download URL. The App prefers getFileDownloadUrl(file_id) and the server never fetches this URL."),
21943
- file_id: z79.string().min(1),
21944
- mime_type: z79.string().min(1).optional(),
21945
- file_name: z79.string().min(1).optional()
22121
+ var OpenAiFileReference = z80.object({
22122
+ download_url: z80.string().url().optional().describe("Optional host-provided download URL. The App prefers getFileDownloadUrl(file_id) and the server never fetches this URL."),
22123
+ file_id: z80.string().min(1),
22124
+ mime_type: z80.string().min(1).optional(),
22125
+ file_name: z80.string().min(1).optional()
21946
22126
  });
21947
22127
  var UploadSessionToolInputShape = {
21948
22128
  ...UploadSessionInputBase.shape,
21949
- files: z79.array(OpenAiFileReference).max(10).optional().describe("Optional OpenAI-hosted file references provided by ChatGPT. They are only metadata for the UI bridge and are never forwarded to ProductMaker.")
22129
+ 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.")
21950
22130
  };
21951
- var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
22131
+ var UploadSessionToolInput = z80.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
21952
22132
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
21953
22133
  ctx.addIssue({
21954
- code: z79.ZodIssueCode.custom,
22134
+ code: z80.ZodIssueCode.custom,
21955
22135
  path: [
21956
22136
  "mediaKind"
21957
22137
  ],
@@ -21960,7 +22140,7 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
21960
22140
  }
21961
22141
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
21962
22142
  ctx.addIssue({
21963
- code: z79.ZodIssueCode.custom,
22143
+ code: z80.ZodIssueCode.custom,
21964
22144
  path: [
21965
22145
  "maxFiles"
21966
22146
  ],
@@ -21969,7 +22149,7 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
21969
22149
  }
21970
22150
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
21971
22151
  ctx.addIssue({
21972
- code: z79.ZodIssueCode.custom,
22152
+ code: z80.ZodIssueCode.custom,
21973
22153
  path: [
21974
22154
  "maxFiles"
21975
22155
  ],
@@ -21977,38 +22157,38 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
21977
22157
  });
21978
22158
  }
21979
22159
  });
21980
- var UploadSessionResponse = z79.object({
21981
- sessionId: z79.string().uuid(),
21982
- uploadPageUrl: z79.string().url(),
21983
- mediaKind: z79.enum([
22160
+ var UploadSessionResponse = z80.object({
22161
+ sessionId: z80.string().uuid(),
22162
+ uploadPageUrl: z80.string().url(),
22163
+ mediaKind: z80.enum([
21984
22164
  "image",
21985
22165
  "video",
21986
22166
  "mixed"
21987
22167
  ]),
21988
- assetRole: z79.enum([
22168
+ assetRole: z80.enum([
21989
22169
  "media",
21990
22170
  "thumbnail"
21991
22171
  ]),
21992
- maxFiles: z79.number().int().positive(),
21993
- expiresAt: z79.string().datetime()
22172
+ maxFiles: z80.number().int().positive(),
22173
+ expiresAt: z80.string().datetime()
21994
22174
  });
21995
- var UploadStatusInput = z79.object({
21996
- sessionId: z79.string().uuid().describe("The sessionId returned by request_media_upload.")
22175
+ var UploadStatusInput = z80.object({
22176
+ sessionId: z80.string().uuid().describe("The sessionId returned by request_media_upload.")
21997
22177
  });
21998
- var UniversalUploadStatusResponse = z79.discriminatedUnion("status", [
21999
- z79.object({
22000
- status: z79.literal("pending"),
22001
- assets: z79.array(z79.never()).length(0)
22178
+ var UniversalUploadStatusResponse = z80.discriminatedUnion("status", [
22179
+ z80.object({
22180
+ status: z80.literal("pending"),
22181
+ assets: z80.array(z80.never()).length(0)
22002
22182
  }),
22003
- z79.object({
22004
- status: z79.literal("uploaded"),
22005
- assets: z79.array(z79.object({
22006
- assetId: z79.string().uuid(),
22007
- mediaKind: z79.enum([
22183
+ z80.object({
22184
+ status: z80.literal("uploaded"),
22185
+ assets: z80.array(z80.object({
22186
+ assetId: z80.string().uuid(),
22187
+ mediaKind: z80.enum([
22008
22188
  "image",
22009
22189
  "video"
22010
22190
  ]),
22011
- assetRole: z79.enum([
22191
+ assetRole: z80.enum([
22012
22192
  "media",
22013
22193
  "thumbnail"
22014
22194
  ])
@@ -22016,13 +22196,13 @@ var UniversalUploadStatusResponse = z79.discriminatedUnion("status", [
22016
22196
  })
22017
22197
  ]);
22018
22198
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
22019
- uploadPurpose: z79.enum([
22199
+ uploadPurpose: z80.enum([
22020
22200
  "product_reference",
22021
22201
  "creative",
22022
22202
  "generic"
22023
22203
  ]),
22024
- checkToolName: z79.literal("check_media_upload"),
22025
- resolveEndpoint: z79.string().url()
22204
+ checkToolName: z80.literal("check_media_upload"),
22205
+ resolveEndpoint: z80.string().url()
22026
22206
  });
22027
22207
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
22028
22208
  const url = new URL(uploadPageUrl);
@@ -22113,15 +22293,15 @@ function registerMediaUploadTools(server, api) {
22113
22293
  __name(registerMediaUploadTools, "registerMediaUploadTools");
22114
22294
 
22115
22295
  // src/tools/campaigns.ts
22116
- import { z as z80 } from "zod";
22296
+ import { z as z81 } from "zod";
22117
22297
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
22118
22298
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
22119
- var MetaStatusInput = z80.object({
22120
- campaignId: z80.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
22299
+ var MetaStatusInput = z81.object({
22300
+ campaignId: z81.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
22121
22301
  });
22122
- var TikTokStatusInput = z80.object({
22123
- campaignId: z80.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
22124
- advertiserId: z80.string().min(1).describe("The same advertiserId used to publish the campaign.")
22302
+ var TikTokStatusInput = z81.object({
22303
+ campaignId: z81.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
22304
+ advertiserId: z81.string().min(1).describe("The same advertiserId used to publish the campaign.")
22125
22305
  });
22126
22306
  function registerCampaignTools(server, api) {
22127
22307
  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) => {
@@ -22218,10 +22398,10 @@ function renderTikTokStatusMarkdown(r) {
22218
22398
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
22219
22399
 
22220
22400
  // ../../packages/product-economics/src/product-costing.ts
22221
- import { z as z82 } from "zod";
22401
+ import { z as z83 } from "zod";
22222
22402
 
22223
22403
  // ../../packages/product-economics/src/product-costing-countries.ts
22224
- import { z as z81 } from "zod";
22404
+ import { z as z82 } from "zod";
22225
22405
 
22226
22406
  // ../../packages/product-economics/src/product-costing-shipping-references.json
22227
22407
  var product_costing_shipping_references_default = {
@@ -22285,21 +22465,21 @@ var product_costing_shipping_references_default = {
22285
22465
  };
22286
22466
 
22287
22467
  // ../../packages/product-economics/src/product-costing-countries.ts
22288
- var ShippingReferenceSchema = z81.object({
22289
- reference: z81.number().positive(),
22290
- min: z81.number().nonnegative(),
22291
- max: z81.number().positive(),
22292
- updatedAt: z81.string().date(),
22293
- confidence: z81.enum([
22468
+ var ShippingReferenceSchema = z82.object({
22469
+ reference: z82.number().positive(),
22470
+ min: z82.number().nonnegative(),
22471
+ max: z82.number().positive(),
22472
+ updatedAt: z82.string().date(),
22473
+ confidence: z82.enum([
22294
22474
  "high",
22295
22475
  "medium",
22296
22476
  "medium-low"
22297
22477
  ]),
22298
- sources: z81.array(z81.string().url().startsWith("https://")).min(1).max(3)
22478
+ sources: z82.array(z82.string().url().startsWith("https://")).min(1).max(3)
22299
22479
  }).superRefine(({ reference, min, max }, context) => {
22300
22480
  if (min > reference || reference > max) {
22301
22481
  context.addIssue({
22302
- code: z81.ZodIssueCode.custom,
22482
+ code: z82.ZodIssueCode.custom,
22303
22483
  message: "shipping_reference_outside_range",
22304
22484
  path: [
22305
22485
  "reference"
@@ -22307,7 +22487,7 @@ var ShippingReferenceSchema = z81.object({
22307
22487
  });
22308
22488
  }
22309
22489
  });
22310
- var SHIPPING_REFERENCES = z81.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
22490
+ var SHIPPING_REFERENCES = z82.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
22311
22491
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
22312
22492
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
22313
22493
  "MX",
@@ -22489,18 +22669,18 @@ function getProductCostingCountryName(country) {
22489
22669
  __name(getProductCostingCountryName, "getProductCostingCountryName");
22490
22670
 
22491
22671
  // ../../packages/product-economics/src/product-costing.ts
22492
- var ProductCostingInputSchema = z82.object({
22493
- country: z82.string().refine(isProductCostingCountryCode, "unsupported_country"),
22494
- supplierCost: z82.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
22495
- shippingCost: z82.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
22496
- returnRate: z82.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22497
- cancellationRate: z82.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22498
- adsManagerCpa: z82.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
22499
- desiredMargin: z82.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
22672
+ var ProductCostingInputSchema = z83.object({
22673
+ country: z83.string().refine(isProductCostingCountryCode, "unsupported_country"),
22674
+ supplierCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
22675
+ shippingCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
22676
+ returnRate: z83.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22677
+ cancellationRate: z83.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
22678
+ adsManagerCpa: z83.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
22679
+ desiredMargin: z83.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
22500
22680
  }).superRefine(({ returnRate, cancellationRate }, context) => {
22501
22681
  if (returnRate + cancellationRate >= 1) {
22502
22682
  context.addIssue({
22503
- code: z82.ZodIssueCode.custom,
22683
+ code: z83.ZodIssueCode.custom,
22504
22684
  message: "delivery_rate_positive",
22505
22685
  path: [
22506
22686
  "cancellationRate"
@@ -22597,15 +22777,15 @@ function calculateProductCosting(rawInput) {
22597
22777
  __name(calculateProductCosting, "calculateProductCosting");
22598
22778
 
22599
22779
  // src/tools/product-costing.ts
22600
- import { z as z83 } from "zod";
22780
+ import { z as z84 } from "zod";
22601
22781
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
22602
- var optionalAmount = /* @__PURE__ */ __name((description) => z83.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
22603
- var optionalPercent = /* @__PURE__ */ __name((description) => z83.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
22604
- var ProductCostingToolInput = z83.object({
22605
- country: z83.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
22782
+ var optionalAmount = /* @__PURE__ */ __name((description) => z84.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
22783
+ var optionalPercent = /* @__PURE__ */ __name((description) => z84.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
22784
+ var ProductCostingToolInput = z84.object({
22785
+ country: z84.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
22606
22786
  message: "Pa\xEDs no soportado por ProductMaker."
22607
22787
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
22608
- supplierCost: z83.number().finite().max(Number.MAX_SAFE_INTEGER).positive().optional().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. Requerido salvo que uses supplierCostCop para Colombia."),
22788
+ 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."),
22609
22789
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
22610
22790
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
22611
22791
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -22764,7 +22944,7 @@ function formatPercent(value) {
22764
22944
  __name(formatPercent, "formatPercent");
22765
22945
 
22766
22946
  // src/tools/product-research.ts
22767
- import { z as z84 } from "zod";
22947
+ import { z as z85 } from "zod";
22768
22948
 
22769
22949
  // src/tools/product-research-idempotency.ts
22770
22950
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -23135,17 +23315,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
23135
23315
  ]);
23136
23316
  var POLL_INTERVAL_MS = 5e3;
23137
23317
  var MAX_WAIT_SECONDS = 120;
23138
- var FindInput = z84.object({
23318
+ var FindInput = z85.object({
23139
23319
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
23140
23320
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
23141
- confirmed: z84.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
23142
- waitSeconds: z84.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
23321
+ 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.`),
23322
+ 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.")
23143
23323
  });
23144
- var GetInput = z84.object({
23145
- runId: z84.string().uuid().describe("ID del run devuelto por find_winning_products.")
23324
+ var GetInput = z85.object({
23325
+ runId: z85.string().uuid().describe("ID del run devuelto por find_winning_products.")
23146
23326
  });
23147
- var ListInput = z84.object({
23148
- limit: z84.number().int().min(1).max(20).default(10)
23327
+ var ListInput = z85.object({
23328
+ limit: z85.number().int().min(1).max(20).default(10)
23149
23329
  });
23150
23330
  function textResult(text) {
23151
23331
  return {
@@ -23268,17 +23448,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
23268
23448
  __name(registerProductResearchTools, "registerProductResearchTools");
23269
23449
 
23270
23450
  // src/tools/dropshipping-projects.ts
23271
- import { z as z85 } from "zod";
23451
+ import { z as z86 } from "zod";
23272
23452
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
23273
23453
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
23274
23454
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
23275
- var ProjectId = z85.string().uuid();
23276
- var DropshippingProjectStatus = z85.enum([
23455
+ var ProjectId = z86.string().uuid();
23456
+ var DropshippingProjectStatus = z86.enum([
23277
23457
  "active",
23278
23458
  "completed",
23279
23459
  "archived"
23280
23460
  ]);
23281
- var DropshippingProjectPhase = z85.enum([
23461
+ var DropshippingProjectPhase = z86.enum([
23282
23462
  "research",
23283
23463
  "costing",
23284
23464
  "media",
@@ -23287,21 +23467,21 @@ var DropshippingProjectPhase = z85.enum([
23287
23467
  "advertising",
23288
23468
  "complete"
23289
23469
  ]);
23290
- var DropshippingRewardMilestone = z85.enum([
23470
+ var DropshippingRewardMilestone = z86.enum([
23291
23471
  "product_selected",
23292
23472
  "costing_saved",
23293
23473
  "product_media_ready",
23294
23474
  "creatives_completed",
23295
23475
  "campaign_created"
23296
23476
  ]);
23297
- var TargetCountry = z85.enum([
23477
+ var TargetCountry = z86.enum([
23298
23478
  "CO",
23299
23479
  "MX",
23300
23480
  "PE",
23301
23481
  "EC",
23302
23482
  "CL"
23303
23483
  ]);
23304
- var ResearchCategory = z85.enum([
23484
+ var ResearchCategory = z86.enum([
23305
23485
  "auto",
23306
23486
  "automotive",
23307
23487
  "kitchen",
@@ -23316,7 +23496,7 @@ var ResearchCategory = z85.enum([
23316
23496
  "garden",
23317
23497
  "cleaning"
23318
23498
  ]);
23319
- var HttpUrl3 = z85.string().url().max(2e3).refine((value) => {
23499
+ var HttpUrl3 = z86.string().url().max(2e3).refine((value) => {
23320
23500
  try {
23321
23501
  return [
23322
23502
  "http:",
@@ -23326,45 +23506,45 @@ var HttpUrl3 = z85.string().url().max(2e3).refine((value) => {
23326
23506
  return false;
23327
23507
  }
23328
23508
  }, "URL must use HTTP(S)");
23329
- var ResearchCandidateOrigin = z85.object({
23330
- type: z85.literal("research_candidate"),
23509
+ var ResearchCandidateOrigin = z86.object({
23510
+ type: z86.literal("research_candidate"),
23331
23511
  runId: ProjectId,
23332
- candidateSourceId: z85.string().min(1).max(160)
23512
+ candidateSourceId: z86.string().min(1).max(160)
23333
23513
  });
23334
- var TaskOrigin = z85.object({
23335
- type: z85.literal("task"),
23514
+ var TaskOrigin = z86.object({
23515
+ type: z86.literal("task"),
23336
23516
  taskId: ProjectId
23337
23517
  });
23338
- var ManualOrigin = z85.object({
23339
- type: z85.literal("manual"),
23518
+ var ManualOrigin = z86.object({
23519
+ type: z86.literal("manual"),
23340
23520
  clientRequestId: ProjectId,
23341
- country: z85.string().min(2).max(3).optional()
23521
+ country: z86.string().min(2).max(3).optional()
23342
23522
  });
23343
- var StartProjectInput = z85.object({
23344
- origin: z85.discriminatedUnion("type", [
23523
+ var StartProjectInput = z86.object({
23524
+ origin: z86.discriminatedUnion("type", [
23345
23525
  ResearchCandidateOrigin,
23346
23526
  TaskOrigin,
23347
23527
  ManualOrigin
23348
23528
  ]),
23349
- productName: z85.string().trim().min(1).max(240).optional(),
23529
+ productName: z86.string().trim().min(1).max(240).optional(),
23350
23530
  productUrl: HttpUrl3.optional(),
23351
- country: z85.string().min(2).max(3).optional(),
23352
- languageCode: z85.string().min(2).max(16).optional()
23531
+ country: z86.string().min(2).max(3).optional(),
23532
+ languageCode: z86.string().min(2).max(16).optional()
23353
23533
  }).strict();
23354
- var CostProjectInput = z85.object({
23534
+ var CostProjectInput = z86.object({
23355
23535
  projectId: ProjectId,
23356
- version: z85.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
23357
- country: z85.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
23536
+ version: z86.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
23537
+ country: z86.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
23358
23538
  message: "Pa\xEDs no soportado por ProductMaker."
23359
23539
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
23360
- supplierCost: z85.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
23361
- shippingCost: z85.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
23362
- returnRate: z85.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
23363
- cancellationRate: z85.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
23364
- adsManagerCpa: z85.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
23365
- desiredMargin: z85.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
23366
- });
23367
- var GuideInput = z85.object({
23540
+ 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."),
23541
+ 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."),
23542
+ 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."),
23543
+ 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."),
23544
+ adsManagerCpa: z86.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
23545
+ 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.")
23546
+ });
23547
+ var GuideInput = z86.object({
23368
23548
  projectId: ProjectId.optional()
23369
23549
  }).strict();
23370
23550
  var NEXT_ACTION_KINDS = [
@@ -23382,29 +23562,29 @@ var NEXT_ACTION_KINDS = [
23382
23562
  "repair_meta_campaign",
23383
23563
  "review_paused_campaign"
23384
23564
  ];
23385
- var DropshippingProjectNextAction = z85.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z85.object({
23386
- kind: z85.literal(kind),
23387
- href: z85.string().min(1)
23565
+ var DropshippingProjectNextAction = z86.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z86.object({
23566
+ kind: z86.literal(kind),
23567
+ href: z86.string().min(1)
23388
23568
  })));
23389
- var CostingInputSchema = z85.object({
23390
- country: z85.string().min(2).max(3),
23391
- supplierCost: z85.number().finite().positive(),
23392
- shippingCost: z85.number().finite().nonnegative(),
23393
- returnRate: z85.number().finite().min(0).lt(1),
23394
- cancellationRate: z85.number().finite().min(0).lt(1),
23395
- adsManagerCpa: z85.number().finite().nonnegative(),
23396
- desiredMargin: z85.number().finite().min(0).lt(1)
23569
+ var CostingInputSchema = z86.object({
23570
+ country: z86.string().min(2).max(3),
23571
+ supplierCost: z86.number().finite().positive(),
23572
+ shippingCost: z86.number().finite().nonnegative(),
23573
+ returnRate: z86.number().finite().min(0).lt(1),
23574
+ cancellationRate: z86.number().finite().min(0).lt(1),
23575
+ adsManagerCpa: z86.number().finite().nonnegative(),
23576
+ desiredMargin: z86.number().finite().min(0).lt(1)
23397
23577
  }).superRefine(({ returnRate, cancellationRate }, context) => {
23398
23578
  if (returnRate + cancellationRate >= 1) context.addIssue({
23399
- code: z85.ZodIssueCode.custom,
23579
+ code: z86.ZodIssueCode.custom,
23400
23580
  path: [
23401
23581
  "cancellationRate"
23402
23582
  ]
23403
23583
  });
23404
23584
  });
23405
- var FiniteCostingNumber = z85.number().finite();
23406
- var CostingResultSchema = z85.object({
23407
- country: z85.string().min(2).max(3),
23585
+ var FiniteCostingNumber = z86.number().finite();
23586
+ var CostingResultSchema = z86.object({
23587
+ country: z86.string().min(2).max(3),
23408
23588
  deliveryRate: FiniteCostingNumber,
23409
23589
  adjustedShippingCost: FiniteCostingNumber,
23410
23590
  adjustedCpa: FiniteCostingNumber,
@@ -23417,45 +23597,45 @@ var CostingResultSchema = z85.object({
23417
23597
  estimatedProfit: FiniteCostingNumber,
23418
23598
  actualMargin: FiniteCostingNumber,
23419
23599
  breakEvenAdsManagerCpa: FiniteCostingNumber,
23420
- wasPriceAutoAdjusted: z85.boolean(),
23421
- profitabilityStatus: z85.literal("healthy")
23422
- });
23423
- var RewardProgressSchema = z85.object({
23424
- campaignKey: z85.literal("dropshipping-launch-v1"),
23425
- totalCredits: z85.number().int().positive(),
23426
- earnedCredits: z85.number().int().nonnegative(),
23427
- milestones: z85.array(z85.object({
23600
+ wasPriceAutoAdjusted: z86.boolean(),
23601
+ profitabilityStatus: z86.literal("healthy")
23602
+ });
23603
+ var RewardProgressSchema = z86.object({
23604
+ campaignKey: z86.literal("dropshipping-launch-v1"),
23605
+ totalCredits: z86.number().int().positive(),
23606
+ earnedCredits: z86.number().int().nonnegative(),
23607
+ milestones: z86.array(z86.object({
23428
23608
  milestone: DropshippingRewardMilestone,
23429
- credits: z85.number().int().positive(),
23430
- available: z85.boolean().optional(),
23431
- earned: z85.boolean(),
23609
+ credits: z86.number().int().positive(),
23610
+ available: z86.boolean().optional(),
23611
+ earned: z86.boolean(),
23432
23612
  grantId: ProjectId.nullable(),
23433
- grantedAt: z85.string().datetime().nullable()
23613
+ grantedAt: z86.string().datetime().nullable()
23434
23614
  })).length(DropshippingRewardMilestone.options.length)
23435
23615
  });
23436
- var ProjectResponseSchema = z85.object({
23616
+ var ProjectResponseSchema = z86.object({
23437
23617
  id: ProjectId,
23438
23618
  taskId: ProjectId.nullable(),
23439
23619
  status: DropshippingProjectStatus,
23440
- originKey: z85.string().min(1),
23620
+ originKey: z86.string().min(1),
23441
23621
  researchRunId: ProjectId.nullable(),
23442
- candidateSourceId: z85.string().nullable(),
23443
- productName: z85.string().nullable(),
23622
+ candidateSourceId: z86.string().nullable(),
23623
+ productName: z86.string().nullable(),
23444
23624
  productUrl: HttpUrl3.nullable(),
23445
23625
  referenceImageUrl: HttpUrl3.nullable(),
23446
- targetCountry: z85.string().nullable(),
23447
- languageCode: z85.string().nullable(),
23448
- hasReferenceImage: z85.boolean(),
23449
- hasWinnerReferenceImage: z85.boolean(),
23626
+ targetCountry: z86.string().nullable(),
23627
+ languageCode: z86.string().nullable(),
23628
+ hasReferenceImage: z86.boolean(),
23629
+ hasWinnerReferenceImage: z86.boolean(),
23450
23630
  costingInput: CostingInputSchema.nullable(),
23451
23631
  costingResult: CostingResultSchema.nullable(),
23452
- costingVersion: z85.number().int().positive().nullable(),
23453
- version: z85.number().int().positive(),
23632
+ costingVersion: z86.number().int().positive().nullable(),
23633
+ version: z86.number().int().positive(),
23454
23634
  phase: DropshippingProjectPhase,
23455
23635
  nextAction: DropshippingProjectNextAction.nullable(),
23456
23636
  rewards: RewardProgressSchema,
23457
- createdAt: z85.string().datetime(),
23458
- updatedAt: z85.string().datetime()
23637
+ createdAt: z86.string().datetime(),
23638
+ updatedAt: z86.string().datetime()
23459
23639
  }).passthrough();
23460
23640
  var NEXT_ACTION_GUIDANCE = {
23461
23641
  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.",
@@ -23573,58 +23753,58 @@ function registerDropshippingProjectTools(server, api) {
23573
23753
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
23574
23754
 
23575
23755
  // src/tools/daily-control.ts
23576
- import { z as z86 } from "zod";
23756
+ import { z as z87 } from "zod";
23577
23757
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
23578
23758
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
23579
23759
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
23580
- var ProviderCampaignIdentifier = z86.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
23581
- var DateOnly = z86.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23582
- var DailyControlInput = z86.object({
23760
+ var ProviderCampaignIdentifier = z87.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
23761
+ var DateOnly = z87.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23762
+ var DailyControlInput = z87.object({
23583
23763
  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."),
23584
- days: z86.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23585
- projectId: z86.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
23764
+ days: z87.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23765
+ projectId: z87.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
23586
23766
  }).strict();
23587
- var LinkCampaignInput = z86.object({
23588
- projectId: z86.string().uuid(),
23589
- provider: z86.enum([
23767
+ var LinkCampaignInput = z87.object({
23768
+ projectId: z87.string().uuid(),
23769
+ provider: z87.enum([
23590
23770
  "meta",
23591
23771
  "tiktok"
23592
23772
  ]),
23593
23773
  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."),
23594
23774
  campaignId: ProviderCampaignIdentifier
23595
23775
  }).strict();
23596
- var ReportReturnsInput = z86.object({
23597
- projectId: z86.string().uuid(),
23776
+ var ReportReturnsInput = z87.object({
23777
+ projectId: z87.string().uuid(),
23598
23778
  date: DateOnly,
23599
- returnedOrders: z86.number().int().min(0).max(1e5),
23600
- note: z86.string().trim().max(280).optional()
23779
+ returnedOrders: z87.number().int().min(0).max(1e5),
23780
+ note: z87.string().trim().max(280).optional()
23601
23781
  }).strict();
23602
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z86.string());
23603
- var DailyControlLightMirror = DailyControlLightEnum.or(z86.string());
23604
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z86.string());
23605
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z86.string());
23606
- var DailyControlDayMirror = z86.object({
23607
- date: z86.string(),
23608
- returnedOrders: z86.number(),
23782
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z87.string());
23783
+ var DailyControlLightMirror = DailyControlLightEnum.or(z87.string());
23784
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z87.string());
23785
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z87.string());
23786
+ var DailyControlDayMirror = z87.object({
23787
+ date: z87.string(),
23788
+ returnedOrders: z87.number(),
23609
23789
  returnedSource: DailyControlSourceMirror,
23610
23790
  cancelledSource: DailyControlSourceMirror,
23611
- hasEstimates: z86.boolean(),
23791
+ hasEstimates: z87.boolean(),
23612
23792
  light: DailyControlLightMirror
23613
23793
  }).passthrough();
23614
- var DailyControlProductMirror = z86.object({
23615
- projectId: z86.string().uuid(),
23616
- productName: z86.string().nullable(),
23794
+ var DailyControlProductMirror = z87.object({
23795
+ projectId: z87.string().uuid(),
23796
+ productName: z87.string().nullable(),
23617
23797
  status: DailyControlStatusMirror,
23618
- statusMessage: z86.string().nullable(),
23619
- days: z86.array(DailyControlDayMirror),
23798
+ statusMessage: z87.string().nullable(),
23799
+ days: z87.array(DailyControlDayMirror),
23620
23800
  verdict: DailyControlVerdictMirror.nullable(),
23621
- rationale: z86.string().nullable()
23801
+ rationale: z87.string().nullable()
23622
23802
  }).passthrough();
23623
- var DailyControlResponseMirror = z86.object({
23624
- since: z86.string(),
23625
- until: z86.string(),
23626
- products: z86.array(DailyControlProductMirror),
23627
- archivedProjectSpend: z86.array(z86.unknown())
23803
+ var DailyControlResponseMirror = z87.object({
23804
+ since: z87.string(),
23805
+ until: z87.string(),
23806
+ products: z87.array(DailyControlProductMirror),
23807
+ archivedProjectSpend: z87.array(z87.unknown())
23628
23808
  }).passthrough();
23629
23809
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
23630
23810
  function withWarnings(response) {
@@ -23708,42 +23888,42 @@ function registerDailyControlTools(server, api) {
23708
23888
  __name(registerDailyControlTools, "registerDailyControlTools");
23709
23889
 
23710
23890
  // src/tools/product-control.ts
23711
- import { z as z87 } from "zod";
23891
+ import { z as z88 } from "zod";
23712
23892
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
23713
23893
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
23714
23894
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
23715
23895
  var setProductCostingGuidance = getProductMakerCapabilityModelGuidance("set_product_costing");
23716
23896
  var reportProductCountsGuidance = getProductMakerCapabilityModelGuidance("report_product_counts");
23717
- var DateOnly2 = z87.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23897
+ var DateOnly2 = z88.string().regex(/^\d{4}-\d{2}-\d{2}$/);
23718
23898
  var IMPORT_BATCH_MAX2 = 50;
23719
- var ProductControlListInput = z87.object({
23720
- days: z87.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23899
+ var ProductControlListInput = z88.object({
23900
+ days: z88.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
23721
23901
  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."),
23722
- shopDomain: z87.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
23902
+ shopDomain: z88.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
23723
23903
  }).strict();
23724
- var ImportableProductsInput = z87.object({
23725
- q: z87.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
23726
- after: z87.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
23727
- shopDomain: z87.string().min(1).optional()
23904
+ var ImportableProductsInput = z88.object({
23905
+ q: z88.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
23906
+ after: z88.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
23907
+ shopDomain: z88.string().min(1).optional()
23728
23908
  }).strict();
23729
- var ImportProductControlsInput = z87.object({
23730
- shopifyProductIds: z87.array(z87.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
23909
+ var ImportProductControlsInput = z88.object({
23910
+ 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."),
23731
23911
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
23732
23912
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
23733
- shopDomain: z87.string().min(1)
23913
+ shopDomain: z88.string().min(1)
23734
23914
  }).strict();
23735
- var SetProductCostingInput = z87.object({
23736
- shopDomain: z87.string().min(1),
23737
- shopifyProductId: z87.string().min(1).max(64),
23738
- targetCountry: z87.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
23739
- supplierCost: z87.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
23740
- shippingCost: z87.number().finite().nonnegative(),
23741
- returnRate: z87.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
23742
- cancellationRate: z87.number().finite().min(0).lt(1)
23915
+ var SetProductCostingInput = z88.object({
23916
+ shopDomain: z88.string().min(1),
23917
+ shopifyProductId: z88.string().min(1).max(64),
23918
+ targetCountry: z88.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
23919
+ supplierCost: z88.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
23920
+ shippingCost: z88.number().finite().nonnegative(),
23921
+ returnRate: z88.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
23922
+ cancellationRate: z88.number().finite().min(0).lt(1)
23743
23923
  }).strict();
23744
- var Count = z87.number().int().min(0).max(1e5).nullable().optional();
23745
- var ReportProductCountsInput = z87.object({
23746
- productControlId: z87.string().uuid().describe("El identificador que devuelve get_product_control."),
23924
+ var Count = z88.number().int().min(0).max(1e5).nullable().optional();
23925
+ var ReportProductCountsInput = z88.object({
23926
+ productControlId: z88.string().uuid().describe("El identificador que devuelve get_product_control."),
23747
23927
  date: DateOnly2,
23748
23928
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
23749
23929
  cancelledOrders: Count,