@productmaker/mcp 2.8.3 → 2.9.2

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/http.js CHANGED
@@ -153,7 +153,7 @@ var ApiClient = class {
153
153
  };
154
154
 
155
155
  // src/index.ts
156
- var MCP_VERSION = "2.8.3";
156
+ var MCP_VERSION = "2.9.2";
157
157
 
158
158
  // src/meta-upload-app.ts
159
159
  import { readFileSync } from "fs";
@@ -206,7 +206,7 @@ function registerMetaUploadAppResource(server) {
206
206
  __name(registerMetaUploadAppResource, "registerMetaUploadAppResource");
207
207
 
208
208
  // src/tools/tasks.ts
209
- import { z as z45 } from "zod";
209
+ import { z as z46 } from "zod";
210
210
 
211
211
  // src/resolve-image.ts
212
212
  import { lookup as dnsLookup } from "dns/promises";
@@ -2306,6 +2306,25 @@ var ShopifyPublicationStatus = z19.enum([
2306
2306
  "success",
2307
2307
  "error"
2308
2308
  ]);
2309
+ var ShopifyTrackingSyncStatus = z19.enum([
2310
+ "synced",
2311
+ "migrated",
2312
+ "not_detected"
2313
+ ]);
2314
+ var ShopifyTrackingSource = z19.enum([
2315
+ "theme",
2316
+ "legacy_layout",
2317
+ "theme_and_legacy",
2318
+ "none"
2319
+ ]);
2320
+ var ShopifyTrackingResult = z19.object({
2321
+ status: ShopifyTrackingSyncStatus,
2322
+ manualCodeDetected: z19.boolean(),
2323
+ /** True when code from a prior ProductMaker layout was preserved automatically. */
2324
+ legacyCodeMigrated: z19.boolean().default(false),
2325
+ source: ShopifyTrackingSource.default("none"),
2326
+ syncedAt: z19.string().datetime()
2327
+ });
2309
2328
  var ShopifyPublishResponse = z19.object({
2310
2329
  publicationId: z19.string().uuid(),
2311
2330
  taskId: z19.string().uuid(),
@@ -2321,6 +2340,8 @@ var ShopifyPublishResponse = z19.object({
2321
2340
  needsThemeSetup: z19.boolean().optional(),
2322
2341
  /** One-click theme-editor deep link to add the Code Landing block (when needsThemeSetup). */
2323
2342
  themeEditorDeepLink: z19.string().url().optional(),
2343
+ /** Tracking copied from the theme or migrated from a previous ProductMaker layout. */
2344
+ tracking: ShopifyTrackingResult.optional(),
2324
2345
  createdAt: z19.string().datetime().optional(),
2325
2346
  updatedAt: z19.string().datetime().optional()
2326
2347
  });
@@ -3219,7 +3240,9 @@ var ImageCreativeEstimationOptions = z24.object({
3219
3240
  });
3220
3241
  var RegenerateLandingRoleBody = z24.object({
3221
3242
  comment: z24.string().max(500).optional(),
3222
- sourceKey: z24.string().max(200).optional()
3243
+ sourceKey: z24.string().max(200).optional(),
3244
+ /** Client-generated key lets a lost response be retried without another charge. */
3245
+ clientRequestId: z24.string().uuid().optional()
3223
3246
  }).strict();
3224
3247
  var LandingRegenerateEstimationOptions = z24.object({
3225
3248
  /** KIE image endpoint has non-linear pricing by nVariants; for landing we default to 2. */
@@ -6165,8 +6188,7 @@ var DEFAULT_PRICING = {
6165
6188
  userPriceCents: 0.04
6166
6189
  }
6167
6190
  };
6168
- var REGEN_I2V_CLIP_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok15-persec-480p"].ourCostCents * 3;
6169
- var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-480p"].ourCostCents;
6191
+ var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-720p"].ourCostCents;
6170
6192
  var SC_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].ourCostCents;
6171
6193
  var SC_FRAME_COMPOSE_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].userPriceCents;
6172
6194
  var MS_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:nano-banana-2"].ourCostCents;
@@ -7443,10 +7465,35 @@ var ListLandingEditsResponse = z37.object({
7443
7465
  edits: z37.array(LandingEditDto)
7444
7466
  });
7445
7467
 
7446
- // ../../packages/types/src/video-edit.ts
7468
+ // ../../packages/types/src/landing-regeneration.ts
7447
7469
  import { z as z38 } from "zod";
7470
+ var LandingRegenerationStatus = z38.enum([
7471
+ "queued",
7472
+ "processing",
7473
+ "published",
7474
+ "failed"
7475
+ ]);
7476
+ var RegenerateLandingRoleResponse = z38.object({
7477
+ ok: z38.literal(true),
7478
+ role: LandingRole,
7479
+ promptIndex: z38.number().int().nonnegative(),
7480
+ operationId: z38.string().min(1)
7481
+ });
7482
+ var LandingRegenerationStatusResponse = z38.object({
7483
+ ok: z38.literal(true),
7484
+ operationId: z38.string().min(1),
7485
+ role: LandingRole,
7486
+ status: LandingRegenerationStatus,
7487
+ refunded: z38.boolean(),
7488
+ failureReason: z38.string().nullable(),
7489
+ publishedAssetKey: z38.string().nullable(),
7490
+ updatedAt: z38.string().datetime()
7491
+ });
7492
+
7493
+ // ../../packages/types/src/video-edit.ts
7494
+ import { z as z39 } from "zod";
7448
7495
  var MAX_SEGMENT_SECONDS = 3;
7449
- var VideoEditStatusSchema = z38.enum([
7496
+ var VideoEditStatusSchema = z39.enum([
7450
7497
  "pending",
7451
7498
  "processing",
7452
7499
  "assembling",
@@ -7455,9 +7502,9 @@ var VideoEditStatusSchema = z38.enum([
7455
7502
  "discarded",
7456
7503
  "failed"
7457
7504
  ]);
7458
- var VideoEditTimeSectionSchema = z38.object({
7459
- startSec: z38.number().min(0),
7460
- endSec: z38.number().positive()
7505
+ var VideoEditTimeSectionSchema = z39.object({
7506
+ startSec: z39.number().min(0),
7507
+ endSec: z39.number().positive()
7461
7508
  }).refine((v) => v.endSec > v.startSec, {
7462
7509
  message: "endSec must be after startSec",
7463
7510
  path: [
@@ -7469,35 +7516,35 @@ var VideoEditTimeSectionSchema = z38.object({
7469
7516
  "endSec"
7470
7517
  ]
7471
7518
  });
7472
- var VideoEditRequestSchema = z38.object({
7473
- comment: z38.string().trim().min(1).max(2e3),
7474
- sections: z38.array(VideoEditTimeSectionSchema).min(1).optional()
7519
+ var VideoEditRequestSchema = z39.object({
7520
+ comment: z39.string().trim().min(1).max(2e3),
7521
+ sections: z39.array(VideoEditTimeSectionSchema).min(1).optional()
7475
7522
  });
7476
- var VideoEditModeSchema = z38.enum([
7523
+ var VideoEditModeSchema = z39.enum([
7477
7524
  "wan_edit",
7478
7525
  "regenerate"
7479
7526
  ]);
7480
- var VideoRegenerationEngineSchema = z38.enum([
7527
+ var VideoRegenerationEngineSchema = z39.enum([
7481
7528
  "free_text",
7482
7529
  "free_image",
7483
7530
  "single_call",
7484
7531
  "multi_shot"
7485
7532
  ]);
7486
- var VideoRegenerationRouteFingerprintSchema = z38.string().trim().min(1).max(128);
7487
- var RegenerateEditRequestSchema = z38.object({
7488
- angleKey: z38.string().min(1),
7489
- comment: z38.string().min(1).max(2e3)
7533
+ var VideoRegenerationRouteFingerprintSchema = z39.string().trim().min(1).max(128);
7534
+ var RegenerateEditRequestSchema = z39.object({
7535
+ angleKey: z39.string().min(1),
7536
+ comment: z39.string().min(1).max(2e3)
7490
7537
  });
7491
7538
 
7492
7539
  // ../../packages/types/src/dropshipping-project.ts
7493
- import { z as z39 } from "zod";
7494
- var DropshippingProjectStatusSchema = z39.enum([
7540
+ import { z as z40 } from "zod";
7541
+ var DropshippingProjectStatusSchema = z40.enum([
7495
7542
  "active",
7496
7543
  "completed",
7497
7544
  "archived"
7498
7545
  ]);
7499
7546
  var DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN = "dropshipping-launch-v1";
7500
- var DropshippingRewardMilestoneSchema = z39.enum([
7547
+ var DropshippingRewardMilestoneSchema = z40.enum([
7501
7548
  "product_selected",
7502
7549
  "costing_saved",
7503
7550
  "product_media_ready",
@@ -7512,21 +7559,21 @@ var DROPSHIPPING_LAUNCH_REWARD_CREDITS = {
7512
7559
  campaign_created: 200
7513
7560
  };
7514
7561
  var DROPSHIPPING_LAUNCH_REWARD_TOTAL_CREDITS = Object.values(DROPSHIPPING_LAUNCH_REWARD_CREDITS).reduce((sum, credits) => sum + credits, 0);
7515
- var DropshippingProjectRewardMilestoneStateSchema = z39.object({
7562
+ var DropshippingProjectRewardMilestoneStateSchema = z40.object({
7516
7563
  milestone: DropshippingRewardMilestoneSchema,
7517
- credits: z39.number().int().positive(),
7518
- available: z39.boolean().optional(),
7519
- earned: z39.boolean(),
7520
- grantId: z39.string().uuid().nullable(),
7521
- grantedAt: z39.string().datetime().nullable()
7522
- });
7523
- var DropshippingProjectRewardProgressSchema = z39.object({
7524
- campaignKey: z39.literal(DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN),
7525
- totalCredits: z39.number().int().positive(),
7526
- earnedCredits: z39.number().int().nonnegative(),
7527
- milestones: z39.array(DropshippingProjectRewardMilestoneStateSchema).length(DropshippingRewardMilestoneSchema.options.length)
7528
- });
7529
- var DropshippingProjectPhaseSchema = z39.enum([
7564
+ credits: z40.number().int().positive(),
7565
+ available: z40.boolean().optional(),
7566
+ earned: z40.boolean(),
7567
+ grantId: z40.string().uuid().nullable(),
7568
+ grantedAt: z40.string().datetime().nullable()
7569
+ });
7570
+ var DropshippingProjectRewardProgressSchema = z40.object({
7571
+ campaignKey: z40.literal(DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN),
7572
+ totalCredits: z40.number().int().positive(),
7573
+ earnedCredits: z40.number().int().nonnegative(),
7574
+ milestones: z40.array(DropshippingProjectRewardMilestoneStateSchema).length(DropshippingRewardMilestoneSchema.options.length)
7575
+ });
7576
+ var DropshippingProjectPhaseSchema = z40.enum([
7530
7577
  "research",
7531
7578
  "costing",
7532
7579
  "media",
@@ -7535,18 +7582,18 @@ var DropshippingProjectPhaseSchema = z39.enum([
7535
7582
  "advertising",
7536
7583
  "complete"
7537
7584
  ]);
7538
- var DropshippingProjectCostingInputSchema = z39.object({
7539
- country: z39.string().min(2).max(3),
7540
- supplierCost: z39.number().finite().positive(),
7541
- shippingCost: z39.number().finite().nonnegative(),
7542
- returnRate: z39.number().finite().min(0).lt(1),
7543
- cancellationRate: z39.number().finite().min(0).lt(1),
7544
- adsManagerCpa: z39.number().finite().nonnegative(),
7545
- desiredMargin: z39.number().finite().min(0).lt(1)
7585
+ var DropshippingProjectCostingInputSchema = z40.object({
7586
+ country: z40.string().min(2).max(3),
7587
+ supplierCost: z40.number().finite().positive(),
7588
+ shippingCost: z40.number().finite().nonnegative(),
7589
+ returnRate: z40.number().finite().min(0).lt(1),
7590
+ cancellationRate: z40.number().finite().min(0).lt(1),
7591
+ adsManagerCpa: z40.number().finite().nonnegative(),
7592
+ desiredMargin: z40.number().finite().min(0).lt(1)
7546
7593
  }).superRefine(({ returnRate, cancellationRate }, context) => {
7547
7594
  if (returnRate + cancellationRate >= 1) {
7548
7595
  context.addIssue({
7549
- code: z39.ZodIssueCode.custom,
7596
+ code: z40.ZodIssueCode.custom,
7550
7597
  path: [
7551
7598
  "cancellationRate"
7552
7599
  ],
@@ -7554,24 +7601,24 @@ var DropshippingProjectCostingInputSchema = z39.object({
7554
7601
  });
7555
7602
  }
7556
7603
  });
7557
- var DropshippingProjectCostingResultSchema = z39.object({
7558
- country: z39.string().min(2).max(3),
7559
- deliveryRate: z39.number().finite(),
7560
- adjustedShippingCost: z39.number().finite(),
7561
- adjustedCpa: z39.number().finite(),
7562
- totalCost: z39.number().finite(),
7563
- suggestedPrice: z39.number().finite(),
7564
- baseCommercialPrice: z39.number().finite(),
7565
- minimumSafePrice: z39.number().finite(),
7566
- commercialPrice: z39.number().finite(),
7567
- comparisonPrice: z39.number().finite(),
7568
- estimatedProfit: z39.number().finite(),
7569
- actualMargin: z39.number().finite(),
7570
- breakEvenAdsManagerCpa: z39.number().finite(),
7571
- wasPriceAutoAdjusted: z39.boolean(),
7572
- profitabilityStatus: z39.literal("healthy")
7573
- });
7574
- var HttpUrlSchema = z39.string().url().max(2e3).refine((value) => {
7604
+ var DropshippingProjectCostingResultSchema = z40.object({
7605
+ country: z40.string().min(2).max(3),
7606
+ deliveryRate: z40.number().finite(),
7607
+ adjustedShippingCost: z40.number().finite(),
7608
+ adjustedCpa: z40.number().finite(),
7609
+ totalCost: z40.number().finite(),
7610
+ suggestedPrice: z40.number().finite(),
7611
+ baseCommercialPrice: z40.number().finite(),
7612
+ minimumSafePrice: z40.number().finite(),
7613
+ commercialPrice: z40.number().finite(),
7614
+ comparisonPrice: z40.number().finite(),
7615
+ estimatedProfit: z40.number().finite(),
7616
+ actualMargin: z40.number().finite(),
7617
+ breakEvenAdsManagerCpa: z40.number().finite(),
7618
+ wasPriceAutoAdjusted: z40.boolean(),
7619
+ profitabilityStatus: z40.literal("healthy")
7620
+ });
7621
+ var HttpUrlSchema = z40.string().url().max(2e3).refine((value) => {
7575
7622
  try {
7576
7623
  return [
7577
7624
  "http:",
@@ -7581,124 +7628,124 @@ var HttpUrlSchema = z39.string().url().max(2e3).refine((value) => {
7581
7628
  return false;
7582
7629
  }
7583
7630
  }, "Product URL must use HTTP(S)");
7584
- var ResearchCandidateOriginSchema = z39.object({
7585
- type: z39.literal("research_candidate"),
7586
- runId: z39.string().uuid(),
7587
- candidateSourceId: z39.string().min(1).max(160)
7588
- });
7589
- var TaskOriginSchema = z39.object({
7590
- type: z39.literal("task"),
7591
- taskId: z39.string().uuid()
7592
- });
7593
- var ManualOriginSchema = z39.object({
7594
- type: z39.literal("manual"),
7595
- clientRequestId: z39.string().uuid(),
7596
- country: z39.string().min(2).max(3).optional()
7597
- });
7598
- var CreateDropshippingProjectRequestSchema = z39.object({
7599
- origin: z39.discriminatedUnion("type", [
7631
+ var ResearchCandidateOriginSchema = z40.object({
7632
+ type: z40.literal("research_candidate"),
7633
+ runId: z40.string().uuid(),
7634
+ candidateSourceId: z40.string().min(1).max(160)
7635
+ });
7636
+ var TaskOriginSchema = z40.object({
7637
+ type: z40.literal("task"),
7638
+ taskId: z40.string().uuid()
7639
+ });
7640
+ var ManualOriginSchema = z40.object({
7641
+ type: z40.literal("manual"),
7642
+ clientRequestId: z40.string().uuid(),
7643
+ country: z40.string().min(2).max(3).optional()
7644
+ });
7645
+ var CreateDropshippingProjectRequestSchema = z40.object({
7646
+ origin: z40.discriminatedUnion("type", [
7600
7647
  ResearchCandidateOriginSchema,
7601
7648
  TaskOriginSchema,
7602
7649
  ManualOriginSchema
7603
7650
  ]),
7604
- productName: z39.string().trim().min(1).max(240).optional(),
7651
+ productName: z40.string().trim().min(1).max(240).optional(),
7605
7652
  productUrl: HttpUrlSchema.optional(),
7606
- country: z39.string().min(2).max(3).optional(),
7607
- languageCode: z39.string().min(2).max(16).optional()
7653
+ country: z40.string().min(2).max(3).optional(),
7654
+ languageCode: z40.string().min(2).max(16).optional()
7608
7655
  }).strict();
7609
- var SaveDropshippingProjectCostingRequestSchema = z39.object({
7656
+ var SaveDropshippingProjectCostingRequestSchema = z40.object({
7610
7657
  input: DropshippingProjectCostingInputSchema,
7611
- version: z39.number().int().positive()
7658
+ version: z40.number().int().positive()
7612
7659
  }).strict();
7613
- var DropshippingProjectNextActionSchema = z39.discriminatedUnion("kind", [
7614
- z39.object({
7615
- kind: z39.literal("cost_product"),
7616
- href: z39.string().min(1)
7660
+ var DropshippingProjectNextActionSchema = z40.discriminatedUnion("kind", [
7661
+ z40.object({
7662
+ kind: z40.literal("cost_product"),
7663
+ href: z40.string().min(1)
7617
7664
  }),
7618
- z39.object({
7619
- kind: z39.literal("provide_product_media"),
7620
- href: z39.string().min(1)
7665
+ z40.object({
7666
+ kind: z40.literal("provide_product_media"),
7667
+ href: z40.string().min(1)
7621
7668
  }),
7622
- z39.object({
7623
- kind: z39.literal("generate_creatives"),
7624
- href: z39.string().min(1)
7669
+ z40.object({
7670
+ kind: z40.literal("generate_creatives"),
7671
+ href: z40.string().min(1)
7625
7672
  }),
7626
- z39.object({
7627
- kind: z39.literal("wait_for_creatives"),
7628
- href: z39.string().min(1)
7673
+ z40.object({
7674
+ kind: z40.literal("wait_for_creatives"),
7675
+ href: z40.string().min(1)
7629
7676
  }),
7630
- z39.object({
7631
- kind: z39.literal("repair_creatives"),
7632
- href: z39.string().min(1)
7677
+ z40.object({
7678
+ kind: z40.literal("repair_creatives"),
7679
+ href: z40.string().min(1)
7633
7680
  }),
7634
- z39.object({
7635
- kind: z39.literal("complete_creative_set"),
7636
- href: z39.string().min(1)
7681
+ z40.object({
7682
+ kind: z40.literal("complete_creative_set"),
7683
+ href: z40.string().min(1)
7637
7684
  }),
7638
- z39.object({
7639
- kind: z39.literal("connect_shopify"),
7640
- href: z39.string().min(1)
7685
+ z40.object({
7686
+ kind: z40.literal("connect_shopify"),
7687
+ href: z40.string().min(1)
7641
7688
  }),
7642
- z39.object({
7643
- kind: z39.literal("publish_storefront"),
7644
- href: z39.string().min(1)
7689
+ z40.object({
7690
+ kind: z40.literal("publish_storefront"),
7691
+ href: z40.string().min(1)
7645
7692
  }),
7646
- z39.object({
7647
- kind: z39.literal("wait_for_storefront"),
7648
- href: z39.string().min(1)
7693
+ z40.object({
7694
+ kind: z40.literal("wait_for_storefront"),
7695
+ href: z40.string().min(1)
7649
7696
  }),
7650
- z39.object({
7651
- kind: z39.literal("connect_meta"),
7652
- href: z39.string().min(1)
7697
+ z40.object({
7698
+ kind: z40.literal("connect_meta"),
7699
+ href: z40.string().min(1)
7653
7700
  }),
7654
- z39.object({
7655
- kind: z39.literal("create_meta_campaign"),
7656
- href: z39.string().min(1)
7701
+ z40.object({
7702
+ kind: z40.literal("create_meta_campaign"),
7703
+ href: z40.string().min(1)
7657
7704
  }),
7658
- z39.object({
7659
- kind: z39.literal("repair_meta_campaign"),
7660
- href: z39.string().min(1)
7705
+ z40.object({
7706
+ kind: z40.literal("repair_meta_campaign"),
7707
+ href: z40.string().min(1)
7661
7708
  }),
7662
- z39.object({
7663
- kind: z39.literal("review_paused_campaign"),
7664
- href: z39.string().min(1)
7709
+ z40.object({
7710
+ kind: z40.literal("review_paused_campaign"),
7711
+ href: z40.string().min(1)
7665
7712
  })
7666
7713
  ]);
7667
- var DropshippingProjectResponseSchema = z39.object({
7668
- id: z39.string().uuid(),
7669
- taskId: z39.string().uuid().nullable(),
7714
+ var DropshippingProjectResponseSchema = z40.object({
7715
+ id: z40.string().uuid(),
7716
+ taskId: z40.string().uuid().nullable(),
7670
7717
  status: DropshippingProjectStatusSchema,
7671
- originKey: z39.string().min(1),
7672
- researchRunId: z39.string().uuid().nullable(),
7673
- candidateSourceId: z39.string().nullable(),
7674
- productName: z39.string().nullable(),
7718
+ originKey: z40.string().min(1),
7719
+ researchRunId: z40.string().uuid().nullable(),
7720
+ candidateSourceId: z40.string().nullable(),
7721
+ productName: z40.string().nullable(),
7675
7722
  productUrl: HttpUrlSchema.nullable(),
7676
- referenceImageUrl: z39.string().url().nullable(),
7677
- hasReferenceImage: z39.boolean(),
7678
- targetCountry: z39.string().nullable(),
7679
- languageCode: z39.string().nullable(),
7723
+ referenceImageUrl: z40.string().url().nullable(),
7724
+ hasReferenceImage: z40.boolean(),
7725
+ targetCountry: z40.string().nullable(),
7726
+ languageCode: z40.string().nullable(),
7680
7727
  costingInput: DropshippingProjectCostingInputSchema.nullable(),
7681
7728
  costingResult: DropshippingProjectCostingResultSchema.nullable(),
7682
- costingVersion: z39.number().int().positive().nullable(),
7683
- version: z39.number().int().positive(),
7729
+ costingVersion: z40.number().int().positive().nullable(),
7730
+ version: z40.number().int().positive(),
7684
7731
  phase: DropshippingProjectPhaseSchema,
7685
7732
  nextAction: DropshippingProjectNextActionSchema.nullable(),
7686
7733
  rewards: DropshippingProjectRewardProgressSchema,
7687
- createdAt: z39.string().datetime(),
7688
- updatedAt: z39.string().datetime()
7734
+ createdAt: z40.string().datetime(),
7735
+ updatedAt: z40.string().datetime()
7689
7736
  });
7690
7737
 
7691
7738
  // ../../packages/types/src/scene-subject-contract.ts
7692
- import { z as z40 } from "zod";
7693
- var SceneSubjectContractSchema = z40.object({
7694
- maxPeople: z40.number().int().min(1).max(10),
7695
- minPeople: z40.number().int().min(0).max(10),
7696
- minDistinctPeople: z40.number().int().min(0).max(10),
7697
- maxHands: z40.number().int().min(0).max(20)
7739
+ import { z as z41 } from "zod";
7740
+ var SceneSubjectContractSchema = z41.object({
7741
+ maxPeople: z41.number().int().min(1).max(10),
7742
+ minPeople: z41.number().int().min(0).max(10),
7743
+ minDistinctPeople: z41.number().int().min(0).max(10),
7744
+ maxHands: z41.number().int().min(0).max(20)
7698
7745
  }).superRefine((value, ctx) => {
7699
7746
  if (value.minPeople > value.maxPeople) {
7700
7747
  ctx.addIssue({
7701
- code: z40.ZodIssueCode.custom,
7748
+ code: z41.ZodIssueCode.custom,
7702
7749
  path: [
7703
7750
  "minPeople"
7704
7751
  ],
@@ -7707,7 +7754,7 @@ var SceneSubjectContractSchema = z40.object({
7707
7754
  }
7708
7755
  if (value.minDistinctPeople > value.maxPeople) {
7709
7756
  ctx.addIssue({
7710
- code: z40.ZodIssueCode.custom,
7757
+ code: z41.ZodIssueCode.custom,
7711
7758
  path: [
7712
7759
  "minDistinctPeople"
7713
7760
  ],
@@ -7716,7 +7763,7 @@ var SceneSubjectContractSchema = z40.object({
7716
7763
  }
7717
7764
  if (value.minDistinctPeople > value.minPeople) {
7718
7765
  ctx.addIssue({
7719
- code: z40.ZodIssueCode.custom,
7766
+ code: z41.ZodIssueCode.custom,
7720
7767
  path: [
7721
7768
  "minDistinctPeople"
7722
7769
  ],
@@ -7726,7 +7773,7 @@ var SceneSubjectContractSchema = z40.object({
7726
7773
  });
7727
7774
 
7728
7775
  // ../../packages/types/src/service-creative.ts
7729
- import { z as z41 } from "zod";
7776
+ import { z as z42 } from "zod";
7730
7777
  var SERVICE_CREATIVE_PUBLIC_PRESETS = [
7731
7778
  "auto",
7732
7779
  "ugc_dynamic",
@@ -7734,19 +7781,19 @@ var SERVICE_CREATIVE_PUBLIC_PRESETS = [
7734
7781
  "cinematic",
7735
7782
  "wild_card"
7736
7783
  ];
7737
- var ServiceCreativePresetSchema = z41.enum(SERVICE_CREATIVE_PUBLIC_PRESETS);
7784
+ var ServiceCreativePresetSchema = z42.enum(SERVICE_CREATIVE_PUBLIC_PRESETS);
7738
7785
  var SERVICE_REVIEW_MODES = [
7739
7786
  "automatic",
7740
7787
  "guided"
7741
7788
  ];
7742
- var ServiceReviewModeSchema = z41.enum(SERVICE_REVIEW_MODES);
7789
+ var ServiceReviewModeSchema = z42.enum(SERVICE_REVIEW_MODES);
7743
7790
  var SERVICE_HIGGSFIELD_MODES = [
7744
7791
  "product_review",
7745
7792
  "ugc_how_to",
7746
7793
  "tv_spot",
7747
7794
  "wild_card"
7748
7795
  ];
7749
- var ServiceHiggsfieldModeSchema = z41.enum(SERVICE_HIGGSFIELD_MODES);
7796
+ var ServiceHiggsfieldModeSchema = z42.enum(SERVICE_HIGGSFIELD_MODES);
7750
7797
  var SERVICE_MEDIA_ROLES = [
7751
7798
  "screen_demo",
7752
7799
  "ad_reference",
@@ -7754,20 +7801,20 @@ var SERVICE_MEDIA_ROLES = [
7754
7801
  "presenter_reference",
7755
7802
  "brand_asset"
7756
7803
  ];
7757
- var ServiceMediaRoleSchema = z41.enum(SERVICE_MEDIA_ROLES);
7758
- var ServiceMediaAssetSchema = z41.object({
7804
+ var ServiceMediaRoleSchema = z42.enum(SERVICE_MEDIA_ROLES);
7805
+ var ServiceMediaAssetSchema = z42.object({
7759
7806
  role: ServiceMediaRoleSchema,
7760
- s3Key: z41.string().min(1),
7807
+ s3Key: z42.string().min(1),
7761
7808
  /** HMAC ticket returned by the authenticated service-media presign route. */
7762
- uploadToken: z41.string().min(1).optional(),
7763
- mimeType: z41.string().min(1),
7764
- durationSec: z41.number().positive().max(30).optional(),
7765
- sourceName: z41.string().max(255).optional()
7809
+ uploadToken: z42.string().min(1).optional(),
7810
+ mimeType: z42.string().min(1),
7811
+ durationSec: z42.number().positive().max(30).optional(),
7812
+ sourceName: z42.string().max(255).optional()
7766
7813
  }).superRefine((asset, ctx) => {
7767
7814
  const isVideoRole = asset.role === "screen_demo" || asset.role === "ad_reference";
7768
7815
  if (isVideoRole && !asset.mimeType.startsWith("video/")) {
7769
7816
  ctx.addIssue({
7770
- code: z41.ZodIssueCode.custom,
7817
+ code: z42.ZodIssueCode.custom,
7771
7818
  message: `${asset.role} requires video media`,
7772
7819
  path: [
7773
7820
  "mimeType"
@@ -7776,7 +7823,7 @@ var ServiceMediaAssetSchema = z41.object({
7776
7823
  }
7777
7824
  if (isVideoRole && asset.durationSec === void 0) {
7778
7825
  ctx.addIssue({
7779
- code: z41.ZodIssueCode.custom,
7826
+ code: z42.ZodIssueCode.custom,
7780
7827
  message: `${asset.role} requires durationSec`,
7781
7828
  path: [
7782
7829
  "durationSec"
@@ -7785,7 +7832,7 @@ var ServiceMediaAssetSchema = z41.object({
7785
7832
  }
7786
7833
  if (!isVideoRole && !asset.mimeType.startsWith("image/")) {
7787
7834
  ctx.addIssue({
7788
- code: z41.ZodIssueCode.custom,
7835
+ code: z42.ZodIssueCode.custom,
7789
7836
  message: `${asset.role} requires image media`,
7790
7837
  path: [
7791
7838
  "mimeType"
@@ -7793,13 +7840,13 @@ var ServiceMediaAssetSchema = z41.object({
7793
7840
  });
7794
7841
  }
7795
7842
  });
7796
- var ServiceMediaBundleSchema = z41.object({
7797
- assets: z41.array(ServiceMediaAssetSchema).max(15).default([])
7843
+ var ServiceMediaBundleSchema = z42.object({
7844
+ assets: z42.array(ServiceMediaAssetSchema).max(15).default([])
7798
7845
  }).superRefine((bundle, ctx) => {
7799
7846
  const adReferences = bundle.assets.filter((asset) => asset.role === "ad_reference");
7800
7847
  if (adReferences.length > 5) {
7801
7848
  ctx.addIssue({
7802
- code: z41.ZodIssueCode.custom,
7849
+ code: z42.ZodIssueCode.custom,
7803
7850
  message: "A maximum of five ad_reference videos is allowed",
7804
7851
  path: [
7805
7852
  "assets"
@@ -7809,7 +7856,7 @@ var ServiceMediaBundleSchema = z41.object({
7809
7856
  const screenDemos = bundle.assets.filter((asset) => asset.role === "screen_demo");
7810
7857
  if (screenDemos.length > 3) {
7811
7858
  ctx.addIssue({
7812
- code: z41.ZodIssueCode.custom,
7859
+ code: z42.ZodIssueCode.custom,
7813
7860
  message: "A maximum of three screen_demo videos is allowed",
7814
7861
  path: [
7815
7862
  "assets"
@@ -7826,33 +7873,33 @@ var SERVICE_MEDIA_ANALYSIS_KINDS = [
7826
7873
  "product",
7827
7874
  "other"
7828
7875
  ];
7829
- var ServiceMediaAnalysisKindSchema = z41.enum(SERVICE_MEDIA_ANALYSIS_KINDS);
7830
- var ServiceMediaAnalysisItemSchema = z41.object({
7831
- assetIndex: z41.number().int().nonnegative(),
7832
- mediaType: z41.enum([
7876
+ var ServiceMediaAnalysisKindSchema = z42.enum(SERVICE_MEDIA_ANALYSIS_KINDS);
7877
+ var ServiceMediaAnalysisItemSchema = z42.object({
7878
+ assetIndex: z42.number().int().nonnegative(),
7879
+ mediaType: z42.enum([
7833
7880
  "image",
7834
7881
  "video"
7835
7882
  ]),
7836
7883
  kind: ServiceMediaAnalysisKindSchema,
7837
- description: z41.string().min(1).max(1200),
7838
- tags: z41.array(z41.string().min(1).max(80)).max(12),
7839
- suggestedRoles: z41.array(ServiceMediaRoleSchema).max(4),
7840
- visiblePeople: z41.number().int().nonnegative().max(20).optional(),
7841
- ocrText: z41.string().max(2e3).optional(),
7842
- speechSummary: z41.string().max(2e3).optional()
7843
- });
7844
- var ServiceMediaAnalysisSchema = z41.object({
7845
- version: z41.literal(1),
7846
- analyzedAt: z41.string().datetime(),
7847
- pricingAction: z41.literal("service-media-analysis"),
7848
- assetFingerprint: z41.string().regex(/^[a-f0-9]{64}$/),
7884
+ description: z42.string().min(1).max(1200),
7885
+ tags: z42.array(z42.string().min(1).max(80)).max(12),
7886
+ suggestedRoles: z42.array(ServiceMediaRoleSchema).max(4),
7887
+ visiblePeople: z42.number().int().nonnegative().max(20).optional(),
7888
+ ocrText: z42.string().max(2e3).optional(),
7889
+ speechSummary: z42.string().max(2e3).optional()
7890
+ });
7891
+ var ServiceMediaAnalysisSchema = z42.object({
7892
+ version: z42.literal(1),
7893
+ analyzedAt: z42.string().datetime(),
7894
+ pricingAction: z42.literal("service-media-analysis"),
7895
+ assetFingerprint: z42.string().regex(/^[a-f0-9]{64}$/),
7849
7896
  /** Language used for human-readable descriptions and tags. Optional for old checkpoints. */
7850
- language: z41.enum([
7897
+ language: z42.enum([
7851
7898
  "es",
7852
7899
  "en",
7853
7900
  "pt"
7854
7901
  ]).optional(),
7855
- items: z41.array(ServiceMediaAnalysisItemSchema).max(15)
7902
+ items: z42.array(ServiceMediaAnalysisItemSchema).max(15)
7856
7903
  });
7857
7904
 
7858
7905
  // ../../packages/types/src/productmaker-chat-capabilities.ts
@@ -8030,7 +8077,7 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
8030
8077
  {
8031
8078
  name: "request_meta_media_upload",
8032
8079
  confirmation: "none",
8033
- schemaHash: "32203d205f414c386ee6ab33e265eb2708c108fca4169d4c12e99d7a4109a132"
8080
+ schemaHash: "fad928b17b4658eb5831bb8b62d5e65bd5220ad94b04b90ace09e658e1895c74"
8034
8081
  },
8035
8082
  {
8036
8083
  name: "resolve_pending_action",
@@ -8046,8 +8093,8 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
8046
8093
  var PRODUCTMAKER_MCP_CAPABILITY_NAMES = PRODUCTMAKER_MCP_CAPABILITIES.map((capability) => capability.name);
8047
8094
 
8048
8095
  // ../../packages/types/src/actor.ts
8049
- import { z as z42 } from "zod";
8050
- var ActorStatusSchema = z42.enum([
8096
+ import { z as z43 } from "zod";
8097
+ var ActorStatusSchema = z43.enum([
8051
8098
  "draft",
8052
8099
  "generating",
8053
8100
  "ready",
@@ -8056,18 +8103,18 @@ var ActorStatusSchema = z42.enum([
8056
8103
  var ACTOR_NAME_MAX_CHARS = 60;
8057
8104
  var ACTOR_DESCRIPTION_MAX_CHARS = 600;
8058
8105
  var ACTOR_CANDIDATE_COUNT = 4;
8059
- var ActorGenderSchema = z42.enum([
8106
+ var ActorGenderSchema = z43.enum([
8060
8107
  "female",
8061
8108
  "male",
8062
8109
  "non_binary"
8063
8110
  ]);
8064
- var ActorSchema = z42.object({
8065
- id: z42.string(),
8066
- name: z42.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8067
- description: z42.string().max(ACTOR_DESCRIPTION_MAX_CHARS),
8111
+ var ActorSchema = z43.object({
8112
+ id: z43.string(),
8113
+ name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8114
+ description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS),
8068
8115
  gender: ActorGenderSchema,
8069
- voiceId: z42.string().nullable().optional(),
8070
- brandId: z42.string().nullable().optional(),
8116
+ voiceId: z43.string().nullable().optional(),
8117
+ brandId: z43.string().nullable().optional(),
8071
8118
  status: ActorStatusSchema,
8072
8119
  /**
8073
8120
  * A candidate-grid run is in flight RIGHT NOW.
@@ -8079,36 +8126,36 @@ var ActorSchema = z42.object({
8079
8126
  * timestamp with a TTL, so an orphaned run reads as `false` instead of
8080
8127
  * pinning the personaje forever.
8081
8128
  */
8082
- generating: z42.boolean().optional(),
8083
- photoUrl: z42.string().url().nullable().optional(),
8084
- avatarUrl: z42.string().url().nullable().optional(),
8085
- candidateUrls: z42.array(z42.string().url()).optional(),
8129
+ generating: z43.boolean().optional(),
8130
+ photoUrl: z43.string().url().nullable().optional(),
8131
+ avatarUrl: z43.string().url().nullable().optional(),
8132
+ candidateUrls: z43.array(z43.string().url()).optional(),
8086
8133
  /** Indices of candidateUrls that failed the anatomy check (Task 6). */
8087
- flaggedCandidateIndices: z42.array(z42.number().int()).optional()
8134
+ flaggedCandidateIndices: z43.array(z43.number().int()).optional()
8088
8135
  });
8089
- var CreateActorRequest = z42.object({
8090
- name: z42.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8091
- description: z42.string().max(ACTOR_DESCRIPTION_MAX_CHARS).default(""),
8136
+ var CreateActorRequest = z43.object({
8137
+ name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
8138
+ description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).default(""),
8092
8139
  gender: ActorGenderSchema,
8093
- voiceId: z42.string().optional(),
8094
- brandId: z42.string().optional(),
8095
- sourcePhotoKey: z42.string().optional()
8140
+ voiceId: z43.string().optional(),
8141
+ brandId: z43.string().optional(),
8142
+ sourcePhotoKey: z43.string().optional()
8096
8143
  }).refine((v) => v.description.trim().length > 0 || !!v.sourcePhotoKey, {
8097
8144
  message: "Se necesita una descripci\xF3n o una foto"
8098
8145
  });
8099
- var UpdateActorRequest = z42.object({
8100
- name: z42.string().min(1).max(ACTOR_NAME_MAX_CHARS).optional(),
8101
- description: z42.string().max(ACTOR_DESCRIPTION_MAX_CHARS).optional(),
8146
+ var UpdateActorRequest = z43.object({
8147
+ name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS).optional(),
8148
+ description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).optional(),
8102
8149
  gender: ActorGenderSchema.optional(),
8103
- voiceId: z42.string().nullable().optional(),
8104
- brandId: z42.string().nullable().optional()
8150
+ voiceId: z43.string().nullable().optional(),
8151
+ brandId: z43.string().nullable().optional()
8105
8152
  });
8106
- var ApproveActorRequest = z42.object({
8107
- candidateIndex: z42.number().int().min(0).max(ACTOR_CANDIDATE_COUNT - 1)
8153
+ var ApproveActorRequest = z43.object({
8154
+ candidateIndex: z43.number().int().min(0).max(ACTOR_CANDIDATE_COUNT - 1)
8108
8155
  });
8109
8156
 
8110
8157
  // ../../packages/types/src/referral-dashboard.ts
8111
- import { z as z43 } from "zod";
8158
+ import { z as z44 } from "zod";
8112
8159
  var REFERRAL_DASHBOARD_RAW_STATUSES = [
8113
8160
  "ACTIVE",
8114
8161
  "PENDING",
@@ -8127,66 +8174,66 @@ var REFERRAL_DASHBOARD_PLAN_KINDS = [
8127
8174
  "last",
8128
8175
  "none"
8129
8176
  ];
8130
- var ReferralDashboardRawStatusSchema = z43.enum(REFERRAL_DASHBOARD_RAW_STATUSES);
8131
- var ReferralDashboardStateSchema = z43.enum(REFERRAL_DASHBOARD_STATES);
8132
- var ReferralDashboardPlanKindSchema = z43.enum(REFERRAL_DASHBOARD_PLAN_KINDS);
8133
- var ReferralDashboardStatusSchema = z43.enum([
8177
+ var ReferralDashboardRawStatusSchema = z44.enum(REFERRAL_DASHBOARD_RAW_STATUSES);
8178
+ var ReferralDashboardStateSchema = z44.enum(REFERRAL_DASHBOARD_STATES);
8179
+ var ReferralDashboardPlanKindSchema = z44.enum(REFERRAL_DASHBOARD_PLAN_KINDS);
8180
+ var ReferralDashboardStatusSchema = z44.enum([
8134
8181
  "all",
8135
8182
  "active",
8136
8183
  "pending",
8137
8184
  "inactive"
8138
8185
  ]).default("all");
8139
- var ReferralDashboardPlanSchema = z43.string().trim().min(1).max(100).optional();
8140
- var ReferralDashboardFiltersSchema = z43.object({
8186
+ var ReferralDashboardPlanSchema = z44.string().trim().min(1).max(100).optional();
8187
+ var ReferralDashboardFiltersSchema = z44.object({
8141
8188
  status: ReferralDashboardStatusSchema,
8142
8189
  plan: ReferralDashboardPlanSchema
8143
8190
  });
8144
- var ReferralDashboardSubscriptionSchema = z43.object({
8145
- planName: z43.string().nullable(),
8191
+ var ReferralDashboardSubscriptionSchema = z44.object({
8192
+ planName: z44.string().nullable(),
8146
8193
  planKind: ReferralDashboardPlanKindSchema,
8147
8194
  rawStatus: ReferralDashboardRawStatusSchema.nullable(),
8148
8195
  state: ReferralDashboardStateSchema,
8149
- currentPeriodEnd: z43.string().datetime({
8196
+ currentPeriodEnd: z44.string().datetime({
8150
8197
  offset: true
8151
8198
  }).nullable(),
8152
- cancelAtPeriodEnd: z43.boolean()
8199
+ cancelAtPeriodEnd: z44.boolean()
8153
8200
  });
8154
- var ReferralDashboardReferralSchema = z43.object({
8155
- id: z43.string().min(1),
8156
- registeredAt: z43.string().datetime({
8201
+ var ReferralDashboardReferralSchema = z44.object({
8202
+ id: z44.string().min(1),
8203
+ registeredAt: z44.string().datetime({
8157
8204
  offset: true
8158
8205
  }),
8159
8206
  // Kept in the response for compatibility with existing referral API clients.
8160
8207
  // The referrer dashboard intentionally does not render these legacy fields.
8161
- expiresAt: z43.string().datetime({
8208
+ expiresAt: z44.string().datetime({
8162
8209
  offset: true
8163
8210
  }).nullable().optional(),
8164
- status: z43.string().min(1).optional(),
8165
- referredUser: z43.object({
8166
- email: z43.string().nullable()
8211
+ status: z44.string().min(1).optional(),
8212
+ referredUser: z44.object({
8213
+ email: z44.string().nullable()
8167
8214
  }),
8168
8215
  subscription: ReferralDashboardSubscriptionSchema
8169
8216
  });
8170
- var ReferralDashboardReferralsPageSchema = z43.object({
8171
- referrals: z43.array(ReferralDashboardReferralSchema),
8172
- total: z43.number().int().nonnegative()
8217
+ var ReferralDashboardReferralsPageSchema = z44.object({
8218
+ referrals: z44.array(ReferralDashboardReferralSchema),
8219
+ total: z44.number().int().nonnegative()
8173
8220
  });
8174
- var ReferralDashboardPlanBreakdownSchema = z43.object({
8175
- planName: z43.string().nullable(),
8176
- count: z43.number().int().nonnegative()
8221
+ var ReferralDashboardPlanBreakdownSchema = z44.object({
8222
+ planName: z44.string().nullable(),
8223
+ count: z44.number().int().nonnegative()
8177
8224
  });
8178
- var ReferralDashboardMonthlyRegistrationSchema = z43.object({
8179
- month: z43.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
8180
- count: z43.number().int().nonnegative()
8225
+ var ReferralDashboardMonthlyRegistrationSchema = z44.object({
8226
+ month: z44.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
8227
+ count: z44.number().int().nonnegative()
8181
8228
  });
8182
- var ReferralDashboardOverviewSchema = z43.object({
8183
- totalReferredUsers: z43.number().int().nonnegative(),
8184
- activeUsers: z43.number().int().nonnegative(),
8185
- pendingUsers: z43.number().int().nonnegative(),
8186
- inactiveUsers: z43.number().int().nonnegative(),
8187
- noPlanUsers: z43.number().int().nonnegative(),
8188
- planBreakdown: z43.array(ReferralDashboardPlanBreakdownSchema),
8189
- monthlyRegistrations: z43.array(ReferralDashboardMonthlyRegistrationSchema).refine((months) => months.length === 6, "Expected six monthly registration buckets")
8229
+ var ReferralDashboardOverviewSchema = z44.object({
8230
+ totalReferredUsers: z44.number().int().nonnegative(),
8231
+ activeUsers: z44.number().int().nonnegative(),
8232
+ pendingUsers: z44.number().int().nonnegative(),
8233
+ inactiveUsers: z44.number().int().nonnegative(),
8234
+ noPlanUsers: z44.number().int().nonnegative(),
8235
+ planBreakdown: z44.array(ReferralDashboardPlanBreakdownSchema),
8236
+ monthlyRegistrations: z44.array(ReferralDashboardMonthlyRegistrationSchema).refine((months) => months.length === 6, "Expected six monthly registration buckets")
8190
8237
  });
8191
8238
 
8192
8239
  // src/resolve-media.ts
@@ -8428,10 +8475,10 @@ async function resolveMediaRef(ref, opts) {
8428
8475
  __name(resolveMediaRef, "resolveMediaRef");
8429
8476
 
8430
8477
  // src/tools/shared.ts
8431
- import { z as z44 } from "zod";
8432
- var Lang = z44.string().min(2).max(10);
8433
- var Country = z44.string().min(2).max(3);
8434
- var LandingStrategyEnum = z44.enum([
8478
+ import { z as z45 } from "zod";
8479
+ var Lang = z45.string().min(2).max(10);
8480
+ var Country = z45.string().min(2).max(3);
8481
+ var LandingStrategyEnum = z45.enum([
8435
8482
  "auto",
8436
8483
  "classic",
8437
8484
  "pain_solution",
@@ -8440,12 +8487,12 @@ var LandingStrategyEnum = z44.enum([
8440
8487
  "offer_value",
8441
8488
  "lifestyle_identity"
8442
8489
  ]);
8443
- var LandingImageFormatEnum = z44.enum([
8490
+ var LandingImageFormatEnum = z45.enum([
8444
8491
  "9:16",
8445
8492
  "4:5",
8446
8493
  "1:1"
8447
8494
  ]);
8448
- var VideoPresetEnum = z44.enum([
8495
+ var VideoPresetEnum = z45.enum([
8449
8496
  "auto",
8450
8497
  "ugc_dynamic",
8451
8498
  "ugc_how_to",
@@ -8458,7 +8505,7 @@ var VideoPresetEnum = z44.enum([
8458
8505
  "pixar_problem",
8459
8506
  "pixar_sassy"
8460
8507
  ]);
8461
- var TaskCreativeVariantVideoPresetEnum = z44.enum([
8508
+ var TaskCreativeVariantVideoPresetEnum = z45.enum([
8462
8509
  "auto",
8463
8510
  "ugc_dynamic",
8464
8511
  "ugc_how_to",
@@ -8529,7 +8576,7 @@ function resolveVideoPreset(preset) {
8529
8576
  return VIDEO_PRESET_RESOLUTION[preset] ?? null;
8530
8577
  }
8531
8578
  __name(resolveVideoPreset, "resolveVideoPreset");
8532
- var VideoTierEnum = z44.enum([
8579
+ var VideoTierEnum = z45.enum([
8533
8580
  "basic"
8534
8581
  ]);
8535
8582
  function resolveVideoTier(_tier) {
@@ -8544,17 +8591,17 @@ function resolveVideoFormatForDuration(durationSeconds) {
8544
8591
  return durationSeconds === 30 ? "double_30s" : "single_15s";
8545
8592
  }
8546
8593
  __name(resolveVideoFormatForDuration, "resolveVideoFormatForDuration");
8547
- var VideoResolutionEnum = z44.enum([
8594
+ var VideoResolutionEnum = z45.enum([
8548
8595
  "480p",
8549
8596
  "720p"
8550
8597
  ]);
8551
- var VideoStyleEnum = z44.enum([
8598
+ var VideoStyleEnum = z45.enum([
8552
8599
  "ugc",
8553
8600
  "cartoon_3d",
8554
8601
  "product_only",
8555
8602
  "ai_dynamic"
8556
8603
  ]);
8557
- var NarrativeStyleEnum = z44.enum([
8604
+ var NarrativeStyleEnum = z45.enum([
8558
8605
  "review",
8559
8606
  "ugc_how_to",
8560
8607
  "problem_product_cta",
@@ -8571,7 +8618,7 @@ var NarrativeStyleEnum = z44.enum([
8571
8618
  "ugc_skeptic_confession",
8572
8619
  "ugc_demo_review"
8573
8620
  ]);
8574
- var PublicNarrativeStyleEnum = z44.enum([
8621
+ var PublicNarrativeStyleEnum = z45.enum([
8575
8622
  "review",
8576
8623
  "ugc_how_to",
8577
8624
  "ugc_unboxing_chaos",
@@ -8583,7 +8630,7 @@ var PublicNarrativeStyleEnum = z44.enum([
8583
8630
  "animated_problem_pixar",
8584
8631
  "sassy_product_pixar"
8585
8632
  ]);
8586
- var VideoModelEnum = z44.enum([
8633
+ var VideoModelEnum = z45.enum([
8587
8634
  "veo",
8588
8635
  "wan",
8589
8636
  "bytedance",
@@ -8591,25 +8638,25 @@ var VideoModelEnum = z44.enum([
8591
8638
  "grok",
8592
8639
  "kling"
8593
8640
  ]);
8594
- var ProductReferenceUserChoiceEnum = z44.enum([
8641
+ var ProductReferenceUserChoiceEnum = z45.enum([
8595
8642
  "same_product",
8596
8643
  "variants",
8597
8644
  "different_products",
8598
8645
  "combo_distinct"
8599
8646
  ]);
8600
- var ProductReferenceCandidateGroupingEnum = z44.enum([
8647
+ var ProductReferenceCandidateGroupingEnum = z45.enum([
8601
8648
  "same_product_same_variant",
8602
8649
  "same_product_different_variants",
8603
8650
  "different_products",
8604
8651
  "unclear"
8605
8652
  ]);
8606
- var GapDurationChoiceMirror = z44.object({
8607
- angleIndex: z44.number().int().nonnegative(),
8608
- recommendedSec: z44.union([
8609
- z44.literal(15),
8610
- z44.literal(30)
8653
+ var GapDurationChoiceMirror = z45.object({
8654
+ angleIndex: z45.number().int().nonnegative(),
8655
+ recommendedSec: z45.union([
8656
+ z45.literal(15),
8657
+ z45.literal(30)
8611
8658
  ]),
8612
- estimatedDeltaCredits: z44.number().int().nonnegative().optional()
8659
+ estimatedDeltaCredits: z45.number().int().nonnegative().optional()
8613
8660
  });
8614
8661
  function buildSelectedImageUrlsHash(urls) {
8615
8662
  const input = [
@@ -8623,13 +8670,13 @@ function buildSelectedImageUrlsHash(urls) {
8623
8670
  return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
8624
8671
  }
8625
8672
  __name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
8626
- var ImageCreativeStyleEnum = z44.enum([
8673
+ var ImageCreativeStyleEnum = z45.enum([
8627
8674
  "studio",
8628
8675
  "floating",
8629
8676
  "ingredients",
8630
8677
  "in_use"
8631
8678
  ]);
8632
- var ImageCreativeArchetypeEnum = z44.enum([
8679
+ var ImageCreativeArchetypeEnum = z45.enum([
8633
8680
  "direct_response_product_ad",
8634
8681
  "hero_outcome",
8635
8682
  "offer_value_prop",
@@ -8638,23 +8685,23 @@ var ImageCreativeArchetypeEnum = z44.enum([
8638
8685
  "problem_solution",
8639
8686
  "lifestyle_identity"
8640
8687
  ]);
8641
- var ImageCreativeVisualTreatmentEnum = z44.enum([
8688
+ var ImageCreativeVisualTreatmentEnum = z45.enum([
8642
8689
  "performance_product_ad",
8643
8690
  "premium_dtc_carousel"
8644
8691
  ]);
8645
- var ImageCreativeAspectRatioEnum = z44.enum([
8692
+ var ImageCreativeAspectRatioEnum = z45.enum([
8646
8693
  "1:1",
8647
8694
  "4:5",
8648
8695
  "9:16",
8649
8696
  "16:9"
8650
8697
  ]);
8651
- var ImageRefSchema = z44.object({
8652
- 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.'),
8653
- 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`.')
8698
+ var ImageRefSchema = z45.object({
8699
+ 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.'),
8700
+ 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`.')
8654
8701
  }).refine((v) => Boolean(v.url) !== Boolean(v.path), {
8655
8702
  message: "each image entry must have exactly one of `url` or `path`"
8656
8703
  });
8657
- 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.');
8704
+ 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.');
8658
8705
  function asText(value) {
8659
8706
  return {
8660
8707
  content: [
@@ -8707,14 +8754,14 @@ async function submitCreative(api, opts) {
8707
8754
  });
8708
8755
  }
8709
8756
  __name(submitCreative, "submitCreative");
8710
- var ResearchTargetCountryEnum = z44.enum([
8757
+ var ResearchTargetCountryEnum = z45.enum([
8711
8758
  "CO",
8712
8759
  "MX",
8713
8760
  "PE",
8714
8761
  "EC",
8715
8762
  "CL"
8716
8763
  ]);
8717
- var ResearchCategoryEnum = z44.enum([
8764
+ var ResearchCategoryEnum = z45.enum([
8718
8765
  "auto",
8719
8766
  "automotive",
8720
8767
  "kitchen",
@@ -9400,53 +9447,53 @@ function renderOutputsMarkdown(outputs) {
9400
9447
  __name(renderOutputsMarkdown, "renderOutputsMarkdown");
9401
9448
 
9402
9449
  // src/tools/tasks.ts
9403
- var CreateProductTaskInput = z45.object({
9450
+ var CreateProductTaskInput = z46.object({
9404
9451
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
9405
- 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."),
9406
- 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."),
9452
+ 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."),
9453
+ 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."),
9407
9454
  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.'),
9408
9455
  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.'),
9409
- 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.'),
9410
- 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".'),
9411
- 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.'),
9412
- 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.'),
9413
- 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."),
9414
- 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.'),
9456
+ 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.'),
9457
+ 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".'),
9458
+ 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.'),
9459
+ 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.'),
9460
+ 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."),
9461
+ 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.'),
9415
9462
  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.'),
9416
- durationSeconds: z45.union([
9417
- z45.literal(15),
9418
- z45.literal(30)
9463
+ durationSeconds: z46.union([
9464
+ z46.literal(15),
9465
+ z46.literal(30)
9419
9466
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
9420
- 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."),
9467
+ 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."),
9421
9468
  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.'),
9422
9469
  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).'),
9423
- 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."),
9470
+ 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."),
9424
9471
  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.'),
9425
- outputs: z45.array(z45.enum([
9472
+ outputs: z46.array(z46.enum([
9426
9473
  "landing",
9427
9474
  "video",
9428
9475
  "image"
9429
9476
  ])).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.'),
9430
- 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."),
9431
- 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."),
9432
- 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."),
9433
- 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.'),
9434
- 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."),
9435
- 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."),
9477
+ 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."),
9478
+ 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."),
9479
+ 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."),
9480
+ 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.'),
9481
+ 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."),
9482
+ 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."),
9436
9483
  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".'),
9437
9484
  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".')
9438
9485
  }).strict();
9439
- var CreateServiceVideoInput = z45.object({
9440
- 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."),
9441
- 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.'),
9486
+ var CreateServiceVideoInput = z46.object({
9487
+ 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."),
9488
+ 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.'),
9442
9489
  language: Lang.describe("Idioma del video: es, en o pt."),
9443
- 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.'),
9444
- brandId: z45.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
9445
- reviewMode: z45.enum([
9490
+ 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.'),
9491
+ brandId: z46.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
9492
+ reviewMode: z46.enum([
9446
9493
  "automatic",
9447
9494
  "guided"
9448
9495
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
9449
- videoPreset: z45.enum([
9496
+ videoPreset: z46.enum([
9450
9497
  "auto",
9451
9498
  "ugc_dynamic",
9452
9499
  "ugc_how_to",
@@ -9454,35 +9501,35 @@ var CreateServiceVideoInput = z45.object({
9454
9501
  "wild_card"
9455
9502
  ]).default("auto")
9456
9503
  }).strict();
9457
- var GetTaskStatusInput = z45.object({
9458
- taskId: z45.string().min(1),
9459
- waitSeconds: z45.number().int().min(0).max(120).optional()
9460
- });
9461
- var ListTasksInput = z45.object({
9462
- limit: z45.number().int().min(1).max(50).optional(),
9463
- offset: z45.number().int().min(0).optional(),
9464
- search: z45.string().optional()
9465
- });
9466
- var EditTaskDraftInput = z45.object({
9467
- taskId: z45.string().min(1),
9468
- angleIndex: z45.number().int().min(0),
9469
- angle: z45.object({
9470
- angle: z45.string().min(1).max(480),
9471
- buyerPersona: z45.string().min(1).max(360),
9472
- actor: z45.string().min(1).max(360).optional(),
9473
- 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."),
9474
- gender: z45.enum([
9504
+ var GetTaskStatusInput = z46.object({
9505
+ taskId: z46.string().min(1),
9506
+ waitSeconds: z46.number().int().min(0).max(120).optional()
9507
+ });
9508
+ var ListTasksInput = z46.object({
9509
+ limit: z46.number().int().min(1).max(50).optional(),
9510
+ offset: z46.number().int().min(0).optional(),
9511
+ search: z46.string().optional()
9512
+ });
9513
+ var EditTaskDraftInput = z46.object({
9514
+ taskId: z46.string().min(1),
9515
+ angleIndex: z46.number().int().min(0),
9516
+ angle: z46.object({
9517
+ angle: z46.string().min(1).max(480),
9518
+ buyerPersona: z46.string().min(1).max(360),
9519
+ actor: z46.string().min(1).max(360).optional(),
9520
+ 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."),
9521
+ gender: z46.enum([
9475
9522
  "female",
9476
9523
  "male"
9477
9524
  ]).optional(),
9478
- scriptNotes: z45.string().max(2e3).optional()
9525
+ scriptNotes: z46.string().max(2e3).optional()
9479
9526
  })
9480
9527
  });
9481
- var PendingActionPayload = z45.discriminatedUnion("kind", [
9482
- z45.object({
9483
- kind: z45.literal("product_reference_confirmation"),
9528
+ var PendingActionPayload = z46.discriminatedUnion("kind", [
9529
+ z46.object({
9530
+ kind: z46.literal("product_reference_confirmation"),
9484
9531
  userChoice: ProductReferenceUserChoiceEnum,
9485
- confirmedProductNames: z45.array(z45.string().min(1).max(120)).min(2).max(8).optional(),
9532
+ confirmedProductNames: z46.array(z46.string().min(1).max(120)).min(2).max(8).optional(),
9486
9533
  // SCOPED multi-scene opt-in — the ONLY way STANDARD ("Multiescena") is
9487
9534
  // reachable via MCP. Valid ONLY together with userChoice='variants' (same
9488
9535
  // product in several colors): renders one shot per color and stitches them,
@@ -9493,50 +9540,50 @@ var PendingActionPayload = z45.discriminatedUnion("kind", [
9493
9540
  // safe because multi-scene IS the intended render for a color variant set,
9494
9541
  // not a blind quality upsell. Maps to `videoTier: 'standard'` on the
9495
9542
  // confirm call; the backend re-gates it (variants + variant_set only).
9496
- 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".')
9543
+ 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".')
9497
9544
  }),
9498
- z45.object({
9499
- kind: z45.literal("angle_review_approval"),
9545
+ z46.object({
9546
+ kind: z46.literal("angle_review_approval"),
9500
9547
  // All edits are optional — empty action body just approves the
9501
9548
  // backend-generated draft as-is. Field shapes mirror the angle-review
9502
9549
  // request contracts in @packages/types/wizard.ts; the handler routes to
9503
9550
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
9504
- customAngle: z45.string().min(1).max(480).optional(),
9551
+ customAngle: z46.string().min(1).max(480).optional(),
9505
9552
  // Keep the shared MCP action within the strictest downstream contract:
9506
9553
  // autopilot/image resume endpoints cap these fields at 1500 characters.
9507
- painPoints: z45.string().max(1500).optional(),
9508
- benefits: z45.string().max(1500).optional(),
9509
- features: z45.array(z45.string().min(1).max(300)).max(10).optional(),
9510
- gapDurationSeconds: z45.union([
9511
- z45.literal(15),
9512
- z45.literal(30)
9554
+ painPoints: z46.string().max(1500).optional(),
9555
+ benefits: z46.string().max(1500).optional(),
9556
+ features: z46.array(z46.string().min(1).max(300)).max(10).optional(),
9557
+ gapDurationSeconds: z46.union([
9558
+ z46.literal(15),
9559
+ z46.literal(30)
9513
9560
  ]).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.")
9514
9561
  }),
9515
- z45.object({
9516
- kind: z45.literal("service_angle_approval"),
9517
- angleId: z45.string().uuid(),
9518
- content: z45.string().min(1).max(480).optional(),
9519
- creativeDirection: z45.string().min(1).max(1500).optional(),
9520
- actor: z45.string().min(1).max(360).optional()
9562
+ z46.object({
9563
+ kind: z46.literal("service_angle_approval"),
9564
+ angleId: z46.string().uuid(),
9565
+ content: z46.string().min(1).max(480).optional(),
9566
+ creativeDirection: z46.string().min(1).max(1500).optional(),
9567
+ actor: z46.string().min(1).max(360).optional()
9521
9568
  }),
9522
- z45.object({
9523
- kind: z45.literal("service_script_approval"),
9524
- voiceovers: z45.record(z45.string(), z45.string().min(1).max(600)).optional(),
9525
- visualDirections: z45.record(z45.string(), z45.string().min(1).max(1200)).optional()
9569
+ z46.object({
9570
+ kind: z46.literal("service_script_approval"),
9571
+ voiceovers: z46.record(z46.string(), z46.string().min(1).max(600)).optional(),
9572
+ visualDirections: z46.record(z46.string(), z46.string().min(1).max(1200)).optional()
9526
9573
  })
9527
9574
  ]);
9528
- var ResolvePendingActionInput = z45.object({
9529
- taskId: z45.string().min(1),
9575
+ var ResolvePendingActionInput = z46.object({
9576
+ taskId: z46.string().min(1),
9530
9577
  action: PendingActionPayload
9531
9578
  }).strict();
9532
9579
  function resolveVariantConfirmVideoTier(action) {
9533
9580
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
9534
9581
  }
9535
9582
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
9536
- var StatusForResolveSchema = z45.object({
9583
+ var StatusForResolveSchema = z46.object({
9537
9584
  // Metadata used to select the backend resume contract. Older API responses
9538
9585
  // may omit these fields, so the resolver keeps the generic fallback.
9539
- kind: z45.enum([
9586
+ kind: z46.enum([
9540
9587
  "autopilot",
9541
9588
  "video",
9542
9589
  "image",
@@ -9544,24 +9591,24 @@ var StatusForResolveSchema = z45.object({
9544
9591
  "mix",
9545
9592
  "service"
9546
9593
  ]).optional(),
9547
- selectedOutputs: z45.array(z45.enum([
9594
+ selectedOutputs: z46.array(z46.enum([
9548
9595
  "landing",
9549
9596
  "video",
9550
9597
  "image"
9551
9598
  ])).optional(),
9552
- videoAngleCount: z45.number().int().min(1).max(3).optional(),
9553
- ugcFormat: z45.enum([
9599
+ videoAngleCount: z46.number().int().min(1).max(3).optional(),
9600
+ ugcFormat: z46.enum([
9554
9601
  "single_8s",
9555
9602
  "single_15s",
9556
9603
  "double_30s"
9557
9604
  ]).optional(),
9558
- videoStyle: z45.enum([
9605
+ videoStyle: z46.enum([
9559
9606
  "ugc",
9560
9607
  "cartoon_3d",
9561
9608
  "product_only",
9562
9609
  "ai_dynamic"
9563
9610
  ]).optional(),
9564
- videoModel: z45.enum([
9611
+ videoModel: z46.enum([
9565
9612
  "veo",
9566
9613
  "wan",
9567
9614
  "bytedance",
@@ -9569,26 +9616,26 @@ var StatusForResolveSchema = z45.object({
9569
9616
  "grok",
9570
9617
  "kling"
9571
9618
  ]).optional(),
9572
- videoTier: z45.enum([
9619
+ videoTier: z46.enum([
9573
9620
  "legacy",
9574
9621
  "standard",
9575
9622
  "pro",
9576
9623
  "single_call"
9577
9624
  ]).optional(),
9578
- videoResolution: z45.enum([
9625
+ videoResolution: z46.enum([
9579
9626
  "480p",
9580
9627
  "720p"
9581
9628
  ]).optional(),
9582
9629
  narrativeStyle: NarrativeStyleEnum.optional(),
9583
- pendingUserAction: z45.object({
9584
- kind: z45.string(),
9585
- candidateGrouping: z45.string().optional(),
9586
- selectedImageUrls: z45.array(z45.string()).optional(),
9587
- proposedProductNames: z45.array(z45.string()).optional(),
9588
- customAngleDraft: z45.string().optional(),
9589
- painPointsDraft: z45.string().optional(),
9590
- benefitsDraft: z45.string().optional(),
9591
- featuresDraft: z45.array(z45.string()).optional(),
9630
+ pendingUserAction: z46.object({
9631
+ kind: z46.string(),
9632
+ candidateGrouping: z46.string().optional(),
9633
+ selectedImageUrls: z46.array(z46.string()).optional(),
9634
+ proposedProductNames: z46.array(z46.string()).optional(),
9635
+ customAngleDraft: z46.string().optional(),
9636
+ painPointsDraft: z46.string().optional(),
9637
+ benefitsDraft: z46.string().optional(),
9638
+ featuresDraft: z46.array(z46.string()).optional(),
9592
9639
  // Recommendation consumed only when the caller explicitly sends
9593
9640
  // gapDurationSeconds: 30 in the angle approval action.
9594
9641
  gapDurationChoice: GapDurationChoiceMirror.optional(),
@@ -9597,17 +9644,17 @@ var StatusForResolveSchema = z45.object({
9597
9644
  // keys. `actorId` (the saved custom actor the picker stored) was silently
9598
9645
  // dropped here, so the approval handler below could not echo it back on the
9599
9646
  // PATCH — the selection looked accepted and reached no render.
9600
- angles: z45.array(z45.object({
9601
- id: z45.string().uuid(),
9602
- content: z45.string(),
9603
- creativeDirection: z45.string(),
9604
- actor: z45.string(),
9605
- actorId: z45.string().nullable().optional()
9647
+ angles: z46.array(z46.object({
9648
+ id: z46.string().uuid(),
9649
+ content: z46.string(),
9650
+ creativeDirection: z46.string(),
9651
+ actor: z46.string(),
9652
+ actorId: z46.string().nullable().optional()
9606
9653
  }).passthrough()).optional(),
9607
- panels: z45.array(z45.object({
9608
- beatId: z45.string(),
9609
- voiceover: z45.string(),
9610
- visualDirection: z45.string()
9654
+ panels: z46.array(z46.object({
9655
+ beatId: z46.string(),
9656
+ voiceover: z46.string(),
9657
+ visualDirection: z46.string()
9611
9658
  }).passthrough()).optional()
9612
9659
  }).optional()
9613
9660
  }).passthrough();
@@ -10047,58 +10094,58 @@ __name(registerTaskTools, "registerTaskTools");
10047
10094
 
10048
10095
  // src/tools/creatives.ts
10049
10096
  import { randomUUID } from "crypto";
10050
- import { z as z46 } from "zod";
10097
+ import { z as z47 } from "zod";
10051
10098
  var CreativeRefs = {
10052
10099
  images: ImagesInput,
10053
10100
  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.'),
10054
10101
  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.'),
10055
- 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.'),
10056
- 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.'),
10057
- 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".'),
10058
- 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.'),
10059
- 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."),
10060
- 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.'),
10061
- 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.'),
10062
- isCombo: z46.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
10063
- 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."),
10064
- 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."),
10065
- 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."),
10066
- 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.'),
10067
- 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."),
10068
- 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.")
10102
+ 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.'),
10103
+ 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.'),
10104
+ 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".'),
10105
+ 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.'),
10106
+ 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."),
10107
+ 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.'),
10108
+ 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.'),
10109
+ isCombo: z47.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
10110
+ 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."),
10111
+ 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."),
10112
+ 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."),
10113
+ 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.'),
10114
+ 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."),
10115
+ 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.")
10069
10116
  };
10070
- var VideoInput = z46.object({
10117
+ var VideoInput = z47.object({
10071
10118
  images: CreativeRefs.images,
10072
- title: z46.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
10073
- 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".'),
10119
+ title: z47.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
10120
+ 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".'),
10074
10121
  language: CreativeRefs.language,
10075
10122
  country: CreativeRefs.country,
10076
- aspectRatio: z46.enum([
10123
+ aspectRatio: z47.enum([
10077
10124
  "9:16",
10078
10125
  "16:9",
10079
10126
  "Auto"
10080
10127
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
10081
- durationSeconds: z46.union([
10082
- z46.literal(15),
10083
- z46.literal(30)
10128
+ durationSeconds: z47.union([
10129
+ z47.literal(15),
10130
+ z47.literal(30)
10084
10131
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
10085
10132
  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).'),
10086
10133
  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.'),
10087
10134
  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).'),
10088
- 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"].'),
10135
+ 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"].'),
10089
10136
  price: CreativeRefs.price,
10090
10137
  offer: CreativeRefs.offer,
10091
10138
  productContext: CreativeRefs.productContext,
10092
10139
  productLabel: CreativeRefs.productLabel,
10093
- 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.'),
10094
- 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.'),
10095
- 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."),
10096
- 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."),
10140
+ 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.'),
10141
+ 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.'),
10142
+ 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."),
10143
+ 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."),
10097
10144
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
10098
10145
  brandId: CreativeRefs.brandId,
10099
10146
  projectId: CreativeRefs.projectId
10100
10147
  }).strict();
10101
- var FreeVideoQualityEnum = z46.enum([
10148
+ var FreeVideoQualityEnum = z47.enum([
10102
10149
  "economical",
10103
10150
  "high_detail"
10104
10151
  ]);
@@ -10120,38 +10167,38 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
10120
10167
  15
10121
10168
  ]
10122
10169
  };
10123
- var FreeVideoInput = z46.object({
10170
+ var FreeVideoInput = z47.object({
10124
10171
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
10125
- 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."),
10172
+ 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."),
10126
10173
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economical" = Econ\xF3mico o "high_detail" = Alto detalle.'),
10127
- 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."),
10174
+ 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."),
10128
10175
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
10129
- generateAiMusic: z46.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
10130
- addSubtitles: z46.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
10131
- 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.")
10176
+ generateAiMusic: z47.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
10177
+ addSubtitles: z47.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
10178
+ 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.")
10132
10179
  }).strict();
10133
10180
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
10134
10181
  var archetypeList = ImageCreativeArchetypeEnum.options.join(" | ");
10135
10182
  var visualTreatmentList = ImageCreativeVisualTreatmentEnum.options.join(" | ");
10136
10183
  var aspectRatioList = ImageCreativeAspectRatioEnum.options.join(" | ");
10137
- var ImageInput = z46.object({
10184
+ var ImageInput = z47.object({
10138
10185
  images: CreativeRefs.images,
10139
- productTitle: z46.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
10140
- primaryAngle: z46.string().min(1).describe('\xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas".'),
10186
+ productTitle: z47.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
10187
+ primaryAngle: z47.string().min(1).describe('\xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas".'),
10141
10188
  buyerPersona: CreativeRefs.buyerPersona,
10142
10189
  language: CreativeRefs.language,
10143
10190
  country: CreativeRefs.country,
10144
- nVariants: z46.number().int().min(1).max(6).optional().describe("Opcional. N\xFAmero de variantes a generar (1-6). Default 3."),
10145
- 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.'),
10191
+ nVariants: z47.number().int().min(1).max(6).optional().describe("Opcional. N\xFAmero de variantes a generar (1-6). Default 3."),
10192
+ 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.'),
10146
10193
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
10147
10194
  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).`),
10148
10195
  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.`),
10149
- 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."),
10196
+ 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."),
10150
10197
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe(`Opcional. Relaci\xF3n de aspecto. Valores: ${aspectRatioList}. Default "4:5" (vertical Instagram feed).`),
10151
- generateAdCopy: z46.boolean().optional().describe("Opcional. Si true, tambi\xE9n genera headline/body/CTA para el ad. Default false."),
10152
- 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."),
10153
- features: z46.array(z46.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
10154
- 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.'),
10198
+ generateAdCopy: z47.boolean().optional().describe("Opcional. Si true, tambi\xE9n genera headline/body/CTA para el ad. Default false."),
10199
+ 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."),
10200
+ features: z47.array(z47.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
10201
+ 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.'),
10155
10202
  price: CreativeRefs.price,
10156
10203
  compareAtPrice: CreativeRefs.compareAtPrice,
10157
10204
  offer: CreativeRefs.offer,
@@ -10165,16 +10212,16 @@ var ImageInput = z46.object({
10165
10212
  headline: CreativeRefs.headline,
10166
10213
  subheadline: CreativeRefs.subheadline
10167
10214
  });
10168
- var EditImageCreativeInput = z46.object({
10169
- taskId: z46.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
10170
- variantIndex: z46.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
10171
- 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".')
10215
+ var EditImageCreativeInput = z47.object({
10216
+ taskId: z47.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
10217
+ variantIndex: z47.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
10218
+ 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".')
10172
10219
  });
10173
- var LandingInput = z46.object({
10220
+ var LandingInput = z47.object({
10174
10221
  images: CreativeRefs.images,
10175
10222
  language: CreativeRefs.language,
10176
10223
  country: CreativeRefs.country,
10177
- 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.'),
10224
+ 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.'),
10178
10225
  buyerPersona: CreativeRefs.buyerPersona,
10179
10226
  price: CreativeRefs.price,
10180
10227
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -10299,8 +10346,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
10299
10346
  __name(registerCreativeTools, "registerCreativeTools");
10300
10347
 
10301
10348
  // src/tools/creative-variants.ts
10302
- import { z as z47 } from "zod";
10303
- var LandingSectionKeyEnum = z47.enum([
10349
+ import { z as z48 } from "zod";
10350
+ var LandingSectionKeyEnum = z48.enum([
10304
10351
  "problem_hook",
10305
10352
  "problem_cost",
10306
10353
  "solution_mechanism",
@@ -10340,24 +10387,24 @@ var LandingSectionKeyEnum = z47.enum([
10340
10387
  "lifestyle_fit",
10341
10388
  "join_lifestyle"
10342
10389
  ]);
10343
- var CreativeVariantKindEnum = z47.enum([
10390
+ var CreativeVariantKindEnum = z48.enum([
10344
10391
  "video",
10345
10392
  "image",
10346
10393
  "landing"
10347
10394
  ]);
10348
- var EstimateCreativeVariantInputBase = z47.object({
10349
- sourceTaskId: z47.string().uuid().describe("ID de la tarea original completada."),
10395
+ var EstimateCreativeVariantInputBase = z48.object({
10396
+ sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
10350
10397
  kind: CreativeVariantKindEnum,
10351
10398
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
10352
10399
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
10353
- nVariants: z47.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10400
+ nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10354
10401
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
10355
- 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.")
10402
+ 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.")
10356
10403
  }).strict();
10357
10404
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
10358
10405
  if (input.kind === "video" && input.nVariants !== void 0) {
10359
10406
  ctx.addIssue({
10360
- code: z47.ZodIssueCode.custom,
10407
+ code: z48.ZodIssueCode.custom,
10361
10408
  path: [
10362
10409
  "nVariants"
10363
10410
  ],
@@ -10367,7 +10414,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10367
10414
  if (input.kind !== "video") {
10368
10415
  if (input.videoPreset !== void 0) {
10369
10416
  ctx.addIssue({
10370
- code: z47.ZodIssueCode.custom,
10417
+ code: z48.ZodIssueCode.custom,
10371
10418
  path: [
10372
10419
  "videoPreset"
10373
10420
  ],
@@ -10376,7 +10423,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10376
10423
  }
10377
10424
  if (input.videoResolution !== void 0) {
10378
10425
  ctx.addIssue({
10379
- code: z47.ZodIssueCode.custom,
10426
+ code: z48.ZodIssueCode.custom,
10380
10427
  path: [
10381
10428
  "videoResolution"
10382
10429
  ],
@@ -10386,7 +10433,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10386
10433
  }
10387
10434
  if (input.kind !== "image" && input.nVariants !== void 0) {
10388
10435
  ctx.addIssue({
10389
- code: z47.ZodIssueCode.custom,
10436
+ code: z48.ZodIssueCode.custom,
10390
10437
  path: [
10391
10438
  "nVariants"
10392
10439
  ],
@@ -10396,7 +10443,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10396
10443
  if (input.kind !== "landing") {
10397
10444
  if (input.sectionKey !== void 0) {
10398
10445
  ctx.addIssue({
10399
- code: z47.ZodIssueCode.custom,
10446
+ code: z48.ZodIssueCode.custom,
10400
10447
  path: [
10401
10448
  "sectionKey"
10402
10449
  ],
@@ -10405,7 +10452,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10405
10452
  }
10406
10453
  if (input.instructions !== void 0) {
10407
10454
  ctx.addIssue({
10408
- code: z47.ZodIssueCode.custom,
10455
+ code: z48.ZodIssueCode.custom,
10409
10456
  path: [
10410
10457
  "instructions"
10411
10458
  ],
@@ -10414,31 +10461,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
10414
10461
  }
10415
10462
  }
10416
10463
  });
10417
- var CreateCreativeVariantInputBase = z47.object({
10418
- sourceTaskId: z47.string().uuid().describe("ID de la tarea original completada."),
10464
+ var CreateCreativeVariantInputBase = z48.object({
10465
+ sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
10419
10466
  kind: CreativeVariantKindEnum,
10420
- confirm: z47.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
10421
- 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."),
10422
- angle: z47.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
10423
- buyerPersona: z47.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
10424
- scriptNotes: z47.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
10425
- creativeDirection: z47.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
10467
+ confirm: z48.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
10468
+ 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."),
10469
+ angle: z48.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
10470
+ buyerPersona: z48.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
10471
+ scriptNotes: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
10472
+ creativeDirection: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
10426
10473
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
10427
10474
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
10428
- generateAiMusic: z47.boolean().optional().describe("Opcional para video."),
10429
- nVariants: z47.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10475
+ generateAiMusic: z48.boolean().optional().describe("Opcional para video."),
10476
+ nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
10430
10477
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
10431
10478
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
10432
10479
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
10433
10480
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
10434
- styleMix: z47.boolean().optional().describe("Opcional para imagen."),
10481
+ styleMix: z48.boolean().optional().describe("Opcional para imagen."),
10435
10482
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
10436
- 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.")
10483
+ 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.")
10437
10484
  }).strict();
10438
10485
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
10439
10486
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
10440
10487
  ctx.addIssue({
10441
- code: z47.ZodIssueCode.custom,
10488
+ code: z48.ZodIssueCode.custom,
10442
10489
  path: [
10443
10490
  "angle"
10444
10491
  ],
@@ -10447,7 +10494,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
10447
10494
  }
10448
10495
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
10449
10496
  ctx.addIssue({
10450
- code: z47.ZodIssueCode.custom,
10497
+ code: z48.ZodIssueCode.custom,
10451
10498
  path: [
10452
10499
  "instructions"
10453
10500
  ],
@@ -10493,7 +10540,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
10493
10540
  for (const field of fieldsByKind[input.kind]) {
10494
10541
  if (input[field] !== void 0) {
10495
10542
  ctx.addIssue({
10496
- code: z47.ZodIssueCode.custom,
10543
+ code: z48.ZodIssueCode.custom,
10497
10544
  path: [
10498
10545
  field
10499
10546
  ],
@@ -10610,27 +10657,27 @@ function registerCreativeVariantTools(server, api) {
10610
10657
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
10611
10658
 
10612
10659
  // src/tools/script-review.ts
10613
- import { z as z48 } from "zod";
10614
- var GetVideoScriptInput = z48.object({
10615
- taskId: z48.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
10616
- 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.')
10660
+ import { z as z49 } from "zod";
10661
+ var GetVideoScriptInput = z49.object({
10662
+ taskId: z49.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
10663
+ 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.')
10617
10664
  }).strict();
10618
10665
  var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
10619
10666
  var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
10620
- var ApproveSceneEdit = z48.object({
10621
- index: z48.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
10622
- dialogue: z48.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
10667
+ var ApproveSceneEdit = z49.object({
10668
+ index: z49.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
10669
+ dialogue: z49.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
10623
10670
  message: "dialogue no puede ser s\xF3lo espacios"
10624
10671
  }).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.")
10625
10672
  }).strict();
10626
- var ApproveVideoScriptInput = z48.object({
10627
- taskId: z48.string().min(1).describe("ID de la tarea."),
10628
- 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.'),
10629
- 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.")
10673
+ var ApproveVideoScriptInput = z49.object({
10674
+ taskId: z49.string().min(1).describe("ID de la tarea."),
10675
+ 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.'),
10676
+ 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.")
10630
10677
  }).strict();
10631
- var RegenerateVideoScriptInput = z48.object({
10632
- taskId: z48.string().min(1).describe("ID de la tarea."),
10633
- 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.'),
10678
+ var RegenerateVideoScriptInput = z49.object({
10679
+ taskId: z49.string().min(1).describe("ID de la tarea."),
10680
+ 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.'),
10634
10681
  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).')
10635
10682
  }).strict();
10636
10683
  function registerScriptReviewTools(server, api) {
@@ -10670,9 +10717,9 @@ function registerScriptReviewTools(server, api) {
10670
10717
  __name(registerScriptReviewTools, "registerScriptReviewTools");
10671
10718
 
10672
10719
  // src/tools/connections.ts
10673
- import { z as z49 } from "zod";
10720
+ import { z as z50 } from "zod";
10674
10721
  function registerConnectionTools(server, api) {
10675
- 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 () => {
10722
+ 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 () => {
10676
10723
  try {
10677
10724
  const r = await api.getJson("/v1/shopify/shops");
10678
10725
  return asText(r);
@@ -10680,10 +10727,10 @@ function registerConnectionTools(server, api) {
10680
10727
  throw translateError(e);
10681
10728
  }
10682
10729
  });
10683
- 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({
10684
- shopDomain: z49.string().min(3).max(120),
10685
- query: z49.string().trim().max(120).optional(),
10686
- taskId: z49.string().uuid().optional()
10730
+ 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({
10731
+ shopDomain: z50.string().min(3).max(120),
10732
+ query: z50.string().trim().max(120).optional(),
10733
+ taskId: z50.string().uuid().optional()
10687
10734
  }).shape, async ({ shopDomain, query, taskId }) => {
10688
10735
  try {
10689
10736
  const params = new URLSearchParams({
@@ -10697,7 +10744,7 @@ function registerConnectionTools(server, api) {
10697
10744
  throw translateError(e);
10698
10745
  }
10699
10746
  });
10700
- 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 () => {
10747
+ 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 () => {
10701
10748
  try {
10702
10749
  const r = await api.getJson("/v1/facebook/ad-accounts");
10703
10750
  return asText(r);
@@ -10705,7 +10752,13 @@ function registerConnectionTools(server, api) {
10705
10752
  throw translateError(e);
10706
10753
  }
10707
10754
  });
10708
- 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 () => {
10755
+ server.registerTool("list_meta_destinations", {
10756
+ 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.",
10757
+ inputSchema: z50.object({}).shape,
10758
+ _meta: {
10759
+ "openai/widgetAccessible": true
10760
+ }
10761
+ }, async () => {
10709
10762
  try {
10710
10763
  const r = await api.getJson("/v1/facebook/destinations");
10711
10764
  return asText(r);
@@ -10713,7 +10766,7 @@ function registerConnectionTools(server, api) {
10713
10766
  throw translateError(e);
10714
10767
  }
10715
10768
  });
10716
- 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 () => {
10769
+ 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 () => {
10717
10770
  try {
10718
10771
  const r = await api.getJson("/v1/tiktok/advertisers");
10719
10772
  return asText(r);
@@ -10725,9 +10778,9 @@ function registerConnectionTools(server, api) {
10725
10778
  __name(registerConnectionTools, "registerConnectionTools");
10726
10779
 
10727
10780
  // src/tools/actors.ts
10728
- import { z as z50 } from "zod";
10781
+ import { z as z51 } from "zod";
10729
10782
  function registerActorTools(server, api) {
10730
- 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 () => {
10783
+ 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 () => {
10731
10784
  try {
10732
10785
  const rows = await api.getJson("/v1/actors");
10733
10786
  const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
@@ -10748,116 +10801,116 @@ function registerActorTools(server, api) {
10748
10801
  __name(registerActorTools, "registerActorTools");
10749
10802
 
10750
10803
  // src/tools/publish.ts
10751
- import { z as z51 } from "zod";
10752
- var ShopifyInput = z51.object({
10753
- taskId: z51.string().min(1),
10754
- shopDomain: z51.string().min(1),
10804
+ import { z as z52 } from "zod";
10805
+ var ShopifyInput = z52.object({
10806
+ taskId: z52.string().min(1),
10807
+ shopDomain: z52.string().min(1),
10755
10808
  /** Override: number of landing images to include. Default = ALL images the
10756
10809
  * task generated (the MCP fetches /v1/results first to count). Bounded
10757
10810
  * generously here; the backend validates each index against
10758
10811
  * landing.images.length and rejects out-of-range. */
10759
- numLandingImages: z51.number().int().min(1).max(20).optional(),
10760
- variantIndex: z51.number().int().min(0).optional(),
10812
+ numLandingImages: z52.number().int().min(1).max(20).optional(),
10813
+ variantIndex: z52.number().int().min(0).optional(),
10761
10814
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
10762
10815
  * When true, the landing renders variant-picker pills; when false, it ships
10763
10816
  * a single-option product page. Defaults to false. */
10764
- showVariantPicker: z51.boolean().optional(),
10817
+ showVariantPicker: z52.boolean().optional(),
10765
10818
  /** Default `auto` updates the product previously published for this task and
10766
10819
  * shop. Use `existing` with targetProductId to choose another product, or
10767
10820
  * `new` only when the user explicitly wants a duplicate/new listing. */
10768
- publicationMode: z51.enum([
10821
+ publicationMode: z52.enum([
10769
10822
  "auto",
10770
10823
  "existing",
10771
10824
  "new"
10772
10825
  ]).optional(),
10773
10826
  /** Shopify product GID, numeric id, or admin product URL. Required when
10774
10827
  * publicationMode is `existing`. */
10775
- targetProductId: z51.string().trim().min(1).max(300).optional()
10828
+ targetProductId: z52.string().trim().min(1).max(300).optional()
10776
10829
  });
10777
- var McpCampaignConfig = z51.object({
10830
+ var McpCampaignConfig = z52.object({
10778
10831
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
10779
10832
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
10780
10833
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
10781
- dailyBudgetUsd: z51.number().positive().optional(),
10834
+ dailyBudgetUsd: z52.number().positive().optional(),
10782
10835
  /** ISO-3166-1 alpha-2 country codes. Meta accepts max 1 (single-country
10783
10836
  * ad set). TikTok takes only the first entry. */
10784
- targetCountries: z51.array(z51.string().length(2)).max(1).optional(),
10785
- campaignName: z51.string().trim().min(1).max(100).optional()
10837
+ targetCountries: z52.array(z52.string().length(2)).max(1).optional(),
10838
+ campaignName: z52.string().trim().min(1).max(100).optional()
10786
10839
  });
10787
10840
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
10788
- var MetaInput = z51.object({
10789
- taskId: z51.string().min(1),
10841
+ var MetaInput = z52.object({
10842
+ taskId: z52.string().min(1),
10790
10843
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
10791
- portfolioId: z51.string().trim().min(1),
10844
+ portfolioId: z52.string().trim().min(1),
10792
10845
  /** Exact Facebook Page selected from `list_meta_destinations`. */
10793
- pageId: z51.string().trim().min(1),
10846
+ pageId: z52.string().trim().min(1),
10794
10847
  adAccountId: McpAdAccountId,
10795
- pixelId: z51.string().min(1).optional(),
10796
- landingUrl: z51.string().url().optional(),
10848
+ pixelId: z52.string().min(1).optional(),
10849
+ landingUrl: z52.string().url().optional(),
10797
10850
  /** Select which angles to publish by 0-based index. Omit to publish all
10798
10851
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
10799
- angleIndexes: z51.array(z51.number().int().nonnegative()).optional(),
10852
+ angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
10800
10853
  campaignConfig: McpCampaignConfig.optional(),
10801
10854
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
10802
10855
  * uses the auto-generated copy attached to the task. Capped at 500 chars
10803
10856
  * (Meta's primary-text limit). */
10804
- primaryText: z51.string().trim().min(1).max(500).optional(),
10857
+ primaryText: z52.string().trim().min(1).max(500).optional(),
10805
10858
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
10806
10859
  * (wa.me) instead of a landing page. */
10807
- phoneNumber: z51.string().min(8).max(32).optional()
10860
+ phoneNumber: z52.string().min(8).max(32).optional()
10808
10861
  });
10809
- var GroupedTaskSource = z51.object({
10810
- type: z51.literal("task"),
10811
- taskId: z51.string().min(1),
10812
- angleIndex: z51.number().int().min(0).optional(),
10813
- videoVariant: z51.enum([
10862
+ var GroupedTaskSource = z52.object({
10863
+ type: z52.literal("task"),
10864
+ taskId: z52.string().min(1),
10865
+ angleIndex: z52.number().int().min(0).optional(),
10866
+ videoVariant: z52.enum([
10814
10867
  "with_subtitles",
10815
10868
  "without_subtitles"
10816
10869
  ]).optional(),
10817
- imageVariantIndex: z51.number().int().min(0).optional()
10818
- });
10819
- var GroupedMediaSource = z51.object({
10820
- type: z51.literal("media"),
10821
- 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."),
10822
- 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".'),
10823
- thumbnailUrl: z51.string().url().optional(),
10824
- thumbnailPath: z51.string().min(1).optional()
10870
+ imageVariantIndex: z52.number().int().min(0).optional()
10871
+ });
10872
+ var GroupedMediaSource = z52.object({
10873
+ type: z52.literal("media"),
10874
+ 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."),
10875
+ 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".'),
10876
+ thumbnailUrl: z52.string().url().optional(),
10877
+ thumbnailPath: z52.string().min(1).optional()
10825
10878
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
10826
10879
  message: "media source needs exactly one of `url` or `path`"
10827
10880
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
10828
10881
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
10829
10882
  });
10830
- var GroupedStagedMediaSource = z51.object({
10831
- type: z51.literal("staged"),
10883
+ var GroupedStagedMediaSource = z52.object({
10884
+ type: z52.literal("staged"),
10832
10885
  /** Returned by check_meta_media_upload after the user selects a local file. */
10833
- stagingAssetId: z51.string().uuid(),
10834
- thumbnailAssetId: z51.string().uuid().optional()
10886
+ stagingAssetId: z52.string().uuid(),
10887
+ thumbnailAssetId: z52.string().uuid().optional()
10835
10888
  });
10836
- var GroupedCreative = z51.object({
10837
- type: z51.enum([
10889
+ var GroupedCreative = z52.object({
10890
+ type: z52.enum([
10838
10891
  "image",
10839
10892
  "video"
10840
10893
  ]),
10841
- source: z51.union([
10894
+ source: z52.union([
10842
10895
  GroupedTaskSource,
10843
10896
  GroupedMediaSource,
10844
10897
  GroupedStagedMediaSource
10845
10898
  ]),
10846
- title: z51.string().max(120).optional(),
10847
- description: z51.string().max(500).optional(),
10899
+ title: z52.string().max(120).optional(),
10900
+ description: z52.string().max(500).optional(),
10848
10901
  cta: MetaCtaType.optional(),
10849
- creativeId: z51.string().min(1).optional()
10902
+ creativeId: z52.string().min(1).optional()
10850
10903
  });
10851
- var GroupedCampaignConfig = z51.object({
10904
+ var GroupedCampaignConfig = z52.object({
10852
10905
  campaignType: MetaCampaignType.default("sales"),
10853
10906
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
10854
10907
  budgetMode: MetaBudgetMode.default("campaign"),
10855
- campaignDailyBudget: z51.number().int().positive().optional(),
10856
- adSets: z51.array(z51.object({
10857
- tempId: z51.string().min(1).max(80),
10858
- name: z51.string().min(1).max(100),
10859
- dailyBudget: z51.number().int().positive().optional(),
10860
- creativeIds: z51.array(z51.string().min(1)).min(1)
10908
+ campaignDailyBudget: z52.number().int().positive().optional(),
10909
+ adSets: z52.array(z52.object({
10910
+ tempId: z52.string().min(1).max(80),
10911
+ name: z52.string().min(1).max(100),
10912
+ dailyBudget: z52.number().int().positive().optional(),
10913
+ creativeIds: z52.array(z52.string().min(1)).min(1)
10861
10914
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
10862
10915
  /**
10863
10916
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -10865,22 +10918,22 @@ var GroupedCampaignConfig = z51.object({
10865
10918
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
10866
10919
  * the API since #849 — unreachable from this tool.
10867
10920
  */
10868
- destination: z51.discriminatedUnion("type", [
10869
- z51.object({
10870
- type: z51.literal("landing"),
10871
- landingUrl: z51.string().url()
10921
+ destination: z52.discriminatedUnion("type", [
10922
+ z52.object({
10923
+ type: z52.literal("landing"),
10924
+ landingUrl: z52.string().url()
10872
10925
  }),
10873
- z51.object({
10874
- type: z51.literal("whatsapp"),
10875
- phoneNumber: z51.string().min(8).max(32)
10926
+ z52.object({
10927
+ type: z52.literal("whatsapp"),
10928
+ phoneNumber: z52.string().min(8).max(32)
10876
10929
  })
10877
10930
  ]),
10878
- saveAsDefault: z51.boolean().default(false),
10931
+ saveAsDefault: z52.boolean().default(false),
10879
10932
  budgetPolicy: MetaBudgetPolicy.optional()
10880
10933
  }).superRefine((value, ctx) => {
10881
10934
  if (value.budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
10882
10935
  ctx.addIssue({
10883
- code: z51.ZodIssueCode.custom,
10936
+ code: z52.ZodIssueCode.custom,
10884
10937
  path: [
10885
10938
  "campaignDailyBudget"
10886
10939
  ],
@@ -10891,7 +10944,7 @@ var GroupedCampaignConfig = z51.object({
10891
10944
  value.adSets.forEach((adSet, index) => {
10892
10945
  if (adSet.dailyBudget === void 0) {
10893
10946
  ctx.addIssue({
10894
- code: z51.ZodIssueCode.custom,
10947
+ code: z52.ZodIssueCode.custom,
10895
10948
  path: [
10896
10949
  "adSets",
10897
10950
  index,
@@ -10903,26 +10956,26 @@ var GroupedCampaignConfig = z51.object({
10903
10956
  });
10904
10957
  }
10905
10958
  });
10906
- var PublishCreativesToMetaInputBase = z51.object({
10907
- creatives: z51.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
10959
+ var PublishCreativesToMetaInputBase = z52.object({
10960
+ creatives: z52.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
10908
10961
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
10909
- portfolioId: z51.string().trim().min(1),
10962
+ portfolioId: z52.string().trim().min(1),
10910
10963
  /** Exact Facebook Page selected from `list_meta_destinations`. */
10911
- pageId: z51.string().trim().min(1),
10964
+ pageId: z52.string().trim().min(1),
10912
10965
  adAccountId: McpAdAccountId,
10913
- pixelId: z51.string().min(1).optional(),
10966
+ pixelId: z52.string().min(1).optional(),
10914
10967
  /** Required unless `campaignConfig.destination` is whatsapp — see the
10915
10968
  * superRefine below. Mirrors the API's `UploadToMetaRequest`. */
10916
- landingUrl: z51.string().url().optional(),
10917
- targetCountry: z51.string().length(2),
10918
- campaignName: z51.string().trim().min(1).max(100),
10969
+ landingUrl: z52.string().url().optional(),
10970
+ targetCountry: z52.string().length(2),
10971
+ campaignName: z52.string().trim().min(1).max(100),
10919
10972
  campaignConfig: GroupedCampaignConfig.optional()
10920
10973
  });
10921
10974
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
10922
10975
  const destination = value.campaignConfig?.destination;
10923
10976
  if (destination?.type !== "whatsapp" && !value.landingUrl) {
10924
10977
  ctx.addIssue({
10925
- code: z51.ZodIssueCode.custom,
10978
+ code: z52.ZodIssueCode.custom,
10926
10979
  path: [
10927
10980
  "landingUrl"
10928
10981
  ],
@@ -10931,7 +10984,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
10931
10984
  }
10932
10985
  if (destination?.type === "landing" && destination.landingUrl !== value.landingUrl) {
10933
10986
  ctx.addIssue({
10934
- code: z51.ZodIssueCode.custom,
10987
+ code: z52.ZodIssueCode.custom,
10935
10988
  path: [
10936
10989
  "campaignConfig",
10937
10990
  "destination",
@@ -10941,16 +10994,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
10941
10994
  });
10942
10995
  }
10943
10996
  });
10944
- var PresignUploadResponseSchema = z51.object({
10945
- uploadUrl: z51.string().url().refine((value) => {
10997
+ var PresignUploadResponseSchema = z52.object({
10998
+ uploadUrl: z52.string().url().refine((value) => {
10946
10999
  const url = new URL(value);
10947
11000
  return !url.username && !url.password && url.protocol === "https:";
10948
11001
  }, "presigned upload URL must be HTTPS without embedded credentials"),
10949
- publicUrl: z51.string().url().refine((value) => {
11002
+ publicUrl: z52.string().url().refine((value) => {
10950
11003
  const url = new URL(value);
10951
11004
  return !url.username && !url.password;
10952
11005
  }, "public media URL must not contain embedded credentials"),
10953
- stagingAssetId: z51.string().uuid()
11006
+ stagingAssetId: z52.string().uuid()
10954
11007
  });
10955
11008
  async function uploadResolvedMedia(api, media, assetRole) {
10956
11009
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -10975,16 +11028,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
10975
11028
  return uploadResolvedMedia(api, media, assetRole);
10976
11029
  }
10977
11030
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
10978
- var TikTokInput = z51.object({
10979
- taskId: z51.string().min(1),
10980
- advertiserId: z51.string().min(1),
10981
- pixelId: z51.string().min(1).optional(),
10982
- landingUrl: z51.string().url().optional(),
10983
- angleIndexes: z51.array(z51.number().int().nonnegative()).optional(),
11031
+ var TikTokInput = z52.object({
11032
+ taskId: z52.string().min(1),
11033
+ advertiserId: z52.string().min(1),
11034
+ pixelId: z52.string().min(1).optional(),
11035
+ landingUrl: z52.string().url().optional(),
11036
+ angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
10984
11037
  campaignConfig: McpCampaignConfig.optional(),
10985
11038
  /** Override the ad's description (TikTok's body copy). If omitted,
10986
11039
  * ProductMaker uses the auto-generated copy attached to the task. */
10987
- primaryText: z51.string().trim().min(1).max(500).optional()
11040
+ primaryText: z52.string().trim().min(1).max(500).optional()
10988
11041
  });
10989
11042
  function registerPublishTools(server, api, opts = {}) {
10990
11043
  const transport = opts.transport ?? "http";
@@ -11172,6 +11225,17 @@ function renderShopifyPublishMarkdown(r) {
11172
11225
  if (r.productUrl) lines.push(`
11173
11226
  ### Producto
11174
11227
  [Ver producto](${r.productUrl})`);
11228
+ if (r.needsThemeSetup) {
11229
+ lines.push(r.themeEditorDeepLink ? `
11230
+ \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.");
11231
+ }
11232
+ if (r.tracking?.status === "migrated") {
11233
+ lines.push("\nTracking: \u2705 configuraci\xF3n anterior migrada autom\xE1ticamente. No necesitas editar el tema.");
11234
+ } else if (r.tracking?.status === "synced") {
11235
+ lines.push("\nTracking: \u2705 c\xF3digo manual sincronizado desde `theme.liquid` al layout de ProductMaker.");
11236
+ } else if (r.tracking?.status === "not_detected") {
11237
+ 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.");
11238
+ }
11175
11239
  if (!r.pageUrl && !r.productUrl && r.status !== "success") {
11176
11240
  lines.push("\n_La publicaci\xF3n a\xFAn est\xE1 proces\xE1ndose. Usa `get_task_status` para verificar progreso._");
11177
11241
  }
@@ -11216,71 +11280,81 @@ function toTikTokCampaignConfig(cfg) {
11216
11280
  __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
11217
11281
 
11218
11282
  // src/tools/meta-upload.ts
11219
- import { z as z52 } from "zod";
11220
- var MetaUploadSessionInputBase = z52.object({
11221
- mediaKind: z52.enum([
11283
+ import { z as z53 } from "zod";
11284
+ var MetaUploadSessionInputBase = z53.object({
11285
+ mediaKind: z53.enum([
11222
11286
  "image",
11223
11287
  "video",
11224
11288
  "mixed"
11225
11289
  ]).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."),
11226
- assetRole: z52.enum([
11290
+ assetRole: z53.enum([
11227
11291
  "media",
11228
11292
  "thumbnail"
11229
- ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail.")
11230
- });
11231
- var OpenAiFileReference = z52.object({
11232
- download_url: z52.string().url(),
11233
- file_id: z52.string().min(1),
11234
- mime_type: z52.string().min(1).optional(),
11235
- file_name: z52.string().min(1).optional()
11293
+ ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
11294
+ maxFiles: z53.number().int().min(1).max(10).optional().describe("Optional batch limit. Use 1 for a single creative; mixed media defaults to 10.")
11295
+ });
11296
+ var OpenAiFileReference = z53.object({
11297
+ download_url: z53.string().url(),
11298
+ file_id: z53.string().min(1),
11299
+ mime_type: z53.string().min(1).optional(),
11300
+ file_name: z53.string().min(1).optional()
11236
11301
  }).strict();
11237
11302
  var MetaUploadSessionToolInputShape = {
11238
11303
  ...MetaUploadSessionInputBase.shape,
11239
- 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.")
11304
+ 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.")
11240
11305
  };
11241
- var MetaUploadSessionToolInput = z52.object(MetaUploadSessionToolInputShape).superRefine((value, ctx) => {
11306
+ var MetaUploadSessionToolInput = z53.object(MetaUploadSessionToolInputShape).superRefine((value, ctx) => {
11242
11307
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
11243
11308
  ctx.addIssue({
11244
- code: z52.ZodIssueCode.custom,
11309
+ code: z53.ZodIssueCode.custom,
11245
11310
  path: [
11246
11311
  "mediaKind"
11247
11312
  ],
11248
11313
  message: "Meta thumbnails must be images"
11249
11314
  });
11250
11315
  }
11316
+ if (value.mediaKind !== "mixed" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
11317
+ ctx.addIssue({
11318
+ code: z53.ZodIssueCode.custom,
11319
+ path: [
11320
+ "maxFiles"
11321
+ ],
11322
+ message: "Image and video sessions accept exactly one file"
11323
+ });
11324
+ }
11251
11325
  });
11252
- var MetaUploadSessionResponse2 = z52.object({
11253
- sessionId: z52.string().uuid(),
11254
- uploadPageUrl: z52.string().url(),
11255
- mediaKind: z52.enum([
11326
+ var MetaUploadSessionResponse2 = z53.object({
11327
+ sessionId: z53.string().uuid(),
11328
+ uploadPageUrl: z53.string().url(),
11329
+ mediaKind: z53.enum([
11256
11330
  "image",
11257
11331
  "video",
11258
11332
  "mixed"
11259
11333
  ]),
11260
- assetRole: z52.enum([
11334
+ assetRole: z53.enum([
11261
11335
  "media",
11262
11336
  "thumbnail"
11263
11337
  ]),
11264
- maxFiles: z52.number().int().positive(),
11265
- expiresAt: z52.string().datetime()
11338
+ maxFiles: z53.number().int().positive(),
11339
+ expiresAt: z53.string().datetime()
11266
11340
  });
11267
- var MetaUploadStatusInput = z52.object({
11268
- sessionId: z52.string().uuid().describe("The sessionId returned by request_meta_media_upload.")
11341
+ var MetaUploadStatusInput = z53.object({
11342
+ sessionId: z53.string().uuid().describe("The sessionId returned by request_meta_media_upload.")
11269
11343
  });
11270
- var MetaUploadStatusResponse = z52.object({
11271
- sessionId: z52.string().uuid(),
11272
- status: z52.enum([
11344
+ var MetaUploadStatusResponse = z53.object({
11345
+ sessionId: z53.string().uuid(),
11346
+ status: z53.enum([
11273
11347
  "pending",
11274
11348
  "uploaded"
11275
11349
  ]),
11276
- assets: z52.array(z52.object({
11277
- stagingAssetId: z52.string().uuid(),
11278
- mediaKind: z52.enum([
11350
+ assets: z53.array(z53.object({
11351
+ stagingAssetId: z53.string().uuid(),
11352
+ mediaKind: z53.enum([
11279
11353
  "image",
11280
11354
  "video"
11281
11355
  ])
11282
11356
  })).max(10).default([]),
11283
- stagingAssetId: z52.string().uuid().optional()
11357
+ stagingAssetId: z53.string().uuid().optional()
11284
11358
  });
11285
11359
  function uploadSessionText(result) {
11286
11360
  const mediaLabel = result.mediaKind === "mixed" ? "archivos" : result.mediaKind === "video" ? "video" : "imagen";
@@ -11289,8 +11363,8 @@ function uploadSessionText(result) {
11289
11363
  {
11290
11364
  type: "text",
11291
11365
  text: [
11292
- `### Sube tu ${mediaLabel} a ProductMaker`,
11293
- `[Abrir carga segura](${result.uploadPageUrl})`,
11366
+ `### Prepara tu ${mediaLabel} en ProductMaker`,
11367
+ `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})`,
11294
11368
  `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.`,
11295
11369
  `sessionId: \`${result.sessionId}\``,
11296
11370
  `Este enlace expira: ${result.expiresAt}`
@@ -11303,7 +11377,7 @@ __name(uploadSessionText, "uploadSessionText");
11303
11377
  function registerMetaUploadTools(server, api) {
11304
11378
  server.registerTool("request_meta_media_upload", {
11305
11379
  title: "Solicitar carga segura de Meta",
11306
- 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.",
11380
+ 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.",
11307
11381
  inputSchema: MetaUploadSessionToolInputShape,
11308
11382
  outputSchema: MetaUploadSessionResponse2,
11309
11383
  _meta: {
@@ -11335,7 +11409,13 @@ function registerMetaUploadTools(server, api) {
11335
11409
  throw translateError(error);
11336
11410
  }
11337
11411
  });
11338
- 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) => {
11412
+ server.registerTool("check_meta_media_upload", {
11413
+ 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.',
11414
+ inputSchema: MetaUploadStatusInput.shape,
11415
+ _meta: {
11416
+ "openai/widgetAccessible": true
11417
+ }
11418
+ }, async (rawInput) => {
11339
11419
  try {
11340
11420
  const input = MetaUploadStatusInput.parse(rawInput);
11341
11421
  const result = MetaUploadStatusResponse.parse(await api.getJson(`/v1/ads/meta-upload-sessions/${encodeURIComponent(input.sessionId)}`));
@@ -11348,13 +11428,13 @@ function registerMetaUploadTools(server, api) {
11348
11428
  __name(registerMetaUploadTools, "registerMetaUploadTools");
11349
11429
 
11350
11430
  // src/tools/campaigns.ts
11351
- import { z as z53 } from "zod";
11352
- var MetaStatusInput = z53.object({
11353
- campaignId: z53.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
11431
+ import { z as z54 } from "zod";
11432
+ var MetaStatusInput = z54.object({
11433
+ campaignId: z54.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
11354
11434
  });
11355
- var TikTokStatusInput = z53.object({
11356
- campaignId: z53.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
11357
- advertiserId: z53.string().min(1).describe("The same advertiserId used to publish the campaign.")
11435
+ var TikTokStatusInput = z54.object({
11436
+ campaignId: z54.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
11437
+ advertiserId: z54.string().min(1).describe("The same advertiserId used to publish the campaign.")
11358
11438
  });
11359
11439
  function registerCampaignTools(server, api) {
11360
11440
  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) => {
@@ -11451,10 +11531,10 @@ function renderTikTokStatusMarkdown(r) {
11451
11531
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
11452
11532
 
11453
11533
  // ../../packages/product-economics/src/product-costing.ts
11454
- import { z as z55 } from "zod";
11534
+ import { z as z56 } from "zod";
11455
11535
 
11456
11536
  // ../../packages/product-economics/src/product-costing-countries.ts
11457
- import { z as z54 } from "zod";
11537
+ import { z as z55 } from "zod";
11458
11538
 
11459
11539
  // ../../packages/product-economics/src/product-costing-shipping-references.json
11460
11540
  var product_costing_shipping_references_default = {
@@ -11518,21 +11598,21 @@ var product_costing_shipping_references_default = {
11518
11598
  };
11519
11599
 
11520
11600
  // ../../packages/product-economics/src/product-costing-countries.ts
11521
- var ShippingReferenceSchema = z54.object({
11522
- reference: z54.number().positive(),
11523
- min: z54.number().nonnegative(),
11524
- max: z54.number().positive(),
11525
- updatedAt: z54.string().date(),
11526
- confidence: z54.enum([
11601
+ var ShippingReferenceSchema = z55.object({
11602
+ reference: z55.number().positive(),
11603
+ min: z55.number().nonnegative(),
11604
+ max: z55.number().positive(),
11605
+ updatedAt: z55.string().date(),
11606
+ confidence: z55.enum([
11527
11607
  "high",
11528
11608
  "medium",
11529
11609
  "medium-low"
11530
11610
  ]),
11531
- sources: z54.array(z54.string().url().startsWith("https://")).min(1).max(3)
11611
+ sources: z55.array(z55.string().url().startsWith("https://")).min(1).max(3)
11532
11612
  }).superRefine(({ reference, min, max }, context) => {
11533
11613
  if (min > reference || reference > max) {
11534
11614
  context.addIssue({
11535
- code: z54.ZodIssueCode.custom,
11615
+ code: z55.ZodIssueCode.custom,
11536
11616
  message: "shipping_reference_outside_range",
11537
11617
  path: [
11538
11618
  "reference"
@@ -11540,7 +11620,7 @@ var ShippingReferenceSchema = z54.object({
11540
11620
  });
11541
11621
  }
11542
11622
  });
11543
- var SHIPPING_REFERENCES = z54.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
11623
+ var SHIPPING_REFERENCES = z55.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
11544
11624
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
11545
11625
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
11546
11626
  "MX",
@@ -11722,18 +11802,18 @@ function getProductCostingCountryName(country) {
11722
11802
  __name(getProductCostingCountryName, "getProductCostingCountryName");
11723
11803
 
11724
11804
  // ../../packages/product-economics/src/product-costing.ts
11725
- var ProductCostingInputSchema = z55.object({
11726
- country: z55.string().refine(isProductCostingCountryCode, "unsupported_country"),
11727
- supplierCost: z55.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
11728
- shippingCost: z55.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
11729
- returnRate: z55.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11730
- cancellationRate: z55.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11731
- adsManagerCpa: z55.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
11732
- desiredMargin: z55.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
11805
+ var ProductCostingInputSchema = z56.object({
11806
+ country: z56.string().refine(isProductCostingCountryCode, "unsupported_country"),
11807
+ supplierCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
11808
+ shippingCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
11809
+ returnRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11810
+ cancellationRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
11811
+ adsManagerCpa: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
11812
+ desiredMargin: z56.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
11733
11813
  }).superRefine(({ returnRate, cancellationRate }, context) => {
11734
11814
  if (returnRate + cancellationRate >= 1) {
11735
11815
  context.addIssue({
11736
- code: z55.ZodIssueCode.custom,
11816
+ code: z56.ZodIssueCode.custom,
11737
11817
  message: "delivery_rate_positive",
11738
11818
  path: [
11739
11819
  "cancellationRate"
@@ -11800,14 +11880,14 @@ function calculateProductCosting(rawInput) {
11800
11880
  __name(calculateProductCosting, "calculateProductCosting");
11801
11881
 
11802
11882
  // src/tools/product-costing.ts
11803
- import { z as z56 } from "zod";
11804
- var optionalAmount = /* @__PURE__ */ __name((description) => z56.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
11805
- var optionalPercent = /* @__PURE__ */ __name((description) => z56.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
11806
- var ProductCostingToolInput = z56.object({
11807
- country: z56.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
11883
+ import { z as z57 } from "zod";
11884
+ var optionalAmount = /* @__PURE__ */ __name((description) => z57.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
11885
+ var optionalPercent = /* @__PURE__ */ __name((description) => z57.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
11886
+ var ProductCostingToolInput = z57.object({
11887
+ country: z57.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
11808
11888
  message: "Pa\xEDs no soportado por ProductMaker."
11809
11889
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
11810
- 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."),
11890
+ 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."),
11811
11891
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
11812
11892
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
11813
11893
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -11939,7 +12019,7 @@ function formatPercent(value) {
11939
12019
  __name(formatPercent, "formatPercent");
11940
12020
 
11941
12021
  // src/tools/product-research.ts
11942
- import { z as z57 } from "zod";
12022
+ import { z as z58 } from "zod";
11943
12023
 
11944
12024
  // src/tools/product-research-idempotency.ts
11945
12025
  import { createHash as createHash2 } from "crypto";
@@ -12055,17 +12135,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
12055
12135
  ]);
12056
12136
  var POLL_INTERVAL_MS = 5e3;
12057
12137
  var MAX_WAIT_SECONDS = 120;
12058
- var FindInput = z57.object({
12138
+ var FindInput = z58.object({
12059
12139
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
12060
12140
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
12061
- 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.`),
12062
- 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.")
12141
+ 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.`),
12142
+ 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.")
12063
12143
  });
12064
- var GetInput = z57.object({
12065
- runId: z57.string().uuid().describe("ID del run devuelto por find_winning_products.")
12144
+ var GetInput = z58.object({
12145
+ runId: z58.string().uuid().describe("ID del run devuelto por find_winning_products.")
12066
12146
  });
12067
- var ListInput = z57.object({
12068
- limit: z57.number().int().min(1).max(20).default(10)
12147
+ var ListInput = z58.object({
12148
+ limit: z58.number().int().min(1).max(20).default(10)
12069
12149
  });
12070
12150
  function textResult(text) {
12071
12151
  return {
@@ -12157,14 +12237,14 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
12157
12237
  __name(registerProductResearchTools, "registerProductResearchTools");
12158
12238
 
12159
12239
  // src/tools/dropshipping-projects.ts
12160
- import { z as z58 } from "zod";
12161
- var ProjectId = z58.string().uuid();
12162
- var DropshippingProjectStatus = z58.enum([
12240
+ import { z as z59 } from "zod";
12241
+ var ProjectId = z59.string().uuid();
12242
+ var DropshippingProjectStatus = z59.enum([
12163
12243
  "active",
12164
12244
  "completed",
12165
12245
  "archived"
12166
12246
  ]);
12167
- var DropshippingProjectPhase = z58.enum([
12247
+ var DropshippingProjectPhase = z59.enum([
12168
12248
  "research",
12169
12249
  "costing",
12170
12250
  "media",
@@ -12173,21 +12253,21 @@ var DropshippingProjectPhase = z58.enum([
12173
12253
  "advertising",
12174
12254
  "complete"
12175
12255
  ]);
12176
- var DropshippingRewardMilestone = z58.enum([
12256
+ var DropshippingRewardMilestone = z59.enum([
12177
12257
  "product_selected",
12178
12258
  "costing_saved",
12179
12259
  "product_media_ready",
12180
12260
  "creatives_completed",
12181
12261
  "campaign_created"
12182
12262
  ]);
12183
- var TargetCountry = z58.enum([
12263
+ var TargetCountry = z59.enum([
12184
12264
  "CO",
12185
12265
  "MX",
12186
12266
  "PE",
12187
12267
  "EC",
12188
12268
  "CL"
12189
12269
  ]);
12190
- var ResearchCategory = z58.enum([
12270
+ var ResearchCategory = z59.enum([
12191
12271
  "auto",
12192
12272
  "automotive",
12193
12273
  "kitchen",
@@ -12202,7 +12282,7 @@ var ResearchCategory = z58.enum([
12202
12282
  "garden",
12203
12283
  "cleaning"
12204
12284
  ]);
12205
- var HttpUrl3 = z58.string().url().max(2e3).refine((value) => {
12285
+ var HttpUrl3 = z59.string().url().max(2e3).refine((value) => {
12206
12286
  try {
12207
12287
  return [
12208
12288
  "http:",
@@ -12212,46 +12292,46 @@ var HttpUrl3 = z58.string().url().max(2e3).refine((value) => {
12212
12292
  return false;
12213
12293
  }
12214
12294
  }, "URL must use HTTP(S)");
12215
- var ResearchCandidateOrigin = z58.object({
12216
- type: z58.literal("research_candidate"),
12295
+ var ResearchCandidateOrigin = z59.object({
12296
+ type: z59.literal("research_candidate"),
12217
12297
  runId: ProjectId,
12218
- candidateSourceId: z58.string().min(1).max(160)
12298
+ candidateSourceId: z59.string().min(1).max(160)
12219
12299
  });
12220
- var TaskOrigin = z58.object({
12221
- type: z58.literal("task"),
12300
+ var TaskOrigin = z59.object({
12301
+ type: z59.literal("task"),
12222
12302
  taskId: ProjectId
12223
12303
  });
12224
- var ManualOrigin = z58.object({
12225
- type: z58.literal("manual"),
12304
+ var ManualOrigin = z59.object({
12305
+ type: z59.literal("manual"),
12226
12306
  clientRequestId: ProjectId,
12227
- country: z58.string().min(2).max(3).optional()
12307
+ country: z59.string().min(2).max(3).optional()
12228
12308
  });
12229
- var StartProjectInput = z58.object({
12230
- origin: z58.discriminatedUnion("type", [
12309
+ var StartProjectInput = z59.object({
12310
+ origin: z59.discriminatedUnion("type", [
12231
12311
  ResearchCandidateOrigin,
12232
12312
  TaskOrigin,
12233
12313
  ManualOrigin
12234
12314
  ]),
12235
- productName: z58.string().trim().min(1).max(240).optional(),
12315
+ productName: z59.string().trim().min(1).max(240).optional(),
12236
12316
  productUrl: HttpUrl3.optional(),
12237
- country: z58.string().min(2).max(3).optional(),
12238
- languageCode: z58.string().min(2).max(16).optional()
12317
+ country: z59.string().min(2).max(3).optional(),
12318
+ languageCode: z59.string().min(2).max(16).optional()
12239
12319
  }).strict();
12240
- var CostProjectInput = z58.object({
12320
+ var CostProjectInput = z59.object({
12241
12321
  projectId: ProjectId,
12242
- version: z58.number().int().positive(),
12243
- country: z58.string().trim().min(2).max(3),
12244
- supplierCost: z58.number().finite().positive(),
12245
- shippingCost: z58.number().finite().nonnegative(),
12246
- returnRate: z58.number().finite().min(0).lt(1),
12247
- cancellationRate: z58.number().finite().min(0).lt(1),
12248
- adsManagerCpa: z58.number().finite().nonnegative(),
12249
- desiredMargin: z58.number().finite().min(0).lt(1)
12250
- });
12251
- var GuideInput = z58.object({
12322
+ version: z59.number().int().positive(),
12323
+ country: z59.string().trim().min(2).max(3),
12324
+ supplierCost: z59.number().finite().positive(),
12325
+ shippingCost: z59.number().finite().nonnegative(),
12326
+ returnRate: z59.number().finite().min(0).lt(1),
12327
+ cancellationRate: z59.number().finite().min(0).lt(1),
12328
+ adsManagerCpa: z59.number().finite().nonnegative(),
12329
+ desiredMargin: z59.number().finite().min(0).lt(1)
12330
+ });
12331
+ var GuideInput = z59.object({
12252
12332
  projectId: ProjectId.optional()
12253
12333
  }).strict();
12254
- var DropshippingProjectNextAction = z58.discriminatedUnion("kind", [
12334
+ var DropshippingProjectNextAction = z59.discriminatedUnion("kind", [
12255
12335
  "cost_product",
12256
12336
  "provide_product_media",
12257
12337
  "generate_creatives",
@@ -12265,78 +12345,78 @@ var DropshippingProjectNextAction = z58.discriminatedUnion("kind", [
12265
12345
  "create_meta_campaign",
12266
12346
  "repair_meta_campaign",
12267
12347
  "review_paused_campaign"
12268
- ].map((kind) => z58.object({
12269
- kind: z58.literal(kind),
12270
- href: z58.string().min(1)
12348
+ ].map((kind) => z59.object({
12349
+ kind: z59.literal(kind),
12350
+ href: z59.string().min(1)
12271
12351
  })));
12272
- var CostingInputSchema = z58.object({
12273
- country: z58.string().min(2).max(3),
12274
- supplierCost: z58.number().finite().positive(),
12275
- shippingCost: z58.number().finite().nonnegative(),
12276
- returnRate: z58.number().finite().min(0).lt(1),
12277
- cancellationRate: z58.number().finite().min(0).lt(1),
12278
- adsManagerCpa: z58.number().finite().nonnegative(),
12279
- desiredMargin: z58.number().finite().min(0).lt(1)
12352
+ var CostingInputSchema = z59.object({
12353
+ country: z59.string().min(2).max(3),
12354
+ supplierCost: z59.number().finite().positive(),
12355
+ shippingCost: z59.number().finite().nonnegative(),
12356
+ returnRate: z59.number().finite().min(0).lt(1),
12357
+ cancellationRate: z59.number().finite().min(0).lt(1),
12358
+ adsManagerCpa: z59.number().finite().nonnegative(),
12359
+ desiredMargin: z59.number().finite().min(0).lt(1)
12280
12360
  }).superRefine(({ returnRate, cancellationRate }, context) => {
12281
12361
  if (returnRate + cancellationRate >= 1) context.addIssue({
12282
- code: z58.ZodIssueCode.custom,
12362
+ code: z59.ZodIssueCode.custom,
12283
12363
  path: [
12284
12364
  "cancellationRate"
12285
12365
  ]
12286
12366
  });
12287
12367
  });
12288
- var CostingResultSchema = z58.object({
12289
- country: z58.string().min(2).max(3),
12290
- deliveryRate: z58.number().finite(),
12291
- adjustedShippingCost: z58.number().finite(),
12292
- adjustedCpa: z58.number().finite(),
12293
- totalCost: z58.number().finite(),
12294
- suggestedPrice: z58.number().finite(),
12295
- baseCommercialPrice: z58.number().finite(),
12296
- minimumSafePrice: z58.number().finite(),
12297
- commercialPrice: z58.number().finite(),
12298
- comparisonPrice: z58.number().finite(),
12299
- estimatedProfit: z58.number().finite(),
12300
- actualMargin: z58.number().finite(),
12301
- breakEvenAdsManagerCpa: z58.number().finite(),
12302
- wasPriceAutoAdjusted: z58.boolean(),
12303
- profitabilityStatus: z58.literal("healthy")
12304
- });
12305
- var RewardProgressSchema = z58.object({
12306
- campaignKey: z58.literal("dropshipping-launch-v1"),
12307
- totalCredits: z58.number().int().positive(),
12308
- earnedCredits: z58.number().int().nonnegative(),
12309
- milestones: z58.array(z58.object({
12368
+ var CostingResultSchema = z59.object({
12369
+ country: z59.string().min(2).max(3),
12370
+ deliveryRate: z59.number().finite(),
12371
+ adjustedShippingCost: z59.number().finite(),
12372
+ adjustedCpa: z59.number().finite(),
12373
+ totalCost: z59.number().finite(),
12374
+ suggestedPrice: z59.number().finite(),
12375
+ baseCommercialPrice: z59.number().finite(),
12376
+ minimumSafePrice: z59.number().finite(),
12377
+ commercialPrice: z59.number().finite(),
12378
+ comparisonPrice: z59.number().finite(),
12379
+ estimatedProfit: z59.number().finite(),
12380
+ actualMargin: z59.number().finite(),
12381
+ breakEvenAdsManagerCpa: z59.number().finite(),
12382
+ wasPriceAutoAdjusted: z59.boolean(),
12383
+ profitabilityStatus: z59.literal("healthy")
12384
+ });
12385
+ var RewardProgressSchema = z59.object({
12386
+ campaignKey: z59.literal("dropshipping-launch-v1"),
12387
+ totalCredits: z59.number().int().positive(),
12388
+ earnedCredits: z59.number().int().nonnegative(),
12389
+ milestones: z59.array(z59.object({
12310
12390
  milestone: DropshippingRewardMilestone,
12311
- credits: z58.number().int().positive(),
12312
- available: z58.boolean().optional(),
12313
- earned: z58.boolean(),
12391
+ credits: z59.number().int().positive(),
12392
+ available: z59.boolean().optional(),
12393
+ earned: z59.boolean(),
12314
12394
  grantId: ProjectId.nullable(),
12315
- grantedAt: z58.string().datetime().nullable()
12395
+ grantedAt: z59.string().datetime().nullable()
12316
12396
  })).length(DropshippingRewardMilestone.options.length)
12317
12397
  });
12318
- var ProjectResponseSchema = z58.object({
12398
+ var ProjectResponseSchema = z59.object({
12319
12399
  id: ProjectId,
12320
12400
  taskId: ProjectId.nullable(),
12321
12401
  status: DropshippingProjectStatus,
12322
- originKey: z58.string().min(1),
12402
+ originKey: z59.string().min(1),
12323
12403
  researchRunId: ProjectId.nullable(),
12324
- candidateSourceId: z58.string().nullable(),
12325
- productName: z58.string().nullable(),
12404
+ candidateSourceId: z59.string().nullable(),
12405
+ productName: z59.string().nullable(),
12326
12406
  productUrl: HttpUrl3.nullable(),
12327
12407
  referenceImageUrl: HttpUrl3.nullable(),
12328
- targetCountry: z58.string().nullable(),
12329
- languageCode: z58.string().nullable(),
12330
- hasReferenceImage: z58.boolean(),
12408
+ targetCountry: z59.string().nullable(),
12409
+ languageCode: z59.string().nullable(),
12410
+ hasReferenceImage: z59.boolean(),
12331
12411
  costingInput: CostingInputSchema.nullable(),
12332
12412
  costingResult: CostingResultSchema.nullable(),
12333
- costingVersion: z58.number().int().positive().nullable(),
12334
- version: z58.number().int().positive(),
12413
+ costingVersion: z59.number().int().positive().nullable(),
12414
+ version: z59.number().int().positive(),
12335
12415
  phase: DropshippingProjectPhase,
12336
12416
  nextAction: DropshippingProjectNextAction.nullable(),
12337
12417
  rewards: RewardProgressSchema,
12338
- createdAt: z58.string().datetime(),
12339
- updatedAt: z58.string().datetime()
12418
+ createdAt: z59.string().datetime(),
12419
+ updatedAt: z59.string().datetime()
12340
12420
  }).passthrough();
12341
12421
  function projectText(raw) {
12342
12422
  const project = ProjectResponseSchema.parse(raw);