@productmaker/mcp 2.8.3 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stdio.js CHANGED
@@ -150,7 +150,7 @@ var ApiClient = class {
150
150
  };
151
151
 
152
152
  // src/index.ts
153
- var MCP_VERSION = "2.8.3";
153
+ var MCP_VERSION = "2.9.1";
154
154
 
155
155
  // src/meta-upload-app.ts
156
156
  import { readFileSync } from "fs";
@@ -203,7 +203,7 @@ function registerMetaUploadAppResource(server) {
203
203
  __name(registerMetaUploadAppResource, "registerMetaUploadAppResource");
204
204
 
205
205
  // src/tools/tasks.ts
206
- import { z as z45 } from "zod";
206
+ import { z as z46 } from "zod";
207
207
 
208
208
  // src/resolve-image.ts
209
209
  import { lookup as dnsLookup } from "dns/promises";
@@ -2303,6 +2303,25 @@ var ShopifyPublicationStatus = z19.enum([
2303
2303
  "success",
2304
2304
  "error"
2305
2305
  ]);
2306
+ var ShopifyTrackingSyncStatus = z19.enum([
2307
+ "synced",
2308
+ "migrated",
2309
+ "not_detected"
2310
+ ]);
2311
+ var ShopifyTrackingSource = z19.enum([
2312
+ "theme",
2313
+ "legacy_layout",
2314
+ "theme_and_legacy",
2315
+ "none"
2316
+ ]);
2317
+ var ShopifyTrackingResult = z19.object({
2318
+ status: ShopifyTrackingSyncStatus,
2319
+ manualCodeDetected: z19.boolean(),
2320
+ /** True when code from a prior ProductMaker layout was preserved automatically. */
2321
+ legacyCodeMigrated: z19.boolean().default(false),
2322
+ source: ShopifyTrackingSource.default("none"),
2323
+ syncedAt: z19.string().datetime()
2324
+ });
2306
2325
  var ShopifyPublishResponse = z19.object({
2307
2326
  publicationId: z19.string().uuid(),
2308
2327
  taskId: z19.string().uuid(),
@@ -2318,6 +2337,8 @@ var ShopifyPublishResponse = z19.object({
2318
2337
  needsThemeSetup: z19.boolean().optional(),
2319
2338
  /** One-click theme-editor deep link to add the Code Landing block (when needsThemeSetup). */
2320
2339
  themeEditorDeepLink: z19.string().url().optional(),
2340
+ /** Tracking copied from the theme or migrated from a previous ProductMaker layout. */
2341
+ tracking: ShopifyTrackingResult.optional(),
2321
2342
  createdAt: z19.string().datetime().optional(),
2322
2343
  updatedAt: z19.string().datetime().optional()
2323
2344
  });
@@ -3216,7 +3237,9 @@ var ImageCreativeEstimationOptions = z24.object({
3216
3237
  });
3217
3238
  var RegenerateLandingRoleBody = z24.object({
3218
3239
  comment: z24.string().max(500).optional(),
3219
- sourceKey: z24.string().max(200).optional()
3240
+ sourceKey: z24.string().max(200).optional(),
3241
+ /** Client-generated key lets a lost response be retried without another charge. */
3242
+ clientRequestId: z24.string().uuid().optional()
3220
3243
  }).strict();
3221
3244
  var LandingRegenerateEstimationOptions = z24.object({
3222
3245
  /** KIE image endpoint has non-linear pricing by nVariants; for landing we default to 2. */
@@ -6162,8 +6185,7 @@ var DEFAULT_PRICING = {
6162
6185
  userPriceCents: 0.04
6163
6186
  }
6164
6187
  };
6165
- var REGEN_I2V_CLIP_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok15-persec-480p"].ourCostCents * 3;
6166
- var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-480p"].ourCostCents;
6188
+ var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-720p"].ourCostCents;
6167
6189
  var SC_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].ourCostCents;
6168
6190
  var SC_FRAME_COMPOSE_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].userPriceCents;
6169
6191
  var MS_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:nano-banana-2"].ourCostCents;
@@ -7440,10 +7462,35 @@ var ListLandingEditsResponse = z37.object({
7440
7462
  edits: z37.array(LandingEditDto)
7441
7463
  });
7442
7464
 
7443
- // ../../packages/types/src/video-edit.ts
7465
+ // ../../packages/types/src/landing-regeneration.ts
7444
7466
  import { z as z38 } from "zod";
7467
+ var LandingRegenerationStatus = z38.enum([
7468
+ "queued",
7469
+ "processing",
7470
+ "published",
7471
+ "failed"
7472
+ ]);
7473
+ var RegenerateLandingRoleResponse = z38.object({
7474
+ ok: z38.literal(true),
7475
+ role: LandingRole,
7476
+ promptIndex: z38.number().int().nonnegative(),
7477
+ operationId: z38.string().min(1)
7478
+ });
7479
+ var LandingRegenerationStatusResponse = z38.object({
7480
+ ok: z38.literal(true),
7481
+ operationId: z38.string().min(1),
7482
+ role: LandingRole,
7483
+ status: LandingRegenerationStatus,
7484
+ refunded: z38.boolean(),
7485
+ failureReason: z38.string().nullable(),
7486
+ publishedAssetKey: z38.string().nullable(),
7487
+ updatedAt: z38.string().datetime()
7488
+ });
7489
+
7490
+ // ../../packages/types/src/video-edit.ts
7491
+ import { z as z39 } from "zod";
7445
7492
  var MAX_SEGMENT_SECONDS = 3;
7446
- var VideoEditStatusSchema = z38.enum([
7493
+ var VideoEditStatusSchema = z39.enum([
7447
7494
  "pending",
7448
7495
  "processing",
7449
7496
  "assembling",
@@ -7452,9 +7499,9 @@ var VideoEditStatusSchema = z38.enum([
7452
7499
  "discarded",
7453
7500
  "failed"
7454
7501
  ]);
7455
- var VideoEditTimeSectionSchema = z38.object({
7456
- startSec: z38.number().min(0),
7457
- endSec: z38.number().positive()
7502
+ var VideoEditTimeSectionSchema = z39.object({
7503
+ startSec: z39.number().min(0),
7504
+ endSec: z39.number().positive()
7458
7505
  }).refine((v) => v.endSec > v.startSec, {
7459
7506
  message: "endSec must be after startSec",
7460
7507
  path: [
@@ -7466,35 +7513,35 @@ var VideoEditTimeSectionSchema = z38.object({
7466
7513
  "endSec"
7467
7514
  ]
7468
7515
  });
7469
- var VideoEditRequestSchema = z38.object({
7470
- comment: z38.string().trim().min(1).max(2e3),
7471
- sections: z38.array(VideoEditTimeSectionSchema).min(1).optional()
7516
+ var VideoEditRequestSchema = z39.object({
7517
+ comment: z39.string().trim().min(1).max(2e3),
7518
+ sections: z39.array(VideoEditTimeSectionSchema).min(1).optional()
7472
7519
  });
7473
- var VideoEditModeSchema = z38.enum([
7520
+ var VideoEditModeSchema = z39.enum([
7474
7521
  "wan_edit",
7475
7522
  "regenerate"
7476
7523
  ]);
7477
- var VideoRegenerationEngineSchema = z38.enum([
7524
+ var VideoRegenerationEngineSchema = z39.enum([
7478
7525
  "free_text",
7479
7526
  "free_image",
7480
7527
  "single_call",
7481
7528
  "multi_shot"
7482
7529
  ]);
7483
- var VideoRegenerationRouteFingerprintSchema = z38.string().trim().min(1).max(128);
7484
- var RegenerateEditRequestSchema = z38.object({
7485
- angleKey: z38.string().min(1),
7486
- comment: z38.string().min(1).max(2e3)
7530
+ var VideoRegenerationRouteFingerprintSchema = z39.string().trim().min(1).max(128);
7531
+ var RegenerateEditRequestSchema = z39.object({
7532
+ angleKey: z39.string().min(1),
7533
+ comment: z39.string().min(1).max(2e3)
7487
7534
  });
7488
7535
 
7489
7536
  // ../../packages/types/src/dropshipping-project.ts
7490
- import { z as z39 } from "zod";
7491
- var DropshippingProjectStatusSchema = z39.enum([
7537
+ import { z as z40 } from "zod";
7538
+ var DropshippingProjectStatusSchema = z40.enum([
7492
7539
  "active",
7493
7540
  "completed",
7494
7541
  "archived"
7495
7542
  ]);
7496
7543
  var DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN = "dropshipping-launch-v1";
7497
- var DropshippingRewardMilestoneSchema = z39.enum([
7544
+ var DropshippingRewardMilestoneSchema = z40.enum([
7498
7545
  "product_selected",
7499
7546
  "costing_saved",
7500
7547
  "product_media_ready",
@@ -7509,21 +7556,21 @@ var DROPSHIPPING_LAUNCH_REWARD_CREDITS = {
7509
7556
  campaign_created: 200
7510
7557
  };
7511
7558
  var DROPSHIPPING_LAUNCH_REWARD_TOTAL_CREDITS = Object.values(DROPSHIPPING_LAUNCH_REWARD_CREDITS).reduce((sum, credits) => sum + credits, 0);
7512
- var DropshippingProjectRewardMilestoneStateSchema = z39.object({
7559
+ var DropshippingProjectRewardMilestoneStateSchema = z40.object({
7513
7560
  milestone: DropshippingRewardMilestoneSchema,
7514
- credits: z39.number().int().positive(),
7515
- available: z39.boolean().optional(),
7516
- earned: z39.boolean(),
7517
- grantId: z39.string().uuid().nullable(),
7518
- grantedAt: z39.string().datetime().nullable()
7519
- });
7520
- var DropshippingProjectRewardProgressSchema = z39.object({
7521
- campaignKey: z39.literal(DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN),
7522
- totalCredits: z39.number().int().positive(),
7523
- earnedCredits: z39.number().int().nonnegative(),
7524
- milestones: z39.array(DropshippingProjectRewardMilestoneStateSchema).length(DropshippingRewardMilestoneSchema.options.length)
7525
- });
7526
- var DropshippingProjectPhaseSchema = z39.enum([
7561
+ credits: z40.number().int().positive(),
7562
+ available: z40.boolean().optional(),
7563
+ earned: z40.boolean(),
7564
+ grantId: z40.string().uuid().nullable(),
7565
+ grantedAt: z40.string().datetime().nullable()
7566
+ });
7567
+ var DropshippingProjectRewardProgressSchema = z40.object({
7568
+ campaignKey: z40.literal(DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN),
7569
+ totalCredits: z40.number().int().positive(),
7570
+ earnedCredits: z40.number().int().nonnegative(),
7571
+ milestones: z40.array(DropshippingProjectRewardMilestoneStateSchema).length(DropshippingRewardMilestoneSchema.options.length)
7572
+ });
7573
+ var DropshippingProjectPhaseSchema = z40.enum([
7527
7574
  "research",
7528
7575
  "costing",
7529
7576
  "media",
@@ -7532,18 +7579,18 @@ var DropshippingProjectPhaseSchema = z39.enum([
7532
7579
  "advertising",
7533
7580
  "complete"
7534
7581
  ]);
7535
- var DropshippingProjectCostingInputSchema = z39.object({
7536
- country: z39.string().min(2).max(3),
7537
- supplierCost: z39.number().finite().positive(),
7538
- shippingCost: z39.number().finite().nonnegative(),
7539
- returnRate: z39.number().finite().min(0).lt(1),
7540
- cancellationRate: z39.number().finite().min(0).lt(1),
7541
- adsManagerCpa: z39.number().finite().nonnegative(),
7542
- desiredMargin: z39.number().finite().min(0).lt(1)
7582
+ var DropshippingProjectCostingInputSchema = z40.object({
7583
+ country: z40.string().min(2).max(3),
7584
+ supplierCost: z40.number().finite().positive(),
7585
+ shippingCost: z40.number().finite().nonnegative(),
7586
+ returnRate: z40.number().finite().min(0).lt(1),
7587
+ cancellationRate: z40.number().finite().min(0).lt(1),
7588
+ adsManagerCpa: z40.number().finite().nonnegative(),
7589
+ desiredMargin: z40.number().finite().min(0).lt(1)
7543
7590
  }).superRefine(({ returnRate, cancellationRate }, context) => {
7544
7591
  if (returnRate + cancellationRate >= 1) {
7545
7592
  context.addIssue({
7546
- code: z39.ZodIssueCode.custom,
7593
+ code: z40.ZodIssueCode.custom,
7547
7594
  path: [
7548
7595
  "cancellationRate"
7549
7596
  ],
@@ -7551,24 +7598,24 @@ var DropshippingProjectCostingInputSchema = z39.object({
7551
7598
  });
7552
7599
  }
7553
7600
  });
7554
- var DropshippingProjectCostingResultSchema = z39.object({
7555
- country: z39.string().min(2).max(3),
7556
- deliveryRate: z39.number().finite(),
7557
- adjustedShippingCost: z39.number().finite(),
7558
- adjustedCpa: z39.number().finite(),
7559
- totalCost: z39.number().finite(),
7560
- suggestedPrice: z39.number().finite(),
7561
- baseCommercialPrice: z39.number().finite(),
7562
- minimumSafePrice: z39.number().finite(),
7563
- commercialPrice: z39.number().finite(),
7564
- comparisonPrice: z39.number().finite(),
7565
- estimatedProfit: z39.number().finite(),
7566
- actualMargin: z39.number().finite(),
7567
- breakEvenAdsManagerCpa: z39.number().finite(),
7568
- wasPriceAutoAdjusted: z39.boolean(),
7569
- profitabilityStatus: z39.literal("healthy")
7570
- });
7571
- var HttpUrlSchema = z39.string().url().max(2e3).refine((value) => {
7601
+ var DropshippingProjectCostingResultSchema = z40.object({
7602
+ country: z40.string().min(2).max(3),
7603
+ deliveryRate: z40.number().finite(),
7604
+ adjustedShippingCost: z40.number().finite(),
7605
+ adjustedCpa: z40.number().finite(),
7606
+ totalCost: z40.number().finite(),
7607
+ suggestedPrice: z40.number().finite(),
7608
+ baseCommercialPrice: z40.number().finite(),
7609
+ minimumSafePrice: z40.number().finite(),
7610
+ commercialPrice: z40.number().finite(),
7611
+ comparisonPrice: z40.number().finite(),
7612
+ estimatedProfit: z40.number().finite(),
7613
+ actualMargin: z40.number().finite(),
7614
+ breakEvenAdsManagerCpa: z40.number().finite(),
7615
+ wasPriceAutoAdjusted: z40.boolean(),
7616
+ profitabilityStatus: z40.literal("healthy")
7617
+ });
7618
+ var HttpUrlSchema = z40.string().url().max(2e3).refine((value) => {
7572
7619
  try {
7573
7620
  return [
7574
7621
  "http:",
@@ -7578,124 +7625,124 @@ var HttpUrlSchema = z39.string().url().max(2e3).refine((value) => {
7578
7625
  return false;
7579
7626
  }
7580
7627
  }, "Product URL must use HTTP(S)");
7581
- var ResearchCandidateOriginSchema = z39.object({
7582
- type: z39.literal("research_candidate"),
7583
- runId: z39.string().uuid(),
7584
- candidateSourceId: z39.string().min(1).max(160)
7585
- });
7586
- var TaskOriginSchema = z39.object({
7587
- type: z39.literal("task"),
7588
- taskId: z39.string().uuid()
7589
- });
7590
- var ManualOriginSchema = z39.object({
7591
- type: z39.literal("manual"),
7592
- clientRequestId: z39.string().uuid(),
7593
- country: z39.string().min(2).max(3).optional()
7594
- });
7595
- var CreateDropshippingProjectRequestSchema = z39.object({
7596
- origin: z39.discriminatedUnion("type", [
7628
+ var ResearchCandidateOriginSchema = z40.object({
7629
+ type: z40.literal("research_candidate"),
7630
+ runId: z40.string().uuid(),
7631
+ candidateSourceId: z40.string().min(1).max(160)
7632
+ });
7633
+ var TaskOriginSchema = z40.object({
7634
+ type: z40.literal("task"),
7635
+ taskId: z40.string().uuid()
7636
+ });
7637
+ var ManualOriginSchema = z40.object({
7638
+ type: z40.literal("manual"),
7639
+ clientRequestId: z40.string().uuid(),
7640
+ country: z40.string().min(2).max(3).optional()
7641
+ });
7642
+ var CreateDropshippingProjectRequestSchema = z40.object({
7643
+ origin: z40.discriminatedUnion("type", [
7597
7644
  ResearchCandidateOriginSchema,
7598
7645
  TaskOriginSchema,
7599
7646
  ManualOriginSchema
7600
7647
  ]),
7601
- productName: z39.string().trim().min(1).max(240).optional(),
7648
+ productName: z40.string().trim().min(1).max(240).optional(),
7602
7649
  productUrl: HttpUrlSchema.optional(),
7603
- country: z39.string().min(2).max(3).optional(),
7604
- languageCode: z39.string().min(2).max(16).optional()
7650
+ country: z40.string().min(2).max(3).optional(),
7651
+ languageCode: z40.string().min(2).max(16).optional()
7605
7652
  }).strict();
7606
- var SaveDropshippingProjectCostingRequestSchema = z39.object({
7653
+ var SaveDropshippingProjectCostingRequestSchema = z40.object({
7607
7654
  input: DropshippingProjectCostingInputSchema,
7608
- version: z39.number().int().positive()
7655
+ version: z40.number().int().positive()
7609
7656
  }).strict();
7610
- var DropshippingProjectNextActionSchema = z39.discriminatedUnion("kind", [
7611
- z39.object({
7612
- kind: z39.literal("cost_product"),
7613
- href: z39.string().min(1)
7657
+ var DropshippingProjectNextActionSchema = z40.discriminatedUnion("kind", [
7658
+ z40.object({
7659
+ kind: z40.literal("cost_product"),
7660
+ href: z40.string().min(1)
7614
7661
  }),
7615
- z39.object({
7616
- kind: z39.literal("provide_product_media"),
7617
- href: z39.string().min(1)
7662
+ z40.object({
7663
+ kind: z40.literal("provide_product_media"),
7664
+ href: z40.string().min(1)
7618
7665
  }),
7619
- z39.object({
7620
- kind: z39.literal("generate_creatives"),
7621
- href: z39.string().min(1)
7666
+ z40.object({
7667
+ kind: z40.literal("generate_creatives"),
7668
+ href: z40.string().min(1)
7622
7669
  }),
7623
- z39.object({
7624
- kind: z39.literal("wait_for_creatives"),
7625
- href: z39.string().min(1)
7670
+ z40.object({
7671
+ kind: z40.literal("wait_for_creatives"),
7672
+ href: z40.string().min(1)
7626
7673
  }),
7627
- z39.object({
7628
- kind: z39.literal("repair_creatives"),
7629
- href: z39.string().min(1)
7674
+ z40.object({
7675
+ kind: z40.literal("repair_creatives"),
7676
+ href: z40.string().min(1)
7630
7677
  }),
7631
- z39.object({
7632
- kind: z39.literal("complete_creative_set"),
7633
- href: z39.string().min(1)
7678
+ z40.object({
7679
+ kind: z40.literal("complete_creative_set"),
7680
+ href: z40.string().min(1)
7634
7681
  }),
7635
- z39.object({
7636
- kind: z39.literal("connect_shopify"),
7637
- href: z39.string().min(1)
7682
+ z40.object({
7683
+ kind: z40.literal("connect_shopify"),
7684
+ href: z40.string().min(1)
7638
7685
  }),
7639
- z39.object({
7640
- kind: z39.literal("publish_storefront"),
7641
- href: z39.string().min(1)
7686
+ z40.object({
7687
+ kind: z40.literal("publish_storefront"),
7688
+ href: z40.string().min(1)
7642
7689
  }),
7643
- z39.object({
7644
- kind: z39.literal("wait_for_storefront"),
7645
- href: z39.string().min(1)
7690
+ z40.object({
7691
+ kind: z40.literal("wait_for_storefront"),
7692
+ href: z40.string().min(1)
7646
7693
  }),
7647
- z39.object({
7648
- kind: z39.literal("connect_meta"),
7649
- href: z39.string().min(1)
7694
+ z40.object({
7695
+ kind: z40.literal("connect_meta"),
7696
+ href: z40.string().min(1)
7650
7697
  }),
7651
- z39.object({
7652
- kind: z39.literal("create_meta_campaign"),
7653
- href: z39.string().min(1)
7698
+ z40.object({
7699
+ kind: z40.literal("create_meta_campaign"),
7700
+ href: z40.string().min(1)
7654
7701
  }),
7655
- z39.object({
7656
- kind: z39.literal("repair_meta_campaign"),
7657
- href: z39.string().min(1)
7702
+ z40.object({
7703
+ kind: z40.literal("repair_meta_campaign"),
7704
+ href: z40.string().min(1)
7658
7705
  }),
7659
- z39.object({
7660
- kind: z39.literal("review_paused_campaign"),
7661
- href: z39.string().min(1)
7706
+ z40.object({
7707
+ kind: z40.literal("review_paused_campaign"),
7708
+ href: z40.string().min(1)
7662
7709
  })
7663
7710
  ]);
7664
- var DropshippingProjectResponseSchema = z39.object({
7665
- id: z39.string().uuid(),
7666
- taskId: z39.string().uuid().nullable(),
7711
+ var DropshippingProjectResponseSchema = z40.object({
7712
+ id: z40.string().uuid(),
7713
+ taskId: z40.string().uuid().nullable(),
7667
7714
  status: DropshippingProjectStatusSchema,
7668
- originKey: z39.string().min(1),
7669
- researchRunId: z39.string().uuid().nullable(),
7670
- candidateSourceId: z39.string().nullable(),
7671
- productName: z39.string().nullable(),
7715
+ originKey: z40.string().min(1),
7716
+ researchRunId: z40.string().uuid().nullable(),
7717
+ candidateSourceId: z40.string().nullable(),
7718
+ productName: z40.string().nullable(),
7672
7719
  productUrl: HttpUrlSchema.nullable(),
7673
- referenceImageUrl: z39.string().url().nullable(),
7674
- hasReferenceImage: z39.boolean(),
7675
- targetCountry: z39.string().nullable(),
7676
- languageCode: z39.string().nullable(),
7720
+ referenceImageUrl: z40.string().url().nullable(),
7721
+ hasReferenceImage: z40.boolean(),
7722
+ targetCountry: z40.string().nullable(),
7723
+ languageCode: z40.string().nullable(),
7677
7724
  costingInput: DropshippingProjectCostingInputSchema.nullable(),
7678
7725
  costingResult: DropshippingProjectCostingResultSchema.nullable(),
7679
- costingVersion: z39.number().int().positive().nullable(),
7680
- version: z39.number().int().positive(),
7726
+ costingVersion: z40.number().int().positive().nullable(),
7727
+ version: z40.number().int().positive(),
7681
7728
  phase: DropshippingProjectPhaseSchema,
7682
7729
  nextAction: DropshippingProjectNextActionSchema.nullable(),
7683
7730
  rewards: DropshippingProjectRewardProgressSchema,
7684
- createdAt: z39.string().datetime(),
7685
- updatedAt: z39.string().datetime()
7731
+ createdAt: z40.string().datetime(),
7732
+ updatedAt: z40.string().datetime()
7686
7733
  });
7687
7734
 
7688
7735
  // ../../packages/types/src/scene-subject-contract.ts
7689
- import { z as z40 } from "zod";
7690
- var SceneSubjectContractSchema = z40.object({
7691
- maxPeople: z40.number().int().min(1).max(10),
7692
- minPeople: z40.number().int().min(0).max(10),
7693
- minDistinctPeople: z40.number().int().min(0).max(10),
7694
- maxHands: z40.number().int().min(0).max(20)
7736
+ import { z as z41 } from "zod";
7737
+ var SceneSubjectContractSchema = z41.object({
7738
+ maxPeople: z41.number().int().min(1).max(10),
7739
+ minPeople: z41.number().int().min(0).max(10),
7740
+ minDistinctPeople: z41.number().int().min(0).max(10),
7741
+ maxHands: z41.number().int().min(0).max(20)
7695
7742
  }).superRefine((value, ctx) => {
7696
7743
  if (value.minPeople > value.maxPeople) {
7697
7744
  ctx.addIssue({
7698
- code: z40.ZodIssueCode.custom,
7745
+ code: z41.ZodIssueCode.custom,
7699
7746
  path: [
7700
7747
  "minPeople"
7701
7748
  ],
@@ -7704,7 +7751,7 @@ var SceneSubjectContractSchema = z40.object({
7704
7751
  }
7705
7752
  if (value.minDistinctPeople > value.maxPeople) {
7706
7753
  ctx.addIssue({
7707
- code: z40.ZodIssueCode.custom,
7754
+ code: z41.ZodIssueCode.custom,
7708
7755
  path: [
7709
7756
  "minDistinctPeople"
7710
7757
  ],
@@ -7713,7 +7760,7 @@ var SceneSubjectContractSchema = z40.object({
7713
7760
  }
7714
7761
  if (value.minDistinctPeople > value.minPeople) {
7715
7762
  ctx.addIssue({
7716
- code: z40.ZodIssueCode.custom,
7763
+ code: z41.ZodIssueCode.custom,
7717
7764
  path: [
7718
7765
  "minDistinctPeople"
7719
7766
  ],
@@ -7723,7 +7770,7 @@ var SceneSubjectContractSchema = z40.object({
7723
7770
  });
7724
7771
 
7725
7772
  // ../../packages/types/src/service-creative.ts
7726
- import { z as z41 } from "zod";
7773
+ import { z as z42 } from "zod";
7727
7774
  var SERVICE_CREATIVE_PUBLIC_PRESETS = [
7728
7775
  "auto",
7729
7776
  "ugc_dynamic",
@@ -7731,19 +7778,19 @@ var SERVICE_CREATIVE_PUBLIC_PRESETS = [
7731
7778
  "cinematic",
7732
7779
  "wild_card"
7733
7780
  ];
7734
- var ServiceCreativePresetSchema = z41.enum(SERVICE_CREATIVE_PUBLIC_PRESETS);
7781
+ var ServiceCreativePresetSchema = z42.enum(SERVICE_CREATIVE_PUBLIC_PRESETS);
7735
7782
  var SERVICE_REVIEW_MODES = [
7736
7783
  "automatic",
7737
7784
  "guided"
7738
7785
  ];
7739
- var ServiceReviewModeSchema = z41.enum(SERVICE_REVIEW_MODES);
7786
+ var ServiceReviewModeSchema = z42.enum(SERVICE_REVIEW_MODES);
7740
7787
  var SERVICE_HIGGSFIELD_MODES = [
7741
7788
  "product_review",
7742
7789
  "ugc_how_to",
7743
7790
  "tv_spot",
7744
7791
  "wild_card"
7745
7792
  ];
7746
- var ServiceHiggsfieldModeSchema = z41.enum(SERVICE_HIGGSFIELD_MODES);
7793
+ var ServiceHiggsfieldModeSchema = z42.enum(SERVICE_HIGGSFIELD_MODES);
7747
7794
  var SERVICE_MEDIA_ROLES = [
7748
7795
  "screen_demo",
7749
7796
  "ad_reference",
@@ -7751,20 +7798,20 @@ var SERVICE_MEDIA_ROLES = [
7751
7798
  "presenter_reference",
7752
7799
  "brand_asset"
7753
7800
  ];
7754
- var ServiceMediaRoleSchema = z41.enum(SERVICE_MEDIA_ROLES);
7755
- var ServiceMediaAssetSchema = z41.object({
7801
+ var ServiceMediaRoleSchema = z42.enum(SERVICE_MEDIA_ROLES);
7802
+ var ServiceMediaAssetSchema = z42.object({
7756
7803
  role: ServiceMediaRoleSchema,
7757
- s3Key: z41.string().min(1),
7804
+ s3Key: z42.string().min(1),
7758
7805
  /** HMAC ticket returned by the authenticated service-media presign route. */
7759
- uploadToken: z41.string().min(1).optional(),
7760
- mimeType: z41.string().min(1),
7761
- durationSec: z41.number().positive().max(30).optional(),
7762
- sourceName: z41.string().max(255).optional()
7806
+ uploadToken: z42.string().min(1).optional(),
7807
+ mimeType: z42.string().min(1),
7808
+ durationSec: z42.number().positive().max(30).optional(),
7809
+ sourceName: z42.string().max(255).optional()
7763
7810
  }).superRefine((asset, ctx) => {
7764
7811
  const isVideoRole = asset.role === "screen_demo" || asset.role === "ad_reference";
7765
7812
  if (isVideoRole && !asset.mimeType.startsWith("video/")) {
7766
7813
  ctx.addIssue({
7767
- code: z41.ZodIssueCode.custom,
7814
+ code: z42.ZodIssueCode.custom,
7768
7815
  message: `${asset.role} requires video media`,
7769
7816
  path: [
7770
7817
  "mimeType"
@@ -7773,7 +7820,7 @@ var ServiceMediaAssetSchema = z41.object({
7773
7820
  }
7774
7821
  if (isVideoRole && asset.durationSec === void 0) {
7775
7822
  ctx.addIssue({
7776
- code: z41.ZodIssueCode.custom,
7823
+ code: z42.ZodIssueCode.custom,
7777
7824
  message: `${asset.role} requires durationSec`,
7778
7825
  path: [
7779
7826
  "durationSec"
@@ -7782,7 +7829,7 @@ var ServiceMediaAssetSchema = z41.object({
7782
7829
  }
7783
7830
  if (!isVideoRole && !asset.mimeType.startsWith("image/")) {
7784
7831
  ctx.addIssue({
7785
- code: z41.ZodIssueCode.custom,
7832
+ code: z42.ZodIssueCode.custom,
7786
7833
  message: `${asset.role} requires image media`,
7787
7834
  path: [
7788
7835
  "mimeType"
@@ -7790,13 +7837,13 @@ var ServiceMediaAssetSchema = z41.object({
7790
7837
  });
7791
7838
  }
7792
7839
  });
7793
- var ServiceMediaBundleSchema = z41.object({
7794
- assets: z41.array(ServiceMediaAssetSchema).max(15).default([])
7840
+ var ServiceMediaBundleSchema = z42.object({
7841
+ assets: z42.array(ServiceMediaAssetSchema).max(15).default([])
7795
7842
  }).superRefine((bundle, ctx) => {
7796
7843
  const adReferences = bundle.assets.filter((asset) => asset.role === "ad_reference");
7797
7844
  if (adReferences.length > 5) {
7798
7845
  ctx.addIssue({
7799
- code: z41.ZodIssueCode.custom,
7846
+ code: z42.ZodIssueCode.custom,
7800
7847
  message: "A maximum of five ad_reference videos is allowed",
7801
7848
  path: [
7802
7849
  "assets"
@@ -7806,7 +7853,7 @@ var ServiceMediaBundleSchema = z41.object({
7806
7853
  const screenDemos = bundle.assets.filter((asset) => asset.role === "screen_demo");
7807
7854
  if (screenDemos.length > 3) {
7808
7855
  ctx.addIssue({
7809
- code: z41.ZodIssueCode.custom,
7856
+ code: z42.ZodIssueCode.custom,
7810
7857
  message: "A maximum of three screen_demo videos is allowed",
7811
7858
  path: [
7812
7859
  "assets"
@@ -7823,33 +7870,33 @@ var SERVICE_MEDIA_ANALYSIS_KINDS = [
7823
7870
  "product",
7824
7871
  "other"
7825
7872
  ];
7826
- var ServiceMediaAnalysisKindSchema = z41.enum(SERVICE_MEDIA_ANALYSIS_KINDS);
7827
- var ServiceMediaAnalysisItemSchema = z41.object({
7828
- assetIndex: z41.number().int().nonnegative(),
7829
- mediaType: z41.enum([
7873
+ var ServiceMediaAnalysisKindSchema = z42.enum(SERVICE_MEDIA_ANALYSIS_KINDS);
7874
+ var ServiceMediaAnalysisItemSchema = z42.object({
7875
+ assetIndex: z42.number().int().nonnegative(),
7876
+ mediaType: z42.enum([
7830
7877
  "image",
7831
7878
  "video"
7832
7879
  ]),
7833
7880
  kind: ServiceMediaAnalysisKindSchema,
7834
- description: z41.string().min(1).max(1200),
7835
- tags: z41.array(z41.string().min(1).max(80)).max(12),
7836
- suggestedRoles: z41.array(ServiceMediaRoleSchema).max(4),
7837
- visiblePeople: z41.number().int().nonnegative().max(20).optional(),
7838
- ocrText: z41.string().max(2e3).optional(),
7839
- speechSummary: z41.string().max(2e3).optional()
7840
- });
7841
- var ServiceMediaAnalysisSchema = z41.object({
7842
- version: z41.literal(1),
7843
- analyzedAt: z41.string().datetime(),
7844
- pricingAction: z41.literal("service-media-analysis"),
7845
- assetFingerprint: z41.string().regex(/^[a-f0-9]{64}$/),
7881
+ description: z42.string().min(1).max(1200),
7882
+ tags: z42.array(z42.string().min(1).max(80)).max(12),
7883
+ suggestedRoles: z42.array(ServiceMediaRoleSchema).max(4),
7884
+ visiblePeople: z42.number().int().nonnegative().max(20).optional(),
7885
+ ocrText: z42.string().max(2e3).optional(),
7886
+ speechSummary: z42.string().max(2e3).optional()
7887
+ });
7888
+ var ServiceMediaAnalysisSchema = z42.object({
7889
+ version: z42.literal(1),
7890
+ analyzedAt: z42.string().datetime(),
7891
+ pricingAction: z42.literal("service-media-analysis"),
7892
+ assetFingerprint: z42.string().regex(/^[a-f0-9]{64}$/),
7846
7893
  /** Language used for human-readable descriptions and tags. Optional for old checkpoints. */
7847
- language: z41.enum([
7894
+ language: z42.enum([
7848
7895
  "es",
7849
7896
  "en",
7850
7897
  "pt"
7851
7898
  ]).optional(),
7852
- items: z41.array(ServiceMediaAnalysisItemSchema).max(15)
7899
+ items: z42.array(ServiceMediaAnalysisItemSchema).max(15)
7853
7900
  });
7854
7901
 
7855
7902
  // ../../packages/types/src/productmaker-chat-capabilities.ts
@@ -8027,7 +8074,7 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
8027
8074
  {
8028
8075
  name: "request_meta_media_upload",
8029
8076
  confirmation: "none",
8030
- schemaHash: "32203d205f414c386ee6ab33e265eb2708c108fca4169d4c12e99d7a4109a132"
8077
+ schemaHash: "fad928b17b4658eb5831bb8b62d5e65bd5220ad94b04b90ace09e658e1895c74"
8031
8078
  },
8032
8079
  {
8033
8080
  name: "resolve_pending_action",
@@ -8043,8 +8090,8 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
8043
8090
  var PRODUCTMAKER_MCP_CAPABILITY_NAMES = PRODUCTMAKER_MCP_CAPABILITIES.map((capability) => capability.name);
8044
8091
 
8045
8092
  // ../../packages/types/src/actor.ts
8046
- import { z as z42 } from "zod";
8047
- var ActorStatusSchema = z42.enum([
8093
+ import { z as z43 } from "zod";
8094
+ var ActorStatusSchema = z43.enum([
8048
8095
  "draft",
8049
8096
  "generating",
8050
8097
  "ready",
@@ -8053,18 +8100,18 @@ var ActorStatusSchema = z42.enum([
8053
8100
  var ACTOR_NAME_MAX_CHARS = 60;
8054
8101
  var ACTOR_DESCRIPTION_MAX_CHARS = 600;
8055
8102
  var ACTOR_CANDIDATE_COUNT = 4;
8056
- var ActorGenderSchema = z42.enum([
8103
+ var ActorGenderSchema = z43.enum([
8057
8104
  "female",
8058
8105
  "male",
8059
8106
  "non_binary"
8060
8107
  ]);
8061
- var ActorSchema = z42.object({
8062
- id: z42.string(),
8063
- name: z42.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8064
- description: z42.string().max(ACTOR_DESCRIPTION_MAX_CHARS),
8108
+ var ActorSchema = z43.object({
8109
+ id: z43.string(),
8110
+ name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8111
+ description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS),
8065
8112
  gender: ActorGenderSchema,
8066
- voiceId: z42.string().nullable().optional(),
8067
- brandId: z42.string().nullable().optional(),
8113
+ voiceId: z43.string().nullable().optional(),
8114
+ brandId: z43.string().nullable().optional(),
8068
8115
  status: ActorStatusSchema,
8069
8116
  /**
8070
8117
  * A candidate-grid run is in flight RIGHT NOW.
@@ -8076,36 +8123,36 @@ var ActorSchema = z42.object({
8076
8123
  * timestamp with a TTL, so an orphaned run reads as `false` instead of
8077
8124
  * pinning the personaje forever.
8078
8125
  */
8079
- generating: z42.boolean().optional(),
8080
- photoUrl: z42.string().url().nullable().optional(),
8081
- avatarUrl: z42.string().url().nullable().optional(),
8082
- candidateUrls: z42.array(z42.string().url()).optional(),
8126
+ generating: z43.boolean().optional(),
8127
+ photoUrl: z43.string().url().nullable().optional(),
8128
+ avatarUrl: z43.string().url().nullable().optional(),
8129
+ candidateUrls: z43.array(z43.string().url()).optional(),
8083
8130
  /** Indices of candidateUrls that failed the anatomy check (Task 6). */
8084
- flaggedCandidateIndices: z42.array(z42.number().int()).optional()
8131
+ flaggedCandidateIndices: z43.array(z43.number().int()).optional()
8085
8132
  });
8086
- var CreateActorRequest = z42.object({
8087
- name: z42.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8088
- description: z42.string().max(ACTOR_DESCRIPTION_MAX_CHARS).default(""),
8133
+ var CreateActorRequest = z43.object({
8134
+ name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8135
+ description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).default(""),
8089
8136
  gender: ActorGenderSchema,
8090
- voiceId: z42.string().optional(),
8091
- brandId: z42.string().optional(),
8092
- sourcePhotoKey: z42.string().optional()
8137
+ voiceId: z43.string().optional(),
8138
+ brandId: z43.string().optional(),
8139
+ sourcePhotoKey: z43.string().optional()
8093
8140
  }).refine((v) => v.description.trim().length > 0 || !!v.sourcePhotoKey, {
8094
8141
  message: "Se necesita una descripci\xF3n o una foto"
8095
8142
  });
8096
- var UpdateActorRequest = z42.object({
8097
- name: z42.string().min(1).max(ACTOR_NAME_MAX_CHARS).optional(),
8098
- description: z42.string().max(ACTOR_DESCRIPTION_MAX_CHARS).optional(),
8143
+ var UpdateActorRequest = z43.object({
8144
+ name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS).optional(),
8145
+ description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).optional(),
8099
8146
  gender: ActorGenderSchema.optional(),
8100
- voiceId: z42.string().nullable().optional(),
8101
- brandId: z42.string().nullable().optional()
8147
+ voiceId: z43.string().nullable().optional(),
8148
+ brandId: z43.string().nullable().optional()
8102
8149
  });
8103
- var ApproveActorRequest = z42.object({
8104
- candidateIndex: z42.number().int().min(0).max(ACTOR_CANDIDATE_COUNT - 1)
8150
+ var ApproveActorRequest = z43.object({
8151
+ candidateIndex: z43.number().int().min(0).max(ACTOR_CANDIDATE_COUNT - 1)
8105
8152
  });
8106
8153
 
8107
8154
  // ../../packages/types/src/referral-dashboard.ts
8108
- import { z as z43 } from "zod";
8155
+ import { z as z44 } from "zod";
8109
8156
  var REFERRAL_DASHBOARD_RAW_STATUSES = [
8110
8157
  "ACTIVE",
8111
8158
  "PENDING",
@@ -8124,66 +8171,66 @@ var REFERRAL_DASHBOARD_PLAN_KINDS = [
8124
8171
  "last",
8125
8172
  "none"
8126
8173
  ];
8127
- var ReferralDashboardRawStatusSchema = z43.enum(REFERRAL_DASHBOARD_RAW_STATUSES);
8128
- var ReferralDashboardStateSchema = z43.enum(REFERRAL_DASHBOARD_STATES);
8129
- var ReferralDashboardPlanKindSchema = z43.enum(REFERRAL_DASHBOARD_PLAN_KINDS);
8130
- var ReferralDashboardStatusSchema = z43.enum([
8174
+ var ReferralDashboardRawStatusSchema = z44.enum(REFERRAL_DASHBOARD_RAW_STATUSES);
8175
+ var ReferralDashboardStateSchema = z44.enum(REFERRAL_DASHBOARD_STATES);
8176
+ var ReferralDashboardPlanKindSchema = z44.enum(REFERRAL_DASHBOARD_PLAN_KINDS);
8177
+ var ReferralDashboardStatusSchema = z44.enum([
8131
8178
  "all",
8132
8179
  "active",
8133
8180
  "pending",
8134
8181
  "inactive"
8135
8182
  ]).default("all");
8136
- var ReferralDashboardPlanSchema = z43.string().trim().min(1).max(100).optional();
8137
- var ReferralDashboardFiltersSchema = z43.object({
8183
+ var ReferralDashboardPlanSchema = z44.string().trim().min(1).max(100).optional();
8184
+ var ReferralDashboardFiltersSchema = z44.object({
8138
8185
  status: ReferralDashboardStatusSchema,
8139
8186
  plan: ReferralDashboardPlanSchema
8140
8187
  });
8141
- var ReferralDashboardSubscriptionSchema = z43.object({
8142
- planName: z43.string().nullable(),
8188
+ var ReferralDashboardSubscriptionSchema = z44.object({
8189
+ planName: z44.string().nullable(),
8143
8190
  planKind: ReferralDashboardPlanKindSchema,
8144
8191
  rawStatus: ReferralDashboardRawStatusSchema.nullable(),
8145
8192
  state: ReferralDashboardStateSchema,
8146
- currentPeriodEnd: z43.string().datetime({
8193
+ currentPeriodEnd: z44.string().datetime({
8147
8194
  offset: true
8148
8195
  }).nullable(),
8149
- cancelAtPeriodEnd: z43.boolean()
8196
+ cancelAtPeriodEnd: z44.boolean()
8150
8197
  });
8151
- var ReferralDashboardReferralSchema = z43.object({
8152
- id: z43.string().min(1),
8153
- registeredAt: z43.string().datetime({
8198
+ var ReferralDashboardReferralSchema = z44.object({
8199
+ id: z44.string().min(1),
8200
+ registeredAt: z44.string().datetime({
8154
8201
  offset: true
8155
8202
  }),
8156
8203
  // Kept in the response for compatibility with existing referral API clients.
8157
8204
  // The referrer dashboard intentionally does not render these legacy fields.
8158
- expiresAt: z43.string().datetime({
8205
+ expiresAt: z44.string().datetime({
8159
8206
  offset: true
8160
8207
  }).nullable().optional(),
8161
- status: z43.string().min(1).optional(),
8162
- referredUser: z43.object({
8163
- email: z43.string().nullable()
8208
+ status: z44.string().min(1).optional(),
8209
+ referredUser: z44.object({
8210
+ email: z44.string().nullable()
8164
8211
  }),
8165
8212
  subscription: ReferralDashboardSubscriptionSchema
8166
8213
  });
8167
- var ReferralDashboardReferralsPageSchema = z43.object({
8168
- referrals: z43.array(ReferralDashboardReferralSchema),
8169
- total: z43.number().int().nonnegative()
8214
+ var ReferralDashboardReferralsPageSchema = z44.object({
8215
+ referrals: z44.array(ReferralDashboardReferralSchema),
8216
+ total: z44.number().int().nonnegative()
8170
8217
  });
8171
- var ReferralDashboardPlanBreakdownSchema = z43.object({
8172
- planName: z43.string().nullable(),
8173
- count: z43.number().int().nonnegative()
8218
+ var ReferralDashboardPlanBreakdownSchema = z44.object({
8219
+ planName: z44.string().nullable(),
8220
+ count: z44.number().int().nonnegative()
8174
8221
  });
8175
- var ReferralDashboardMonthlyRegistrationSchema = z43.object({
8176
- month: z43.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
8177
- count: z43.number().int().nonnegative()
8222
+ var ReferralDashboardMonthlyRegistrationSchema = z44.object({
8223
+ month: z44.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
8224
+ count: z44.number().int().nonnegative()
8178
8225
  });
8179
- var ReferralDashboardOverviewSchema = z43.object({
8180
- totalReferredUsers: z43.number().int().nonnegative(),
8181
- activeUsers: z43.number().int().nonnegative(),
8182
- pendingUsers: z43.number().int().nonnegative(),
8183
- inactiveUsers: z43.number().int().nonnegative(),
8184
- noPlanUsers: z43.number().int().nonnegative(),
8185
- planBreakdown: z43.array(ReferralDashboardPlanBreakdownSchema),
8186
- monthlyRegistrations: z43.array(ReferralDashboardMonthlyRegistrationSchema).refine((months) => months.length === 6, "Expected six monthly registration buckets")
8226
+ var ReferralDashboardOverviewSchema = z44.object({
8227
+ totalReferredUsers: z44.number().int().nonnegative(),
8228
+ activeUsers: z44.number().int().nonnegative(),
8229
+ pendingUsers: z44.number().int().nonnegative(),
8230
+ inactiveUsers: z44.number().int().nonnegative(),
8231
+ noPlanUsers: z44.number().int().nonnegative(),
8232
+ planBreakdown: z44.array(ReferralDashboardPlanBreakdownSchema),
8233
+ monthlyRegistrations: z44.array(ReferralDashboardMonthlyRegistrationSchema).refine((months) => months.length === 6, "Expected six monthly registration buckets")
8187
8234
  });
8188
8235
 
8189
8236
  // src/resolve-media.ts
@@ -8425,10 +8472,10 @@ async function resolveMediaRef(ref, opts) {
8425
8472
  __name(resolveMediaRef, "resolveMediaRef");
8426
8473
 
8427
8474
  // src/tools/shared.ts
8428
- import { z as z44 } from "zod";
8429
- var Lang = z44.string().min(2).max(10);
8430
- var Country = z44.string().min(2).max(3);
8431
- var LandingStrategyEnum = z44.enum([
8475
+ import { z as z45 } from "zod";
8476
+ var Lang = z45.string().min(2).max(10);
8477
+ var Country = z45.string().min(2).max(3);
8478
+ var LandingStrategyEnum = z45.enum([
8432
8479
  "auto",
8433
8480
  "classic",
8434
8481
  "pain_solution",
@@ -8437,12 +8484,12 @@ var LandingStrategyEnum = z44.enum([
8437
8484
  "offer_value",
8438
8485
  "lifestyle_identity"
8439
8486
  ]);
8440
- var LandingImageFormatEnum = z44.enum([
8487
+ var LandingImageFormatEnum = z45.enum([
8441
8488
  "9:16",
8442
8489
  "4:5",
8443
8490
  "1:1"
8444
8491
  ]);
8445
- var VideoPresetEnum = z44.enum([
8492
+ var VideoPresetEnum = z45.enum([
8446
8493
  "auto",
8447
8494
  "ugc_dynamic",
8448
8495
  "ugc_how_to",
@@ -8455,7 +8502,7 @@ var VideoPresetEnum = z44.enum([
8455
8502
  "pixar_problem",
8456
8503
  "pixar_sassy"
8457
8504
  ]);
8458
- var TaskCreativeVariantVideoPresetEnum = z44.enum([
8505
+ var TaskCreativeVariantVideoPresetEnum = z45.enum([
8459
8506
  "auto",
8460
8507
  "ugc_dynamic",
8461
8508
  "ugc_how_to",
@@ -8526,7 +8573,7 @@ function resolveVideoPreset(preset) {
8526
8573
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
8527
8574
  }
8528
8575
  __name(resolveVideoPreset, "resolveVideoPreset");
8529
- var VideoTierEnum = z44.enum([
8576
+ var VideoTierEnum = z45.enum([
8530
8577
  "basic"
8531
8578
  ]);
8532
8579
  function resolveVideoTier(_tier) {
@@ -8541,17 +8588,17 @@ function resolveVideoFormatForDuration(durationSeconds) {
8541
8588
  return durationSeconds === 30 ? "double_30s" : "single_15s";
8542
8589
  }
8543
8590
  __name(resolveVideoFormatForDuration, "resolveVideoFormatForDuration");
8544
- var VideoResolutionEnum = z44.enum([
8591
+ var VideoResolutionEnum = z45.enum([
8545
8592
  "480p",
8546
8593
  "720p"
8547
8594
  ]);
8548
- var VideoStyleEnum = z44.enum([
8595
+ var VideoStyleEnum = z45.enum([
8549
8596
  "ugc",
8550
8597
  "cartoon_3d",
8551
8598
  "product_only",
8552
8599
  "ai_dynamic"
8553
8600
  ]);
8554
- var NarrativeStyleEnum = z44.enum([
8601
+ var NarrativeStyleEnum = z45.enum([
8555
8602
  "review",
8556
8603
  "ugc_how_to",
8557
8604
  "problem_product_cta",
@@ -8568,7 +8615,7 @@ var NarrativeStyleEnum = z44.enum([
8568
8615
  "ugc_skeptic_confession",
8569
8616
  "ugc_demo_review"
8570
8617
  ]);
8571
- var PublicNarrativeStyleEnum = z44.enum([
8618
+ var PublicNarrativeStyleEnum = z45.enum([
8572
8619
  "review",
8573
8620
  "ugc_how_to",
8574
8621
  "ugc_unboxing_chaos",
@@ -8580,7 +8627,7 @@ var PublicNarrativeStyleEnum = z44.enum([
8580
8627
  "animated_problem_pixar",
8581
8628
  "sassy_product_pixar"
8582
8629
  ]);
8583
- var VideoModelEnum = z44.enum([
8630
+ var VideoModelEnum = z45.enum([
8584
8631
  "veo",
8585
8632
  "wan",
8586
8633
  "bytedance",
@@ -8588,25 +8635,25 @@ var VideoModelEnum = z44.enum([
8588
8635
  "grok",
8589
8636
  "kling"
8590
8637
  ]);
8591
- var ProductReferenceUserChoiceEnum = z44.enum([
8638
+ var ProductReferenceUserChoiceEnum = z45.enum([
8592
8639
  "same_product",
8593
8640
  "variants",
8594
8641
  "different_products",
8595
8642
  "combo_distinct"
8596
8643
  ]);
8597
- var ProductReferenceCandidateGroupingEnum = z44.enum([
8644
+ var ProductReferenceCandidateGroupingEnum = z45.enum([
8598
8645
  "same_product_same_variant",
8599
8646
  "same_product_different_variants",
8600
8647
  "different_products",
8601
8648
  "unclear"
8602
8649
  ]);
8603
- var GapDurationChoiceMirror = z44.object({
8604
- angleIndex: z44.number().int().nonnegative(),
8605
- recommendedSec: z44.union([
8606
- z44.literal(15),
8607
- z44.literal(30)
8650
+ var GapDurationChoiceMirror = z45.object({
8651
+ angleIndex: z45.number().int().nonnegative(),
8652
+ recommendedSec: z45.union([
8653
+ z45.literal(15),
8654
+ z45.literal(30)
8608
8655
  ]),
8609
- estimatedDeltaCredits: z44.number().int().nonnegative().optional()
8656
+ estimatedDeltaCredits: z45.number().int().nonnegative().optional()
8610
8657
  });
8611
8658
  function buildSelectedImageUrlsHash(urls) {
8612
8659
  const input = [
@@ -8620,13 +8667,13 @@ function buildSelectedImageUrlsHash(urls) {
8620
8667
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
8621
8668
  }
8622
8669
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
8623
- var ImageCreativeStyleEnum = z44.enum([
8670
+ var ImageCreativeStyleEnum = z45.enum([
8624
8671
  "studio",
8625
8672
  "floating",
8626
8673
  "ingredients",
8627
8674
  "in_use"
8628
8675
  ]);
8629
- var ImageCreativeArchetypeEnum = z44.enum([
8676
+ var ImageCreativeArchetypeEnum = z45.enum([
8630
8677
  "direct_response_product_ad",
8631
8678
  "hero_outcome",
8632
8679
  "offer_value_prop",
@@ -8635,23 +8682,23 @@ var ImageCreativeArchetypeEnum = z44.enum([
8635
8682
  "problem_solution",
8636
8683
  "lifestyle_identity"
8637
8684
  ]);
8638
- var ImageCreativeVisualTreatmentEnum = z44.enum([
8685
+ var ImageCreativeVisualTreatmentEnum = z45.enum([
8639
8686
  "performance_product_ad",
8640
8687
  "premium_dtc_carousel"
8641
8688
  ]);
8642
- var ImageCreativeAspectRatioEnum = z44.enum([
8689
+ var ImageCreativeAspectRatioEnum = z45.enum([
8643
8690
  "1:1",
8644
8691
  "4:5",
8645
8692
  "9:16",
8646
8693
  "16:9"
8647
8694
  ]);
8648
- var ImageRefSchema = z44.object({
8649
- url: z44.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.'),
8650
- path: z44.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`.')
8695
+ var ImageRefSchema = z45.object({
8696
+ url: z45.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.'),
8697
+ path: z45.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`.')
8651
8698
  }).refine((v) => Boolean(v.url) !== Boolean(v.path), {
8652
8699
  message: "each image entry must have exactly one of `url` or `path`"
8653
8700
  });
8654
- var ImagesInput = z44.array(ImageRefSchema).min(1).max(5).describe('1 a 5 fotos del MISMO producto. La PRIMERA es la principal (hero); las dem\xE1s son \xE1ngulos adicionales. NO mezcles productos distintos en una sola llamada.\n\nCada entrada tiene EXACTAMENTE uno de:\n\u2022 `url` \u2014 URL p\xFAblica HTTPS (Shopify CDN, Cloudinary). Prefi\xE9rela si la foto ya est\xE1 hospedada.\n\u2022 `path` \u2014 Ruta del archivo en el computador del usuario (ej. "/Users/maria/Desktop/foto.jpg", "~/Downloads/camiseta.png"). \xDAsala cuando el usuario te dijo d\xF3nde guard\xF3 la foto. Solo MCP local \u2014 el cliente web rechaza paths.\n\nSi el usuario te peg\xF3 la foto en el chat pero no te dio ni URL ni ruta: PREG\xDANTALE d\xF3nde la tiene guardada (Escritorio, Descargas, etc.). Si el `path` falla con IMAGE_PATH_NOT_FOUND, prueba 1-2 ubicaciones obvias alternativas (~/Desktop, ~/Downloads) antes de molestar al usuario. Tras 3 intentos fallidos, p\xEDdele la ruta completa.');
8701
+ var ImagesInput = z45.array(ImageRefSchema).min(1).max(5).describe('1 a 5 fotos del MISMO producto. La PRIMERA es la principal (hero); las dem\xE1s son \xE1ngulos adicionales. NO mezcles productos distintos en una sola llamada.\n\nCada entrada tiene EXACTAMENTE uno de:\n\u2022 `url` \u2014 URL p\xFAblica HTTPS (Shopify CDN, Cloudinary). Prefi\xE9rela si la foto ya est\xE1 hospedada.\n\u2022 `path` \u2014 Ruta del archivo en el computador del usuario (ej. "/Users/maria/Desktop/foto.jpg", "~/Downloads/camiseta.png"). \xDAsala cuando el usuario te dijo d\xF3nde guard\xF3 la foto. Solo MCP local \u2014 el cliente web rechaza paths.\n\nSi el usuario te peg\xF3 la foto en el chat pero no te dio ni URL ni ruta: PREG\xDANTALE d\xF3nde la tiene guardada (Escritorio, Descargas, etc.). Si el `path` falla con IMAGE_PATH_NOT_FOUND, prueba 1-2 ubicaciones obvias alternativas (~/Desktop, ~/Downloads) antes de molestar al usuario. Tras 3 intentos fallidos, p\xEDdele la ruta completa.');
8655
8702
  function asText(value) {
8656
8703
  return {
8657
8704
  content: [
@@ -8704,14 +8751,14 @@ async function submitCreative(api, opts) {
8704
8751
  });
8705
8752
  }
8706
8753
  __name(submitCreative, "submitCreative");
8707
- var ResearchTargetCountryEnum = z44.enum([
8754
+ var ResearchTargetCountryEnum = z45.enum([
8708
8755
  "CO",
8709
8756
  "MX",
8710
8757
  "PE",
8711
8758
  "EC",
8712
8759
  "CL"
8713
8760
  ]);
8714
- var ResearchCategoryEnum = z44.enum([
8761
+ var ResearchCategoryEnum = z45.enum([
8715
8762
  "auto",
8716
8763
  "automotive",
8717
8764
  "kitchen",
@@ -9356,53 +9403,53 @@ function renderOutputsMarkdown(outputs) {
9356
9403
  __name(renderOutputsMarkdown, "renderOutputsMarkdown");
9357
9404
 
9358
9405
  // src/tools/tasks.ts
9359
- var CreateProductTaskInput = z45.object({
9406
+ var CreateProductTaskInput = z46.object({
9360
9407
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
9361
- projectId: z45.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
9362
- productUrl: z45.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."),
9408
+ projectId: z46.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
9409
+ productUrl: z46.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."),
9363
9410
  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.'),
9364
9411
  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.'),
9365
- price: z45.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.'),
9366
- compareAtPrice: z45.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".'),
9367
- offer: z45.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.'),
9368
- paymentMethods: z45.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.'),
9369
- productContext: z45.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."),
9370
- productLabel: z45.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.'),
9412
+ price: z46.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.'),
9413
+ compareAtPrice: z46.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".'),
9414
+ offer: z46.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.'),
9415
+ paymentMethods: z46.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.'),
9416
+ productContext: z46.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."),
9417
+ productLabel: z46.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.'),
9371
9418
  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). 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" (una regla visual experimental original), "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.'),
9372
- durationSeconds: z45.union([
9373
- z45.literal(15),
9374
- z45.literal(30)
9419
+ durationSeconds: z46.union([
9420
+ z46.literal(15),
9421
+ z46.literal(30)
9375
9422
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
9376
- pauseForAngleReview: z45.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo para que el usuario lo confirme o edite antes del render. \xDAsalo si quiere decidir 15/30s cuando aparezca un winner. Default false."),
9423
+ pauseForAngleReview: z46.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo para que el usuario lo confirme o edite antes del render. \xDAsalo si quiere decidir 15/30s cuando aparezca un winner. Default false."),
9377
9424
  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.'),
9378
9425
  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).'),
9379
- multiAngleVideos: z45.boolean().optional().describe("Opcional. Si true, genera m\xFAltiples \xE1ngulos de venta en paralelo (3-5 videos). Si false/omitido, genera 1 video del \xE1ngulo principal. Default false."),
9426
+ multiAngleVideos: z46.boolean().optional().describe("Opcional. Si true, genera m\xFAltiples \xE1ngulos de venta en paralelo (3-5 videos). Si false/omitido, genera 1 video del \xE1ngulo principal. Default false."),
9380
9427
  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". angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. Requiere multiAngleVideos:true para varios \xE1ngulos.'),
9381
- outputs: z45.array(z45.enum([
9428
+ outputs: z46.array(z46.enum([
9382
9429
  "landing",
9383
9430
  "video",
9384
9431
  "image"
9385
9432
  ])).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). Para 1 solo output, usa generate_landing / generate_video_creative / generate_image_creatives.'),
9386
- competitorScanEnabled: z45.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true."),
9387
- brandId: z45.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."),
9388
- actorId: z45.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."),
9389
- creativeDirection: z45.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.'),
9390
- headline: z45.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."),
9391
- subheadline: z45.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."),
9433
+ competitorScanEnabled: z46.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true."),
9434
+ brandId: z46.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."),
9435
+ actorId: z46.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."),
9436
+ creativeDirection: z46.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.'),
9437
+ headline: z46.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."),
9438
+ subheadline: z46.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."),
9392
9439
  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".'),
9393
9440
  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".')
9394
9441
  }).strict();
9395
- var CreateServiceVideoInput = z45.object({
9396
- landingUrl: z45.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
9397
- additionalContext: z45.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
9442
+ var CreateServiceVideoInput = z46.object({
9443
+ landingUrl: z46.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
9444
+ additionalContext: z46.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
9398
9445
  language: Lang.describe("Idioma del video: es, en o pt."),
9399
- voiceId: z45.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.'),
9400
- brandId: z45.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
9401
- reviewMode: z45.enum([
9446
+ voiceId: z46.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.'),
9447
+ brandId: z46.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
9448
+ reviewMode: z46.enum([
9402
9449
  "automatic",
9403
9450
  "guided"
9404
9451
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
9405
- videoPreset: z45.enum([
9452
+ videoPreset: z46.enum([
9406
9453
  "auto",
9407
9454
  "ugc_dynamic",
9408
9455
  "ugc_how_to",
@@ -9410,35 +9457,35 @@ var CreateServiceVideoInput = z45.object({
9410
9457
  "wild_card"
9411
9458
  ]).default("auto")
9412
9459
  }).strict();
9413
- var GetTaskStatusInput = z45.object({
9414
- taskId: z45.string().min(1),
9415
- waitSeconds: z45.number().int().min(0).max(120).optional()
9416
- });
9417
- var ListTasksInput = z45.object({
9418
- limit: z45.number().int().min(1).max(50).optional(),
9419
- offset: z45.number().int().min(0).optional(),
9420
- search: z45.string().optional()
9421
- });
9422
- var EditTaskDraftInput = z45.object({
9423
- taskId: z45.string().min(1),
9424
- angleIndex: z45.number().int().min(0),
9425
- angle: z45.object({
9426
- angle: z45.string().min(1).max(480),
9427
- buyerPersona: z45.string().min(1).max(360),
9428
- actor: z45.string().min(1).max(360).optional(),
9429
- actorId: z45.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."),
9430
- gender: z45.enum([
9460
+ var GetTaskStatusInput = z46.object({
9461
+ taskId: z46.string().min(1),
9462
+ waitSeconds: z46.number().int().min(0).max(120).optional()
9463
+ });
9464
+ var ListTasksInput = z46.object({
9465
+ limit: z46.number().int().min(1).max(50).optional(),
9466
+ offset: z46.number().int().min(0).optional(),
9467
+ search: z46.string().optional()
9468
+ });
9469
+ var EditTaskDraftInput = z46.object({
9470
+ taskId: z46.string().min(1),
9471
+ angleIndex: z46.number().int().min(0),
9472
+ angle: z46.object({
9473
+ angle: z46.string().min(1).max(480),
9474
+ buyerPersona: z46.string().min(1).max(360),
9475
+ actor: z46.string().min(1).max(360).optional(),
9476
+ actorId: z46.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."),
9477
+ gender: z46.enum([
9431
9478
  "female",
9432
9479
  "male"
9433
9480
  ]).optional(),
9434
- scriptNotes: z45.string().max(2e3).optional()
9481
+ scriptNotes: z46.string().max(2e3).optional()
9435
9482
  })
9436
9483
  });
9437
- var PendingActionPayload = z45.discriminatedUnion("kind", [
9438
- z45.object({
9439
- kind: z45.literal("product_reference_confirmation"),
9484
+ var PendingActionPayload = z46.discriminatedUnion("kind", [
9485
+ z46.object({
9486
+ kind: z46.literal("product_reference_confirmation"),
9440
9487
  userChoice: ProductReferenceUserChoiceEnum,
9441
- confirmedProductNames: z45.array(z45.string().min(1).max(120)).min(2).max(8).optional(),
9488
+ confirmedProductNames: z46.array(z46.string().min(1).max(120)).min(2).max(8).optional(),
9442
9489
  // SCOPED multi-scene opt-in — the ONLY way STANDARD ("Multiescena") is
9443
9490
  // reachable via MCP. Valid ONLY together with userChoice='variants' (same
9444
9491
  // product in several colors): renders one shot per color and stitches them,
@@ -9449,50 +9496,50 @@ var PendingActionPayload = z45.discriminatedUnion("kind", [
9449
9496
  // safe because multi-scene IS the intended render for a color variant set,
9450
9497
  // not a blind quality upsell. Maps to `videoTier: 'standard'` on the
9451
9498
  // confirm call; the backend re-gates it (variants + variant_set only).
9452
- useMultiSceneShowcase: z45.boolean().optional().describe('Opcional (SOLO con userChoice="variants"). true = render Multiescena: una toma por color, mostrando todas las variantes, hasta 30s. Se factura POR ESCENA (m\xE1s caro que el render normal de una sola toma) \u2014 AV\xCDSALE del mayor costo al usuario antes de activarlo. Omitir = render est\xE1ndar de una sola toma. Se ignora si userChoice no es "variants".')
9499
+ useMultiSceneShowcase: z46.boolean().optional().describe('Opcional (SOLO con userChoice="variants"). true = render Multiescena: una toma por color, mostrando todas las variantes, hasta 30s. Se factura POR ESCENA (m\xE1s caro que el render normal de una sola toma) \u2014 AV\xCDSALE del mayor costo al usuario antes de activarlo. Omitir = render est\xE1ndar de una sola toma. Se ignora si userChoice no es "variants".')
9453
9500
  }),
9454
- z45.object({
9455
- kind: z45.literal("angle_review_approval"),
9501
+ z46.object({
9502
+ kind: z46.literal("angle_review_approval"),
9456
9503
  // All edits are optional — empty action body just approves the
9457
9504
  // backend-generated draft as-is. Field shapes mirror the angle-review
9458
9505
  // request contracts in @packages/types/wizard.ts; the handler routes to
9459
9506
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
9460
- customAngle: z45.string().min(1).max(480).optional(),
9507
+ customAngle: z46.string().min(1).max(480).optional(),
9461
9508
  // Keep the shared MCP action within the strictest downstream contract:
9462
9509
  // autopilot/image resume endpoints cap these fields at 1500 characters.
9463
- painPoints: z45.string().max(1500).optional(),
9464
- benefits: z45.string().max(1500).optional(),
9465
- features: z45.array(z45.string().min(1).max(300)).max(10).optional(),
9466
- gapDurationSeconds: z45.union([
9467
- z45.literal(15),
9468
- z45.literal(30)
9510
+ painPoints: z46.string().max(1500).optional(),
9511
+ benefits: z46.string().max(1500).optional(),
9512
+ features: z46.array(z46.string().min(1).max(300)).max(10).optional(),
9513
+ gapDurationSeconds: z46.union([
9514
+ z46.literal(15),
9515
+ z46.literal(30)
9469
9516
  ]).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.")
9470
9517
  }),
9471
- z45.object({
9472
- kind: z45.literal("service_angle_approval"),
9473
- angleId: z45.string().uuid(),
9474
- content: z45.string().min(1).max(480).optional(),
9475
- creativeDirection: z45.string().min(1).max(1500).optional(),
9476
- actor: z45.string().min(1).max(360).optional()
9518
+ z46.object({
9519
+ kind: z46.literal("service_angle_approval"),
9520
+ angleId: z46.string().uuid(),
9521
+ content: z46.string().min(1).max(480).optional(),
9522
+ creativeDirection: z46.string().min(1).max(1500).optional(),
9523
+ actor: z46.string().min(1).max(360).optional()
9477
9524
  }),
9478
- z45.object({
9479
- kind: z45.literal("service_script_approval"),
9480
- voiceovers: z45.record(z45.string(), z45.string().min(1).max(600)).optional(),
9481
- visualDirections: z45.record(z45.string(), z45.string().min(1).max(1200)).optional()
9525
+ z46.object({
9526
+ kind: z46.literal("service_script_approval"),
9527
+ voiceovers: z46.record(z46.string(), z46.string().min(1).max(600)).optional(),
9528
+ visualDirections: z46.record(z46.string(), z46.string().min(1).max(1200)).optional()
9482
9529
  })
9483
9530
  ]);
9484
- var ResolvePendingActionInput = z45.object({
9485
- taskId: z45.string().min(1),
9531
+ var ResolvePendingActionInput = z46.object({
9532
+ taskId: z46.string().min(1),
9486
9533
  action: PendingActionPayload
9487
9534
  }).strict();
9488
9535
  function resolveVariantConfirmVideoTier(action) {
9489
9536
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
9490
9537
  }
9491
9538
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
9492
- var StatusForResolveSchema = z45.object({
9539
+ var StatusForResolveSchema = z46.object({
9493
9540
  // Metadata used to select the backend resume contract. Older API responses
9494
9541
  // may omit these fields, so the resolver keeps the generic fallback.
9495
- kind: z45.enum([
9542
+ kind: z46.enum([
9496
9543
  "autopilot",
9497
9544
  "video",
9498
9545
  "image",
@@ -9500,24 +9547,24 @@ var StatusForResolveSchema = z45.object({
9500
9547
  "mix",
9501
9548
  "service"
9502
9549
  ]).optional(),
9503
- selectedOutputs: z45.array(z45.enum([
9550
+ selectedOutputs: z46.array(z46.enum([
9504
9551
  "landing",
9505
9552
  "video",
9506
9553
  "image"
9507
9554
  ])).optional(),
9508
- videoAngleCount: z45.number().int().min(1).max(3).optional(),
9509
- ugcFormat: z45.enum([
9555
+ videoAngleCount: z46.number().int().min(1).max(3).optional(),
9556
+ ugcFormat: z46.enum([
9510
9557
  "single_8s",
9511
9558
  "single_15s",
9512
9559
  "double_30s"
9513
9560
  ]).optional(),
9514
- videoStyle: z45.enum([
9561
+ videoStyle: z46.enum([
9515
9562
  "ugc",
9516
9563
  "cartoon_3d",
9517
9564
  "product_only",
9518
9565
  "ai_dynamic"
9519
9566
  ]).optional(),
9520
- videoModel: z45.enum([
9567
+ videoModel: z46.enum([
9521
9568
  "veo",
9522
9569
  "wan",
9523
9570
  "bytedance",
@@ -9525,26 +9572,26 @@ var StatusForResolveSchema = z45.object({
9525
9572
  "grok",
9526
9573
  "kling"
9527
9574
  ]).optional(),
9528
- videoTier: z45.enum([
9575
+ videoTier: z46.enum([
9529
9576
  "legacy",
9530
9577
  "standard",
9531
9578
  "pro",
9532
9579
  "single_call"
9533
9580
  ]).optional(),
9534
- videoResolution: z45.enum([
9581
+ videoResolution: z46.enum([
9535
9582
  "480p",
9536
9583
  "720p"
9537
9584
  ]).optional(),
9538
9585
  narrativeStyle: NarrativeStyleEnum.optional(),
9539
- pendingUserAction: z45.object({
9540
- kind: z45.string(),
9541
- candidateGrouping: z45.string().optional(),
9542
- selectedImageUrls: z45.array(z45.string()).optional(),
9543
- proposedProductNames: z45.array(z45.string()).optional(),
9544
- customAngleDraft: z45.string().optional(),
9545
- painPointsDraft: z45.string().optional(),
9546
- benefitsDraft: z45.string().optional(),
9547
- featuresDraft: z45.array(z45.string()).optional(),
9586
+ pendingUserAction: z46.object({
9587
+ kind: z46.string(),
9588
+ candidateGrouping: z46.string().optional(),
9589
+ selectedImageUrls: z46.array(z46.string()).optional(),
9590
+ proposedProductNames: z46.array(z46.string()).optional(),
9591
+ customAngleDraft: z46.string().optional(),
9592
+ painPointsDraft: z46.string().optional(),
9593
+ benefitsDraft: z46.string().optional(),
9594
+ featuresDraft: z46.array(z46.string()).optional(),
9548
9595
  // Recommendation consumed only when the caller explicitly sends
9549
9596
  // gapDurationSeconds: 30 in the angle approval action.
9550
9597
  gapDurationChoice: GapDurationChoiceMirror.optional(),
@@ -9553,17 +9600,17 @@ var StatusForResolveSchema = z45.object({
9553
9600
  // keys. `actorId` (the saved custom actor the picker stored) was silently
9554
9601
  // dropped here, so the approval handler below could not echo it back on the
9555
9602
  // PATCH — the selection looked accepted and reached no render.
9556
- angles: z45.array(z45.object({
9557
- id: z45.string().uuid(),
9558
- content: z45.string(),
9559
- creativeDirection: z45.string(),
9560
- actor: z45.string(),
9561
- actorId: z45.string().nullable().optional()
9603
+ angles: z46.array(z46.object({
9604
+ id: z46.string().uuid(),
9605
+ content: z46.string(),
9606
+ creativeDirection: z46.string(),
9607
+ actor: z46.string(),
9608
+ actorId: z46.string().nullable().optional()
9562
9609
  }).passthrough()).optional(),
9563
- panels: z45.array(z45.object({
9564
- beatId: z45.string(),
9565
- voiceover: z45.string(),
9566
- visualDirection: z45.string()
9610
+ panels: z46.array(z46.object({
9611
+ beatId: z46.string(),
9612
+ voiceover: z46.string(),
9613
+ visualDirection: z46.string()
9567
9614
  }).passthrough()).optional()
9568
9615
  }).optional()
9569
9616
  }).passthrough();
@@ -10003,58 +10050,58 @@ __name(registerTaskTools, "registerTaskTools");
10003
10050
 
10004
10051
  // src/tools/creatives.ts
10005
10052
  import { randomUUID } from "crypto";
10006
- import { z as z46 } from "zod";
10053
+ import { z as z47 } from "zod";
10007
10054
  var CreativeRefs = {
10008
10055
  images: ImagesInput,
10009
10056
  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.'),
10010
10057
  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.'),
10011
- price: z46.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.'),
10012
- offer: z46.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.'),
10013
- compareAtPrice: z46.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
10014
- paymentMethods: z46.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago a mostrar. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
10015
- productContext: z46.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."),
10016
- productLabel: z46.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.'),
10017
- buyerPersona: z46.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.'),
10018
- isCombo: z46.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
10019
- competitorScanEnabled: z46.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true."),
10020
- brandId: z46.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."),
10021
- projectId: z46.string().uuid().optional().describe("Opcional. ID de un proyecto guiado de dropshipping activo del usuario. Enlaza esta generaci\xF3n con su progreso y recompensas."),
10022
- creativeDirection: z46.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Aplica SOLO a im\xE1genes y landing. Ej. im\xE1genes: "amarillo, azul y rojo, minimalista"; landing: "elegante, paleta fr\xEDa". Para video usa scriptNotes (ambiente/escenario). M\xE1x 500 caracteres.'),
10023
- headline: z46.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar en la imagen (o en la portada de la landing). Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
10024
- subheadline: z46.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.")
10058
+ price: z47.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.'),
10059
+ offer: z47.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.'),
10060
+ compareAtPrice: z47.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
10061
+ paymentMethods: z47.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago a mostrar. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
10062
+ productContext: z47.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."),
10063
+ productLabel: z47.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.'),
10064
+ buyerPersona: z47.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.'),
10065
+ isCombo: z47.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
10066
+ competitorScanEnabled: z47.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true."),
10067
+ brandId: z47.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."),
10068
+ projectId: z47.string().uuid().optional().describe("Opcional. ID de un proyecto guiado de dropshipping activo del usuario. Enlaza esta generaci\xF3n con su progreso y recompensas."),
10069
+ creativeDirection: z47.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Aplica SOLO a im\xE1genes y landing. Ej. im\xE1genes: "amarillo, azul y rojo, minimalista"; landing: "elegante, paleta fr\xEDa". Para video usa scriptNotes (ambiente/escenario). M\xE1x 500 caracteres.'),
10070
+ headline: z47.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar en la imagen (o en la portada de la landing). Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
10071
+ subheadline: z47.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.")
10025
10072
  };
10026
- var VideoInput = z46.object({
10073
+ var VideoInput = z47.object({
10027
10074
  images: CreativeRefs.images,
10028
- title: z46.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
10029
- primaryAngle: z46.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".'),
10075
+ title: z47.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
10076
+ primaryAngle: z47.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".'),
10030
10077
  language: CreativeRefs.language,
10031
10078
  country: CreativeRefs.country,
10032
- aspectRatio: z46.enum([
10079
+ aspectRatio: z47.enum([
10033
10080
  "9:16",
10034
10081
  "16:9",
10035
10082
  "Auto"
10036
10083
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
10037
- durationSeconds: z46.union([
10038
- z46.literal(15),
10039
- z46.literal(30)
10084
+ durationSeconds: z47.union([
10085
+ z47.literal(15),
10086
+ z47.literal(30)
10040
10087
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
10041
10088
  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). 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" (una regla visual experimental original), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla).'),
10042
10089
  videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video. "basic" = "Realista"; para durationSeconds=30 el sistema selecciona internamente Multiescena. No se expone el tier interno directamente.'),
10043
10090
  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).'),
10044
- features: z46.array(z46.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
10091
+ features: z47.array(z47.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
10045
10092
  price: CreativeRefs.price,
10046
10093
  offer: CreativeRefs.offer,
10047
10094
  productContext: CreativeRefs.productContext,
10048
10095
  productLabel: CreativeRefs.productLabel,
10049
- cta: z46.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.'),
10050
- scriptNotes: z46.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 \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
10051
- pauseForVideoScriptReview: z46.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
10052
- pauseForAngleReview: z46.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo para que el usuario lo confirme o edite antes del render. Default false."),
10096
+ cta: z47.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.'),
10097
+ scriptNotes: z47.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 \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
10098
+ pauseForVideoScriptReview: z47.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
10099
+ pauseForAngleReview: z47.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo para que el usuario lo confirme o edite antes del render. Default false."),
10053
10100
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
10054
10101
  brandId: CreativeRefs.brandId,
10055
10102
  projectId: CreativeRefs.projectId
10056
10103
  }).strict();
10057
- var FreeVideoQualityEnum = z46.enum([
10104
+ var FreeVideoQualityEnum = z47.enum([
10058
10105
  "economical",
10059
10106
  "high_detail"
10060
10107
  ]);
@@ -10076,38 +10123,38 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
10076
10123
  15
10077
10124
  ]
10078
10125
  };
10079
- var FreeVideoInput = z46.object({
10126
+ var FreeVideoInput = z47.object({
10080
10127
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
10081
- rawPrompt: z46.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."),
10128
+ rawPrompt: z47.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."),
10082
10129
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economical" = Econ\xF3mico o "high_detail" = Alto detalle.'),
10083
- durationSeconds: z46.number().int().min(1).max(15).describe("Duraci\xF3n exacta. Econ\xF3mico permite 6, 8, 10 o 15s; Alto detalle permite 4, 8, 12 o 15s."),
10130
+ durationSeconds: z47.number().int().min(1).max(15).describe("Duraci\xF3n exacta. Econ\xF3mico permite 6, 8, 10 o 15s; Alto detalle permite 4, 8, 12 o 15s."),
10084
10131
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
10085
- generateAiMusic: z46.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
10086
- addSubtitles: z46.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
10087
- idempotencyKey: z46.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.")
10132
+ generateAiMusic: z47.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
10133
+ addSubtitles: z47.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
10134
+ idempotencyKey: z47.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.")
10088
10135
  }).strict();
10089
10136
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
10090
10137
  var archetypeList = ImageCreativeArchetypeEnum.options.join(" | ");
10091
10138
  var visualTreatmentList = ImageCreativeVisualTreatmentEnum.options.join(" | ");
10092
10139
  var aspectRatioList = ImageCreativeAspectRatioEnum.options.join(" | ");
10093
- var ImageInput = z46.object({
10140
+ var ImageInput = z47.object({
10094
10141
  images: CreativeRefs.images,
10095
- productTitle: z46.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
10096
- primaryAngle: z46.string().min(1).describe('\xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas".'),
10142
+ productTitle: z47.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
10143
+ primaryAngle: z47.string().min(1).describe('\xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas".'),
10097
10144
  buyerPersona: CreativeRefs.buyerPersona,
10098
10145
  language: CreativeRefs.language,
10099
10146
  country: CreativeRefs.country,
10100
- nVariants: z46.number().int().min(1).max(6).optional().describe("Opcional. N\xFAmero de variantes a generar (1-6). Default 3."),
10101
- imageModel: z46.string().optional().describe('Opcional. Modelo de imagen. Ej. "gpt-image-2", "nano-banana-2". Om\xEDtelo para usar el default optimizado por costo/calidad.'),
10147
+ nVariants: z47.number().int().min(1).max(6).optional().describe("Opcional. N\xFAmero de variantes a generar (1-6). Default 3."),
10148
+ imageModel: z47.string().optional().describe('Opcional. Modelo de imagen. Ej. "gpt-image-2", "nano-banana-2". Om\xEDtelo para usar el default optimizado por costo/calidad.'),
10102
10149
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
10103
10150
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe(`Opcional. Arquetipo CRO de la composici\xF3n. Valores: ${archetypeList}. Si se omite, la IA escoge seg\xFAn \xE1ngulo+oferta (ej. "offer_value_prop" cuando hay descuento, "social_proof_trust" cuando el \xE1ngulo es testimonial).`),
10104
10151
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe(`Opcional. Tratamiento gr\xE1fico. Valores: ${visualTreatmentList} ("performance_product_ad" = dealer-style alto CTR para Meta/TikTok ads; "premium_dtc_carousel" = fotograf\xEDa limpia estilo Allbirds/Glossier). Si se omite, la IA escoge.`),
10105
- styleMix: z46.boolean().optional().describe("Opcional. Si true, las N variantes mezclan distintos imageStyle para A/B test. Si false/omitido, todas comparten estilo. Default false."),
10152
+ styleMix: z47.boolean().optional().describe("Opcional. Si true, las N variantes mezclan distintos imageStyle para A/B test. Si false/omitido, todas comparten estilo. Default false."),
10106
10153
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe(`Opcional. Relaci\xF3n de aspecto. Valores: ${aspectRatioList}. Default "4:5" (vertical Instagram feed).`),
10107
- generateAdCopy: z46.boolean().optional().describe("Opcional. Si true, tambi\xE9n genera headline/body/CTA para el ad. Default false."),
10108
- pauseForAngleReview: z46.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo y antes de las im\xE1genes para que el usuario edite v\xEDa edit_task_draft. Default false."),
10109
- features: z46.array(z46.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
10110
- brandColors: z46.array(z46.string()).optional().describe('Opcional. Paleta de marca en hex. Ej. ["#FF6B35", "#004E89"]. Si se omite, la IA elige seg\xFAn el producto.'),
10154
+ generateAdCopy: z47.boolean().optional().describe("Opcional. Si true, tambi\xE9n genera headline/body/CTA para el ad. Default false."),
10155
+ pauseForAngleReview: z47.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo y antes de las im\xE1genes para que el usuario edite v\xEDa edit_task_draft. Default false."),
10156
+ features: z47.array(z47.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
10157
+ brandColors: z47.array(z47.string()).optional().describe('Opcional. Paleta de marca en hex. Ej. ["#FF6B35", "#004E89"]. Si se omite, la IA elige seg\xFAn el producto.'),
10111
10158
  price: CreativeRefs.price,
10112
10159
  compareAtPrice: CreativeRefs.compareAtPrice,
10113
10160
  offer: CreativeRefs.offer,
@@ -10121,16 +10168,16 @@ var ImageInput = z46.object({
10121
10168
  headline: CreativeRefs.headline,
10122
10169
  subheadline: CreativeRefs.subheadline
10123
10170
  });
10124
- var EditImageCreativeInput = z46.object({
10125
- taskId: z46.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
10126
- variantIndex: z46.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
10127
- instruction: z46.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".')
10171
+ var EditImageCreativeInput = z47.object({
10172
+ taskId: z47.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
10173
+ variantIndex: z47.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
10174
+ instruction: z47.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".')
10128
10175
  });
10129
- var LandingInput = z46.object({
10176
+ var LandingInput = z47.object({
10130
10177
  images: CreativeRefs.images,
10131
10178
  language: CreativeRefs.language,
10132
10179
  country: CreativeRefs.country,
10133
- salesAngle: z46.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.'),
10180
+ salesAngle: z47.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.'),
10134
10181
  buyerPersona: CreativeRefs.buyerPersona,
10135
10182
  price: CreativeRefs.price,
10136
10183
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -10255,8 +10302,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
10255
10302
  __name(registerCreativeTools, "registerCreativeTools");
10256
10303
 
10257
10304
  // src/tools/creative-variants.ts
10258
- import { z as z47 } from "zod";
10259
- var LandingSectionKeyEnum = z47.enum([
10305
+ import { z as z48 } from "zod";
10306
+ var LandingSectionKeyEnum = z48.enum([
10260
10307
  "problem_hook",
10261
10308
  "problem_cost",
10262
10309
  "solution_mechanism",
@@ -10296,24 +10343,24 @@ var LandingSectionKeyEnum = z47.enum([
10296
10343
  "lifestyle_fit",
10297
10344
  "join_lifestyle"
10298
10345
  ]);
10299
- var CreativeVariantKindEnum = z47.enum([
10346
+ var CreativeVariantKindEnum = z48.enum([
10300
10347
  "video",
10301
10348
  "image",
10302
10349
  "landing"
10303
10350
  ]);
10304
- var EstimateCreativeVariantInputBase = z47.object({
10305
- sourceTaskId: z47.string().uuid().describe("ID de la tarea original completada."),
10351
+ var EstimateCreativeVariantInputBase = z48.object({
10352
+ sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
10306
10353
  kind: CreativeVariantKindEnum,
10307
10354
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
10308
10355
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
10309
- nVariants: z47.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10356
+ nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10310
10357
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
10311
- instructions: z47.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.")
10358
+ instructions: z48.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.")
10312
10359
  }).strict();
10313
10360
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
10314
10361
  if (input.kind === "video" && input.nVariants !== void 0) {
10315
10362
  ctx.addIssue({
10316
- code: z47.ZodIssueCode.custom,
10363
+ code: z48.ZodIssueCode.custom,
10317
10364
  path: [
10318
10365
  "nVariants"
10319
10366
  ],
@@ -10323,7 +10370,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10323
10370
  if (input.kind !== "video") {
10324
10371
  if (input.videoPreset !== void 0) {
10325
10372
  ctx.addIssue({
10326
- code: z47.ZodIssueCode.custom,
10373
+ code: z48.ZodIssueCode.custom,
10327
10374
  path: [
10328
10375
  "videoPreset"
10329
10376
  ],
@@ -10332,7 +10379,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10332
10379
  }
10333
10380
  if (input.videoResolution !== void 0) {
10334
10381
  ctx.addIssue({
10335
- code: z47.ZodIssueCode.custom,
10382
+ code: z48.ZodIssueCode.custom,
10336
10383
  path: [
10337
10384
  "videoResolution"
10338
10385
  ],
@@ -10342,7 +10389,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10342
10389
  }
10343
10390
  if (input.kind !== "image" && input.nVariants !== void 0) {
10344
10391
  ctx.addIssue({
10345
- code: z47.ZodIssueCode.custom,
10392
+ code: z48.ZodIssueCode.custom,
10346
10393
  path: [
10347
10394
  "nVariants"
10348
10395
  ],
@@ -10352,7 +10399,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10352
10399
  if (input.kind !== "landing") {
10353
10400
  if (input.sectionKey !== void 0) {
10354
10401
  ctx.addIssue({
10355
- code: z47.ZodIssueCode.custom,
10402
+ code: z48.ZodIssueCode.custom,
10356
10403
  path: [
10357
10404
  "sectionKey"
10358
10405
  ],
@@ -10361,7 +10408,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10361
10408
  }
10362
10409
  if (input.instructions !== void 0) {
10363
10410
  ctx.addIssue({
10364
- code: z47.ZodIssueCode.custom,
10411
+ code: z48.ZodIssueCode.custom,
10365
10412
  path: [
10366
10413
  "instructions"
10367
10414
  ],
@@ -10370,31 +10417,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10370
10417
  }
10371
10418
  }
10372
10419
  });
10373
- var CreateCreativeVariantInputBase = z47.object({
10374
- sourceTaskId: z47.string().uuid().describe("ID de la tarea original completada."),
10420
+ var CreateCreativeVariantInputBase = z48.object({
10421
+ sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
10375
10422
  kind: CreativeVariantKindEnum,
10376
- confirm: z47.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
10377
- clientRequestId: z47.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."),
10378
- angle: z47.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
10379
- buyerPersona: z47.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
10380
- scriptNotes: z47.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
10381
- creativeDirection: z47.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
10423
+ confirm: z48.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
10424
+ clientRequestId: z48.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."),
10425
+ angle: z48.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
10426
+ buyerPersona: z48.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
10427
+ scriptNotes: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
10428
+ creativeDirection: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
10382
10429
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
10383
10430
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
10384
- generateAiMusic: z47.boolean().optional().describe("Opcional para video."),
10385
- nVariants: z47.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10431
+ generateAiMusic: z48.boolean().optional().describe("Opcional para video."),
10432
+ nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10386
10433
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
10387
10434
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
10388
10435
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
10389
10436
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
10390
- styleMix: z47.boolean().optional().describe("Opcional para imagen."),
10437
+ styleMix: z48.boolean().optional().describe("Opcional para imagen."),
10391
10438
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
10392
- instructions: z47.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.")
10439
+ instructions: z48.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.")
10393
10440
  }).strict();
10394
10441
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
10395
10442
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
10396
10443
  ctx.addIssue({
10397
- code: z47.ZodIssueCode.custom,
10444
+ code: z48.ZodIssueCode.custom,
10398
10445
  path: [
10399
10446
  "angle"
10400
10447
  ],
@@ -10403,7 +10450,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
10403
10450
  }
10404
10451
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
10405
10452
  ctx.addIssue({
10406
- code: z47.ZodIssueCode.custom,
10453
+ code: z48.ZodIssueCode.custom,
10407
10454
  path: [
10408
10455
  "instructions"
10409
10456
  ],
@@ -10449,7 +10496,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
10449
10496
  for (const field of fieldsByKind[input.kind]) {
10450
10497
  if (input[field] !== void 0) {
10451
10498
  ctx.addIssue({
10452
- code: z47.ZodIssueCode.custom,
10499
+ code: z48.ZodIssueCode.custom,
10453
10500
  path: [
10454
10501
  field
10455
10502
  ],
@@ -10566,27 +10613,27 @@ function registerCreativeVariantTools(server, api) {
10566
10613
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
10567
10614
 
10568
10615
  // src/tools/script-review.ts
10569
- import { z as z48 } from "zod";
10570
- var GetVideoScriptInput = z48.object({
10571
- taskId: z48.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
10572
- angleKey: z48.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.')
10616
+ import { z as z49 } from "zod";
10617
+ var GetVideoScriptInput = z49.object({
10618
+ taskId: z49.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
10619
+ angleKey: z49.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.')
10573
10620
  }).strict();
10574
10621
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
10575
10622
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
10576
- var ApproveSceneEdit = z48.object({
10577
- index: z48.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
10578
- dialogue: z48.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
10623
+ var ApproveSceneEdit = z49.object({
10624
+ index: z49.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
10625
+ dialogue: z49.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
10579
10626
  message: "dialogue no puede ser s\xF3lo espacios"
10580
10627
  }).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.")
10581
10628
  }).strict();
10582
- var ApproveVideoScriptInput = z48.object({
10583
- taskId: z48.string().min(1).describe("ID de la tarea."),
10584
- angleKey: z48.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.'),
10585
- scenes: z48.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.")
10629
+ var ApproveVideoScriptInput = z49.object({
10630
+ taskId: z49.string().min(1).describe("ID de la tarea."),
10631
+ angleKey: z49.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.'),
10632
+ scenes: z49.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.")
10586
10633
  }).strict();
10587
- var RegenerateVideoScriptInput = z48.object({
10588
- taskId: z48.string().min(1).describe("ID de la tarea."),
10589
- angleKey: z48.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.'),
10634
+ var RegenerateVideoScriptInput = z49.object({
10635
+ taskId: z49.string().min(1).describe("ID de la tarea."),
10636
+ angleKey: z49.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.'),
10590
10637
  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).')
10591
10638
  }).strict();
10592
10639
  function registerScriptReviewTools(server, api) {
@@ -10626,9 +10673,9 @@ function registerScriptReviewTools(server, api) {
10626
10673
  __name(registerScriptReviewTools, "registerScriptReviewTools");
10627
10674
 
10628
10675
  // src/tools/connections.ts
10629
- import { z as z49 } from "zod";
10676
+ import { z as z50 } from "zod";
10630
10677
  function registerConnectionTools(server, api) {
10631
- server.tool("list_shopify_shops", "Lista las tiendas Shopify conectadas por este usuario. Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z49.object({}).shape, async () => {
10678
+ server.tool("list_shopify_shops", "Lista las tiendas Shopify conectadas por este usuario. Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z50.object({}).shape, async () => {
10632
10679
  try {
10633
10680
  const r = await api.getJson("/v1/shopify/shops");
10634
10681
  return asText(r);
@@ -10636,10 +10683,10 @@ function registerConnectionTools(server, api) {
10636
10683
  throw translateError(e);
10637
10684
  }
10638
10685
  });
10639
- server.tool("list_shopify_products", 'Busca productos en una tienda Shopify conectada para elegir el target de una republicaci\xF3n. 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.', z49.object({
10640
- shopDomain: z49.string().min(3).max(120),
10641
- query: z49.string().trim().max(120).optional(),
10642
- taskId: z49.string().uuid().optional()
10686
+ server.tool("list_shopify_products", 'Busca productos en una tienda Shopify conectada para elegir el target de una republicaci\xF3n. 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.', z50.object({
10687
+ shopDomain: z50.string().min(3).max(120),
10688
+ query: z50.string().trim().max(120).optional(),
10689
+ taskId: z50.string().uuid().optional()
10643
10690
  }).shape, async ({ shopDomain, query, taskId }) => {
10644
10691
  try {
10645
10692
  const params = new URLSearchParams({
@@ -10653,7 +10700,7 @@ function registerConnectionTools(server, api) {
10653
10700
  throw translateError(e);
10654
10701
  }
10655
10702
  });
10656
- server.tool("list_meta_ad_accounts", "Lista las cuentas publicitarias de Meta conectadas. 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.", z49.object({}).shape, async () => {
10703
+ server.tool("list_meta_ad_accounts", "Lista las cuentas publicitarias de Meta conectadas. 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.", z50.object({}).shape, async () => {
10657
10704
  try {
10658
10705
  const r = await api.getJson("/v1/facebook/ad-accounts");
10659
10706
  return asText(r);
@@ -10661,7 +10708,13 @@ function registerConnectionTools(server, api) {
10661
10708
  throw translateError(e);
10662
10709
  }
10663
10710
  });
10664
- server.tool("list_meta_destinations", "Lista los destinos de publicaci\xF3n de Meta del usuario: Business portfolios, cuentas publicitarias dentro de cada portfolio y Facebook Pages disponibles. 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.", z49.object({}).shape, async () => {
10711
+ server.registerTool("list_meta_destinations", {
10712
+ description: "Lista los destinos de publicaci\xF3n de Meta del usuario: Business portfolios, cuentas publicitarias dentro de cada portfolio y Facebook Pages disponibles. 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.",
10713
+ inputSchema: z50.object({}).shape,
10714
+ _meta: {
10715
+ "openai/widgetAccessible": true
10716
+ }
10717
+ }, async () => {
10665
10718
  try {
10666
10719
  const r = await api.getJson("/v1/facebook/destinations");
10667
10720
  return asText(r);
@@ -10669,7 +10722,7 @@ function registerConnectionTools(server, api) {
10669
10722
  throw translateError(e);
10670
10723
  }
10671
10724
  });
10672
- server.tool("list_tiktok_advertisers", "Lista las cuentas de TikTok Ads conectadas. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z49.object({}).shape, async () => {
10725
+ server.tool("list_tiktok_advertisers", "Lista las cuentas de TikTok Ads conectadas. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z50.object({}).shape, async () => {
10673
10726
  try {
10674
10727
  const r = await api.getJson("/v1/tiktok/advertisers");
10675
10728
  return asText(r);
@@ -10681,9 +10734,9 @@ function registerConnectionTools(server, api) {
10681
10734
  __name(registerConnectionTools, "registerConnectionTools");
10682
10735
 
10683
10736
  // src/tools/actors.ts
10684
- import { z as z50 } from "zod";
10737
+ import { z as z51 } from "zod";
10685
10738
  function registerActorTools(server, api) {
10686
- server.tool("list_actors", "Lista los personajes guardados del usuario (personas creadas con IA que pueden protagonizar los videos e im\xE1genes). 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.", z50.object({}).shape, async () => {
10739
+ server.tool("list_actors", "Lista los personajes guardados del usuario (personas creadas con IA que pueden protagonizar los videos e im\xE1genes). 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.", z51.object({}).shape, async () => {
10687
10740
  try {
10688
10741
  const rows = await api.getJson("/v1/actors");
10689
10742
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -10704,116 +10757,116 @@ function registerActorTools(server, api) {
10704
10757
  __name(registerActorTools, "registerActorTools");
10705
10758
 
10706
10759
  // src/tools/publish.ts
10707
- import { z as z51 } from "zod";
10708
- var ShopifyInput = z51.object({
10709
- taskId: z51.string().min(1),
10710
- shopDomain: z51.string().min(1),
10760
+ import { z as z52 } from "zod";
10761
+ var ShopifyInput = z52.object({
10762
+ taskId: z52.string().min(1),
10763
+ shopDomain: z52.string().min(1),
10711
10764
  /** Override: number of landing images to include. Default = ALL images the
10712
10765
  * task generated (the MCP fetches /v1/results first to count). Bounded
10713
10766
  * generously here; the backend validates each index against
10714
10767
  * landing.images.length and rejects out-of-range. */
10715
- numLandingImages: z51.number().int().min(1).max(20).optional(),
10716
- variantIndex: z51.number().int().min(0).optional(),
10768
+ numLandingImages: z52.number().int().min(1).max(20).optional(),
10769
+ variantIndex: z52.number().int().min(0).optional(),
10717
10770
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
10718
10771
  * When true, the landing renders variant-picker pills; when false, it ships
10719
10772
  * a single-option product page. Defaults to false. */
10720
- showVariantPicker: z51.boolean().optional(),
10773
+ showVariantPicker: z52.boolean().optional(),
10721
10774
  /** Default `auto` updates the product previously published for this task and
10722
10775
  * shop. Use `existing` with targetProductId to choose another product, or
10723
10776
  * `new` only when the user explicitly wants a duplicate/new listing. */
10724
- publicationMode: z51.enum([
10777
+ publicationMode: z52.enum([
10725
10778
  "auto",
10726
10779
  "existing",
10727
10780
  "new"
10728
10781
  ]).optional(),
10729
10782
  /** Shopify product GID, numeric id, or admin product URL. Required when
10730
10783
  * publicationMode is `existing`. */
10731
- targetProductId: z51.string().trim().min(1).max(300).optional()
10784
+ targetProductId: z52.string().trim().min(1).max(300).optional()
10732
10785
  });
10733
- var McpCampaignConfig = z51.object({
10786
+ var McpCampaignConfig = z52.object({
10734
10787
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
10735
10788
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
10736
10789
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
10737
- dailyBudgetUsd: z51.number().positive().optional(),
10790
+ dailyBudgetUsd: z52.number().positive().optional(),
10738
10791
  /** ISO-3166-1 alpha-2 country codes. Meta accepts max 1 (single-country
10739
10792
  * ad set). TikTok takes only the first entry. */
10740
- targetCountries: z51.array(z51.string().length(2)).max(1).optional(),
10741
- campaignName: z51.string().trim().min(1).max(100).optional()
10793
+ targetCountries: z52.array(z52.string().length(2)).max(1).optional(),
10794
+ campaignName: z52.string().trim().min(1).max(100).optional()
10742
10795
  });
10743
10796
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
10744
- var MetaInput = z51.object({
10745
- taskId: z51.string().min(1),
10797
+ var MetaInput = z52.object({
10798
+ taskId: z52.string().min(1),
10746
10799
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
10747
- portfolioId: z51.string().trim().min(1),
10800
+ portfolioId: z52.string().trim().min(1),
10748
10801
  /** Exact Facebook Page selected from `list_meta_destinations`. */
10749
- pageId: z51.string().trim().min(1),
10802
+ pageId: z52.string().trim().min(1),
10750
10803
  adAccountId: McpAdAccountId,
10751
- pixelId: z51.string().min(1).optional(),
10752
- landingUrl: z51.string().url().optional(),
10804
+ pixelId: z52.string().min(1).optional(),
10805
+ landingUrl: z52.string().url().optional(),
10753
10806
  /** Select which angles to publish by 0-based index. Omit to publish all
10754
10807
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
10755
- angleIndexes: z51.array(z51.number().int().nonnegative()).optional(),
10808
+ angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
10756
10809
  campaignConfig: McpCampaignConfig.optional(),
10757
10810
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
10758
10811
  * uses the auto-generated copy attached to the task. Capped at 500 chars
10759
10812
  * (Meta's primary-text limit). */
10760
- primaryText: z51.string().trim().min(1).max(500).optional(),
10813
+ primaryText: z52.string().trim().min(1).max(500).optional(),
10761
10814
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
10762
10815
  * (wa.me) instead of a landing page. */
10763
- phoneNumber: z51.string().min(8).max(32).optional()
10816
+ phoneNumber: z52.string().min(8).max(32).optional()
10764
10817
  });
10765
- var GroupedTaskSource = z51.object({
10766
- type: z51.literal("task"),
10767
- taskId: z51.string().min(1),
10768
- angleIndex: z51.number().int().min(0).optional(),
10769
- videoVariant: z51.enum([
10818
+ var GroupedTaskSource = z52.object({
10819
+ type: z52.literal("task"),
10820
+ taskId: z52.string().min(1),
10821
+ angleIndex: z52.number().int().min(0).optional(),
10822
+ videoVariant: z52.enum([
10770
10823
  "with_subtitles",
10771
10824
  "without_subtitles"
10772
10825
  ]).optional(),
10773
- imageVariantIndex: z51.number().int().min(0).optional()
10774
- });
10775
- var GroupedMediaSource = z51.object({
10776
- type: z51.literal("media"),
10777
- url: z51.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_meta_media_upload on the hosted MCP instead."),
10778
- path: z51.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_meta_media_upload and then use source.type="staged".'),
10779
- thumbnailUrl: z51.string().url().optional(),
10780
- thumbnailPath: z51.string().min(1).optional()
10826
+ imageVariantIndex: z52.number().int().min(0).optional()
10827
+ });
10828
+ var GroupedMediaSource = z52.object({
10829
+ type: z52.literal("media"),
10830
+ url: z52.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_meta_media_upload on the hosted MCP instead."),
10831
+ path: z52.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_meta_media_upload and then use source.type="staged".'),
10832
+ thumbnailUrl: z52.string().url().optional(),
10833
+ thumbnailPath: z52.string().min(1).optional()
10781
10834
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
10782
10835
  message: "media source needs exactly one of `url` or `path`"
10783
10836
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
10784
10837
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
10785
10838
  });
10786
- var GroupedStagedMediaSource = z51.object({
10787
- type: z51.literal("staged"),
10839
+ var GroupedStagedMediaSource = z52.object({
10840
+ type: z52.literal("staged"),
10788
10841
  /** Returned by check_meta_media_upload after the user selects a local file. */
10789
- stagingAssetId: z51.string().uuid(),
10790
- thumbnailAssetId: z51.string().uuid().optional()
10842
+ stagingAssetId: z52.string().uuid(),
10843
+ thumbnailAssetId: z52.string().uuid().optional()
10791
10844
  });
10792
- var GroupedCreative = z51.object({
10793
- type: z51.enum([
10845
+ var GroupedCreative = z52.object({
10846
+ type: z52.enum([
10794
10847
  "image",
10795
10848
  "video"
10796
10849
  ]),
10797
- source: z51.union([
10850
+ source: z52.union([
10798
10851
  GroupedTaskSource,
10799
10852
  GroupedMediaSource,
10800
10853
  GroupedStagedMediaSource
10801
10854
  ]),
10802
- title: z51.string().max(120).optional(),
10803
- description: z51.string().max(500).optional(),
10855
+ title: z52.string().max(120).optional(),
10856
+ description: z52.string().max(500).optional(),
10804
10857
  cta: MetaCtaType.optional(),
10805
- creativeId: z51.string().min(1).optional()
10858
+ creativeId: z52.string().min(1).optional()
10806
10859
  });
10807
- var GroupedCampaignConfig = z51.object({
10860
+ var GroupedCampaignConfig = z52.object({
10808
10861
  campaignType: MetaCampaignType.default("sales"),
10809
10862
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
10810
10863
  budgetMode: MetaBudgetMode.default("campaign"),
10811
- campaignDailyBudget: z51.number().int().positive().optional(),
10812
- adSets: z51.array(z51.object({
10813
- tempId: z51.string().min(1).max(80),
10814
- name: z51.string().min(1).max(100),
10815
- dailyBudget: z51.number().int().positive().optional(),
10816
- creativeIds: z51.array(z51.string().min(1)).min(1)
10864
+ campaignDailyBudget: z52.number().int().positive().optional(),
10865
+ adSets: z52.array(z52.object({
10866
+ tempId: z52.string().min(1).max(80),
10867
+ name: z52.string().min(1).max(100),
10868
+ dailyBudget: z52.number().int().positive().optional(),
10869
+ creativeIds: z52.array(z52.string().min(1)).min(1)
10817
10870
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
10818
10871
  /**
10819
10872
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -10821,22 +10874,22 @@ var GroupedCampaignConfig = z51.object({
10821
10874
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
10822
10875
  * the API since #849 — unreachable from this tool.
10823
10876
  */
10824
- destination: z51.discriminatedUnion("type", [
10825
- z51.object({
10826
- type: z51.literal("landing"),
10827
- landingUrl: z51.string().url()
10877
+ destination: z52.discriminatedUnion("type", [
10878
+ z52.object({
10879
+ type: z52.literal("landing"),
10880
+ landingUrl: z52.string().url()
10828
10881
  }),
10829
- z51.object({
10830
- type: z51.literal("whatsapp"),
10831
- phoneNumber: z51.string().min(8).max(32)
10882
+ z52.object({
10883
+ type: z52.literal("whatsapp"),
10884
+ phoneNumber: z52.string().min(8).max(32)
10832
10885
  })
10833
10886
  ]),
10834
- saveAsDefault: z51.boolean().default(false),
10887
+ saveAsDefault: z52.boolean().default(false),
10835
10888
  budgetPolicy: MetaBudgetPolicy.optional()
10836
10889
  }).superRefine((value, ctx) => {
10837
10890
  if (value.budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
10838
10891
  ctx.addIssue({
10839
- code: z51.ZodIssueCode.custom,
10892
+ code: z52.ZodIssueCode.custom,
10840
10893
  path: [
10841
10894
  "campaignDailyBudget"
10842
10895
  ],
@@ -10847,7 +10900,7 @@ var GroupedCampaignConfig = z51.object({
10847
10900
  value.adSets.forEach((adSet, index) => {
10848
10901
  if (adSet.dailyBudget === void 0) {
10849
10902
  ctx.addIssue({
10850
- code: z51.ZodIssueCode.custom,
10903
+ code: z52.ZodIssueCode.custom,
10851
10904
  path: [
10852
10905
  "adSets",
10853
10906
  index,
@@ -10859,26 +10912,26 @@ var GroupedCampaignConfig = z51.object({
10859
10912
  });
10860
10913
  }
10861
10914
  });
10862
- var PublishCreativesToMetaInputBase = z51.object({
10863
- creatives: z51.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
10915
+ var PublishCreativesToMetaInputBase = z52.object({
10916
+ creatives: z52.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
10864
10917
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
10865
- portfolioId: z51.string().trim().min(1),
10918
+ portfolioId: z52.string().trim().min(1),
10866
10919
  /** Exact Facebook Page selected from `list_meta_destinations`. */
10867
- pageId: z51.string().trim().min(1),
10920
+ pageId: z52.string().trim().min(1),
10868
10921
  adAccountId: McpAdAccountId,
10869
- pixelId: z51.string().min(1).optional(),
10922
+ pixelId: z52.string().min(1).optional(),
10870
10923
  /** Required unless `campaignConfig.destination` is whatsapp — see the
10871
10924
  * superRefine below. Mirrors the API's `UploadToMetaRequest`. */
10872
- landingUrl: z51.string().url().optional(),
10873
- targetCountry: z51.string().length(2),
10874
- campaignName: z51.string().trim().min(1).max(100),
10925
+ landingUrl: z52.string().url().optional(),
10926
+ targetCountry: z52.string().length(2),
10927
+ campaignName: z52.string().trim().min(1).max(100),
10875
10928
  campaignConfig: GroupedCampaignConfig.optional()
10876
10929
  });
10877
10930
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
10878
10931
  const destination = value.campaignConfig?.destination;
10879
10932
  if (destination?.type !== "whatsapp" && !value.landingUrl) {
10880
10933
  ctx.addIssue({
10881
- code: z51.ZodIssueCode.custom,
10934
+ code: z52.ZodIssueCode.custom,
10882
10935
  path: [
10883
10936
  "landingUrl"
10884
10937
  ],
@@ -10887,7 +10940,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
10887
10940
  }
10888
10941
  if (destination?.type === "landing" && destination.landingUrl !== value.landingUrl) {
10889
10942
  ctx.addIssue({
10890
- code: z51.ZodIssueCode.custom,
10943
+ code: z52.ZodIssueCode.custom,
10891
10944
  path: [
10892
10945
  "campaignConfig",
10893
10946
  "destination",
@@ -10897,16 +10950,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
10897
10950
  });
10898
10951
  }
10899
10952
  });
10900
- var PresignUploadResponseSchema = z51.object({
10901
- uploadUrl: z51.string().url().refine((value) => {
10953
+ var PresignUploadResponseSchema = z52.object({
10954
+ uploadUrl: z52.string().url().refine((value) => {
10902
10955
  const url = new URL(value);
10903
10956
  return !url.username && !url.password && url.protocol === "https:";
10904
10957
  }, "presigned upload URL must be HTTPS without embedded credentials"),
10905
- publicUrl: z51.string().url().refine((value) => {
10958
+ publicUrl: z52.string().url().refine((value) => {
10906
10959
  const url = new URL(value);
10907
10960
  return !url.username && !url.password;
10908
10961
  }, "public media URL must not contain embedded credentials"),
10909
- stagingAssetId: z51.string().uuid()
10962
+ stagingAssetId: z52.string().uuid()
10910
10963
  });
10911
10964
  async function uploadResolvedMedia(api, media, assetRole) {
10912
10965
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -10931,16 +10984,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
10931
10984
  return uploadResolvedMedia(api, media, assetRole);
10932
10985
  }
10933
10986
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
10934
- var TikTokInput = z51.object({
10935
- taskId: z51.string().min(1),
10936
- advertiserId: z51.string().min(1),
10937
- pixelId: z51.string().min(1).optional(),
10938
- landingUrl: z51.string().url().optional(),
10939
- angleIndexes: z51.array(z51.number().int().nonnegative()).optional(),
10987
+ var TikTokInput = z52.object({
10988
+ taskId: z52.string().min(1),
10989
+ advertiserId: z52.string().min(1),
10990
+ pixelId: z52.string().min(1).optional(),
10991
+ landingUrl: z52.string().url().optional(),
10992
+ angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
10940
10993
  campaignConfig: McpCampaignConfig.optional(),
10941
10994
  /** Override the ad's description (TikTok's body copy). If omitted,
10942
10995
  * ProductMaker uses the auto-generated copy attached to the task. */
10943
- primaryText: z51.string().trim().min(1).max(500).optional()
10996
+ primaryText: z52.string().trim().min(1).max(500).optional()
10944
10997
  });
10945
10998
  function registerPublishTools(server, api, opts = {}) {
10946
10999
  const transport = opts.transport ?? "http";
@@ -11128,6 +11181,17 @@ function renderShopifyPublishMarkdown(r) {
11128
11181
  if (r.productUrl) lines.push(`
11129
11182
  ### Producto
11130
11183
  [Ver producto](${r.productUrl})`);
11184
+ if (r.needsThemeSetup) {
11185
+ lines.push(r.themeEditorDeepLink ? `
11186
+ \u26A0\uFE0F La landing est\xE1 publicada, pero falta activar el bloque Code Landing en el tema. [Abrir editor de Shopify](${r.themeEditorDeepLink}) y guardar una vez.` : "\n\u26A0\uFE0F La landing est\xE1 publicada, pero falta activar el bloque Code Landing en el tema. Abre el editor de Shopify, agrega el bloque y guarda una vez.");
11187
+ }
11188
+ if (r.tracking?.status === "migrated") {
11189
+ lines.push("\nTracking: \u2705 configuraci\xF3n anterior migrada autom\xE1ticamente. No necesitas editar el tema.");
11190
+ } else if (r.tracking?.status === "synced") {
11191
+ lines.push("\nTracking: \u2705 c\xF3digo manual sincronizado desde `theme.liquid` al layout de ProductMaker.");
11192
+ } else if (r.tracking?.status === "not_detected") {
11193
+ lines.push("\nTracking: \u2705 ProductMaker dej\xF3 la landing compatible con el tracking nativo de Shopify; no se encontr\xF3 c\xF3digo manual para migrar.");
11194
+ }
11131
11195
  if (!r.pageUrl && !r.productUrl && r.status !== "success") {
11132
11196
  lines.push("\n_La publicaci\xF3n a\xFAn est\xE1 proces\xE1ndose. Usa `get_task_status` para verificar progreso._");
11133
11197
  }
@@ -11172,71 +11236,81 @@ function toTikTokCampaignConfig(cfg) {
11172
11236
  __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
11173
11237
 
11174
11238
  // src/tools/meta-upload.ts
11175
- import { z as z52 } from "zod";
11176
- var MetaUploadSessionInputBase = z52.object({
11177
- mediaKind: z52.enum([
11239
+ import { z as z53 } from "zod";
11240
+ var MetaUploadSessionInputBase = z53.object({
11241
+ mediaKind: z53.enum([
11178
11242
  "image",
11179
11243
  "video",
11180
11244
  "mixed"
11181
11245
  ]).default("mixed").describe("The kind of file the user will select in the upload page. Use mixed for a normal batch of image and video creatives."),
11182
- assetRole: z52.enum([
11246
+ assetRole: z53.enum([
11183
11247
  "media",
11184
11248
  "thumbnail"
11185
- ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail.")
11186
- });
11187
- var OpenAiFileReference = z52.object({
11188
- download_url: z52.string().url(),
11189
- file_id: z52.string().min(1),
11190
- mime_type: z52.string().min(1).optional(),
11191
- file_name: z52.string().min(1).optional()
11249
+ ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
11250
+ maxFiles: z53.number().int().min(1).max(10).optional().describe("Optional batch limit. Use 1 for a single creative; mixed media defaults to 10.")
11251
+ });
11252
+ var OpenAiFileReference = z53.object({
11253
+ download_url: z53.string().url(),
11254
+ file_id: z53.string().min(1),
11255
+ mime_type: z53.string().min(1).optional(),
11256
+ file_name: z53.string().min(1).optional()
11192
11257
  }).strict();
11193
11258
  var MetaUploadSessionToolInputShape = {
11194
11259
  ...MetaUploadSessionInputBase.shape,
11195
- files: z52.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.")
11260
+ files: z53.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.")
11196
11261
  };
11197
- var MetaUploadSessionToolInput = z52.object(MetaUploadSessionToolInputShape).superRefine((value, ctx) => {
11262
+ var MetaUploadSessionToolInput = z53.object(MetaUploadSessionToolInputShape).superRefine((value, ctx) => {
11198
11263
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
11199
11264
  ctx.addIssue({
11200
- code: z52.ZodIssueCode.custom,
11265
+ code: z53.ZodIssueCode.custom,
11201
11266
  path: [
11202
11267
  "mediaKind"
11203
11268
  ],
11204
11269
  message: "Meta thumbnails must be images"
11205
11270
  });
11206
11271
  }
11272
+ if (value.mediaKind !== "mixed" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
11273
+ ctx.addIssue({
11274
+ code: z53.ZodIssueCode.custom,
11275
+ path: [
11276
+ "maxFiles"
11277
+ ],
11278
+ message: "Image and video sessions accept exactly one file"
11279
+ });
11280
+ }
11207
11281
  });
11208
- var MetaUploadSessionResponse2 = z52.object({
11209
- sessionId: z52.string().uuid(),
11210
- uploadPageUrl: z52.string().url(),
11211
- mediaKind: z52.enum([
11282
+ var MetaUploadSessionResponse2 = z53.object({
11283
+ sessionId: z53.string().uuid(),
11284
+ uploadPageUrl: z53.string().url(),
11285
+ mediaKind: z53.enum([
11212
11286
  "image",
11213
11287
  "video",
11214
11288
  "mixed"
11215
11289
  ]),
11216
- assetRole: z52.enum([
11290
+ assetRole: z53.enum([
11217
11291
  "media",
11218
11292
  "thumbnail"
11219
11293
  ]),
11220
- maxFiles: z52.number().int().positive(),
11221
- expiresAt: z52.string().datetime()
11294
+ maxFiles: z53.number().int().positive(),
11295
+ expiresAt: z53.string().datetime()
11222
11296
  });
11223
- var MetaUploadStatusInput = z52.object({
11224
- sessionId: z52.string().uuid().describe("The sessionId returned by request_meta_media_upload.")
11297
+ var MetaUploadStatusInput = z53.object({
11298
+ sessionId: z53.string().uuid().describe("The sessionId returned by request_meta_media_upload.")
11225
11299
  });
11226
- var MetaUploadStatusResponse = z52.object({
11227
- sessionId: z52.string().uuid(),
11228
- status: z52.enum([
11300
+ var MetaUploadStatusResponse = z53.object({
11301
+ sessionId: z53.string().uuid(),
11302
+ status: z53.enum([
11229
11303
  "pending",
11230
11304
  "uploaded"
11231
11305
  ]),
11232
- assets: z52.array(z52.object({
11233
- stagingAssetId: z52.string().uuid(),
11234
- mediaKind: z52.enum([
11306
+ assets: z53.array(z53.object({
11307
+ stagingAssetId: z53.string().uuid(),
11308
+ mediaKind: z53.enum([
11235
11309
  "image",
11236
11310
  "video"
11237
11311
  ])
11238
11312
  })).max(10).default([]),
11239
- stagingAssetId: z52.string().uuid().optional()
11313
+ stagingAssetId: z53.string().uuid().optional()
11240
11314
  });
11241
11315
  function uploadSessionText(result) {
11242
11316
  const mediaLabel = result.mediaKind === "mixed" ? "archivos" : result.mediaKind === "video" ? "video" : "imagen";
@@ -11245,8 +11319,8 @@ function uploadSessionText(result) {
11245
11319
  {
11246
11320
  type: "text",
11247
11321
  text: [
11248
- `### Sube tu ${mediaLabel} a ProductMaker`,
11249
- `[Abrir carga segura](${result.uploadPageUrl})`,
11322
+ `### Prepara tu ${mediaLabel} en ProductMaker`,
11323
+ `Usa primero el App inline de este chat. Si tu host no soporta el bridge de archivos, usa este fallback: [Abrir carga segura](${result.uploadPageUrl})`,
11250
11324
  `Puedes seleccionar hasta ${result.maxFiles} ${result.mediaKind === "mixed" ? "archivos" : "archivo"}. Cuando termine, escribe **\u201Clisto\u201D** en este chat para que ProductMaker contin\xFAe con Meta.`,
11251
11325
  `sessionId: \`${result.sessionId}\``,
11252
11326
  `Este enlace expira: ${result.expiresAt}`
@@ -11259,7 +11333,7 @@ __name(uploadSessionText, "uploadSessionText");
11259
11333
  function registerMetaUploadTools(server, api) {
11260
11334
  server.registerTool("request_meta_media_upload", {
11261
11335
  title: "Solicitar carga segura de Meta",
11262
- description: "Inicia una carga segura desde la laptop del usuario para creativos propios de Meta. Por defecto crea una sesi\xF3n `mixed` de hasta diez archivos; tambi\xE9n admite una sola imagen o video. En ChatGPT puede recibir referencias opcionales de `files`, pero NO las descarga ni las reenv\xEDa: siempre devuelve un enlace de ProductMaker donde el usuario selecciona los archivos. No pidas URL CDN, ruta local, bytes ni base64. Despu\xE9s conserva el `sessionId` y llama `check_meta_media_upload`. Esta herramienta no publica ni consume cr\xE9ditos.",
11336
+ description: "Inicia una carga segura desde la laptop del usuario para creativos propios de Meta. Por defecto crea una sesi\xF3n `mixed` de hasta diez archivos; tambi\xE9n admite una sola imagen o video. Si el usuario adjunta una foto o video en el mismo mensaje de ChatGPT, pasa esas referencias opcionales en `files` para que el MCP App inline las consuma dentro del chat. ProductMaker conserva `files` solo como metadata del UI bridge: NO los descarga y NO los reenv\xEDa. No pidas URL CDN, ruta local, bytes ni base64. El flujo principal es el MCP App inline; el enlace externo de ProductMaker queda como fallback para hosts sin bridge de archivos. Despu\xE9s conserva el `sessionId` y llama `check_meta_media_upload`. Esta herramienta no publica ni consume cr\xE9ditos.",
11263
11337
  inputSchema: MetaUploadSessionToolInputShape,
11264
11338
  outputSchema: MetaUploadSessionResponse2,
11265
11339
  _meta: {
@@ -11291,7 +11365,13 @@ function registerMetaUploadTools(server, api) {
11291
11365
  throw translateError(error);
11292
11366
  }
11293
11367
  });
11294
- server.tool("check_meta_media_upload", 'Comprueba si el usuario ya termin\xF3 de subir desde el enlace de ProductMaker. Si status=uploaded, devuelve `assets[]`; crea un creativo `source.type="staged"` por cada asset, usando su `mediaKind` como el tipo del creativo, hasta diez en el batch. Si la carga fue parcial, publica \xFAnicamente los assets que `assets[]` reporta como subidos. Conserva el `stagingAssetId` legado si aparece. Si status=pending, pide al usuario que termine; no publiques todav\xEDa.', MetaUploadStatusInput.shape, async (rawInput) => {
11368
+ server.registerTool("check_meta_media_upload", {
11369
+ description: 'Comprueba si el usuario ya termin\xF3 de subir desde el enlace de ProductMaker. Si status=uploaded, devuelve `assets[]`; crea un creativo `source.type="staged"` por cada asset, usando su `mediaKind` como el tipo del creativo, hasta diez en el batch. Si la carga fue parcial, publica \xFAnicamente los assets que `assets[]` reporta como subidos. Conserva el `stagingAssetId` legado si aparece. Si status=pending, pide al usuario que termine; no publiques todav\xEDa.',
11370
+ inputSchema: MetaUploadStatusInput.shape,
11371
+ _meta: {
11372
+ "openai/widgetAccessible": true
11373
+ }
11374
+ }, async (rawInput) => {
11295
11375
  try {
11296
11376
  const input = MetaUploadStatusInput.parse(rawInput);
11297
11377
  const result = MetaUploadStatusResponse.parse(await api.getJson(`/v1/ads/meta-upload-sessions/${encodeURIComponent(input.sessionId)}`));
@@ -11304,13 +11384,13 @@ function registerMetaUploadTools(server, api) {
11304
11384
  __name(registerMetaUploadTools, "registerMetaUploadTools");
11305
11385
 
11306
11386
  // src/tools/campaigns.ts
11307
- import { z as z53 } from "zod";
11308
- var MetaStatusInput = z53.object({
11309
- campaignId: z53.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
11387
+ import { z as z54 } from "zod";
11388
+ var MetaStatusInput = z54.object({
11389
+ campaignId: z54.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
11310
11390
  });
11311
- var TikTokStatusInput = z53.object({
11312
- campaignId: z53.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
11313
- advertiserId: z53.string().min(1).describe("The same advertiserId used to publish the campaign.")
11391
+ var TikTokStatusInput = z54.object({
11392
+ campaignId: z54.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
11393
+ advertiserId: z54.string().min(1).describe("The same advertiserId used to publish the campaign.")
11314
11394
  });
11315
11395
  function registerCampaignTools(server, api) {
11316
11396
  server.tool("get_meta_campaign_status", "Consulta el estado actual + m\xE9tricas lifetime (spend, impressions, clicks, reach) de una campa\xF1a Meta publicada. 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, async (input) => {
@@ -11407,10 +11487,10 @@ function renderTikTokStatusMarkdown(r) {
11407
11487
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
11408
11488
 
11409
11489
  // ../../packages/product-economics/src/product-costing.ts
11410
- import { z as z55 } from "zod";
11490
+ import { z as z56 } from "zod";
11411
11491
 
11412
11492
  // ../../packages/product-economics/src/product-costing-countries.ts
11413
- import { z as z54 } from "zod";
11493
+ import { z as z55 } from "zod";
11414
11494
 
11415
11495
  // ../../packages/product-economics/src/product-costing-shipping-references.json
11416
11496
  var product_costing_shipping_references_default = {
@@ -11474,21 +11554,21 @@ var product_costing_shipping_references_default = {
11474
11554
  };
11475
11555
 
11476
11556
  // ../../packages/product-economics/src/product-costing-countries.ts
11477
- var ShippingReferenceSchema = z54.object({
11478
- reference: z54.number().positive(),
11479
- min: z54.number().nonnegative(),
11480
- max: z54.number().positive(),
11481
- updatedAt: z54.string().date(),
11482
- confidence: z54.enum([
11557
+ var ShippingReferenceSchema = z55.object({
11558
+ reference: z55.number().positive(),
11559
+ min: z55.number().nonnegative(),
11560
+ max: z55.number().positive(),
11561
+ updatedAt: z55.string().date(),
11562
+ confidence: z55.enum([
11483
11563
  "high",
11484
11564
  "medium",
11485
11565
  "medium-low"
11486
11566
  ]),
11487
- sources: z54.array(z54.string().url().startsWith("https://")).min(1).max(3)
11567
+ sources: z55.array(z55.string().url().startsWith("https://")).min(1).max(3)
11488
11568
  }).superRefine(({ reference, min, max }, context) => {
11489
11569
  if (min > reference || reference > max) {
11490
11570
  context.addIssue({
11491
- code: z54.ZodIssueCode.custom,
11571
+ code: z55.ZodIssueCode.custom,
11492
11572
  message: "shipping_reference_outside_range",
11493
11573
  path: [
11494
11574
  "reference"
@@ -11496,7 +11576,7 @@ var ShippingReferenceSchema = z54.object({
11496
11576
  });
11497
11577
  }
11498
11578
  });
11499
- var SHIPPING_REFERENCES = z54.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
11579
+ var SHIPPING_REFERENCES = z55.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
11500
11580
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
11501
11581
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
11502
11582
  "MX",
@@ -11678,18 +11758,18 @@ function getProductCostingCountryName(country) {
11678
11758
  __name(getProductCostingCountryName, "getProductCostingCountryName");
11679
11759
 
11680
11760
  // ../../packages/product-economics/src/product-costing.ts
11681
- var ProductCostingInputSchema = z55.object({
11682
- country: z55.string().refine(isProductCostingCountryCode, "unsupported_country"),
11683
- supplierCost: z55.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
11684
- shippingCost: z55.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
11685
- returnRate: z55.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11686
- cancellationRate: z55.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11687
- adsManagerCpa: z55.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
11688
- desiredMargin: z55.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
11761
+ var ProductCostingInputSchema = z56.object({
11762
+ country: z56.string().refine(isProductCostingCountryCode, "unsupported_country"),
11763
+ supplierCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
11764
+ shippingCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
11765
+ returnRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11766
+ cancellationRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11767
+ adsManagerCpa: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
11768
+ desiredMargin: z56.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
11689
11769
  }).superRefine(({ returnRate, cancellationRate }, context) => {
11690
11770
  if (returnRate + cancellationRate >= 1) {
11691
11771
  context.addIssue({
11692
- code: z55.ZodIssueCode.custom,
11772
+ code: z56.ZodIssueCode.custom,
11693
11773
  message: "delivery_rate_positive",
11694
11774
  path: [
11695
11775
  "cancellationRate"
@@ -11756,14 +11836,14 @@ function calculateProductCosting(rawInput) {
11756
11836
  __name(calculateProductCosting, "calculateProductCosting");
11757
11837
 
11758
11838
  // src/tools/product-costing.ts
11759
- import { z as z56 } from "zod";
11760
- var optionalAmount = /* @__PURE__ */ __name((description) => z56.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
11761
- var optionalPercent = /* @__PURE__ */ __name((description) => z56.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
11762
- var ProductCostingToolInput = z56.object({
11763
- country: z56.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
11839
+ import { z as z57 } from "zod";
11840
+ var optionalAmount = /* @__PURE__ */ __name((description) => z57.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
11841
+ var optionalPercent = /* @__PURE__ */ __name((description) => z57.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
11842
+ var ProductCostingToolInput = z57.object({
11843
+ country: z57.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
11764
11844
  message: "Pa\xEDs no soportado por ProductMaker."
11765
11845
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
11766
- supplierCost: z56.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."),
11846
+ supplierCost: z57.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."),
11767
11847
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
11768
11848
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
11769
11849
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -11895,7 +11975,7 @@ function formatPercent(value) {
11895
11975
  __name(formatPercent, "formatPercent");
11896
11976
 
11897
11977
  // src/tools/product-research.ts
11898
- import { z as z57 } from "zod";
11978
+ import { z as z58 } from "zod";
11899
11979
 
11900
11980
  // src/tools/product-research-idempotency.ts
11901
11981
  import { createHash as createHash2 } from "crypto";
@@ -12011,17 +12091,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
12011
12091
  ]);
12012
12092
  var POLL_INTERVAL_MS = 5e3;
12013
12093
  var MAX_WAIT_SECONDS = 120;
12014
- var FindInput = z57.object({
12094
+ var FindInput = z58.object({
12015
12095
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
12016
12096
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
12017
- confirmed: z57.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
12018
- waitSeconds: z57.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
12097
+ confirmed: z58.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
12098
+ waitSeconds: z58.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
12019
12099
  });
12020
- var GetInput = z57.object({
12021
- runId: z57.string().uuid().describe("ID del run devuelto por find_winning_products.")
12100
+ var GetInput = z58.object({
12101
+ runId: z58.string().uuid().describe("ID del run devuelto por find_winning_products.")
12022
12102
  });
12023
- var ListInput = z57.object({
12024
- limit: z57.number().int().min(1).max(20).default(10)
12103
+ var ListInput = z58.object({
12104
+ limit: z58.number().int().min(1).max(20).default(10)
12025
12105
  });
12026
12106
  function textResult(text) {
12027
12107
  return {
@@ -12113,14 +12193,14 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
12113
12193
  __name(registerProductResearchTools, "registerProductResearchTools");
12114
12194
 
12115
12195
  // src/tools/dropshipping-projects.ts
12116
- import { z as z58 } from "zod";
12117
- var ProjectId = z58.string().uuid();
12118
- var DropshippingProjectStatus = z58.enum([
12196
+ import { z as z59 } from "zod";
12197
+ var ProjectId = z59.string().uuid();
12198
+ var DropshippingProjectStatus = z59.enum([
12119
12199
  "active",
12120
12200
  "completed",
12121
12201
  "archived"
12122
12202
  ]);
12123
- var DropshippingProjectPhase = z58.enum([
12203
+ var DropshippingProjectPhase = z59.enum([
12124
12204
  "research",
12125
12205
  "costing",
12126
12206
  "media",
@@ -12129,21 +12209,21 @@ var DropshippingProjectPhase = z58.enum([
12129
12209
  "advertising",
12130
12210
  "complete"
12131
12211
  ]);
12132
- var DropshippingRewardMilestone = z58.enum([
12212
+ var DropshippingRewardMilestone = z59.enum([
12133
12213
  "product_selected",
12134
12214
  "costing_saved",
12135
12215
  "product_media_ready",
12136
12216
  "creatives_completed",
12137
12217
  "campaign_created"
12138
12218
  ]);
12139
- var TargetCountry = z58.enum([
12219
+ var TargetCountry = z59.enum([
12140
12220
  "CO",
12141
12221
  "MX",
12142
12222
  "PE",
12143
12223
  "EC",
12144
12224
  "CL"
12145
12225
  ]);
12146
- var ResearchCategory = z58.enum([
12226
+ var ResearchCategory = z59.enum([
12147
12227
  "auto",
12148
12228
  "automotive",
12149
12229
  "kitchen",
@@ -12158,7 +12238,7 @@ var ResearchCategory = z58.enum([
12158
12238
  "garden",
12159
12239
  "cleaning"
12160
12240
  ]);
12161
- var HttpUrl3 = z58.string().url().max(2e3).refine((value) => {
12241
+ var HttpUrl3 = z59.string().url().max(2e3).refine((value) => {
12162
12242
  try {
12163
12243
  return [
12164
12244
  "http:",
@@ -12168,46 +12248,46 @@ var HttpUrl3 = z58.string().url().max(2e3).refine((value) => {
12168
12248
  return false;
12169
12249
  }
12170
12250
  }, "URL must use HTTP(S)");
12171
- var ResearchCandidateOrigin = z58.object({
12172
- type: z58.literal("research_candidate"),
12251
+ var ResearchCandidateOrigin = z59.object({
12252
+ type: z59.literal("research_candidate"),
12173
12253
  runId: ProjectId,
12174
- candidateSourceId: z58.string().min(1).max(160)
12254
+ candidateSourceId: z59.string().min(1).max(160)
12175
12255
  });
12176
- var TaskOrigin = z58.object({
12177
- type: z58.literal("task"),
12256
+ var TaskOrigin = z59.object({
12257
+ type: z59.literal("task"),
12178
12258
  taskId: ProjectId
12179
12259
  });
12180
- var ManualOrigin = z58.object({
12181
- type: z58.literal("manual"),
12260
+ var ManualOrigin = z59.object({
12261
+ type: z59.literal("manual"),
12182
12262
  clientRequestId: ProjectId,
12183
- country: z58.string().min(2).max(3).optional()
12263
+ country: z59.string().min(2).max(3).optional()
12184
12264
  });
12185
- var StartProjectInput = z58.object({
12186
- origin: z58.discriminatedUnion("type", [
12265
+ var StartProjectInput = z59.object({
12266
+ origin: z59.discriminatedUnion("type", [
12187
12267
  ResearchCandidateOrigin,
12188
12268
  TaskOrigin,
12189
12269
  ManualOrigin
12190
12270
  ]),
12191
- productName: z58.string().trim().min(1).max(240).optional(),
12271
+ productName: z59.string().trim().min(1).max(240).optional(),
12192
12272
  productUrl: HttpUrl3.optional(),
12193
- country: z58.string().min(2).max(3).optional(),
12194
- languageCode: z58.string().min(2).max(16).optional()
12273
+ country: z59.string().min(2).max(3).optional(),
12274
+ languageCode: z59.string().min(2).max(16).optional()
12195
12275
  }).strict();
12196
- var CostProjectInput = z58.object({
12276
+ var CostProjectInput = z59.object({
12197
12277
  projectId: ProjectId,
12198
- version: z58.number().int().positive(),
12199
- country: z58.string().trim().min(2).max(3),
12200
- supplierCost: z58.number().finite().positive(),
12201
- shippingCost: z58.number().finite().nonnegative(),
12202
- returnRate: z58.number().finite().min(0).lt(1),
12203
- cancellationRate: z58.number().finite().min(0).lt(1),
12204
- adsManagerCpa: z58.number().finite().nonnegative(),
12205
- desiredMargin: z58.number().finite().min(0).lt(1)
12206
- });
12207
- var GuideInput = z58.object({
12278
+ version: z59.number().int().positive(),
12279
+ country: z59.string().trim().min(2).max(3),
12280
+ supplierCost: z59.number().finite().positive(),
12281
+ shippingCost: z59.number().finite().nonnegative(),
12282
+ returnRate: z59.number().finite().min(0).lt(1),
12283
+ cancellationRate: z59.number().finite().min(0).lt(1),
12284
+ adsManagerCpa: z59.number().finite().nonnegative(),
12285
+ desiredMargin: z59.number().finite().min(0).lt(1)
12286
+ });
12287
+ var GuideInput = z59.object({
12208
12288
  projectId: ProjectId.optional()
12209
12289
  }).strict();
12210
- var DropshippingProjectNextAction = z58.discriminatedUnion("kind", [
12290
+ var DropshippingProjectNextAction = z59.discriminatedUnion("kind", [
12211
12291
  "cost_product",
12212
12292
  "provide_product_media",
12213
12293
  "generate_creatives",
@@ -12221,78 +12301,78 @@ var DropshippingProjectNextAction = z58.discriminatedUnion("kind", [
12221
12301
  "create_meta_campaign",
12222
12302
  "repair_meta_campaign",
12223
12303
  "review_paused_campaign"
12224
- ].map((kind) => z58.object({
12225
- kind: z58.literal(kind),
12226
- href: z58.string().min(1)
12304
+ ].map((kind) => z59.object({
12305
+ kind: z59.literal(kind),
12306
+ href: z59.string().min(1)
12227
12307
  })));
12228
- var CostingInputSchema = z58.object({
12229
- country: z58.string().min(2).max(3),
12230
- supplierCost: z58.number().finite().positive(),
12231
- shippingCost: z58.number().finite().nonnegative(),
12232
- returnRate: z58.number().finite().min(0).lt(1),
12233
- cancellationRate: z58.number().finite().min(0).lt(1),
12234
- adsManagerCpa: z58.number().finite().nonnegative(),
12235
- desiredMargin: z58.number().finite().min(0).lt(1)
12308
+ var CostingInputSchema = z59.object({
12309
+ country: z59.string().min(2).max(3),
12310
+ supplierCost: z59.number().finite().positive(),
12311
+ shippingCost: z59.number().finite().nonnegative(),
12312
+ returnRate: z59.number().finite().min(0).lt(1),
12313
+ cancellationRate: z59.number().finite().min(0).lt(1),
12314
+ adsManagerCpa: z59.number().finite().nonnegative(),
12315
+ desiredMargin: z59.number().finite().min(0).lt(1)
12236
12316
  }).superRefine(({ returnRate, cancellationRate }, context) => {
12237
12317
  if (returnRate + cancellationRate >= 1) context.addIssue({
12238
- code: z58.ZodIssueCode.custom,
12318
+ code: z59.ZodIssueCode.custom,
12239
12319
  path: [
12240
12320
  "cancellationRate"
12241
12321
  ]
12242
12322
  });
12243
12323
  });
12244
- var CostingResultSchema = z58.object({
12245
- country: z58.string().min(2).max(3),
12246
- deliveryRate: z58.number().finite(),
12247
- adjustedShippingCost: z58.number().finite(),
12248
- adjustedCpa: z58.number().finite(),
12249
- totalCost: z58.number().finite(),
12250
- suggestedPrice: z58.number().finite(),
12251
- baseCommercialPrice: z58.number().finite(),
12252
- minimumSafePrice: z58.number().finite(),
12253
- commercialPrice: z58.number().finite(),
12254
- comparisonPrice: z58.number().finite(),
12255
- estimatedProfit: z58.number().finite(),
12256
- actualMargin: z58.number().finite(),
12257
- breakEvenAdsManagerCpa: z58.number().finite(),
12258
- wasPriceAutoAdjusted: z58.boolean(),
12259
- profitabilityStatus: z58.literal("healthy")
12260
- });
12261
- var RewardProgressSchema = z58.object({
12262
- campaignKey: z58.literal("dropshipping-launch-v1"),
12263
- totalCredits: z58.number().int().positive(),
12264
- earnedCredits: z58.number().int().nonnegative(),
12265
- milestones: z58.array(z58.object({
12324
+ var CostingResultSchema = z59.object({
12325
+ country: z59.string().min(2).max(3),
12326
+ deliveryRate: z59.number().finite(),
12327
+ adjustedShippingCost: z59.number().finite(),
12328
+ adjustedCpa: z59.number().finite(),
12329
+ totalCost: z59.number().finite(),
12330
+ suggestedPrice: z59.number().finite(),
12331
+ baseCommercialPrice: z59.number().finite(),
12332
+ minimumSafePrice: z59.number().finite(),
12333
+ commercialPrice: z59.number().finite(),
12334
+ comparisonPrice: z59.number().finite(),
12335
+ estimatedProfit: z59.number().finite(),
12336
+ actualMargin: z59.number().finite(),
12337
+ breakEvenAdsManagerCpa: z59.number().finite(),
12338
+ wasPriceAutoAdjusted: z59.boolean(),
12339
+ profitabilityStatus: z59.literal("healthy")
12340
+ });
12341
+ var RewardProgressSchema = z59.object({
12342
+ campaignKey: z59.literal("dropshipping-launch-v1"),
12343
+ totalCredits: z59.number().int().positive(),
12344
+ earnedCredits: z59.number().int().nonnegative(),
12345
+ milestones: z59.array(z59.object({
12266
12346
  milestone: DropshippingRewardMilestone,
12267
- credits: z58.number().int().positive(),
12268
- available: z58.boolean().optional(),
12269
- earned: z58.boolean(),
12347
+ credits: z59.number().int().positive(),
12348
+ available: z59.boolean().optional(),
12349
+ earned: z59.boolean(),
12270
12350
  grantId: ProjectId.nullable(),
12271
- grantedAt: z58.string().datetime().nullable()
12351
+ grantedAt: z59.string().datetime().nullable()
12272
12352
  })).length(DropshippingRewardMilestone.options.length)
12273
12353
  });
12274
- var ProjectResponseSchema = z58.object({
12354
+ var ProjectResponseSchema = z59.object({
12275
12355
  id: ProjectId,
12276
12356
  taskId: ProjectId.nullable(),
12277
12357
  status: DropshippingProjectStatus,
12278
- originKey: z58.string().min(1),
12358
+ originKey: z59.string().min(1),
12279
12359
  researchRunId: ProjectId.nullable(),
12280
- candidateSourceId: z58.string().nullable(),
12281
- productName: z58.string().nullable(),
12360
+ candidateSourceId: z59.string().nullable(),
12361
+ productName: z59.string().nullable(),
12282
12362
  productUrl: HttpUrl3.nullable(),
12283
12363
  referenceImageUrl: HttpUrl3.nullable(),
12284
- targetCountry: z58.string().nullable(),
12285
- languageCode: z58.string().nullable(),
12286
- hasReferenceImage: z58.boolean(),
12364
+ targetCountry: z59.string().nullable(),
12365
+ languageCode: z59.string().nullable(),
12366
+ hasReferenceImage: z59.boolean(),
12287
12367
  costingInput: CostingInputSchema.nullable(),
12288
12368
  costingResult: CostingResultSchema.nullable(),
12289
- costingVersion: z58.number().int().positive().nullable(),
12290
- version: z58.number().int().positive(),
12369
+ costingVersion: z59.number().int().positive().nullable(),
12370
+ version: z59.number().int().positive(),
12291
12371
  phase: DropshippingProjectPhase,
12292
12372
  nextAction: DropshippingProjectNextAction.nullable(),
12293
12373
  rewards: RewardProgressSchema,
12294
- createdAt: z58.string().datetime(),
12295
- updatedAt: z58.string().datetime()
12374
+ createdAt: z59.string().datetime(),
12375
+ updatedAt: z59.string().datetime()
12296
12376
  }).passthrough();
12297
12377
  function projectText(raw) {
12298
12378
  const project = ProjectResponseSchema.parse(raw);