@productmaker/mcp 12.1.0 → 12.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stdio.js CHANGED
@@ -5348,6 +5348,7 @@ var ImageCreativeArchetype = z24.enum([
5348
5348
  "problem_solution",
5349
5349
  "lifestyle_identity"
5350
5350
  ]);
5351
+ var MAX_IMAGE_CREATIVE_VARIANTS = 6;
5351
5352
  var ImageCreativeVisualTreatment = z24.enum([
5352
5353
  "performance_product_ad",
5353
5354
  "premium_dtc_carousel"
@@ -23552,14 +23553,37 @@ var WebsiteCaptureResearchSchema = z116.object({
23552
23553
  });
23553
23554
 
23554
23555
  // ../../packages/types/src/demo-mode.ts
23556
+ import { z as z118 } from "zod";
23557
+
23558
+ // ../../packages/types/src/demo-mode-service-page-assets.ts
23555
23559
  import { z as z117 } from "zod";
23560
+ var DemoServicePageAssetSourceSchema = z117.object({
23561
+ pageId: z117.string().uuid(),
23562
+ ownerId: z117.string().min(1),
23563
+ assets: z117.array(z117.object({
23564
+ id: z117.string().uuid(),
23565
+ storageKey: z117.string().min(1).max(1024),
23566
+ mediaType: z117.enum([
23567
+ "image/webp",
23568
+ "video/mp4"
23569
+ ]),
23570
+ byteSize: z117.number().int().positive().max(32 * 1024 * 1024),
23571
+ width: z117.number().int().positive().max(1920),
23572
+ height: z117.number().int().positive().max(1920),
23573
+ contentHash: z117.string().regex(/^[a-f0-9]{64}$/i),
23574
+ sourceKind: ServicePageSourceKindSchema,
23575
+ approvedAt: z117.string().datetime()
23576
+ }).strict()).max(24)
23577
+ }).strict();
23578
+
23579
+ // ../../packages/types/src/demo-mode.ts
23556
23580
  var DEMO_MODE_FLOWS = [
23557
23581
  "brand",
23558
23582
  "servicePage",
23559
23583
  "motion",
23560
23584
  "image"
23561
23585
  ];
23562
- var DemoModeFlowSchema = z117.enum(DEMO_MODE_FLOWS);
23586
+ var DemoModeFlowSchema = z118.enum(DEMO_MODE_FLOWS);
23563
23587
  var DEMO_MODE_STEPS = [
23564
23588
  "running",
23565
23589
  "research",
@@ -23572,27 +23596,30 @@ var DEMO_MODE_STEPS = [
23572
23596
  "final",
23573
23597
  "watchdog"
23574
23598
  ];
23575
- var DemoModeStepSchema = z117.enum(DEMO_MODE_STEPS);
23599
+ var DemoModeStepSchema = z118.enum(DEMO_MODE_STEPS);
23576
23600
  var DEMO_MODE_WAIT_SECONDS = {
23577
23601
  min: 30,
23578
23602
  max: 450,
23579
23603
  default: 150
23580
23604
  };
23581
- var centsSchema = z117.number().int().min(0).max(1e5);
23582
- var emailSchema = z117.string().trim().toLowerCase().email();
23583
- var DemoModeTemplatesSchema = z117.object({
23584
- brandId: z117.string().uuid(),
23585
- servicePageId: z117.string().uuid(),
23586
- motionTaskId: z117.string().uuid(),
23587
- imageTaskId: z117.string().uuid()
23588
- });
23589
- var DemoModeEditableSchema = z117.object({
23590
- enabled: z117.boolean(),
23591
- emails: z117.array(emailSchema).max(50).transform((list) => [
23605
+ var centsSchema = z118.number().int().min(0).max(1e5);
23606
+ var emailSchema = z118.string().trim().toLowerCase().email();
23607
+ var optionalTemplateId = z118.preprocess((value) => value === "" ? void 0 : value, z118.string().uuid().optional());
23608
+ var DemoModeTemplatesSchema = z118.object({
23609
+ brandId: z118.string().uuid(),
23610
+ servicePageId: z118.string().uuid(),
23611
+ motionTaskId: z118.string().uuid(),
23612
+ motionVariantTaskId: optionalTemplateId,
23613
+ motionThirdTaskId: optionalTemplateId,
23614
+ imageTaskId: z118.string().uuid()
23615
+ });
23616
+ var DemoModeEditableSchema = z118.object({
23617
+ enabled: z118.boolean(),
23618
+ emails: z118.array(emailSchema).max(50).transform((list) => [
23592
23619
  ...new Set(list)
23593
23620
  ]),
23594
- waitSeconds: z117.number().int().min(DEMO_MODE_WAIT_SECONDS.min).max(DEMO_MODE_WAIT_SECONDS.max),
23595
- chargeCents: z117.object({
23621
+ waitSeconds: z118.number().int().min(DEMO_MODE_WAIT_SECONDS.min).max(DEMO_MODE_WAIT_SECONDS.max),
23622
+ chargeCents: z118.object({
23596
23623
  brand: centsSchema,
23597
23624
  servicePage: centsSchema,
23598
23625
  motion: centsSchema,
@@ -23600,73 +23627,77 @@ var DemoModeEditableSchema = z117.object({
23600
23627
  }),
23601
23628
  templates: DemoModeTemplatesSchema
23602
23629
  });
23603
- var nullableString = z117.string().nullable();
23604
- var DemoModeSnapshotSchema = z117.object({
23605
- brand: z117.object({
23630
+ var nullableString = z118.string().nullable();
23631
+ var DemoModeSnapshotSchema = z118.object({
23632
+ brand: z118.object({
23606
23633
  /** Columnas de identidad de `Brand` listas para un `update` (sin id/userId/slug/estado/fechas). */
23607
- identity: z117.record(z117.unknown()),
23608
- productSamples: z117.array(z117.object({
23609
- name: z117.string(),
23610
- priceCents: z117.number().int().nullable(),
23634
+ identity: z118.record(z118.unknown()),
23635
+ productSamples: z118.array(z118.object({
23636
+ name: z118.string(),
23637
+ priceCents: z118.number().int().nullable(),
23611
23638
  currency: nullableString,
23612
- imageKey: z117.string(),
23639
+ imageKey: z118.string(),
23613
23640
  productUrl: nullableString,
23614
- position: z117.number().int()
23641
+ position: z118.number().int()
23615
23642
  })),
23616
- personas: z117.array(z117.object({
23617
- name: z117.string(),
23643
+ personas: z118.array(z118.object({
23644
+ name: z118.string(),
23618
23645
  demographics: nullableString,
23619
23646
  painPoints: nullableString,
23620
23647
  motivations: nullableString,
23621
23648
  objections: nullableString,
23622
23649
  gender: nullableString,
23623
- isDefault: z117.boolean()
23650
+ isDefault: z118.boolean()
23624
23651
  }))
23625
23652
  }),
23626
- servicePage: z117.object({
23627
- facts: z117.unknown(),
23628
- review: z117.unknown(),
23629
- artifact: z117.unknown()
23653
+ servicePage: z118.object({
23654
+ facts: z118.unknown(),
23655
+ review: z118.unknown(),
23656
+ artifact: z118.unknown(),
23657
+ /** Optional only for snapshots saved before page-owned demo media. */
23658
+ assetSource: DemoServicePageAssetSourceSchema.optional()
23630
23659
  }),
23631
- motion: z117.object({
23660
+ motion: z118.object({
23632
23661
  outputs: MotionGraphicsOutputsSchema,
23633
23662
  /**
23634
23663
  * La captura REAL de la web de la plantilla (nunca una fabricada por la
23635
23664
  * demo). Null cuando la plantilla no tiene ninguna: la captura demo nunca
23636
23665
  * va live, así que el servicio usa `DEMO_MODE_PLACEHOLDER_CAPTURE`.
23637
23666
  */
23638
- capture: z117.object({
23639
- bundleKey: z117.string(),
23640
- sha256: z117.string(),
23641
- uploadBytes: z117.number().int().nullable(),
23667
+ capture: z118.object({
23668
+ bundleKey: z118.string(),
23669
+ sha256: z118.string(),
23670
+ uploadBytes: z118.number().int().nullable(),
23642
23671
  previewKey: nullableString
23643
23672
  }).nullable()
23644
23673
  }),
23645
- image: z117.object({
23646
- provider: z117.string(),
23647
- model: z117.string(),
23648
- prompt: z117.string(),
23649
- imageUrl: z117.string(),
23650
- width: z117.number().int(),
23651
- height: z117.number().int(),
23674
+ image: z118.object({
23675
+ provider: z118.string(),
23676
+ model: z118.string(),
23677
+ prompt: z118.string(),
23678
+ imageUrl: z118.string(),
23679
+ width: z118.number().int(),
23680
+ height: z118.number().int(),
23652
23681
  adCopy: nullableString,
23653
- rawResponse: z117.unknown()
23682
+ rawResponse: z118.unknown()
23654
23683
  })
23655
23684
  });
23656
23685
  var DemoModeConfigSchema = DemoModeEditableSchema.extend({
23657
23686
  snapshot: DemoModeSnapshotSchema.nullable(),
23658
- snapshotAt: z117.string().datetime().nullable()
23687
+ snapshotAt: z118.string().datetime().nullable()
23659
23688
  });
23660
23689
  var DemoModeAdminViewSchema = DemoModeEditableSchema.extend({
23661
23690
  // Sin configurar, la API devuelve ids vacíos ("" no es uuid): la vista los
23662
23691
  // admite; el PUT sí exige uuid (`DemoModeEditableSchema`).
23663
- templates: z117.object({
23664
- brandId: z117.string(),
23665
- servicePageId: z117.string(),
23666
- motionTaskId: z117.string(),
23667
- imageTaskId: z117.string()
23692
+ templates: z118.object({
23693
+ brandId: z118.string(),
23694
+ servicePageId: z118.string(),
23695
+ motionTaskId: z118.string(),
23696
+ motionVariantTaskId: z118.string().optional(),
23697
+ motionThirdTaskId: z118.string().optional(),
23698
+ imageTaskId: z118.string()
23668
23699
  }),
23669
- snapshotAt: z117.string().nullable()
23700
+ snapshotAt: z118.string().nullable()
23670
23701
  });
23671
23702
  var DEMO_MODE_TEMPLATE_PROBLEMS = [
23672
23703
  "not_found",
@@ -23677,31 +23708,33 @@ var DEMO_MODE_TEMPLATE_PROBLEMS = [
23677
23708
  "no_video",
23678
23709
  "no_creative"
23679
23710
  ];
23680
- var DemoModeTemplateVerdictSchema = z117.discriminatedUnion("ok", [
23681
- z117.object({
23682
- ok: z117.literal(true)
23711
+ var DemoModeTemplateVerdictSchema = z118.discriminatedUnion("ok", [
23712
+ z118.object({
23713
+ ok: z118.literal(true)
23683
23714
  }),
23684
- z117.object({
23685
- ok: z117.literal(false),
23686
- problem: z117.enum(DEMO_MODE_TEMPLATE_PROBLEMS)
23715
+ z118.object({
23716
+ ok: z118.literal(false),
23717
+ problem: z118.enum(DEMO_MODE_TEMPLATE_PROBLEMS)
23687
23718
  })
23688
23719
  ]);
23689
- var DemoModeValidationSchema = z117.object({
23720
+ var DemoModeValidationSchema = z118.object({
23690
23721
  brandId: DemoModeTemplateVerdictSchema,
23691
23722
  servicePageId: DemoModeTemplateVerdictSchema,
23692
23723
  motionTaskId: DemoModeTemplateVerdictSchema,
23724
+ motionVariantTaskId: DemoModeTemplateVerdictSchema.optional(),
23725
+ motionThirdTaskId: DemoModeTemplateVerdictSchema.optional(),
23693
23726
  imageTaskId: DemoModeTemplateVerdictSchema
23694
23727
  });
23695
- var DemoModeJobSchema = z117.object({
23728
+ var DemoModeJobSchema = z118.object({
23696
23729
  flow: DemoModeFlowSchema,
23697
23730
  step: DemoModeStepSchema,
23698
23731
  /** brandId | servicePageOperationId | taskId según el flujo. */
23699
- targetId: z117.string().uuid(),
23700
- userId: z117.string().min(1),
23732
+ targetId: z118.string().uuid(),
23733
+ userId: z118.string().min(1),
23701
23734
  /** Solo marca: la generación de extracción que el guion completa. */
23702
- generation: z117.number().int().positive().optional(),
23735
+ generation: z118.number().int().positive().optional(),
23703
23736
  /** Solo `final`/`watchdog`: la parte del snapshot de ESTE flujo, congelada al empezar. */
23704
- result: z117.unknown().optional()
23737
+ result: z118.unknown().optional()
23705
23738
  });
23706
23739
 
23707
23740
  // ../../packages/utils/src/retry-after.ts
@@ -24177,7 +24210,7 @@ var ApiClient = class {
24177
24210
  };
24178
24211
 
24179
24212
  // src/index.ts
24180
- var MCP_VERSION = "12.1.0";
24213
+ var MCP_VERSION = "12.1.1";
24181
24214
 
24182
24215
  // src/meta-upload-app.ts
24183
24216
  import { readFileSync } from "fs";
@@ -24248,8 +24281,123 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
24248
24281
  }
24249
24282
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
24250
24283
 
24284
+ // src/task-results-app.ts
24285
+ import { readFileSync as readFileSync2 } from "fs";
24286
+ import { registerAppResource as registerAppResource2, RESOURCE_MIME_TYPE as RESOURCE_MIME_TYPE2 } from "@modelcontextprotocol/ext-apps/server";
24287
+ var TASK_RESULTS_APP_RESOURCE_URI = "ui://task-results/v1.html";
24288
+ var HTML_URL = new URL("./ui/task-results-app.html", import.meta.url);
24289
+ function assetOrigin(value) {
24290
+ if (!value) return null;
24291
+ try {
24292
+ const url = new URL(value);
24293
+ return url.protocol === "https:" && !url.username && !url.password ? url.origin : null;
24294
+ } catch {
24295
+ return null;
24296
+ }
24297
+ }
24298
+ __name(assetOrigin, "assetOrigin");
24299
+ function buildTaskResultsView(media, proxyBaseUrl) {
24300
+ const origin = assetOrigin(proxyBaseUrl);
24301
+ const safeUrl = /* @__PURE__ */ __name((value) => {
24302
+ if (!origin) return null;
24303
+ try {
24304
+ const url = new URL(value);
24305
+ return url.protocol === "https:" && url.origin === origin && url.pathname.startsWith("/assets/") && url.pathname.length > "/assets/".length && !url.username && !url.password ? url.href : null;
24306
+ } catch {
24307
+ return null;
24308
+ }
24309
+ }, "safeUrl");
24310
+ const images = media.images.flatMap((image, index) => {
24311
+ const url = safeUrl(image.url);
24312
+ return url ? [
24313
+ {
24314
+ url,
24315
+ alt: image.alt?.slice(0, 160) ?? `ProductMaker image ${index + 1}`
24316
+ }
24317
+ ] : [];
24318
+ });
24319
+ const videos = media.videos.flatMap((video) => {
24320
+ const url = safeUrl(video.url);
24321
+ return url ? [
24322
+ {
24323
+ url,
24324
+ ...video.label ? {
24325
+ label: video.label.slice(0, 120)
24326
+ } : {},
24327
+ ...video.scriptRewritten === true ? {
24328
+ scriptRewritten: true
24329
+ } : {}
24330
+ }
24331
+ ] : [];
24332
+ });
24333
+ const links = media.links.flatMap((link) => {
24334
+ const url = safeUrl(link.url);
24335
+ return url ? [
24336
+ {
24337
+ url,
24338
+ label: link.label?.slice(0, 120) ?? "Open result"
24339
+ }
24340
+ ] : [];
24341
+ });
24342
+ return {
24343
+ state: images.length || videos.length || links.length ? "ready" : "empty",
24344
+ images,
24345
+ videos,
24346
+ links
24347
+ };
24348
+ }
24349
+ __name(buildTaskResultsView, "buildTaskResultsView");
24350
+ function taskResultsToolMeta() {
24351
+ return {
24352
+ ui: {
24353
+ resourceUri: TASK_RESULTS_APP_RESOURCE_URI
24354
+ },
24355
+ "openai/outputTemplate": TASK_RESULTS_APP_RESOURCE_URI
24356
+ };
24357
+ }
24358
+ __name(taskResultsToolMeta, "taskResultsToolMeta");
24359
+ function renderTaskResultsAppHtml(proxyBaseUrl) {
24360
+ return readFileSync2(HTML_URL, "utf8").replace("__PRODUCTMAKER_ASSET_ORIGIN__", JSON.stringify(assetOrigin(proxyBaseUrl)).replaceAll("<", "\\u003c"));
24361
+ }
24362
+ __name(renderTaskResultsAppHtml, "renderTaskResultsAppHtml");
24363
+ function registerTaskResultsAppResource(server, proxyBaseUrl) {
24364
+ const origin = assetOrigin(proxyBaseUrl);
24365
+ const resourceDomains = origin ? [
24366
+ origin
24367
+ ] : [];
24368
+ const html = renderTaskResultsAppHtml(proxyBaseUrl);
24369
+ const meta = {
24370
+ ui: {
24371
+ csp: {
24372
+ resourceDomains,
24373
+ connectDomains: []
24374
+ }
24375
+ },
24376
+ "openai/widgetCSP": {
24377
+ resource_domains: resourceDomains,
24378
+ connect_domains: []
24379
+ },
24380
+ "openai/widgetDescription": "Displays the actual ProductMaker images and videos with playback controls and download links."
24381
+ };
24382
+ registerAppResource2(server, "ProductMaker task results", TASK_RESULTS_APP_RESOURCE_URI, {
24383
+ title: "Your creative",
24384
+ mimeType: RESOURCE_MIME_TYPE2,
24385
+ _meta: meta
24386
+ }, async () => ({
24387
+ contents: [
24388
+ {
24389
+ uri: TASK_RESULTS_APP_RESOURCE_URI,
24390
+ mimeType: RESOURCE_MIME_TYPE2,
24391
+ text: html,
24392
+ _meta: meta
24393
+ }
24394
+ ]
24395
+ }));
24396
+ }
24397
+ __name(registerTaskResultsAppResource, "registerTaskResultsAppResource");
24398
+
24251
24399
  // src/tools/tasks.ts
24252
- import { z as z123 } from "zod";
24400
+ import { z as z124 } from "zod";
24253
24401
 
24254
24402
  // src/resolve-image.ts
24255
24403
  import { lookup as dnsLookup } from "dns/promises";
@@ -24810,9 +24958,9 @@ async function resolveMediaRef(ref, opts) {
24810
24958
  __name(resolveMediaRef, "resolveMediaRef");
24811
24959
 
24812
24960
  // src/tools/shared.ts
24813
- import { z as z118 } from "zod";
24814
- var Lang = z118.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
24815
- var Country = z118.string().min(2).max(3);
24961
+ import { z as z119 } from "zod";
24962
+ var Lang = z119.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
24963
+ var Country = z119.string().min(2).max(3);
24816
24964
  var LandingStrategyEnum = LandingStrategySchema;
24817
24965
  var LandingImageFormatEnum = LandingImageFormatSchema;
24818
24966
  var VideoPresetEnum = VideoPreset.extract([
@@ -24916,7 +25064,7 @@ function animationStyleApplies(videoPreset, angleNarratives) {
24916
25064
  return ANIMATED_VIDEO_PRESETS.has(videoPreset ?? "") || (angleNarratives ?? []).some((n) => ANIMATED_NARRATIVE_STYLES.has(n));
24917
25065
  }
24918
25066
  __name(animationStyleApplies, "animationStyleApplies");
24919
- var VideoTierEnum = z118.enum([
25067
+ var VideoTierEnum = z119.enum([
24920
25068
  "basic"
24921
25069
  ]);
24922
25070
  function resolveVideoTier(_tier) {
@@ -24974,10 +25122,10 @@ var ImageCreativeStyleEnum = ImageCreativeStyle;
24974
25122
  var ImageCreativeArchetypeEnum = ImageCreativeArchetype;
24975
25123
  var ImageCreativeVisualTreatmentEnum = ImageCreativeVisualTreatment;
24976
25124
  var ImageCreativeAspectRatioEnum = ImageCreativeAspectRatio;
24977
- var ImageRefSchema = z118.object({
24978
- url: z118.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.'),
24979
- path: z118.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`.'),
24980
- assetId: z118.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
25125
+ var ImageRefSchema = z119.object({
25126
+ url: z119.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.'),
25127
+ path: z119.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`.'),
25128
+ assetId: z119.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
24981
25129
  }).refine((v) => [
24982
25130
  v.url,
24983
25131
  v.path,
@@ -24985,11 +25133,11 @@ var ImageRefSchema = z118.object({
24985
25133
  ].filter(Boolean).length === 1, {
24986
25134
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
24987
25135
  });
24988
- var ImagesInput = z118.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
25136
+ var ImagesInput = z119.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
24989
25137
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
24990
25138
  if (assetCount > 0 && assetCount !== images.length) {
24991
25139
  ctx.addIssue({
24992
- code: z118.ZodIssueCode.custom,
25140
+ code: z119.ZodIssueCode.custom,
24993
25141
  message: "all image entries must use assetId, or all must use URL/path sources"
24994
25142
  });
24995
25143
  }
@@ -25070,14 +25218,14 @@ async function submitCreative(api, opts) {
25070
25218
  });
25071
25219
  }
25072
25220
  __name(submitCreative, "submitCreative");
25073
- var ResearchTargetCountryEnum = z118.enum([
25221
+ var ResearchTargetCountryEnum = z119.enum([
25074
25222
  "CO",
25075
25223
  "MX",
25076
25224
  "PE",
25077
25225
  "EC",
25078
25226
  "CL"
25079
25227
  ]);
25080
- var ResearchCategoryEnum = z118.enum([
25228
+ var ResearchCategoryEnum = z119.enum([
25081
25229
  "auto",
25082
25230
  "automotive",
25083
25231
  "kitchen",
@@ -25872,7 +26020,7 @@ function approveRefusalMessage(reason) {
25872
26020
  __name(approveRefusalMessage, "approveRefusalMessage");
25873
26021
 
25874
26022
  // src/tools/task-outputs.ts
25875
- import { z as z119 } from "zod";
26023
+ import { z as z120 } from "zod";
25876
26024
 
25877
26025
  // src/asset-proxy.ts
25878
26026
  import { createHmac, timingSafeEqual } from "crypto";
@@ -25978,12 +26126,90 @@ __name(formatCredits, "formatCredits");
25978
26126
 
25979
26127
  // src/tools/task-outputs.ts
25980
26128
  var WEBAPP_BASE = "https://productmaker.app";
25981
- var CreativeVariantIdentity = z119.object({
25982
- variantTaskId: z119.string().uuid(),
25983
- sourceTaskId: z119.string().uuid(),
26129
+ function proxifyServiceVideoResult(result, proxyBaseUrl) {
26130
+ if (!proxyBaseUrl || !isProxyEnabled()) return result;
26131
+ const rewrite = /* @__PURE__ */ __name((url, filename) => buildProxyUrl({
26132
+ r2Url: url,
26133
+ filename,
26134
+ proxyBaseUrl
26135
+ }) ?? url, "rewrite");
26136
+ const mg = result.motionGraphics;
26137
+ return {
26138
+ ...result,
26139
+ ...result.finalMp4Url ? {
26140
+ finalMp4Url: rewrite(result.finalMp4Url, "video-final.mp4")
26141
+ } : {},
26142
+ ...result.concatMp4Url ? {
26143
+ concatMp4Url: rewrite(result.concatMp4Url, "video-voices.mp4")
26144
+ } : {},
26145
+ ...mg ? {
26146
+ motionGraphics: {
26147
+ ...mg,
26148
+ ...Array.isArray(mg.variantUrls) ? {
26149
+ variantUrls: mg.variantUrls.map((url, i) => rewrite(url, `video-variant-${i + 2}.mp4`))
26150
+ } : {},
26151
+ ...mg.cleanVideoUrl ? {
26152
+ cleanVideoUrl: rewrite(mg.cleanVideoUrl, "video-clean.mp4")
26153
+ } : {},
26154
+ ...Array.isArray(mg.cleanVariantUrls) ? {
26155
+ cleanVariantUrls: mg.cleanVariantUrls.map((url, i) => rewrite(url, `video-clean-variant-${i + 2}.mp4`))
26156
+ } : {},
26157
+ ...mg.previewUrl ? {
26158
+ previewUrl: rewrite(mg.previewUrl, "service-preview.png")
26159
+ } : {}
26160
+ }
26161
+ } : {}
26162
+ };
26163
+ }
26164
+ __name(proxifyServiceVideoResult, "proxifyServiceVideoResult");
26165
+ function serviceVideoResultMedia(result) {
26166
+ const mg = result.motionGraphics;
26167
+ const candidates = [
26168
+ {
26169
+ url: result.finalMp4Url,
26170
+ label: "Video final"
26171
+ },
26172
+ {
26173
+ url: result.concatMp4Url,
26174
+ label: "Video solo voces"
26175
+ },
26176
+ ...(Array.isArray(mg?.variantUrls) ? mg.variantUrls : []).map((url, i) => ({
26177
+ url,
26178
+ label: `Versi\xF3n ${i + 2}`
26179
+ })),
26180
+ {
26181
+ url: mg?.cleanVideoUrl,
26182
+ label: "Video limpio"
26183
+ },
26184
+ ...(Array.isArray(mg?.cleanVariantUrls) ? mg.cleanVariantUrls : []).map((url, i) => ({
26185
+ url,
26186
+ label: `Versi\xF3n limpia ${i + 2}`
26187
+ }))
26188
+ ];
26189
+ const seen = /* @__PURE__ */ new Set();
26190
+ const videos = candidates.flatMap(({ url, label }) => {
26191
+ if (!url || seen.has(url)) return [];
26192
+ seen.add(url);
26193
+ return [
26194
+ {
26195
+ url,
26196
+ label
26197
+ }
26198
+ ];
26199
+ });
26200
+ return {
26201
+ images: [],
26202
+ videos,
26203
+ links: videos
26204
+ };
26205
+ }
26206
+ __name(serviceVideoResultMedia, "serviceVideoResultMedia");
26207
+ var CreativeVariantIdentity = z120.object({
26208
+ variantTaskId: z120.string().uuid(),
26209
+ sourceTaskId: z120.string().uuid(),
25984
26210
  kind: TaskCreativeVariantKind,
25985
26211
  status: TaskStatusSchema,
25986
- error: z119.string().optional()
26212
+ error: z120.string().optional()
25987
26213
  });
25988
26214
  function proxifyOutputs(outputs, proxyBaseUrl) {
25989
26215
  if (!proxyBaseUrl || !isProxyEnabled()) return outputs;
@@ -26587,29 +26813,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
26587
26813
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
26588
26814
 
26589
26815
  // src/tools/media-presentation.ts
26590
- import { z as z120 } from "zod";
26591
- var HttpsPresentationUrlSchema = z120.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
26816
+ import { z as z121 } from "zod";
26817
+ var HttpsPresentationUrlSchema = z121.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
26592
26818
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
26593
26819
  const hostname = new URL(value).hostname.toLowerCase();
26594
26820
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
26595
26821
  }, "preview URL must be owned by ProductMaker");
26596
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z120.number().int().positive().max(maximum), "positiveIntAtMost");
26597
- var PresentationImageSchema = z120.object({
26598
- kind: z120.literal("image"),
26822
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z121.number().int().positive().max(maximum), "positiveIntAtMost");
26823
+ var PresentationImageSchema = z121.object({
26824
+ kind: z121.literal("image"),
26599
26825
  url: HttpsPresentationUrlSchema,
26600
- mimeType: z120.enum([
26826
+ mimeType: z121.enum([
26601
26827
  "image/jpeg",
26602
26828
  "image/png"
26603
26829
  ]),
26604
26830
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
26605
26831
  width: positiveIntAtMost(16384),
26606
26832
  height: positiveIntAtMost(16384),
26607
- alt: z120.string().trim().min(1).max(240)
26833
+ alt: z121.string().trim().min(1).max(240)
26608
26834
  }).strict();
26609
26835
  var McpMediaPresentationSchema = PresentationImageSchema;
26610
- var GalleryImageSchema = z120.object({
26836
+ var GalleryImageSchema = z121.object({
26611
26837
  url: ProductMakerPreviewUrlSchema,
26612
- alt: z120.string().trim().min(1).max(240)
26838
+ alt: z121.string().trim().min(1).max(240)
26613
26839
  });
26614
26840
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
26615
26841
  async function imageBlocks(image, transport) {
@@ -26666,12 +26892,12 @@ async function buildMcpMediaPresentationContent(rawPresentation, transport = "ht
26666
26892
  ];
26667
26893
  }
26668
26894
  __name(buildMcpMediaPresentationContent, "buildMcpMediaPresentationContent");
26669
- var OwnedImagePreviewSchema = z120.object({
26895
+ var OwnedImagePreviewSchema = z121.object({
26670
26896
  url: HttpsPresentationUrlSchema.refine((value) => {
26671
26897
  const url = new URL(value);
26672
26898
  return !url.username && !url.password && !isPrivateHost(url.hostname);
26673
26899
  }, "Preview URL must be public HTTPS without credentials"),
26674
- alt: z120.string().trim().min(1).max(240)
26900
+ alt: z121.string().trim().min(1).max(240)
26675
26901
  });
26676
26902
  async function buildMcpImagePreviewContent(rawPreview, transport = "http") {
26677
26903
  const preview2 = OwnedImagePreviewSchema.safeParse(rawPreview);
@@ -26686,6 +26912,53 @@ async function buildMcpImagePreviewContent(rawPreview, transport = "http") {
26686
26912
  return imageBlocks(preview2.data, transport);
26687
26913
  }
26688
26914
  __name(buildMcpImagePreviewContent, "buildMcpImagePreviewContent");
26915
+ async function buildMcpGeneratedImageContent(rawItems, transport = "http") {
26916
+ const blocks = await Promise.all(rawItems.slice(0, MAX_IMAGE_CREATIVE_VARIANTS).map(async (rawItem, index) => {
26917
+ const preview2 = OwnedImagePreviewSchema.safeParse(rawItem);
26918
+ if (!preview2.success) {
26919
+ return [
26920
+ {
26921
+ type: "text",
26922
+ text: `Imagen ${index + 1}: vista previa bloqueada por seguridad. No generes ni recrees una imagen sustituta.`
26923
+ }
26924
+ ];
26925
+ }
26926
+ const heading = {
26927
+ type: "text",
26928
+ text: `Imagen ${index + 1} de ProductMaker: ${preview2.data.alt}`
26929
+ };
26930
+ try {
26931
+ const [resolved] = await resolveImages([
26932
+ {
26933
+ url: preview2.data.url
26934
+ }
26935
+ ], {
26936
+ transport,
26937
+ maxBytes: MCP_GALLERY_IMAGE_MAX_BYTES
26938
+ });
26939
+ if (resolved) {
26940
+ return [
26941
+ heading,
26942
+ {
26943
+ type: "image",
26944
+ data: resolved.buffer.toString("base64"),
26945
+ mimeType: resolved.mimetype
26946
+ }
26947
+ ];
26948
+ }
26949
+ } catch {
26950
+ }
26951
+ return [
26952
+ heading,
26953
+ {
26954
+ type: "text",
26955
+ text: `Imagen ${index + 1}: no se pudo mostrar la imagen original de ProductMaker en este resultado. No generes ni recrees una imagen sustituta; usa el enlace protegido devuelto para esta imagen.`
26956
+ }
26957
+ ];
26958
+ }));
26959
+ return blocks.flat();
26960
+ }
26961
+ __name(buildMcpGeneratedImageContent, "buildMcpGeneratedImageContent");
26689
26962
  async function buildMcpImageGalleryContent(rawItems, transport = "http") {
26690
26963
  const items = rawItems.slice(0, 5).map((rawItem, index) => ({
26691
26964
  index,
@@ -26753,8 +27026,174 @@ async function buildMcpImageGalleryContent(rawItems, transport = "http") {
26753
27026
  }
26754
27027
  __name(buildMcpImageGalleryContent, "buildMcpImageGalleryContent");
26755
27028
 
27029
+ // src/analytics.ts
27030
+ import { PostHog } from "posthog-node";
27031
+ var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
27032
+ var REDACTED = "[REDACTED]";
27033
+ var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
27034
+ "token",
27035
+ "authorization",
27036
+ "apikey",
27037
+ "clientsecret",
27038
+ "subjecttoken",
27039
+ "accesstoken",
27040
+ "refreshtoken",
27041
+ "idtoken",
27042
+ "code",
27043
+ "secret",
27044
+ "password"
27045
+ ]);
27046
+ var SENSITIVE_ASSIGNMENT_PATTERN = /(\b(?:access[_-]?token|authorization|client[_-]?secret|subject[_-]?token|refresh[_-]?token|id[_-]?token|api[_-]?key|token|secret|password|code)\b\s*[:=]\s*)(?:(bearer)\s+)?(?:(['"])(.*?)\3|([^\s,;&}"']+))/gi;
27047
+ var BEARER_TOKEN_PATTERN = /\b(bearer\s+)([A-Za-z0-9._~+/=-]+)/gi;
27048
+ var client = null;
27049
+ function getPostHogClient() {
27050
+ if (client) return client;
27051
+ const apiKey = process.env.POSTHOG_API_KEY;
27052
+ if (!apiKey) return null;
27053
+ client = new PostHog(apiKey, {
27054
+ host: process.env.POSTHOG_HOST || DEFAULT_POSTHOG_HOST,
27055
+ flushAt: 20,
27056
+ flushInterval: 1e4
27057
+ });
27058
+ return client;
27059
+ }
27060
+ __name(getPostHogClient, "getPostHogClient");
27061
+ function normalizeKey(key) {
27062
+ return key.replace(/[^a-z0-9]/gi, "").toLowerCase();
27063
+ }
27064
+ __name(normalizeKey, "normalizeKey");
27065
+ function isSensitiveKey(key) {
27066
+ const normalizedKey = normalizeKey(key);
27067
+ return SENSITIVE_KEYS.has(normalizedKey) || normalizedKey.endsWith("token") || normalizedKey.endsWith("secret");
27068
+ }
27069
+ __name(isSensitiveKey, "isSensitiveKey");
27070
+ function sanitizeUrl(value) {
27071
+ try {
27072
+ const parsed = new URL(value);
27073
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
27074
+ return value;
27075
+ }
27076
+ parsed.username = "";
27077
+ parsed.password = "";
27078
+ parsed.search = "";
27079
+ parsed.hash = "";
27080
+ return parsed.toString();
27081
+ } catch {
27082
+ return value;
27083
+ }
27084
+ }
27085
+ __name(sanitizeUrl, "sanitizeUrl");
27086
+ function sanitizeString(value) {
27087
+ const redacted = value.replace(SENSITIVE_ASSIGNMENT_PATTERN, (_match, prefix, scheme, quote) => {
27088
+ const replacement = quote ? `${quote}${REDACTED}${quote}` : REDACTED;
27089
+ return `${prefix}${scheme ? `${scheme} ` : ""}${replacement}`;
27090
+ }).replace(BEARER_TOKEN_PATTERN, `$1${REDACTED}`);
27091
+ const sanitizedUrl = sanitizeUrl(redacted);
27092
+ if (sanitizedUrl !== redacted) return sanitizedUrl;
27093
+ return redacted.replace(/https?:\/\/[^\s"'<>]+/gi, sanitizeUrl);
27094
+ }
27095
+ __name(sanitizeString, "sanitizeString");
27096
+ function sanitizeValue(value) {
27097
+ if (Array.isArray(value)) {
27098
+ return value.map((entry) => sanitizeValue(entry));
27099
+ }
27100
+ if (value && typeof value === "object") {
27101
+ return sanitizeProperties(value);
27102
+ }
27103
+ if (typeof value === "string") {
27104
+ return sanitizeString(value);
27105
+ }
27106
+ return value;
27107
+ }
27108
+ __name(sanitizeValue, "sanitizeValue");
27109
+ function sanitizeProperties(value) {
27110
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
27111
+ key,
27112
+ isSensitiveKey(key) ? REDACTED : sanitizeValue(entry)
27113
+ ]));
27114
+ }
27115
+ __name(sanitizeProperties, "sanitizeProperties");
27116
+ function captureMcpAnalytics(event, subject, properties) {
27117
+ try {
27118
+ const posthog = getPostHogClient();
27119
+ if (!posthog) return;
27120
+ posthog.capture({
27121
+ distinctId: subject ?? "mcp_oauth_aggregate",
27122
+ event,
27123
+ properties: properties ? sanitizeProperties(properties) : void 0
27124
+ });
27125
+ } catch {
27126
+ }
27127
+ }
27128
+ __name(captureMcpAnalytics, "captureMcpAnalytics");
27129
+
27130
+ // src/media-delivery-analytics.ts
27131
+ var MCP_MEDIA_DELIVERY_ANALYTICS_EVENTS = {
27132
+ STARTED: "mcp_media_delivery_started",
27133
+ RESPONSE_DELIVERED: "mcp_media_response_delivered",
27134
+ FAILED: "mcp_media_delivery_failed",
27135
+ SAFE_VARIANT: "mcp_media_delivery_variant"
27136
+ };
27137
+ var RESPONSE_STATES = [
27138
+ "ready",
27139
+ "empty",
27140
+ "pending",
27141
+ "awaiting_review",
27142
+ "error"
27143
+ ];
27144
+ var isRecord4 = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isRecord");
27145
+ function deliveryProperties(result) {
27146
+ const view = result._meta?.taskResults;
27147
+ const data = isRecord4(view) ? view : {};
27148
+ const responseState = RESPONSE_STATES.find((state) => state === data.state) ?? "unknown";
27149
+ const nativeImageCount = result.content.filter((block) => block.type === "image").length;
27150
+ const viewerImageCount = Array.isArray(data.images) ? data.images.length : 0;
27151
+ const viewerVideoCount = Array.isArray(data.videos) ? data.videos.length : 0;
27152
+ const imageFallbackCount = result.content.filter((block) => block.type === "text" && /^Imagen \d+: (?:no se pudo mostrar|vista previa bloqueada por seguridad)/.test(block.text)).length;
27153
+ const hasImages = nativeImageCount > 0 || viewerImageCount > 0 || imageFallbackCount > 0;
27154
+ return {
27155
+ measurement: "response_delivery",
27156
+ responseState,
27157
+ mediaKind: hasImages ? viewerVideoCount ? "mixed" : "image" : viewerVideoCount ? "video" : "none",
27158
+ nativeImageCount,
27159
+ viewerImageCount,
27160
+ viewerVideoCount,
27161
+ imageFallbackCount
27162
+ };
27163
+ }
27164
+ __name(deliveryProperties, "deliveryProperties");
27165
+ async function observeMcpMediaDelivery(fingerprint, work) {
27166
+ const subject = /^[a-f0-9]{32}$/.test(fingerprint) ? `mcp_credential_${fingerprint}` : "mcp_media_aggregate";
27167
+ const events = MCP_MEDIA_DELIVERY_ANALYTICS_EVENTS;
27168
+ captureMcpAnalytics(events.STARTED, subject, {
27169
+ measurement: "response_delivery"
27170
+ });
27171
+ let result;
27172
+ try {
27173
+ result = await work();
27174
+ } catch (error) {
27175
+ captureMcpAnalytics(events.FAILED, subject, {
27176
+ measurement: "response_delivery",
27177
+ reason: "exception"
27178
+ });
27179
+ throw error;
27180
+ }
27181
+ const properties = deliveryProperties(result);
27182
+ captureMcpAnalytics(events.SAFE_VARIANT, subject, properties);
27183
+ if (result.isError || properties.responseState === "error") {
27184
+ captureMcpAnalytics(events.FAILED, subject, {
27185
+ ...properties,
27186
+ reason: result.isError ? "tool_error" : "delivery_error"
27187
+ });
27188
+ } else {
27189
+ captureMcpAnalytics(events.RESPONSE_DELIVERED, subject, properties);
27190
+ }
27191
+ return result;
27192
+ }
27193
+ __name(observeMcpMediaDelivery, "observeMcpMediaDelivery");
27194
+
26756
27195
  // src/tools/animated-video.ts
26757
- import { z as z121 } from "zod";
27196
+ import { z as z122 } from "zod";
26758
27197
 
26759
27198
  // src/tools/paid-confirmation.ts
26760
27199
  function describeMarketStudyChoice(enabled) {
@@ -26867,17 +27306,17 @@ function sortCanonical(items) {
26867
27306
  });
26868
27307
  }
26869
27308
  __name(sortCanonical, "sortCanonical");
26870
- function isRecord4(value) {
27309
+ function isRecord5(value) {
26871
27310
  return typeof value === "object" && value !== null && !Array.isArray(value);
26872
27311
  }
26873
- __name(isRecord4, "isRecord");
27312
+ __name(isRecord5, "isRecord");
26874
27313
  function collectLanguageCodes(value, out) {
26875
27314
  if (Array.isArray(value)) {
26876
27315
  const items = value;
26877
27316
  for (const item of items) collectLanguageCodes(item, out);
26878
27317
  return out;
26879
27318
  }
26880
- if (!isRecord4(value)) return out;
27319
+ if (!isRecord5(value)) return out;
26881
27320
  for (const [key, entry] of Object.entries(value)) {
26882
27321
  if (LANGUAGE_FIELDS.has(key) && typeof entry === "string") {
26883
27322
  const base = entry.trim().split(/[-_]/)[0]?.toLowerCase();
@@ -26923,7 +27362,7 @@ function normalizeForKey(value, languages) {
26923
27362
  const items = value;
26924
27363
  return items.map((item) => normalizeForKey(item, languages));
26925
27364
  }
26926
- if (!isRecord4(value)) return value;
27365
+ if (!isRecord5(value)) return value;
26927
27366
  const out = {};
26928
27367
  for (const [key, entry] of Object.entries(value)) {
26929
27368
  if (PARAPHRASE_PRONE_FIELDS.has(key)) {
@@ -27003,30 +27442,30 @@ function hookVariantsLabel(count) {
27003
27442
  return count === 1 ? "1 versi\xF3n del gancho" : `${count} versiones del gancho`;
27004
27443
  }
27005
27444
  __name(hookVariantsLabel, "hookVariantsLabel");
27006
- var DurationInput = z121.union(MOTION_GRAPHICS_DURATIONS.map((d) => z121.literal(d)));
27007
- var CreateAnimatedVideoInput = z121.object({
27008
- action: z121.enum([
27445
+ var DurationInput = z122.union(MOTION_GRAPHICS_DURATIONS.map((d) => z122.literal(d)));
27446
+ var CreateAnimatedVideoInput = z122.object({
27447
+ action: z122.enum([
27009
27448
  "prepare",
27010
27449
  "status",
27011
27450
  "cancel",
27012
27451
  "generate"
27013
27452
  ]).default("prepare").describe("prepare inicia una captura gratuita; status consulta websiteCaptureId; cancel la cancela; generate requiere captura ready y confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrar vista previa y precio."),
27014
- brandId: z121.string().uuid().optional().describe("ID de un servicio propio y listo (de create_brand). Obligatorio al preparar y crear videos nuevos. Conserva el mismo brandId en reintentos; si recuperas una generaci\xF3n hist\xF3rica aceptada sin este campo, om\xEDtelo como en la petici\xF3n original. status/cancel no lo necesitan."),
27015
- websiteCaptureId: z121.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
27016
- generationRequestId: z121.string().uuid().optional().describe("Identidad opcional de una generaci\xF3n confirmada. Repite el mismo UUID al recuperar una respuesta perdida; usa otro \xFAnicamente cuando el usuario pida y confirme otro video, nunca por un error de transporte."),
27017
- confirmed: z121.boolean().optional().describe("Solo true despu\xE9s de que el usuario confirme esta captura, formato, duraci\xF3n, idioma y precio. Obligatorio para generate; preparar no genera ni cobra."),
27453
+ brandId: z122.string().uuid().optional().describe("ID de un servicio propio y listo (de create_brand). Obligatorio al preparar y crear videos nuevos. Conserva el mismo brandId en reintentos; si recuperas una generaci\xF3n hist\xF3rica aceptada sin este campo, om\xEDtelo como en la petici\xF3n original. status/cancel no lo necesitan."),
27454
+ websiteCaptureId: z122.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
27455
+ generationRequestId: z122.string().uuid().optional().describe("Identidad opcional de una generaci\xF3n confirmada. Repite el mismo UUID al recuperar una respuesta perdida; usa otro \xFAnicamente cuando el usuario pida y confirme otro video, nunca por un error de transporte."),
27456
+ confirmed: z122.boolean().optional().describe("Solo true despu\xE9s de que el usuario confirme esta captura, formato, duraci\xF3n, idioma y precio. Obligatorio para generate; preparar no genera ni cobra."),
27018
27457
  // Plain text, not `.url()`: users type «cal.com», and the web accepts it.
27019
27458
  // normalizeWebAddress (shared with the web) adds https:// and refuses
27020
27459
  // anything that is not a public http(s) address.
27021
- landingUrl: z121.string().trim().min(1).optional().describe("Enlace p\xFAblico de la p\xE1gina del servicio, como lo dio el usuario (\xABcal.com\xBB o \xABhttps://cal.com\xBB). El video sale de lo que muestra esa p\xE1gina: su marca, colores y mensajes."),
27460
+ landingUrl: z122.string().trim().min(1).optional().describe("Enlace p\xFAblico de la p\xE1gina del servicio, como lo dio el usuario (\xABcal.com\xBB o \xABhttps://cal.com\xBB). El video sale de lo que muestra esa p\xE1gina: su marca, colores y mensajes."),
27022
27461
  format: MotionGraphicsFormatSchema.optional().describe('Formato: "vertical" (9:16, Reels/TikTok), "square" (1:1, feed) u "horizontal" (16:9, YouTube/web). Si el usuario no lo dijo, PREG\xDANTALE.'),
27023
27462
  durationSec: DurationInput.optional().describe(`Duraci\xF3n en segundos: ${MOTION_GRAPHICS_DURATIONS.join(", ")}. Fija el precio (ver la descripci\xF3n de la herramienta). Si el usuario no la dijo, PREG\xDANTALE.`),
27024
27463
  language: MotionGraphicsLanguageSchema.optional().describe('Idioma de los textos del video: "es", "en" o "pt".'),
27025
27464
  videoQuality: MotionGraphicsVideoQualitySchema.default(DEFAULT_MOTION_GRAPHICS_VIDEO_QUALITY).describe('Calidad IA: "economy" (econ\xF3mica) o "pro" (alta, por defecto). Afecta el precio de los clips IA.'),
27026
27465
  videoResolution: MotionGraphicsVideoResolutionSchema.default(DEFAULT_MOTION_GRAPHICS_VIDEO_RESOLUTION).describe('Resoluci\xF3n: "480p" (por defecto), "720p" o "1080p". 1080p solo est\xE1 disponible con videoQuality="pro".'),
27027
- notes: z121.string().trim().max(MOTION_GRAPHICS_NOTES_MAX_CHARS).optional().describe("Opcional. Idea creativa, escenarios, acciones, di\xE1logo, voz o m\xFAsica en lenguaje natural. El director puede hacer solo motion graphics, escenas reales o escenas imposibles seg\xFAn la idea; las frases gu\xEDan el guion sin garantizar reproducci\xF3n exacta."),
27466
+ notes: z122.string().trim().max(MOTION_GRAPHICS_NOTES_MAX_CHARS).optional().describe("Opcional. Idea creativa, escenarios, acciones, di\xE1logo, voz o m\xFAsica en lenguaje natural. El director puede hacer solo motion graphics, escenas reales o escenas imposibles seg\xFAn la idea; las frases gu\xEDan el guion sin garantizar reproducci\xF3n exacta."),
27028
27467
  hookVariants: MotionGraphicsHookVariantsSchema.optional().describe(`Opcional. Cantidad de videos independientes, de 1 a ${MOTION_GRAPHICS_HOOK_VARIANTS_MAX} (por defecto 1). Cada uno tiene su propio \xE1ngulo, guion y estilo visual, respetando notes, y reserva el precio completo de un video (ver la descripci\xF3n); \xFAsalo solo si el usuario lo pide.`),
27029
- music: z121.boolean().optional().describe("Opcional. M\xFAsica y efectos dirigidos seg\xFAn el negocio y el video (por defecto true), con una copia adicional solo con voces. false entrega solo voces, sin m\xFAsica ni efectos a\xF1adidos ni el cargo de m\xFAsica. \xDAsalo solo si el usuario lo pide.")
27468
+ music: z122.boolean().optional().describe("Opcional. M\xFAsica y efectos dirigidos seg\xFAn el negocio y el video (por defecto true), con una copia adicional solo con voces. false entrega solo voces, sin m\xFAsica ni efectos a\xF1adidos ni el cargo de m\xFAsica. \xDAsalo solo si el usuario lo pide.")
27030
27469
  }).strict();
27031
27470
  function captureNextAction(capture) {
27032
27471
  if (capture.status === "ready") return "Muestra la vista previa al usuario y confirma formato, duraci\xF3n, idioma, calidad IA, resoluci\xF3n y precio. Solo despu\xE9s llama create_animated_video con action=generate, este websiteCaptureId y confirmed=true.";
@@ -27079,33 +27518,33 @@ var FORMAT_LABELS = {
27079
27518
  square: "cuadrado 1:1",
27080
27519
  horizontal: "horizontal 16:9"
27081
27520
  };
27082
- var AnimatedVideoResultSchema = z121.object({
27083
- status: z121.enum([
27521
+ var AnimatedVideoResultSchema = z122.object({
27522
+ status: z122.enum([
27084
27523
  "pending",
27085
27524
  "done",
27086
27525
  "error"
27087
27526
  ]),
27088
- serviceMode: z121.literal("motion_graphics"),
27089
- finalMp4Url: z121.string().optional(),
27090
- adCopy: z121.string().optional(),
27091
- adCopies: z121.array(z121.string()).optional(),
27092
- error: z121.string().optional(),
27093
- motionGraphics: z121.object({
27527
+ serviceMode: z122.literal("motion_graphics"),
27528
+ finalMp4Url: z122.string().optional(),
27529
+ adCopy: z122.string().optional(),
27530
+ adCopies: z122.array(z122.string()).optional(),
27531
+ error: z122.string().optional(),
27532
+ motionGraphics: z122.object({
27094
27533
  stage: MotionGraphicsStageSchema,
27095
27534
  format: MotionGraphicsFormatSchema,
27096
- durationSec: z121.number(),
27097
- width: z121.number().optional(),
27098
- height: z121.number().optional(),
27535
+ durationSec: z122.number(),
27536
+ width: z122.number().optional(),
27537
+ height: z122.number().optional(),
27099
27538
  language: MotionGraphicsLanguageSchema.optional(),
27100
27539
  videoQuality: MotionGraphicsVideoQualitySchema.optional().catch(void 0),
27101
27540
  videoResolution: MotionGraphicsVideoResolutionSchema.optional().catch(void 0),
27102
- creativeBatch: z121.object({
27541
+ creativeBatch: z122.object({
27103
27542
  index: MotionGraphicsHookVariantsSchema,
27104
27543
  count: MotionGraphicsHookVariantsSchema,
27105
- tasks: z121.array(z121.object({
27106
- taskId: z121.string().uuid(),
27544
+ tasks: z122.array(z122.object({
27545
+ taskId: z122.string().uuid(),
27107
27546
  index: MotionGraphicsHookVariantsSchema,
27108
- status: z121.enum([
27547
+ status: z122.enum([
27109
27548
  "queued",
27110
27549
  "processing",
27111
27550
  "done",
@@ -27113,29 +27552,29 @@ var AnimatedVideoResultSchema = z121.object({
27113
27552
  ])
27114
27553
  })).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX)
27115
27554
  }).optional().catch(void 0),
27116
- queuedAt: z121.string().optional(),
27117
- jobsAhead: z121.number().int().nonnegative().optional(),
27118
- stageStartedAt: z121.string().optional(),
27119
- renderProgress: z121.number().optional(),
27555
+ queuedAt: z122.string().optional(),
27556
+ jobsAhead: z122.number().int().nonnegative().optional(),
27557
+ stageStartedAt: z122.string().optional(),
27558
+ renderProgress: z122.number().optional(),
27120
27559
  // AI clip fields (absent on a video paid before clips, or from an API
27121
27560
  // that predates them). Lenient: an unreadable value is dropped
27122
27561
  // instead of hiding the status.
27123
- clipCount: z121.number().int().nonnegative().optional().catch(void 0),
27124
- clipsUsed: z121.number().int().nonnegative().optional().catch(void 0),
27125
- clipPriceCents: z121.number().finite().nonnegative().optional().catch(void 0),
27126
- clipsRefunded: z121.number().int().nonnegative().optional().catch(void 0),
27562
+ clipCount: z122.number().int().nonnegative().optional().catch(void 0),
27563
+ clipsUsed: z122.number().int().nonnegative().optional().catch(void 0),
27564
+ clipPriceCents: z122.number().finite().nonnegative().optional().catch(void 0),
27565
+ clipsRefunded: z122.number().int().nonnegative().optional().catch(void 0),
27127
27566
  // Hook versions (absent from an API or a video before them): the
27128
27567
  // count ordered and, once done, the signed URLs of the EXTRA versions
27129
27568
  // (hook 2, hook 3); `finalMp4Url` is hook 1.
27130
- hookVariants: z121.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
27131
- cleanVideoUrl: z121.string().url().optional().catch(void 0),
27132
- cleanVariantUrls: z121.array(z121.string().url()).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
27133
- variantUrls: z121.array(z121.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
27569
+ hookVariants: z122.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
27570
+ cleanVideoUrl: z122.string().url().optional().catch(void 0),
27571
+ cleanVariantUrls: z122.array(z122.string().url()).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
27572
+ variantUrls: z122.array(z122.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
27134
27573
  // Extra hook versions given back, as the task recorded it once the
27135
27574
  // refunds landed (absent until then, and from an API before it).
27136
- variantsRefunded: z121.number().int().nonnegative().optional().catch(void 0),
27137
- activity: z121.array(MotionGraphicsActivitySchema).optional().catch(void 0),
27138
- previewUrl: z121.string().optional()
27575
+ variantsRefunded: z122.number().int().nonnegative().optional().catch(void 0),
27576
+ activity: z122.array(MotionGraphicsActivitySchema).optional().catch(void 0),
27577
+ previewUrl: z122.string().optional()
27139
27578
  }).passthrough()
27140
27579
  }).passthrough();
27141
27580
  function parseAnimatedVideoResult(value) {
@@ -27414,7 +27853,7 @@ function registerAnimatedVideoTools(server, api) {
27414
27853
  nowMs: 0
27415
27854
  })
27416
27855
  });
27417
- const parsedTaskIds = z121.array(z121.string().uuid()).min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).safeParse(created.taskIds);
27856
+ const parsedTaskIds = z122.array(z122.string().uuid()).min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).safeParse(created.taskIds);
27418
27857
  const taskIds = parsedTaskIds.success && parsedTaskIds.data[0] === created.taskId ? parsedTaskIds.data : void 0;
27419
27858
  const receipt = {
27420
27859
  taskId: created.taskId,
@@ -27456,10 +27895,10 @@ function registerAnimatedVideoTools(server, api) {
27456
27895
  __name(registerAnimatedVideoTools, "registerAnimatedVideoTools");
27457
27896
 
27458
27897
  // src/tools/winning-product-image.ts
27459
- import { z as z122 } from "zod";
27460
- var WinnerReferenceInput = z122.object({
27461
- runId: z122.string().uuid(),
27462
- candidateSourceId: z122.string().trim().min(1).max(160)
27898
+ import { z as z123 } from "zod";
27899
+ var WinnerReferenceInput = z123.object({
27900
+ runId: z123.string().uuid(),
27901
+ candidateSourceId: z123.string().trim().min(1).max(160)
27463
27902
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
27464
27903
  async function resolveWinnerImages(api, winnerReference, images) {
27465
27904
  if (!winnerReference) return images;
@@ -27496,62 +27935,62 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
27496
27935
  var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
27497
27936
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
27498
27937
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
27499
- var CreateProductTaskInput = z123.object({
27938
+ var CreateProductTaskInput = z124.object({
27500
27939
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
27501
27940
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
27502
- projectId: z123.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
27503
- productUrl: z123.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."),
27941
+ projectId: z124.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
27942
+ productUrl: z124.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."),
27504
27943
  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.'),
27505
27944
  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.'),
27506
- price: z123.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.'),
27507
- compareAtPrice: z123.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".'),
27508
- offer: z123.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.'),
27509
- paymentMethods: z123.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.'),
27510
- productContext: z123.string().max(PRODUCT_CONTEXT_MAX_CHARS).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."),
27511
- productLabel: z123.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.'),
27945
+ price: z124.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.'),
27946
+ compareAtPrice: z124.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".'),
27947
+ offer: z124.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.'),
27948
+ paymentMethods: z124.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.'),
27949
+ productContext: z124.string().max(PRODUCT_CONTEXT_MAX_CHARS).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."),
27950
+ productLabel: z124.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.'),
27512
27951
  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); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
27513
27952
  animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
27514
- durationSeconds: z123.union([
27515
- z123.literal(15),
27516
- z123.literal(30)
27953
+ durationSeconds: z124.union([
27954
+ z124.literal(15),
27955
+ z124.literal(30)
27517
27956
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
27518
- pauseForAngleReview: z123.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
27519
- aiDecidesAll: z123.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
27957
+ pauseForAngleReview: z124.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
27958
+ aiDecidesAll: z124.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
27520
27959
  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.'),
27521
27960
  videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena. Default: single_take.'),
27522
27961
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
27523
27962
  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).'),
27524
- videoAngleCount: z123.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
27963
+ videoAngleCount: z124.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
27525
27964
  angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
27526
- outputs: z123.array(z123.enum([
27965
+ outputs: z124.array(z124.enum([
27527
27966
  "landing",
27528
27967
  "video",
27529
27968
  "image"
27530
27969
  ])).min(1).max(3).optional().describe(`Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). ${createProductTaskSingleOutputDescription}`),
27531
- includeInitialLandingGif: z123.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
27532
- competitorScanEnabled: z123.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost con kind=product_task, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
27970
+ includeInitialLandingGif: z124.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
27971
+ competitorScanEnabled: z124.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost con kind=product_task, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
27533
27972
  generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
27534
- replicateWinnerWhenFound: z123.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
27535
- brandId: z123.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."),
27536
- actorId: z123.string().trim().min(1).max(120).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."),
27973
+ replicateWinnerWhenFound: z124.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
27974
+ brandId: z124.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."),
27975
+ actorId: z124.string().trim().min(1).max(120).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."),
27537
27976
  creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en todos los creativos de la task: el presentador del video, las personas fotografiadas en la landing y la persona del anuncio. NO es la voz. M\xE1ndalo en cuanto el usuario lo diga en cualquier momento de la conversaci\xF3n y con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "esto es para hombres"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario recibe lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. "mixed" solo cuando pida expl\xEDcitamente ambos. Si adem\xE1s mandas actorId, el personaje guardado manda sobre este campo.'),
27538
- creativeDirection: z123.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.'),
27539
- headline: z123.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."),
27540
- subheadline: z123.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."),
27977
+ creativeDirection: z124.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.'),
27978
+ headline: z124.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."),
27979
+ subheadline: z124.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."),
27541
27980
  landingStrategy: LandingStrategyEnum.optional().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".'),
27542
27981
  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".')
27543
27982
  }).strict();
27544
- var CreateServiceVideoInput = z123.object({
27545
- landingUrl: z123.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
27546
- additionalContext: z123.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
27983
+ var CreateServiceVideoInput = z124.object({
27984
+ landingUrl: z124.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
27985
+ additionalContext: z124.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
27547
27986
  language: Lang.describe("Idioma del video: es, en o pt."),
27548
- voiceId: z123.string().trim().min(1).pipe(VoiceId).optional().describe('Opcional. Voz para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador. Las voces del banco compartido fueron retiradas.'),
27549
- brandId: z123.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
27550
- reviewMode: z123.enum([
27987
+ voiceId: z124.string().trim().min(1).pipe(VoiceId).optional().describe('Opcional. Voz para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador. Las voces del banco compartido fueron retiradas.'),
27988
+ brandId: z124.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
27989
+ reviewMode: z124.enum([
27551
27990
  "automatic",
27552
27991
  "guided"
27553
27992
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
27554
- videoPreset: z123.enum([
27993
+ videoPreset: z124.enum([
27555
27994
  "auto",
27556
27995
  "ugc_dynamic",
27557
27996
  "ugc_how_to",
@@ -27561,128 +28000,128 @@ var CreateServiceVideoInput = z123.object({
27561
28000
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
27562
28001
  videoResolution: VideoResolutionEnum.default("480p").describe('Opcional. Resoluci\xF3n: "480p" o "720p". 720p cuesta m\xE1s por segundo y solo est\xE1 disponible en "economy" y "pro" (Medio = 768P). Default: 480p.')
27563
28002
  }).strict();
27564
- var GetTaskStatusInput = z123.object({
27565
- taskId: z123.string().min(1),
27566
- waitSeconds: z123.number().int().min(0).max(120).optional()
28003
+ var GetTaskStatusInput = z124.object({
28004
+ taskId: z124.string().min(1),
28005
+ waitSeconds: z124.number().int().min(0).max(120).optional()
27567
28006
  });
27568
- var ListTasksInput = z123.object({
27569
- limit: z123.number().int().min(1).max(50).optional(),
27570
- offset: z123.number().int().min(0).optional(),
27571
- search: z123.string().optional()
28007
+ var ListTasksInput = z124.object({
28008
+ limit: z124.number().int().min(1).max(50).optional(),
28009
+ offset: z124.number().int().min(0).optional(),
28010
+ search: z124.string().optional()
27572
28011
  });
27573
28012
  var MCP_REVIEW_LIST_FIELD_MAX = IMAGE_WIZARD_LIST_FIELD_MAX;
27574
28013
  var MCP_REVIEW_FEATURE_ITEM_MAX = IMAGE_FEATURE_ITEM_MAX;
27575
- var EditTaskDraftInput = z123.object({
27576
- taskId: z123.string().min(1),
27577
- angleIndex: z123.number().int().min(0),
27578
- angle: z123.object({
27579
- angle: z123.string().min(1).max(480),
27580
- buyerPersona: z123.string().min(1).max(360),
27581
- actor: z123.string().min(1).max(360).optional(),
27582
- actorId: z123.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."),
27583
- gender: z123.enum([
28014
+ var EditTaskDraftInput = z124.object({
28015
+ taskId: z124.string().min(1),
28016
+ angleIndex: z124.number().int().min(0),
28017
+ angle: z124.object({
28018
+ angle: z124.string().min(1).max(480),
28019
+ buyerPersona: z124.string().min(1).max(360),
28020
+ actor: z124.string().min(1).max(360).optional(),
28021
+ actorId: z124.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."),
28022
+ gender: z124.enum([
27584
28023
  "female",
27585
28024
  "male"
27586
28025
  ]).optional(),
27587
- scriptNotes: z123.string().max(2e3).optional()
28026
+ scriptNotes: z124.string().max(2e3).optional()
27588
28027
  })
27589
28028
  });
27590
- var PendingActionPayload = z123.discriminatedUnion("kind", [
27591
- z123.object({
27592
- kind: z123.literal("product_reference_set_approval"),
28029
+ var PendingActionPayload = z124.discriminatedUnion("kind", [
28030
+ z124.object({
28031
+ kind: z124.literal("product_reference_set_approval"),
27593
28032
  scope: ProductReferenceScopeEnum.optional(),
27594
- scopeKey: z123.string().min(1).max(120).optional(),
27595
- scopeSnapshotId: z123.string().uuid().optional(),
27596
- expectedScopeHash: z123.string().min(1).max(128).optional(),
28033
+ scopeKey: z124.string().min(1).max(120).optional(),
28034
+ scopeSnapshotId: z124.string().uuid().optional(),
28035
+ expectedScopeHash: z124.string().min(1).max(128).optional(),
27597
28036
  decision: ProductReferenceResolutionDecisionEnum,
27598
28037
  reason: ProductReferenceRejectionReasonEnum.optional(),
27599
- affectedRefKeys: z123.array(z123.string().min(1).max(200)).min(1).optional(),
27600
- affectedPhotoNumbers: z123.array(z123.number().int().positive()).min(1).optional(),
27601
- recoveryAction: z123.enum([
28038
+ affectedRefKeys: z124.array(z124.string().min(1).max(200)).min(1).optional(),
28039
+ affectedPhotoNumbers: z124.array(z124.number().int().positive()).min(1).optional(),
28040
+ recoveryAction: z124.enum([
27602
28041
  "remove",
27603
28042
  "replace",
27604
28043
  "upload",
27605
28044
  "return_to_selection"
27606
28045
  ]).optional()
27607
28046
  }),
27608
- z123.object({
27609
- kind: z123.literal("product_reference_confirmation"),
27610
- selectedPhotoNumbers: z123.array(z123.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
28047
+ z124.object({
28048
+ kind: z124.literal("product_reference_confirmation"),
28049
+ selectedPhotoNumbers: z124.array(z124.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
27611
28050
  userChoice: ProductReferenceUserChoiceEnum.optional(),
27612
- confirmedProductNames: z123.array(z123.string().min(1).max(120)).min(2).max(8).optional(),
28051
+ confirmedProductNames: z124.array(z124.string().min(1).max(120)).min(2).max(8).optional(),
27613
28052
  videoStructure: VideoStructureEnum.optional().describe("Opcional. Formato para reanudar el video: single_take (Un solo clip, generado completo; puede incluir cambios de plano) o multi_scene (Multiescena). El backend vuelve a validar que sea compatible con el agrupamiento confirmado."),
27614
28053
  videoQuality: VideoQualityEnum.optional().describe("Opcional. Calidad para reanudar el video: economy (Econ\xF3mico), medium (Medio) o pro. El proveedor se elige internamente y el backend vuelve a cotizar la ruta."),
27615
- useMultiSceneShowcase: z123.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
28054
+ useMultiSceneShowcase: z124.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
27616
28055
  }),
27617
- z123.object({
27618
- kind: z123.literal("angle_review_approval"),
28056
+ z124.object({
28057
+ kind: z124.literal("angle_review_approval"),
27619
28058
  // All edits are optional — empty action body just approves the
27620
28059
  // backend-generated draft as-is. Field shapes mirror the angle-review
27621
28060
  // request contracts in @packages/types/wizard.ts; the handler routes to
27622
28061
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
27623
- customAngle: z123.string().min(1).max(480).optional(),
28062
+ customAngle: z124.string().min(1).max(480).optional(),
27624
28063
  // Keep the shared MCP action within the strictest downstream contract:
27625
28064
  // autopilot/image resume endpoints cap these fields at 1500 characters.
27626
- painPoints: z123.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
27627
- benefits: z123.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
28065
+ painPoints: z124.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
28066
+ benefits: z124.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
27628
28067
  // Same policy as the two fields above: the strictest downstream contract
27629
28068
  // wins. The image endpoint caps each feature at 240 while landing/video
27630
28069
  // accept 300, and this single action routes to whichever the task is — so
27631
28070
  // accepting 300 here turns a 250-character feature on an image task into
27632
28071
  // an opaque HTTP 400 after the model already believed it had been saved.
27633
- features: z123.array(z123.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
27634
- buyerPersona: z123.string().min(1).max(360).optional(),
28072
+ features: z124.array(z124.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
28073
+ buyerPersona: z124.string().min(1).max(360).optional(),
27635
28074
  narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
27636
- actor: z123.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
27637
- actorId: z123.string().max(120).nullable().optional(),
27638
- creativeDirection: z123.string().max(2e3).optional(),
27639
- selectedAngleNumbers: z123.array(z123.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
27640
- angleEdits: z123.array(z123.object({
27641
- angleNumber: z123.number().int().positive(),
27642
- narrativeSelection: z123.enum([
28075
+ actor: z124.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
28076
+ actorId: z124.string().max(120).nullable().optional(),
28077
+ creativeDirection: z124.string().max(2e3).optional(),
28078
+ selectedAngleNumbers: z124.array(z124.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
28079
+ angleEdits: z124.array(z124.object({
28080
+ angleNumber: z124.number().int().positive(),
28081
+ narrativeSelection: z124.enum([
27643
28082
  "market",
27644
28083
  "guided"
27645
28084
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
27646
- angle: z123.string().min(1).max(480).optional(),
27647
- buyerPersona: z123.string().min(1).max(360).optional(),
28085
+ angle: z124.string().min(1).max(480).optional(),
28086
+ buyerPersona: z124.string().min(1).max(360).optional(),
27648
28087
  narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
27649
- actor: z123.string().min(1).max(360).optional(),
27650
- actorId: z123.string().max(120).nullable().optional(),
27651
- creativeDirection: z123.string().max(2e3).optional()
28088
+ actor: z124.string().min(1).max(360).optional(),
28089
+ actorId: z124.string().max(120).nullable().optional(),
28090
+ creativeDirection: z124.string().max(2e3).optional()
27652
28091
  }).strict()).max(3).optional().describe("Ediciones independientes por n\xFAmero visible de \xE1ngulo. S\xF3lo se aceptan para \xE1ngulos incluidos en selectedAngleNumbers (o en la selecci\xF3n por defecto)."),
27653
- gapDurationSeconds: z123.union([
27654
- z123.literal(15),
27655
- z123.literal(30)
28092
+ gapDurationSeconds: z124.union([
28093
+ z124.literal(15),
28094
+ z124.literal(30)
27656
28095
  ]).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.")
27657
28096
  }),
27658
- z123.object({
27659
- kind: z123.literal("service_angle_approval"),
27660
- angleId: z123.string().uuid().optional(),
27661
- angleNumber: z123.number().int().positive().optional(),
27662
- content: z123.string().min(1).max(480).optional(),
27663
- creativeDirection: z123.string().min(1).max(1500).optional(),
27664
- actor: z123.string().min(1).max(360).optional()
28097
+ z124.object({
28098
+ kind: z124.literal("service_angle_approval"),
28099
+ angleId: z124.string().uuid().optional(),
28100
+ angleNumber: z124.number().int().positive().optional(),
28101
+ content: z124.string().min(1).max(480).optional(),
28102
+ creativeDirection: z124.string().min(1).max(1500).optional(),
28103
+ actor: z124.string().min(1).max(360).optional()
27665
28104
  }),
27666
- z123.object({
27667
- kind: z123.literal("service_script_approval"),
27668
- voiceovers: z123.record(z123.string(), z123.string().min(1).max(600)).optional(),
27669
- visualDirections: z123.record(z123.string(), z123.string().min(1).max(1200)).optional(),
27670
- voiceoversByScene: z123.record(z123.string(), z123.string().min(1).max(600)).optional(),
27671
- visualDirectionsByScene: z123.record(z123.string(), z123.string().min(1).max(1200)).optional()
28105
+ z124.object({
28106
+ kind: z124.literal("service_script_approval"),
28107
+ voiceovers: z124.record(z124.string(), z124.string().min(1).max(600)).optional(),
28108
+ visualDirections: z124.record(z124.string(), z124.string().min(1).max(1200)).optional(),
28109
+ voiceoversByScene: z124.record(z124.string(), z124.string().min(1).max(600)).optional(),
28110
+ visualDirectionsByScene: z124.record(z124.string(), z124.string().min(1).max(1200)).optional()
27672
28111
  })
27673
28112
  ]);
27674
- var ResolvePendingActionInput = z123.object({
27675
- taskId: z123.string().min(1),
28113
+ var ResolvePendingActionInput = z124.object({
28114
+ taskId: z124.string().min(1),
27676
28115
  action: PendingActionPayload
27677
28116
  }).strict();
27678
28117
  function resolveVariantConfirmVideoTier(action) {
27679
28118
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
27680
28119
  }
27681
28120
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
27682
- var StatusForResolveSchema = z123.object({
28121
+ var StatusForResolveSchema = z124.object({
27683
28122
  // Metadata used to select the backend resume contract. Older API responses
27684
28123
  // may omit these fields, so the resolver keeps the generic fallback.
27685
- kind: z123.enum([
28124
+ kind: z124.enum([
27686
28125
  "autopilot",
27687
28126
  "video",
27688
28127
  "image",
@@ -27690,18 +28129,18 @@ var StatusForResolveSchema = z123.object({
27690
28129
  "mix",
27691
28130
  "service"
27692
28131
  ]).optional(),
27693
- selectedOutputs: z123.array(z123.enum([
28132
+ selectedOutputs: z124.array(z124.enum([
27694
28133
  "landing",
27695
28134
  "video",
27696
28135
  "image"
27697
28136
  ])).optional(),
27698
- videoAngleCount: z123.number().int().min(1).max(3).optional(),
27699
- ugcFormat: z123.enum([
28137
+ videoAngleCount: z124.number().int().min(1).max(3).optional(),
28138
+ ugcFormat: z124.enum([
27700
28139
  "single_8s",
27701
28140
  "single_15s",
27702
28141
  "double_30s"
27703
28142
  ]).optional(),
27704
- videoStyle: z123.enum([
28143
+ videoStyle: z124.enum([
27705
28144
  "ugc",
27706
28145
  "cartoon_3d",
27707
28146
  "product_only",
@@ -27711,13 +28150,13 @@ var StatusForResolveSchema = z123.object({
27711
28150
  videoQuality: VideoQualityEnum.optional(),
27712
28151
  videoRouteId: VideoRouteIdEnum.optional(),
27713
28152
  videoModel: TaskVideoModelEnum.optional(),
27714
- videoTier: z123.enum([
28153
+ videoTier: z124.enum([
27715
28154
  "legacy",
27716
28155
  "standard",
27717
28156
  "pro",
27718
28157
  "single_call"
27719
28158
  ]).optional(),
27720
- videoResolution: z123.enum([
28159
+ videoResolution: z124.enum([
27721
28160
  "480p",
27722
28161
  "720p"
27723
28162
  ]).optional(),
@@ -27725,60 +28164,60 @@ var StatusForResolveSchema = z123.object({
27725
28164
  // A task created before a narrative was blocked/hidden must still parse,
27726
28165
  // or resolve_pending_action could never approve it.
27727
28166
  narrativeStyle: NarrativeStyle.optional(),
27728
- pauseForVideoScriptReview: z123.boolean().optional(),
27729
- pendingUserAction: z123.object({
27730
- kind: z123.string(),
27731
- candidateGrouping: z123.string().optional(),
27732
- selectedImageUrls: z123.array(z123.string()).optional(),
27733
- proposedProductNames: z123.array(z123.string()).optional(),
28167
+ pauseForVideoScriptReview: z124.boolean().optional(),
28168
+ pendingUserAction: z124.object({
28169
+ kind: z124.string(),
28170
+ candidateGrouping: z124.string().optional(),
28171
+ selectedImageUrls: z124.array(z124.string()).optional(),
28172
+ proposedProductNames: z124.array(z124.string()).optional(),
27734
28173
  // Adaptive reference questions are server-owned. Echo only the evidence
27735
28174
  // identity and the choices shown by the current snapshot; never accept a
27736
28175
  // client-supplied reference set as authorization.
27737
- options: z123.array(ProductReferenceUserChoiceEnum).max(4).optional(),
27738
- mode: z123.enum([
28176
+ options: z124.array(ProductReferenceUserChoiceEnum).max(4).optional(),
28177
+ mode: z124.enum([
27739
28178
  "question",
27740
28179
  "visual_recovery"
27741
28180
  ]).optional(),
27742
28181
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
27743
- canKeepSelection: z123.boolean().optional(),
27744
- decisionKey: z123.string().optional(),
27745
- questionOrdinal: z123.number().int().min(1).max(5).optional(),
27746
- questionCeiling: z123.union([
27747
- z123.literal(3),
27748
- z123.literal(5)
28182
+ canKeepSelection: z124.boolean().optional(),
28183
+ decisionKey: z124.string().optional(),
28184
+ questionOrdinal: z124.number().int().min(1).max(5).optional(),
28185
+ questionCeiling: z124.union([
28186
+ z124.literal(3),
28187
+ z124.literal(5)
27749
28188
  ]).optional(),
27750
- referenceEvidenceVersion: z123.number().int().positive().optional(),
27751
- expectedEvidenceHash: z123.string().optional(),
27752
- question: z123.object({
27753
- prompt: z123.string().min(1).max(240),
27754
- helpText: z123.string().min(1).max(300).optional(),
27755
- options: z123.array(z123.object({
28189
+ referenceEvidenceVersion: z124.number().int().positive().optional(),
28190
+ expectedEvidenceHash: z124.string().optional(),
28191
+ question: z124.object({
28192
+ prompt: z124.string().min(1).max(240),
28193
+ helpText: z124.string().min(1).max(300).optional(),
28194
+ options: z124.array(z124.object({
27756
28195
  value: ProductReferenceUserChoiceEnum,
27757
- label: z123.string().min(1).max(120),
27758
- description: z123.string().min(1).max(240).optional()
28196
+ label: z124.string().min(1).max(120),
28197
+ description: z124.string().min(1).max(240).optional()
27759
28198
  })).min(2).max(4)
27760
28199
  }).optional(),
27761
28200
  scope: ProductReferenceScopeEnum.optional(),
27762
- scopeKey: z123.string().optional(),
27763
- scopeSnapshotId: z123.string().uuid().optional(),
27764
- scopeHash: z123.string().optional(),
27765
- baseReferenceSetHash: z123.string().optional(),
27766
- phase: z123.enum([
28201
+ scopeKey: z124.string().optional(),
28202
+ scopeSnapshotId: z124.string().uuid().optional(),
28203
+ scopeHash: z124.string().optional(),
28204
+ baseReferenceSetHash: z124.string().optional(),
28205
+ phase: z124.enum([
27767
28206
  "preparation",
27768
28207
  "final"
27769
28208
  ]).optional(),
27770
- selectedRefKeys: z123.array(z123.string().min(1).max(200)).optional(),
27771
- allowedDecisions: z123.array(ProductReferenceResolutionDecisionEnum).optional(),
27772
- previews: z123.array(z123.object({
27773
- refKey: z123.string().min(1).max(200)
28209
+ selectedRefKeys: z124.array(z124.string().min(1).max(200)).optional(),
28210
+ allowedDecisions: z124.array(ProductReferenceResolutionDecisionEnum).optional(),
28211
+ previews: z124.array(z124.object({
28212
+ refKey: z124.string().min(1).max(200)
27774
28213
  }).passthrough()).optional(),
27775
- customAngleDraft: z123.string().optional(),
27776
- painPointsDraft: z123.string().optional(),
27777
- benefitsDraft: z123.string().optional(),
27778
- featuresDraft: z123.array(z123.string()).optional(),
27779
- angleOptions: z123.array(z123.object({
27780
- index: z123.number().int().nonnegative(),
27781
- angle: z123.string().min(1)
28214
+ customAngleDraft: z124.string().optional(),
28215
+ painPointsDraft: z124.string().optional(),
28216
+ benefitsDraft: z124.string().optional(),
28217
+ featuresDraft: z124.array(z124.string()).optional(),
28218
+ angleOptions: z124.array(z124.object({
28219
+ index: z124.number().int().nonnegative(),
28220
+ angle: z124.string().min(1)
27782
28221
  }).passthrough()).min(1).max(5).optional(),
27783
28222
  // Recommendation consumed only when the caller explicitly sends
27784
28223
  // gapDurationSeconds: 30 in the angle approval action.
@@ -27788,17 +28227,17 @@ var StatusForResolveSchema = z123.object({
27788
28227
  // keys. `actorId` (the saved custom actor the picker stored) was silently
27789
28228
  // dropped here, so the approval handler below could not echo it back on the
27790
28229
  // PATCH — the selection looked accepted and reached no render.
27791
- angles: z123.array(z123.object({
27792
- id: z123.string().uuid(),
27793
- content: z123.string(),
27794
- creativeDirection: z123.string(),
27795
- actor: z123.string(),
27796
- actorId: z123.string().nullable().optional()
28230
+ angles: z124.array(z124.object({
28231
+ id: z124.string().uuid(),
28232
+ content: z124.string(),
28233
+ creativeDirection: z124.string(),
28234
+ actor: z124.string(),
28235
+ actorId: z124.string().nullable().optional()
27797
28236
  }).passthrough()).optional(),
27798
- panels: z123.array(z123.object({
27799
- beatId: z123.string(),
27800
- voiceover: z123.string(),
27801
- visualDirection: z123.string()
28237
+ panels: z124.array(z124.object({
28238
+ beatId: z124.string(),
28239
+ voiceover: z124.string(),
28240
+ visualDirection: z124.string()
27802
28241
  }).passthrough()).optional()
27803
28242
  }).optional()
27804
28243
  }).passthrough();
@@ -28151,8 +28590,8 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28151
28590
  server.registerTool("verify_landing_commerce", {
28152
28591
  description: getProductMakerCapabilityModelGuidance("verify_landing_commerce").summary + " Verifica una correcci\xF3n manual de precios, tachados o packs de una landing editable existente. Solo relee Shopify y los recibos externos; no cambia precios, inventario, SKU ni compra una edici\xF3n. Pasa taskId y editId de la edici\xF3n ya conocida; nunca inventes IDs ni pidas repetir el cambio. Devuelve el estado can\xF3nico por proveedor: conserva el aviso pendiente hasta confirmar los valores reales. Solo despu\xE9s de confirmar todos los valores, el servidor puede volver a habilitar la compra. Web guardada no demuestra publicaci\xF3n p\xFAblica ni checkout; muestra las correcciones y enlaces pendientes sin c\xF3digos t\xE9cnicos. La disponibilidad del editor conserva sus permisos actuales.",
28153
28592
  inputSchema: {
28154
- taskId: z123.string().uuid(),
28155
- editId: z123.string().uuid()
28593
+ taskId: z124.string().uuid(),
28594
+ editId: z124.string().uuid()
28156
28595
  },
28157
28596
  annotations: OVERWRITES_EXTERNAL
28158
28597
  }, async (input) => {
@@ -28173,16 +28612,28 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28173
28612
  }
28174
28613
  });
28175
28614
  server.registerTool("get_task_status", {
28176
- description: `Devuelve estado y outputs. Sigue llam\xE1ndola hasta done/error o una review; un timeout significa que sigue corriendo. Cuando aparece pendingUserAction, la respuesta a\xF1ade Markdown conversacional con el draft y opciones: mu\xE9stralo, pregunta y espera. Usa resolve_pending_action s\xF3lo tras la respuesta del usuario o delegaci\xF3n expl\xEDcita. Nunca expongas IDs, hashes ni payloads t\xE9cnicos. Despu\xE9s de resolver una review, sigue reviewNextAction cuando exista; s\xF3lo vuelve a get_task_status cuando esa transici\xF3n no exista o cuando get_video_script termine en approved/skipped. En un video animado, ${UNTRUSTED_SITE_TEXT_NOTE}`,
28615
+ description: `Devuelve estado y outputs. Sigue llam\xE1ndola hasta done/error o una review; un timeout significa que sigue corriendo. Cuando aparece pendingUserAction, la respuesta a\xF1ade Markdown conversacional con el draft y opciones: mu\xE9stralo, pregunta y espera. Usa resolve_pending_action s\xF3lo tras la respuesta del usuario o delegaci\xF3n expl\xEDcita. Nunca expongas IDs, hashes ni payloads t\xE9cnicos. Despu\xE9s de resolver una review, sigue reviewNextAction cuando exista; s\xF3lo vuelve a get_task_status cuando esa transici\xF3n no exista o cuando get_video_script termine en approved/skipped. Entrega \xFAnicamente los medios originales de ProductMaker en el visor y los bloques de imagen; nunca los sustituyas ni recrees con otra herramienta. En un video animado, ${UNTRUSTED_SITE_TEXT_NOTE}`,
28177
28616
  inputSchema: GetTaskStatusInput.shape,
28178
- annotations: READS_INTERNAL
28179
- }, async (input, extra) => {
28617
+ annotations: READS_INTERNAL,
28618
+ _meta: taskResultsToolMeta()
28619
+ }, async (input, extra) => observeMcpMediaDelivery(api.fingerprint(), async () => {
28180
28620
  try {
28181
28621
  const signal = extra?.signal;
28182
28622
  const fetcher = /* @__PURE__ */ __name(() => api.getJson(`/v1/status/${encodeURIComponent(input.taskId)}`, {
28183
28623
  signal
28184
28624
  }), "fetcher");
28185
28625
  const snapshot = await pollStatus(fetcher, input.waitSeconds ?? 0, signal);
28626
+ const statusMeta = {
28627
+ taskResults: {
28628
+ state: snapshot.status === "error" ? "error" : [
28629
+ "awaiting_review",
28630
+ "waiting_for_user"
28631
+ ].includes(snapshot.status) ? "awaiting_review" : "pending",
28632
+ images: [],
28633
+ videos: [],
28634
+ links: []
28635
+ }
28636
+ };
28186
28637
  if (snapshot.status !== "done") {
28187
28638
  const review = renderPendingActionMarkdown(snapshot);
28188
28639
  if (review) {
@@ -28201,14 +28652,29 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28201
28652
  }) ?? review : review
28202
28653
  }
28203
28654
  ],
28204
- structuredContent: snapshot
28655
+ structuredContent: snapshot,
28656
+ _meta: {
28657
+ taskResults: {
28658
+ ...statusMeta.taskResults,
28659
+ state: "awaiting_review"
28660
+ }
28661
+ }
28205
28662
  };
28206
28663
  }
28207
28664
  if (snapshot.kind === "service") {
28208
- const animated = await fetchAnimatedVideoResult(api, input.taskId, signal, "serviceMode" in snapshot ? snapshot.serviceMode : void 0);
28209
- if (animated) {
28665
+ const rawAnimated = await fetchAnimatedVideoResult(api, input.taskId, signal, "serviceMode" in snapshot ? snapshot.serviceMode : void 0);
28666
+ if (rawAnimated) {
28667
+ const animated = proxifyServiceVideoResult(rawAnimated, proxyBaseUrl);
28210
28668
  const continuation2 = buildPollingContinuation(snapshot);
28669
+ const view = buildTaskResultsView(serviceVideoResultMedia(animated), proxyBaseUrl);
28211
28670
  return {
28671
+ structuredContent: {
28672
+ ...snapshot,
28673
+ animatedVideo: toAgentFacingAnimatedVideo(animated)
28674
+ },
28675
+ _meta: view.state === "ready" ? {
28676
+ taskResults: view
28677
+ } : statusMeta,
28212
28678
  content: [
28213
28679
  {
28214
28680
  type: "text",
@@ -28237,6 +28703,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28237
28703
  const continuation = buildPollingContinuation(snapshot);
28238
28704
  if (continuation) {
28239
28705
  return {
28706
+ _meta: statusMeta,
28240
28707
  content: [
28241
28708
  {
28242
28709
  type: "text",
@@ -28252,15 +28719,26 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28252
28719
  ]
28253
28720
  };
28254
28721
  }
28255
- return asText(snapshot);
28722
+ return {
28723
+ ...asText(snapshot),
28724
+ _meta: statusMeta
28725
+ };
28256
28726
  }
28257
28727
  if (snapshot.kind === "service") {
28258
- const result = await api.getJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/service-result`, {
28728
+ const rawResult = await api.getJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/service-result`, {
28259
28729
  signal
28260
28730
  });
28731
+ const result = proxifyServiceVideoResult(rawResult, proxyBaseUrl);
28261
28732
  const animated = parseAnimatedVideoResult(result);
28262
28733
  if (animated) {
28263
28734
  return {
28735
+ structuredContent: {
28736
+ ...snapshot,
28737
+ result: toAgentFacingAnimatedVideo(animated)
28738
+ },
28739
+ _meta: {
28740
+ taskResults: buildTaskResultsView(serviceVideoResultMedia(animated), proxyBaseUrl)
28741
+ },
28264
28742
  content: [
28265
28743
  {
28266
28744
  type: "text",
@@ -28277,6 +28755,13 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28277
28755
  };
28278
28756
  }
28279
28757
  return {
28758
+ structuredContent: {
28759
+ ...snapshot,
28760
+ result
28761
+ },
28762
+ _meta: {
28763
+ taskResults: buildTaskResultsView(serviceVideoResultMedia(result), proxyBaseUrl)
28764
+ },
28280
28765
  content: [
28281
28766
  {
28282
28767
  type: "text",
@@ -28298,13 +28783,39 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28298
28783
  const rawOutputs = await fetchTaskOutputs(api, input.taskId, {
28299
28784
  signal
28300
28785
  });
28301
- const preview2 = rawOutputs.images[0];
28302
- const imageContent = preview2 ? (await buildMcpImagePreviewContent({
28303
- url: preview2.url,
28304
- alt: "Ad creative"
28305
- }, transport)).filter((block) => block.type === "image") : [];
28786
+ const imageContent = await buildMcpGeneratedImageContent(rawOutputs.images.map((image, i) => ({
28787
+ url: image.url,
28788
+ alt: `Imagen ${i + 1}`
28789
+ })), transport);
28306
28790
  const outputs = proxifyOutputs(rawOutputs, proxyBaseUrl);
28791
+ const media = {
28792
+ images: [
28793
+ ...outputs.images.map((image, i) => ({
28794
+ url: image.url,
28795
+ alt: `Imagen ${i + 1}`
28796
+ })),
28797
+ ...outputs.landing.sections.map((section) => ({
28798
+ url: section.url,
28799
+ alt: section.role
28800
+ }))
28801
+ ],
28802
+ videos: outputs.videos.flatMap((video) => video.variants.map((variant) => ({
28803
+ url: variant.url,
28804
+ label: `${video.angleKey} \xB7 ${variant.kind}`,
28805
+ ...video.scriptRewritten ? {
28806
+ scriptRewritten: true
28807
+ } : {}
28808
+ }))),
28809
+ links: []
28810
+ };
28307
28811
  return {
28812
+ structuredContent: {
28813
+ ...snapshot,
28814
+ outputs
28815
+ },
28816
+ _meta: {
28817
+ taskResults: buildTaskResultsView(media, proxyBaseUrl)
28818
+ },
28308
28819
  content: [
28309
28820
  {
28310
28821
  type: "text",
@@ -28325,12 +28836,20 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28325
28836
  const detail = err instanceof Error ? err.stack ?? err.message : String(err);
28326
28837
  process.stderr.write(`mcp get_task_status: fetchTaskOutputs failed for ${input.taskId}: ${detail}
28327
28838
  `);
28328
- return asText(snapshot);
28839
+ return {
28840
+ ...asText(snapshot),
28841
+ _meta: {
28842
+ taskResults: {
28843
+ ...statusMeta.taskResults,
28844
+ state: "error"
28845
+ }
28846
+ }
28847
+ };
28329
28848
  }
28330
28849
  } catch (e) {
28331
28850
  throw translateError(e);
28332
28851
  }
28333
- });
28852
+ }));
28334
28853
  server.registerTool("list_tasks", {
28335
28854
  description: listTasksGuidance.summary + " \xDAsala para encontrar una tarea previa por nombre o revisar el historial antes de pedir un taskId. Soporta paginaci\xF3n con limit/offset y filtro de texto. No crea, reanuda ni modifica tareas.",
28336
28855
  inputSchema: ListTasksInput.shape,
@@ -28343,16 +28862,16 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28343
28862
  if (input.search) qs.set("search", input.search);
28344
28863
  const path3 = `/v1/tasks${qs.toString() ? "?" + qs.toString() : ""}`;
28345
28864
  const r = await api.getJson(path3);
28346
- const page = z123.object({
28347
- items: z123.array(z123.unknown())
28865
+ const page = z124.object({
28866
+ items: z124.array(z124.unknown())
28348
28867
  }).passthrough().safeParse(r);
28349
28868
  if (!page.success) return asText(r);
28350
28869
  return asText({
28351
28870
  ...page.data,
28352
28871
  items: page.data.items.map((item) => {
28353
- const servicePage = z123.object({
28354
- taskId: z123.string().uuid(),
28355
- resourceType: z123.literal("service_page")
28872
+ const servicePage = z124.object({
28873
+ taskId: z124.string().uuid(),
28874
+ resourceType: z124.literal("service_page")
28356
28875
  }).passthrough().safeParse(item);
28357
28876
  if (!servicePage.success) return item;
28358
28877
  return {
@@ -28842,28 +29361,28 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28842
29361
  __name(registerTaskTools, "registerTaskTools");
28843
29362
 
28844
29363
  // src/tools/brands.ts
28845
- import { z as z124 } from "zod";
29364
+ import { z as z125 } from "zod";
28846
29365
  var guidance2 = getProductMakerCapabilityModelGuidance("create_brand");
28847
29366
  var BRAND_START_REPLAY_WINDOW_MS = 15 * 60 * 1e3;
28848
29367
  var BRAND_NOTES_MAX_CHARS = 2e4;
28849
29368
  var BRAND_AMBIGUOUS_REQUEST_RETENTION_MS = 24 * 60 * 60 * 1e3;
28850
29369
  var BRAND_CREATION_REQUEST_LIMIT = 500;
28851
29370
  var brandCreationRequests = /* @__PURE__ */ new Map();
28852
- var CreateBrandInput = z124.object({
28853
- action: z124.enum([
29371
+ var CreateBrandInput = z125.object({
29372
+ action: z125.enum([
28854
29373
  "start",
28855
29374
  "status",
28856
29375
  "list"
28857
29376
  ]).default("start").describe("start cotiza (sin confirmed) o inicia (confirmed=true) el an\xE1lisis; status consulta brandId hasta ready o failed; list muestra las marcas que el usuario ya tiene."),
28858
- sourceUrl: z124.string().trim().min(1).max(BRAND_SOURCE_URL_MAX_LENGTH).optional().describe("Instagram, Facebook, TikTok o web p\xFAblica del negocio, como la dio el usuario (\xAB@sanlucasbarberia\xBB, \xABinstagram.com/sanlucasbarberia\xBB, \xABmibarberia.com\xBB). Obligatorio para start."),
28859
- businessNotes: z124.string().trim().max(BRAND_NOTES_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cuente de su negocio en el chat (servicios y precios, WhatsApp, ciudad o zona, horarios). Se guarda como documento del negocio y llega tal cual a la marca y a su landing. Copia sus palabras; no inventes datos."),
28860
- language: z124.enum([
29377
+ sourceUrl: z125.string().trim().min(1).max(BRAND_SOURCE_URL_MAX_LENGTH).optional().describe("Instagram, Facebook, TikTok o web p\xFAblica del negocio, como la dio el usuario (\xAB@sanlucasbarberia\xBB, \xABinstagram.com/sanlucasbarberia\xBB, \xABmibarberia.com\xBB). Obligatorio para start."),
29378
+ businessNotes: z125.string().trim().max(BRAND_NOTES_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cuente de su negocio en el chat (servicios y precios, WhatsApp, ciudad o zona, horarios). Se guarda como documento del negocio y llega tal cual a la marca y a su landing. Copia sus palabras; no inventes datos."),
29379
+ language: z125.enum([
28861
29380
  "es",
28862
29381
  "en",
28863
29382
  "pt"
28864
29383
  ]).optional().describe("Idioma de la conversaci\xF3n. Solo se usa si la p\xE1gina del negocio no deja claro su idioma."),
28865
- confirmed: z124.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
28866
- brandId: z124.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
29384
+ confirmed: z125.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
29385
+ brandId: z125.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
28867
29386
  }).strict();
28868
29387
  function normalizeBrandSourceUrl(raw) {
28869
29388
  const value = raw.trim();
@@ -29147,24 +29666,24 @@ __name(registerBrandTools, "registerBrandTools");
29147
29666
 
29148
29667
  // src/tools/service-landing.ts
29149
29668
  import { createHash as createHash3, randomUUID } from "crypto";
29150
- import { z as z125 } from "zod";
29669
+ import { z as z126 } from "zod";
29151
29670
  var guidance3 = getProductMakerCapabilityModelGuidance("create_service_landing");
29152
29671
  var SERVICE_LANDING_KEY_NAMESPACE = "6f1d8c2a-3b4e-5f60-8a7b-9c0d1e2f3a4b";
29153
29672
  var SERVICE_LANDING_INFO_MAX_CHARS = 2e4;
29154
- var CreateServiceLandingInput = z125.object({
29155
- action: z125.enum([
29673
+ var CreateServiceLandingInput = z126.object({
29674
+ action: z126.enum([
29156
29675
  "prepare",
29157
29676
  "build",
29158
29677
  "status",
29159
29678
  "publish"
29160
29679
  ]).default("prepare").describe("prepare (gratis) crea o retoma la landing de la marca y da el precio; build (pagado, confirmed=true) genera la p\xE1gina directamente con la marca y los datos guardados; status sigue el avance; publish la publica y devuelve su enlace."),
29161
- brandId: z125.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
29162
- servicePageId: z125.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
29163
- businessInfo: z125.string().trim().max(SERVICE_LANDING_INFO_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cont\xF3 del negocio y no estaba en su marca: servicios y precios, WhatsApp o tel\xE9fono, ciudad o zona, horarios. Copia sus palabras; no inventes datos."),
29164
- confirmed: z125.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
29165
- maxCredits: z125.number().int().positive().optional().describe("El total en cr\xE9ditos que el usuario acept\xF3 (el que devolvi\xF3 prepare). Obligatorio para build: ninguna etapa se inicia si su precio supera este total."),
29166
- operationId: z125.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
29167
- slug: z125.string().trim().toLowerCase().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(64).optional().describe("Opcional en publish: la direcci\xF3n corta de la p\xE1gina (ej. sanlucas-barberia). Si falta se usa la sugerida desde el nombre del negocio.")
29680
+ brandId: z126.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
29681
+ servicePageId: z126.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
29682
+ businessInfo: z126.string().trim().max(SERVICE_LANDING_INFO_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cont\xF3 del negocio y no estaba en su marca: servicios y precios, WhatsApp o tel\xE9fono, ciudad o zona, horarios. Copia sus palabras; no inventes datos."),
29683
+ confirmed: z126.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
29684
+ maxCredits: z126.number().int().positive().optional().describe("El total en cr\xE9ditos que el usuario acept\xF3 (el que devolvi\xF3 prepare). Obligatorio para build: ninguna etapa se inicia si su precio supera este total."),
29685
+ operationId: z126.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
29686
+ slug: z126.string().trim().toLowerCase().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(64).optional().describe("Opcional en publish: la direcci\xF3n corta de la p\xE1gina (ej. sanlucas-barberia). Si falta se usa la sugerida desde el nombre del negocio.")
29168
29687
  }).strict();
29169
29688
  function serviceKey(...parts) {
29170
29689
  return deriveUuidV5(parts.join(":"), SERVICE_LANDING_KEY_NAMESPACE);
@@ -29397,7 +29916,7 @@ function registerServiceLandingTools(server, api) {
29397
29916
  const build = quoteRange(generationQuote);
29398
29917
  const totalMin = build.min;
29399
29918
  const totalCredits = build.max;
29400
- const requiredBalanceCredits = generationQuote.credits;
29919
+ const requiredBalanceCredits = totalCredits;
29401
29920
  const askFor = page2.facts.contact.channels.some((channel) => channel.kind === "whatsapp") ? "su ciudad o zona y sus servicios con precio (su WhatsApp ya viene de la marca: no lo pidas)" : "su WhatsApp o tel\xE9fono, su ciudad o zona y sus servicios con precio";
29402
29921
  const priceText = totalMin === totalCredits ? `${totalCredits} cr\xE9ditos` : `entre ${totalMin} y ${totalCredits} cr\xE9ditos`;
29403
29922
  return asText({
@@ -29414,7 +29933,7 @@ function registerServiceLandingTools(server, api) {
29414
29933
  totalCredits,
29415
29934
  requiredBalanceCredits
29416
29935
  },
29417
- nextAction: `En un solo mensaje: dile al usuario que crear su landing cuesta ${priceText} en total (se cobra lo que se use; necesita al menos ${requiredBalanceCredits} cr\xE9ditos de saldo para empezar) y preg\xFAntale, solo si no lo dijo ya en esta conversaci\xF3n, ${askFor} (puede omitirlo). Cuando acepte el precio, llama action=build con servicePageId=${page2.id}, confirmed=true, maxCredits=${totalCredits} y businessInfo con lo que respondi\xF3.`
29936
+ nextAction: `En un solo mensaje: dile al usuario que crear su landing cuesta ${priceText} en total (se cobra lo que se use; necesita al menos ${requiredBalanceCredits} cr\xE9ditos de saldo para empezar) y preg\xFAntale, solo si no lo dijo ya en esta conversaci\xF3n, ${askFor} (puede omitirlo). prepare no consulta el saldo: no interpretes un saldo desconocido como insuficiente ni exijas una comprobaci\xF3n manual. Cuando acepte el precio, llama action=build con servicePageId=${page2.id}, confirmed=true, maxCredits=${totalCredits} y businessInfo con lo que respondi\xF3; comunica cualquier rechazo que devuelva el servidor.`
29418
29937
  });
29419
29938
  }
29420
29939
  if (!input.servicePageId) {
@@ -29539,7 +30058,7 @@ function registerServiceLandingTools(server, api) {
29539
30058
  __name(registerServiceLandingTools, "registerServiceLandingTools");
29540
30059
 
29541
30060
  // src/tools/service-images.ts
29542
- import { z as z126 } from "zod";
30061
+ import { z as z127 } from "zod";
29543
30062
  var guidance4 = getProductMakerCapabilityModelGuidance("create_service_images");
29544
30063
  var SERVICE_IMAGE_FORMATS = [
29545
30064
  "4:5",
@@ -29552,23 +30071,23 @@ var LANGUAGE_TAGS = {
29552
30071
  en: "en-US",
29553
30072
  pt: "pt-BR"
29554
30073
  };
29555
- var CreateServiceImagesInput = z126.object({
29556
- brandId: z126.string().uuid().optional().describe("ID de un servicio propio y listo (de create_brand), obligatorio para cotizar y crear im\xE1genes nuevas. En un retry hist\xF3rico ya confirmado que originalmente no ten\xEDa este campo, conserva la petici\xF3n original. Nunca un taskId de producto."),
29557
- instruction: z126.string().trim().max(4e3).optional().describe("Opcional. Qu\xE9 servicio o promoci\xF3n mostrar, con las palabras del usuario (ej. \xABcorte + barba a $35.000 los martes\xBB). Si se omite, la IA propone la imagen usando la informaci\xF3n del servicio."),
29558
- delegateToAi: z126.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su servicio. Tambi\xE9n se delega cuando instruction est\xE1 vac\xEDo."),
29559
- format: z126.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
29560
- count: z126.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
29561
- quality: z126.enum([
30074
+ var CreateServiceImagesInput = z127.object({
30075
+ brandId: z127.string().uuid().optional().describe("ID de un servicio propio y listo (de create_brand), obligatorio para cotizar y crear im\xE1genes nuevas. En un retry hist\xF3rico ya confirmado que originalmente no ten\xEDa este campo, conserva la petici\xF3n original. Nunca un taskId de producto."),
30076
+ instruction: z127.string().trim().max(4e3).optional().describe("Opcional. Qu\xE9 servicio o promoci\xF3n mostrar, con las palabras del usuario (ej. \xABcorte + barba a $35.000 los martes\xBB). Si se omite, la IA propone la imagen usando la informaci\xF3n del servicio."),
30077
+ delegateToAi: z127.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su servicio. Tambi\xE9n se delega cuando instruction est\xE1 vac\xEDo."),
30078
+ format: z127.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
30079
+ count: z127.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
30080
+ quality: z127.enum([
29562
30081
  "standard",
29563
30082
  "high"
29564
30083
  ]).optional().describe('Calidad: "standard" (por defecto) o "high" (m\xE1s cara; no disponible en 4:5).'),
29565
- language: z126.enum([
30084
+ language: z127.enum([
29566
30085
  "es",
29567
30086
  "en",
29568
30087
  "pt"
29569
30088
  ]).optional().describe("Idioma de los textos de la imagen (por defecto es)."),
29570
- adCopy: z126.boolean().optional().describe("Compatibilidad con clientes anteriores: el copy para publicar siempre est\xE1 incluido en cada imagen de servicios."),
29571
- confirmed: z126.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
30089
+ adCopy: z127.boolean().optional().describe("Compatibilidad con clientes anteriores: el copy para publicar siempre est\xE1 incluido en cada imagen de servicios."),
30090
+ confirmed: z127.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
29572
30091
  }).strict();
29573
30092
  function serviceImageModel(quality) {
29574
30093
  return quality === "high" ? AD_CREATIVE_MODELS.PREMIUM : AD_CREATIVE_MODELS.STANDARD;
@@ -29682,10 +30201,10 @@ function registerServiceImageTools(server, api, options = {}) {
29682
30201
  ...priceCredits ? {
29683
30202
  priceCredits
29684
30203
  } : {},
29685
- nextAction: "Dile al usuario que est\xE1s creando sus im\xE1genes. Llama get_task_status con este taskId (waitSeconds=45) hasta done (trae las im\xE1genes) o error."
30204
+ nextAction: "Dile al usuario que est\xE1s creando sus im\xE1genes. Llama get_task_status con este taskId (waitSeconds=45) hasta done (trae las im\xE1genes reales de ProductMaker) o error. Muestra los recursos de imagen devueltos directamente en el chat. Nunca generes ni recrees una imagen sustituta con otra herramienta. Si la vista previa falla, explica el fallo y conserva los enlaces protegidos devueltos."
29686
30205
  });
29687
30206
  } catch (error) {
29688
- if (error instanceof z126.ZodError) throw invalidInputFromZod(error);
30207
+ if (error instanceof z127.ZodError) throw invalidInputFromZod(error);
29689
30208
  throw translateError(error);
29690
30209
  }
29691
30210
  });
@@ -29693,7 +30212,7 @@ function registerServiceImageTools(server, api, options = {}) {
29693
30212
  __name(registerServiceImageTools, "registerServiceImageTools");
29694
30213
 
29695
30214
  // src/tools/creatives.ts
29696
- import { z as z127 } from "zod";
30215
+ import { z as z128 } from "zod";
29697
30216
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
29698
30217
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
29699
30218
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -29704,72 +30223,72 @@ var CreativeRefs = {
29704
30223
  images: ImagesInput,
29705
30224
  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.'),
29706
30225
  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.'),
29707
- price: z127.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.'),
29708
- offer: z127.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.'),
29709
- compareAtPrice: z127.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
29710
- productContext: z127.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."),
29711
- productLabel: z127.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.'),
29712
- buyerPersona: z127.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.'),
29713
- isCombo: z127.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
29714
- competitorScanEnabled: z127.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
29715
- brandId: z127.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.")
30226
+ price: z128.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.'),
30227
+ offer: z128.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.'),
30228
+ compareAtPrice: z128.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
30229
+ productContext: z128.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."),
30230
+ productLabel: z128.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.'),
30231
+ buyerPersona: z128.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.'),
30232
+ isCombo: z128.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
30233
+ competitorScanEnabled: z128.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
30234
+ brandId: z128.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.")
29716
30235
  };
29717
- var VideoPresenter = z127.discriminatedUnion("mode", [
29718
- z127.object({
29719
- mode: z127.literal("none")
30236
+ var VideoPresenter = z128.discriminatedUnion("mode", [
30237
+ z128.object({
30238
+ mode: z128.literal("none")
29720
30239
  }).strict(),
29721
- z127.object({
29722
- mode: z127.literal("saved_actor"),
29723
- actorId: z127.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
30240
+ z128.object({
30241
+ mode: z128.literal("saved_actor"),
30242
+ actorId: z128.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
29724
30243
  }).strict(),
29725
- z127.object({
29726
- mode: z127.literal("described"),
29727
- description: z127.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
30244
+ z128.object({
30245
+ mode: z128.literal("described"),
30246
+ description: z128.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
29728
30247
  }).strict()
29729
30248
  ]);
29730
- var VideoCreativeSetup = z127.discriminatedUnion("mode", [
29731
- z127.object({
29732
- mode: z127.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
30249
+ var VideoCreativeSetup = z128.discriminatedUnion("mode", [
30250
+ z128.object({
30251
+ mode: z128.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
29733
30252
  }).strict(),
29734
- z127.object({
29735
- mode: z127.literal("guided"),
30253
+ z128.object({
30254
+ mode: z128.literal("guided"),
29736
30255
  videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas funcionan en Un solo clip y Multiescena.'),
29737
- buyerPersona: z127.string().trim().min(1).max(360),
30256
+ buyerPersona: z128.string().trim().min(1).max(360),
29738
30257
  animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
29739
30258
  presenter: VideoPresenter,
29740
- creativeDirection: z127.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
30259
+ creativeDirection: z128.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
29741
30260
  }).strict()
29742
30261
  ]);
29743
- var VideoInput = z127.object({
30262
+ var VideoInput = z128.object({
29744
30263
  images: CreativeRefs.images.optional(),
29745
30264
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
29746
- title: z127.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
29747
- primaryAngle: z127.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".'),
30265
+ title: z128.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
30266
+ primaryAngle: z128.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".'),
29748
30267
  language: CreativeRefs.language,
29749
30268
  country: CreativeRefs.country,
29750
- aspectRatio: z127.enum([
30269
+ aspectRatio: z128.enum([
29751
30270
  "9:16",
29752
30271
  "16:9",
29753
30272
  "Auto"
29754
30273
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
29755
30274
  generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
29756
- durationSeconds: z127.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
29757
- videoAngleCount: z127.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
30275
+ durationSeconds: z128.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
30276
+ videoAngleCount: z128.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
29758
30277
  angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
29759
30278
  creativeSetup: VideoCreativeSetup.describe("Configuraci\xF3n creativa obligatoria. En guided pregunta narrativa, p\xFAblico, presentador y direcci\xF3n antes de confirmar. Usa automatic s\xF3lo si el usuario deleg\xF3 todo expl\xEDcitamente."),
29760
30279
  videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena (varias tomas concatenadas). Default: single_take.'),
29761
30280
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
29762
30281
  videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render: "480p" o "720p". Si se omite, se usa 480p; elige 720p expl\xEDcitamente si necesitas m\xE1s nitidez.'),
29763
- features: z127.array(z127.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
30282
+ features: z128.array(z128.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
29764
30283
  price: CreativeRefs.price,
29765
30284
  offer: CreativeRefs.offer,
29766
30285
  productContext: CreativeRefs.productContext,
29767
30286
  productLabel: CreativeRefs.productLabel,
29768
- cta: z127.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.'),
29769
- scriptNotes: z127.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
30287
+ cta: z128.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.'),
30288
+ scriptNotes: z128.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
29770
30289
  creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en el video: mujer ("female"), hombre ("male") o ambos ("mixed"). NO es la voz; cuando se fija, la voz se alinea sola con el personaje. M\xE1ndalo en cuanto el usuario diga qui\xE9n debe SALIR en el video, con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "protagonista femenina"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario puede recibir lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. NO lo mandes cuando hable del P\xDABLICO COMPRADOR ("esto es para hombres", "mi p\xFAblico son mujeres", "va dirigido a mam\xE1s"): eso es a qui\xE9n se le vende, no qui\xE9n act\xFAa, y fijarlo ah\xED pinea un protagonista que nadie pidi\xF3. "mixed" solo cuando pida expl\xEDcitamente ambos, y ten en cuenta que no garantiza una mezcla: no fija ning\xFAn g\xE9nero y cada creativo elige su protagonista. No lo preguntes como paso obligatorio. Si creativeSetup.presenter.mode="saved_actor", el personaje guardado manda sobre este campo.'),
29771
30290
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
29772
- replicateWinnerWhenFound: z127.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
30291
+ replicateWinnerWhenFound: z128.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
29773
30292
  brandId: CreativeRefs.brandId
29774
30293
  }).strict();
29775
30294
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -29787,7 +30306,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
29787
30306
  length: 29
29788
30307
  }, (_, index) => index + 2)
29789
30308
  };
29790
- var FreeVideoModelIdEnum = z127.enum([
30309
+ var FreeVideoModelIdEnum = z128.enum([
29791
30310
  "grok-imagine-video-1-5-preview",
29792
30311
  "minimax-h3/reference-to-video",
29793
30312
  "wan/3-0-video",
@@ -29798,66 +30317,66 @@ var FREE_SELECTABLE_MODEL_IDS = [
29798
30317
  "minimax-h3/reference-to-video",
29799
30318
  "wan/3-0-video"
29800
30319
  ];
29801
- var FreeVideoInput = z127.object({
30320
+ var FreeVideoInput = z128.object({
29802
30321
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
29803
- rawPrompt: z127.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."),
30322
+ rawPrompt: z128.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."),
29804
30323
  language: CreativeRefs.language,
29805
30324
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
29806
30325
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
29807
30326
  // parsed ONLY so the handler can reject it with a message naming its
29808
30327
  // replacement — dropping it silently would turn a caller's explicit
29809
30328
  // Pro++ pick into a quiet fallback to Wan.
29810
- freeProModel: z127.enum([
30329
+ freeProModel: z128.enum([
29811
30330
  "wan",
29812
30331
  "seedance"
29813
30332
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
29814
30333
  modelId: FreeVideoModelIdEnum.optional().describe('Opcional. Elige expl\xEDcitamente el modelo del registro en vez del default de la calidad: "grok-imagine-video-1-5-preview" (Grok 1.5), "minimax-h3/reference-to-video" (H3 Max) o "wan/3-0-video" (Wan 3.0). Om\xEDtelo para usar el modelo por defecto de la calidad elegida. El modelo determina la duraci\xF3n permitida (Grok 6/8/10/15s, H3 Max 4-15s, Wan 2-30s) y el precio. "bytedance/seedance-2-5" est\xE1 inactivo y se rechaza con un error claro, nunca un 500.'),
29815
- durationSeconds: z127.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
30334
+ durationSeconds: z128.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
29816
30335
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
29817
- generateAiMusic: z127.boolean().default(false).describe('Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false. Equivale a generateAiEdit (nivel "pro"): la Edici\xF3n con IA trae su propia m\xFAsica.'),
30336
+ generateAiMusic: z128.boolean().default(false).describe('Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false. Equivale a generateAiEdit (nivel "pro"): la Edici\xF3n con IA trae su propia m\xFAsica.'),
29818
30337
  generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, gr\xE1ficos y m\xFAsica sobre el video ya entregado (variante with_ai_edit; se cobra al entregar). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro". Default sin edici\xF3n.'),
29819
- addSubtitles: z127.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
29820
- idempotencyKey: z127.string().uuid().optional().describe("Opcional. Se acepta por compatibilidad pero se ignora: la identidad del reintento se deriva autom\xE1ticamente de los argumentos sem\xE1nticos, as\xED que un retry con los mismos argumentos ya es idempotente sin este campo.")
30338
+ addSubtitles: z128.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
30339
+ idempotencyKey: z128.string().uuid().optional().describe("Opcional. Se acepta por compatibilidad pero se ignora: la identidad del reintento se deriva autom\xE1ticamente de los argumentos sem\xE1nticos, as\xED que un retry con los mismos argumentos ya es idempotente sin este campo.")
29821
30340
  }).strict();
29822
30341
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
29823
- var ImageCreativeSetup = z127.discriminatedUnion("mode", [
29824
- z127.object({
29825
- mode: z127.literal("automatic")
30342
+ var ImageCreativeSetup = z128.discriminatedUnion("mode", [
30343
+ z128.object({
30344
+ mode: z128.literal("automatic")
29826
30345
  }).strict(),
29827
- z127.object({
29828
- mode: z127.literal("guided"),
29829
- creativeArchetype: z127.union([
30346
+ z128.object({
30347
+ mode: z128.literal("guided"),
30348
+ creativeArchetype: z128.union([
29830
30349
  ImageCreativeArchetypeEnum,
29831
- z127.literal("ai_decides")
30350
+ z128.literal("ai_decides")
29832
30351
  ]),
29833
- visualTreatment: z127.union([
30352
+ visualTreatment: z128.union([
29834
30353
  ImageCreativeVisualTreatmentEnum,
29835
- z127.literal("ai_decides")
30354
+ z128.literal("ai_decides")
29836
30355
  ]),
29837
30356
  aspectRatio: ImageCreativeAspectRatioEnum,
29838
- nVariants: z127.union([
29839
- z127.literal(1),
29840
- z127.literal(2),
29841
- z127.literal(3),
29842
- z127.literal(4),
29843
- z127.literal(6)
30357
+ nVariants: z128.union([
30358
+ z128.literal(1),
30359
+ z128.literal(2),
30360
+ z128.literal(3),
30361
+ z128.literal(4),
30362
+ z128.literal(6)
29844
30363
  ]),
29845
- imageModel: z127.enum(PUBLIC_IMAGE_QUALITY_INPUTS).describe('Calidad: "image:1k" (Est\xE1ndar) o "image:2k" (Premium). Los tokens gpt-image-2-5:{1k,2k} y gpt-image-2:{1k,2k} se siguen aceptando.'),
29846
- styleMix: z127.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
29847
- generateAdCopy: z127.boolean(),
29848
- competitorScanEnabled: z127.boolean(),
29849
- productContext: z127.string().trim().min(1).max(3e3).nullable(),
29850
- creativeDirection: z127.string().trim().min(1).max(500).nullable(),
29851
- brandColors: z127.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
29852
- headline: z127.string().trim().min(1).max(120).nullable(),
29853
- subheadline: z127.string().trim().min(1).max(160).nullable()
30364
+ imageModel: z128.enum(PUBLIC_IMAGE_QUALITY_INPUTS).describe('Calidad: "image:1k" (Est\xE1ndar) o "image:2k" (Premium). Los tokens gpt-image-2-5:{1k,2k} y gpt-image-2:{1k,2k} se siguen aceptando.'),
30365
+ styleMix: z128.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
30366
+ generateAdCopy: z128.boolean(),
30367
+ competitorScanEnabled: z128.boolean(),
30368
+ productContext: z128.string().trim().min(1).max(3e3).nullable(),
30369
+ creativeDirection: z128.string().trim().min(1).max(500).nullable(),
30370
+ brandColors: z128.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
30371
+ headline: z128.string().trim().min(1).max(120).nullable(),
30372
+ subheadline: z128.string().trim().min(1).max(160).nullable()
29854
30373
  }).strict()
29855
30374
  ]).superRefine((setup, context) => {
29856
30375
  if (setup.mode !== "guided") return;
29857
30376
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
29858
30377
  if (needsStyleMix && setup.styleMix === null) {
29859
30378
  context.addIssue({
29860
- code: z127.ZodIssueCode.custom,
30379
+ code: z128.ZodIssueCode.custom,
29861
30380
  path: [
29862
30381
  "styleMix"
29863
30382
  ],
@@ -29866,7 +30385,7 @@ var ImageCreativeSetup = z127.discriminatedUnion("mode", [
29866
30385
  }
29867
30386
  if (!needsStyleMix && setup.styleMix !== null) {
29868
30387
  context.addIssue({
29869
- code: z127.ZodIssueCode.custom,
30388
+ code: z128.ZodIssueCode.custom,
29870
30389
  path: [
29871
30390
  "styleMix"
29872
30391
  ],
@@ -29875,7 +30394,7 @@ var ImageCreativeSetup = z127.discriminatedUnion("mode", [
29875
30394
  }
29876
30395
  if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
29877
30396
  context.addIssue({
29878
- code: z127.ZodIssueCode.custom,
30397
+ code: z128.ZodIssueCode.custom,
29879
30398
  path: [
29880
30399
  "aspectRatio"
29881
30400
  ],
@@ -29883,55 +30402,55 @@ var ImageCreativeSetup = z127.discriminatedUnion("mode", [
29883
30402
  });
29884
30403
  }
29885
30404
  });
29886
- var LandingCreativeSetup = z127.discriminatedUnion("mode", [
29887
- z127.object({
29888
- mode: z127.literal("automatic")
30405
+ var LandingCreativeSetup = z128.discriminatedUnion("mode", [
30406
+ z128.object({
30407
+ mode: z128.literal("automatic")
29889
30408
  }).strict(),
29890
- z127.object({
29891
- mode: z127.literal("guided"),
30409
+ z128.object({
30410
+ mode: z128.literal("guided"),
29892
30411
  landingStrategy: LandingStrategyEnum,
29893
30412
  landingImageFormat: LandingImageFormatEnum,
29894
- competitorScanEnabled: z127.boolean(),
29895
- paymentMethods: z127.string().trim().min(1).max(240).nullable(),
29896
- productContext: z127.string().trim().min(1).max(3e3).nullable(),
29897
- creativeDirection: z127.string().trim().min(1).max(500).nullable(),
29898
- headline: z127.string().trim().min(1).max(120).nullable(),
29899
- subheadline: z127.string().trim().min(1).max(160).nullable()
30413
+ competitorScanEnabled: z128.boolean(),
30414
+ paymentMethods: z128.string().trim().min(1).max(240).nullable(),
30415
+ productContext: z128.string().trim().min(1).max(3e3).nullable(),
30416
+ creativeDirection: z128.string().trim().min(1).max(500).nullable(),
30417
+ headline: z128.string().trim().min(1).max(120).nullable(),
30418
+ subheadline: z128.string().trim().min(1).max(160).nullable()
29900
30419
  }).strict()
29901
30420
  ]);
29902
- var ImageInput = z127.object({
30421
+ var ImageInput = z128.object({
29903
30422
  images: CreativeRefs.images.optional(),
29904
30423
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
29905
- productTitle: z127.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
29906
- primaryAngle: z127.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
30424
+ productTitle: z128.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
30425
+ primaryAngle: z128.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
29907
30426
  buyerPersona: CreativeRefs.buyerPersona,
29908
30427
  language: CreativeRefs.language,
29909
30428
  country: CreativeRefs.country,
29910
30429
  creativeSetup: ImageCreativeSetup.describe("Configuraci\xF3n obligatoria equivalente al wizard web. Usa guided salvo que el usuario delegue expl\xEDcitamente todo; presenta las decisiones guiadas en un \xFAnico checklist compacto."),
29911
30430
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
29912
- features: z127.array(z127.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
30431
+ features: z128.array(z128.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
29913
30432
  price: CreativeRefs.price,
29914
- omitPrice: z127.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
30433
+ omitPrice: z128.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
29915
30434
  compareAtPrice: CreativeRefs.compareAtPrice,
29916
30435
  offer: CreativeRefs.offer,
29917
30436
  productLabel: CreativeRefs.productLabel,
29918
30437
  isCombo: CreativeRefs.isCombo,
29919
30438
  brandId: CreativeRefs.brandId
29920
30439
  });
29921
- var EditImageCreativeInput = z127.object({
29922
- taskId: z127.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
29923
- variantIndex: z127.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
29924
- clientRequestId: z127.string().min(1).max(160).optional().describe("Identidad estable de esta correcci\xF3n; reutil\xEDzala al reconciliar una respuesta perdida, no para otra instrucci\xF3n."),
29925
- instruction: z127.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".')
30440
+ var EditImageCreativeInput = z128.object({
30441
+ taskId: z128.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
30442
+ variantIndex: z128.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
30443
+ clientRequestId: z128.string().min(1).max(160).optional().describe("Identidad estable de esta correcci\xF3n; reutil\xEDzala al reconciliar una respuesta perdida, no para otra instrucci\xF3n."),
30444
+ instruction: z128.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".')
29926
30445
  });
29927
- var LandingInput = z127.object({
29928
- includeInitialLandingGif: z127.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
30446
+ var LandingInput = z128.object({
30447
+ includeInitialLandingGif: z128.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
29929
30448
  images: CreativeRefs.images.optional(),
29930
30449
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
29931
30450
  language: CreativeRefs.language,
29932
30451
  country: CreativeRefs.country,
29933
30452
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
29934
- salesAngle: z127.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.'),
30453
+ salesAngle: z128.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.'),
29935
30454
  buyerPersona: CreativeRefs.buyerPersona,
29936
30455
  price: CreativeRefs.price,
29937
30456
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -30213,8 +30732,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
30213
30732
  server.registerTool("get_image_edit_status", {
30214
30733
  description: imageEditStatusGuidance.summary,
30215
30734
  inputSchema: {
30216
- taskId: z127.string().uuid(),
30217
- operationId: z127.string().uuid()
30735
+ taskId: z128.string().uuid(),
30736
+ operationId: z128.string().uuid()
30218
30737
  },
30219
30738
  annotations: READS_INTERNAL
30220
30739
  }, async (input) => {
@@ -30271,10 +30790,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
30271
30790
  __name(registerCreativeTools, "registerCreativeTools");
30272
30791
 
30273
30792
  // src/tools/creative-variants.ts
30274
- import { z as z128 } from "zod";
30793
+ import { z as z129 } from "zod";
30275
30794
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
30276
30795
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
30277
- var LandingSectionKeyEnum = z128.enum([
30796
+ var LandingSectionKeyEnum = z129.enum([
30278
30797
  "problem_hook",
30279
30798
  "problem_cost",
30280
30799
  "solution_mechanism",
@@ -30314,24 +30833,24 @@ var LandingSectionKeyEnum = z128.enum([
30314
30833
  "lifestyle_fit",
30315
30834
  "join_lifestyle"
30316
30835
  ]);
30317
- var CreativeVariantKindEnum = z128.enum([
30836
+ var CreativeVariantKindEnum = z129.enum([
30318
30837
  "video",
30319
30838
  "image",
30320
30839
  "landing"
30321
30840
  ]);
30322
- var EstimateCreativeVariantInputBase = z128.object({
30323
- sourceTaskId: z128.string().uuid().describe("ID de la tarea original completada."),
30841
+ var EstimateCreativeVariantInputBase = z129.object({
30842
+ sourceTaskId: z129.string().uuid().describe("ID de la tarea original completada."),
30324
30843
  kind: CreativeVariantKindEnum,
30325
30844
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
30326
30845
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
30327
- nVariants: z128.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
30846
+ nVariants: z129.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
30328
30847
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
30329
- instructions: z128.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.")
30848
+ instructions: z129.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.")
30330
30849
  }).strict();
30331
30850
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
30332
30851
  if (input.kind === "video" && input.nVariants !== void 0) {
30333
30852
  ctx.addIssue({
30334
- code: z128.ZodIssueCode.custom,
30853
+ code: z129.ZodIssueCode.custom,
30335
30854
  path: [
30336
30855
  "nVariants"
30337
30856
  ],
@@ -30341,7 +30860,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
30341
30860
  if (input.kind !== "video") {
30342
30861
  if (input.videoPreset !== void 0) {
30343
30862
  ctx.addIssue({
30344
- code: z128.ZodIssueCode.custom,
30863
+ code: z129.ZodIssueCode.custom,
30345
30864
  path: [
30346
30865
  "videoPreset"
30347
30866
  ],
@@ -30350,7 +30869,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
30350
30869
  }
30351
30870
  if (input.videoResolution !== void 0) {
30352
30871
  ctx.addIssue({
30353
- code: z128.ZodIssueCode.custom,
30872
+ code: z129.ZodIssueCode.custom,
30354
30873
  path: [
30355
30874
  "videoResolution"
30356
30875
  ],
@@ -30360,7 +30879,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
30360
30879
  }
30361
30880
  if (input.kind !== "image" && input.nVariants !== void 0) {
30362
30881
  ctx.addIssue({
30363
- code: z128.ZodIssueCode.custom,
30882
+ code: z129.ZodIssueCode.custom,
30364
30883
  path: [
30365
30884
  "nVariants"
30366
30885
  ],
@@ -30370,7 +30889,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
30370
30889
  if (input.kind !== "landing") {
30371
30890
  if (input.sectionKey !== void 0) {
30372
30891
  ctx.addIssue({
30373
- code: z128.ZodIssueCode.custom,
30892
+ code: z129.ZodIssueCode.custom,
30374
30893
  path: [
30375
30894
  "sectionKey"
30376
30895
  ],
@@ -30379,7 +30898,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
30379
30898
  }
30380
30899
  if (input.instructions !== void 0) {
30381
30900
  ctx.addIssue({
30382
- code: z128.ZodIssueCode.custom,
30901
+ code: z129.ZodIssueCode.custom,
30383
30902
  path: [
30384
30903
  "instructions"
30385
30904
  ],
@@ -30388,31 +30907,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
30388
30907
  }
30389
30908
  }
30390
30909
  });
30391
- var CreateCreativeVariantInputBase = z128.object({
30392
- sourceTaskId: z128.string().uuid().describe("ID de la tarea original completada."),
30910
+ var CreateCreativeVariantInputBase = z129.object({
30911
+ sourceTaskId: z129.string().uuid().describe("ID de la tarea original completada."),
30393
30912
  kind: CreativeVariantKindEnum,
30394
- confirm: z128.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
30395
- clientRequestId: z128.string().uuid().describe("UUID estable para esta intenci\xF3n (obligatorio por compatibilidad de contrato; el servidor deriva la identidad real del request desde los argumentos sem\xE1nticos, as\xED que un UUID nuevo en un retry NO crea una variante duplicada). Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n."),
30396
- angle: z128.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
30397
- buyerPersona: z128.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
30398
- scriptNotes: z128.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
30399
- creativeDirection: z128.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
30913
+ confirm: z129.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
30914
+ clientRequestId: z129.string().uuid().describe("UUID estable para esta intenci\xF3n (obligatorio por compatibilidad de contrato; el servidor deriva la identidad real del request desde los argumentos sem\xE1nticos, as\xED que un UUID nuevo en un retry NO crea una variante duplicada). Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n."),
30915
+ angle: z129.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
30916
+ buyerPersona: z129.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
30917
+ scriptNotes: z129.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
30918
+ creativeDirection: z129.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
30400
30919
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
30401
30920
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
30402
- generateAiMusic: z128.boolean().optional().describe("Opcional para video."),
30403
- nVariants: z128.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
30921
+ generateAiMusic: z129.boolean().optional().describe("Opcional para video."),
30922
+ nVariants: z129.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
30404
30923
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
30405
30924
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
30406
30925
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
30407
30926
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
30408
- styleMix: z128.boolean().optional().describe("Opcional para imagen."),
30927
+ styleMix: z129.boolean().optional().describe("Opcional para imagen."),
30409
30928
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
30410
- instructions: z128.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.")
30929
+ instructions: z129.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.")
30411
30930
  }).strict();
30412
30931
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
30413
30932
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
30414
30933
  ctx.addIssue({
30415
- code: z128.ZodIssueCode.custom,
30934
+ code: z129.ZodIssueCode.custom,
30416
30935
  path: [
30417
30936
  "angle"
30418
30937
  ],
@@ -30421,7 +30940,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
30421
30940
  }
30422
30941
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
30423
30942
  ctx.addIssue({
30424
- code: z128.ZodIssueCode.custom,
30943
+ code: z129.ZodIssueCode.custom,
30425
30944
  path: [
30426
30945
  "instructions"
30427
30946
  ],
@@ -30467,7 +30986,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
30467
30986
  for (const field of fieldsByKind[input.kind]) {
30468
30987
  if (input[field] !== void 0) {
30469
30988
  ctx.addIssue({
30470
- code: z128.ZodIssueCode.custom,
30989
+ code: z129.ZodIssueCode.custom,
30471
30990
  path: [
30472
30991
  field
30473
30992
  ],
@@ -30625,13 +31144,13 @@ function registerCreativeVariantTools(server, api) {
30625
31144
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
30626
31145
 
30627
31146
  // src/tools/script-review.ts
30628
- import { z as z129 } from "zod";
31147
+ import { z as z130 } from "zod";
30629
31148
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
30630
31149
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
30631
31150
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
30632
- var GetVideoScriptInput = z129.object({
30633
- taskId: z129.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
30634
- angleKey: z129.string().min(1).optional().describe('Clave persistida del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). Usa exactamente el angleKey recibido en reviewNextAction.calls al aprobar \xE1ngulos, incluso si s\xF3lo elegiste uno. Si se omite, el backend resuelve a "angle_0" literal; elegir el segundo candidato no crea angle_0. No derives esta clave del n\xFAmero visible del candidato.')
31151
+ var GetVideoScriptInput = z130.object({
31152
+ taskId: z130.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
31153
+ angleKey: z130.string().min(1).optional().describe('Clave persistida del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). Usa exactamente el angleKey recibido en reviewNextAction.calls al aprobar \xE1ngulos, incluso si s\xF3lo elegiste uno. Si se omite, el backend resuelve a "angle_0" literal; elegir el segundo candidato no crea angle_0. No derives esta clave del n\xFAmero visible del candidato.')
30635
31154
  }).strict();
30636
31155
  var ApproveVideoScriptInput = ApproveVideoScriptCapabilityRequest;
30637
31156
  var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
@@ -30736,7 +31255,7 @@ Consulta get_task_status con esta tarea antes de reintentar. Si la tarea termin\
30736
31255
  __name(registerScriptReviewTools, "registerScriptReviewTools");
30737
31256
 
30738
31257
  // src/tools/connections.ts
30739
- import { z as z130 } from "zod";
31258
+ import { z as z131 } from "zod";
30740
31259
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
30741
31260
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
30742
31261
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
@@ -30745,7 +31264,7 @@ var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list
30745
31264
  function registerConnectionTools(server, api) {
30746
31265
  server.registerTool("list_shopify_shops", {
30747
31266
  description: listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.",
30748
- inputSchema: z130.object({}).shape,
31267
+ inputSchema: z131.object({}).shape,
30749
31268
  annotations: READS_INTERNAL
30750
31269
  }, async () => {
30751
31270
  try {
@@ -30757,10 +31276,10 @@ function registerConnectionTools(server, api) {
30757
31276
  });
30758
31277
  server.registerTool("list_shopify_products", {
30759
31278
  description: listShopifyProductsGuidance.summary + ' Usa el `id` devuelto junto con `publicationMode="existing"` en `publish_to_shopify`. Si `taskId` se proporciona, la respuesta tambi\xE9n indica el producto publicado actualmente para esa tarea y tienda. No modifica Shopify.',
30760
- inputSchema: z130.object({
30761
- shopDomain: z130.string().min(3).max(120),
30762
- query: z130.string().trim().max(120).optional(),
30763
- taskId: z130.string().uuid().optional()
31279
+ inputSchema: z131.object({
31280
+ shopDomain: z131.string().min(3).max(120),
31281
+ query: z131.string().trim().max(120).optional(),
31282
+ taskId: z131.string().uuid().optional()
30764
31283
  }).shape,
30765
31284
  annotations: READS_EXTERNAL
30766
31285
  }, async ({ shopDomain, query, taskId }) => {
@@ -30778,7 +31297,7 @@ function registerConnectionTools(server, api) {
30778
31297
  });
30779
31298
  server.registerTool("list_meta_ad_accounts", {
30780
31299
  description: listMetaAdAccountsGuidance.summary + " Para publicar, prefiere `list_meta_destinations`, que tambi\xE9n devuelve el portfolio y las p\xE1ginas disponibles. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.",
30781
- inputSchema: z130.object({}).shape,
31300
+ inputSchema: z131.object({}).shape,
30782
31301
  annotations: READS_EXTERNAL
30783
31302
  }, async () => {
30784
31303
  try {
@@ -30790,7 +31309,7 @@ function registerConnectionTools(server, api) {
30790
31309
  });
30791
31310
  server.registerTool("list_meta_destinations", {
30792
31311
  description: listMetaDestinationsGuidance.summary + " Es obligatorio llamar esta herramienta antes de publicar, mostrar las opciones y enviar al publicador el `portfolioId`, `adAccountId` y `pageId` elegidos; nunca elijas silenciosamente la primera p\xE1gina o cuenta. No modifica Meta.",
30793
- inputSchema: z130.object({}).shape,
31312
+ inputSchema: z131.object({}).shape,
30794
31313
  annotations: READS_EXTERNAL,
30795
31314
  _meta: {
30796
31315
  "openai/widgetAccessible": true
@@ -30805,7 +31324,7 @@ function registerConnectionTools(server, api) {
30805
31324
  });
30806
31325
  server.registerTool("list_tiktok_advertisers", {
30807
31326
  description: listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.",
30808
- inputSchema: z130.object({}).shape,
31327
+ inputSchema: z131.object({}).shape,
30809
31328
  annotations: READS_EXTERNAL
30810
31329
  }, async () => {
30811
31330
  try {
@@ -30819,7 +31338,7 @@ function registerConnectionTools(server, api) {
30819
31338
  __name(registerConnectionTools, "registerConnectionTools");
30820
31339
 
30821
31340
  // src/tools/actors.ts
30822
- import { z as z131 } from "zod";
31341
+ import { z as z132 } from "zod";
30823
31342
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
30824
31343
  var actorVoiceGuidance = {
30825
31344
  capabilities: getProductMakerCapabilityModelGuidance("get_actor_voice_capabilities"),
@@ -30859,7 +31378,7 @@ function sanitizeVoiceResult(value) {
30859
31378
  __name(sanitizeVoiceResult, "sanitizeVoiceResult");
30860
31379
  function registerActorTools(server, api) {
30861
31380
  const actor = {
30862
- actorId: z131.string().min(1).max(64)
31381
+ actorId: z132.string().min(1).max(64)
30863
31382
  };
30864
31383
  const safe = /* @__PURE__ */ __name(async (request) => {
30865
31384
  try {
@@ -30888,8 +31407,8 @@ function registerActorTools(server, api) {
30888
31407
  inputSchema: {
30889
31408
  ...actor,
30890
31409
  draft: ActorVoiceDraftSchema,
30891
- requestKey: z131.string().trim().min(1).max(128),
30892
- acceptedQuoteId: z131.string().trim().min(1).max(128)
31410
+ requestKey: z132.string().trim().min(1).max(128),
31411
+ acceptedQuoteId: z132.string().trim().min(1).max(128)
30893
31412
  },
30894
31413
  annotations: CREATES_PAID
30895
31414
  }, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/previews`, body)));
@@ -30897,7 +31416,7 @@ function registerActorTools(server, api) {
30897
31416
  description: actorVoiceGuidance.get.summary,
30898
31417
  inputSchema: {
30899
31418
  ...actor,
30900
- candidateId: z131.string().min(1).max(64)
31419
+ candidateId: z132.string().min(1).max(64)
30901
31420
  },
30902
31421
  // Polling can resume the first paid submission of an accepted quote.
30903
31422
  // The immutable candidate/operation key keeps recovery idempotent.
@@ -30910,16 +31429,16 @@ function registerActorTools(server, api) {
30910
31429
  description: actorVoiceGuidance.approve.summary,
30911
31430
  inputSchema: {
30912
31431
  ...actor,
30913
- candidateId: z131.string().min(1).max(64),
30914
- expectedRevision: z131.number().int().positive(),
30915
- expectedApprovedRevision: z131.number().int().positive().nullable().optional()
31432
+ candidateId: z132.string().min(1).max(64),
31433
+ expectedRevision: z132.number().int().positive(),
31434
+ expectedApprovedRevision: z132.number().int().positive().nullable().optional()
30916
31435
  },
30917
31436
  // Replaces the selected voice and withdraws the old catalog grants.
30918
31437
  annotations: OVERWRITES_INTERNAL
30919
31438
  }, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/approve`, body)));
30920
31439
  server.registerTool("list_actors", {
30921
31440
  description: listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz privada del personaje. Cuando el personaje tiene una voz personalizada, `voice.identityId` y `voice.revision` identifican la versi\xF3n aprobada \u2014 conserva la revisi\xF3n al llamar `approve_actor_voice` (expectedApprovedRevision) para reemplazarla. Los IDs de proveedor nunca se exponen por MCP. 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.",
30922
- inputSchema: z131.object({}).shape,
31441
+ inputSchema: z132.object({}).shape,
30923
31442
  annotations: READS_INTERNAL
30924
31443
  }, async () => {
30925
31444
  try {
@@ -30952,7 +31471,7 @@ function registerActorTools(server, api) {
30952
31471
  __name(registerActorTools, "registerActorTools");
30953
31472
 
30954
31473
  // src/tools/publish.ts
30955
- import { z as z132 } from "zod";
31474
+ import { z as z133 } from "zod";
30956
31475
 
30957
31476
  // src/tools/meta-publish-attempt-id.ts
30958
31477
  var META_PUBLISH_NAMESPACE = "7b19c9ac-b4eb-4db1-970e-c2f24ce30b98";
@@ -30991,40 +31510,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
30991
31510
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
30992
31511
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
30993
31512
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
30994
- var ShopifyInput = z132.object({
30995
- taskId: z132.string().min(1),
30996
- shopDomain: z132.string().min(1),
31513
+ var ShopifyInput = z133.object({
31514
+ taskId: z133.string().min(1),
31515
+ shopDomain: z133.string().min(1),
30997
31516
  /** Override: number of landing images to include. Default = ALL images the
30998
31517
  * task generated (the MCP fetches /v1/results first to count). Bounded
30999
31518
  * generously here; the backend validates each index against
31000
31519
  * landing.images.length and rejects out-of-range. */
31001
- numLandingImages: z132.number().int().min(1).max(20).optional(),
31002
- variantIndex: z132.number().int().min(0).optional(),
31520
+ numLandingImages: z133.number().int().min(1).max(20).optional(),
31521
+ variantIndex: z133.number().int().min(0).optional(),
31003
31522
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
31004
31523
  * When true, the landing renders variant-picker pills; when false, it ships
31005
31524
  * a single-option product page. Defaults to false. */
31006
- showVariantPicker: z132.boolean().optional(),
31525
+ showVariantPicker: z133.boolean().optional(),
31007
31526
  /** Default `auto` updates the product previously published for this task and
31008
31527
  * shop. Use `existing` with targetProductId to choose another product, or
31009
31528
  * `new` only when the user explicitly wants a duplicate/new listing. */
31010
- publicationMode: z132.enum([
31529
+ publicationMode: z133.enum([
31011
31530
  "auto",
31012
31531
  "existing",
31013
31532
  "new"
31014
31533
  ]).optional(),
31015
31534
  /** Shopify product GID, numeric id, or admin product URL. Required when
31016
31535
  * publicationMode is `existing`. */
31017
- targetProductId: z132.string().trim().min(1).max(300).optional(),
31536
+ targetProductId: z133.string().trim().min(1).max(300).optional(),
31018
31537
  /** Add an announcement bar text above add-to-cart (optional). */
31019
- announcementBarEnabled: z132.boolean().optional(),
31020
- announcementBarText: z132.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
31538
+ announcementBarEnabled: z133.boolean().optional(),
31539
+ announcementBarText: z133.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
31021
31540
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
31022
- confirmed: z132.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
31541
+ confirmed: z133.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
31023
31542
  });
31024
31543
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
31025
31544
  if (value.commerceCorrection && value.confirmed !== true) {
31026
31545
  ctx.addIssue({
31027
- code: z132.ZodIssueCode.custom,
31546
+ code: z133.ZodIssueCode.custom,
31028
31547
  path: [
31029
31548
  "confirmed"
31030
31549
  ],
@@ -31033,7 +31552,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
31033
31552
  }
31034
31553
  if (value.announcementBarEnabled && !value.announcementBarText) {
31035
31554
  ctx.addIssue({
31036
- code: z132.ZodIssueCode.custom,
31555
+ code: z133.ZodIssueCode.custom,
31037
31556
  path: [
31038
31557
  "announcementBarText"
31039
31558
  ],
@@ -31042,7 +31561,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
31042
31561
  }
31043
31562
  if (!value.announcementBarEnabled && value.announcementBarText) {
31044
31563
  ctx.addIssue({
31045
- code: z132.ZodIssueCode.custom,
31564
+ code: z133.ZodIssueCode.custom,
31046
31565
  path: [
31047
31566
  "announcementBarText"
31048
31567
  ],
@@ -31056,90 +31575,90 @@ function parseShopifyInput(rawInput) {
31056
31575
  return parsed.data;
31057
31576
  }
31058
31577
  __name(parseShopifyInput, "parseShopifyInput");
31059
- var McpCampaignConfig = z132.object({
31578
+ var McpCampaignConfig = z133.object({
31060
31579
  /** Legacy USD amount. Meta retains its existing conversion; the TikTok
31061
31580
  * schema below restricts this input to USD advertiser accounts. */
31062
- dailyBudgetUsd: z132.number().positive().optional(),
31581
+ dailyBudgetUsd: z133.number().positive().optional(),
31063
31582
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
31064
31583
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
31065
31584
  * TikTok takes only the first entry. */
31066
- targetCountries: z132.array(CountryIso2Schema).max(1).optional(),
31067
- campaignName: z132.string().trim().min(1).max(100).optional()
31585
+ targetCountries: z133.array(CountryIso2Schema).max(1).optional(),
31586
+ campaignName: z133.string().trim().min(1).max(100).optional()
31068
31587
  });
31069
31588
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
31070
- var MetaInput = z132.object({
31071
- taskId: z132.string().min(1),
31589
+ var MetaInput = z133.object({
31590
+ taskId: z133.string().min(1),
31072
31591
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
31073
- portfolioId: z132.string().trim().min(1),
31592
+ portfolioId: z133.string().trim().min(1),
31074
31593
  /** Exact Facebook Page selected from `list_meta_destinations`. */
31075
- pageId: z132.string().trim().min(1),
31594
+ pageId: z133.string().trim().min(1),
31076
31595
  adAccountId: McpAdAccountId,
31077
- pixelId: z132.string().min(1).optional(),
31078
- landingUrl: z132.string().url().optional(),
31596
+ pixelId: z133.string().min(1).optional(),
31597
+ landingUrl: z133.string().url().optional(),
31079
31598
  /** Select which angles to publish by 0-based index. Omit to publish all
31080
31599
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
31081
- angleIndexes: z132.array(z132.number().int().nonnegative()).optional(),
31600
+ angleIndexes: z133.array(z133.number().int().nonnegative()).optional(),
31082
31601
  campaignConfig: McpCampaignConfig.optional(),
31083
31602
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
31084
31603
  * uses the auto-generated copy attached to the task. Capped at 500 chars
31085
31604
  * (Meta's primary-text limit). */
31086
- primaryText: z132.string().trim().min(1).max(500).optional(),
31605
+ primaryText: z133.string().trim().min(1).max(500).optional(),
31087
31606
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
31088
31607
  * (wa.me) instead of a landing page. */
31089
- phoneNumber: z132.string().min(8).max(32).optional()
31608
+ phoneNumber: z133.string().min(8).max(32).optional()
31090
31609
  });
31091
- var GroupedTaskSource = z132.object({
31092
- type: z132.literal("task"),
31093
- taskId: z132.string().min(1),
31094
- angleIndex: z132.number().int().min(0).optional(),
31095
- videoVariant: z132.enum([
31610
+ var GroupedTaskSource = z133.object({
31611
+ type: z133.literal("task"),
31612
+ taskId: z133.string().min(1),
31613
+ angleIndex: z133.number().int().min(0).optional(),
31614
+ videoVariant: z133.enum([
31096
31615
  "with_subtitles",
31097
31616
  "without_subtitles"
31098
31617
  ]).optional(),
31099
- imageVariantIndex: z132.number().int().min(0).optional()
31100
- });
31101
- var GroupedMediaSource = z132.object({
31102
- type: z132.literal("media"),
31103
- url: z132.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
31104
- path: z132.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
31105
- thumbnailUrl: z132.string().url().optional(),
31106
- thumbnailPath: z132.string().min(1).optional()
31618
+ imageVariantIndex: z133.number().int().min(0).optional()
31619
+ });
31620
+ var GroupedMediaSource = z133.object({
31621
+ type: z133.literal("media"),
31622
+ url: z133.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
31623
+ path: z133.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
31624
+ thumbnailUrl: z133.string().url().optional(),
31625
+ thumbnailPath: z133.string().min(1).optional()
31107
31626
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
31108
31627
  message: "media source needs exactly one of `url` or `path`"
31109
31628
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
31110
31629
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
31111
31630
  });
31112
- var GroupedUploadedAssetSource = z132.object({
31113
- type: z132.literal("asset"),
31631
+ var GroupedUploadedAssetSource = z133.object({
31632
+ type: z133.literal("asset"),
31114
31633
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
31115
- assetId: z132.string().uuid(),
31116
- thumbnailAssetId: z132.string().uuid().optional()
31634
+ assetId: z133.string().uuid(),
31635
+ thumbnailAssetId: z133.string().uuid().optional()
31117
31636
  });
31118
- var GroupedCreative = z132.object({
31119
- type: z132.enum([
31637
+ var GroupedCreative = z133.object({
31638
+ type: z133.enum([
31120
31639
  "image",
31121
31640
  "video"
31122
31641
  ]),
31123
- source: z132.union([
31642
+ source: z133.union([
31124
31643
  GroupedTaskSource,
31125
31644
  GroupedMediaSource,
31126
31645
  GroupedUploadedAssetSource
31127
31646
  ]),
31128
- title: z132.string().max(120).optional(),
31129
- description: z132.string().max(500).optional(),
31647
+ title: z133.string().max(120).optional(),
31648
+ description: z133.string().max(500).optional(),
31130
31649
  cta: MetaCtaType.optional(),
31131
- creativeId: z132.string().min(1).optional()
31650
+ creativeId: z133.string().min(1).optional()
31132
31651
  });
31133
- var GroupedCampaignConfigBase = z132.object({
31652
+ var GroupedCampaignConfigBase = z133.object({
31134
31653
  campaignType: MetaCampaignType.default("sales"),
31135
31654
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
31136
31655
  budgetMode: MetaBudgetMode.optional(),
31137
- campaignDailyBudget: z132.number().int().positive().optional(),
31138
- adSets: z132.array(z132.object({
31139
- tempId: z132.string().min(1).max(80),
31140
- name: z132.string().min(1).max(100),
31141
- dailyBudget: z132.number().int().positive().optional(),
31142
- creativeIds: z132.array(z132.string().min(1)).min(1)
31656
+ campaignDailyBudget: z133.number().int().positive().optional(),
31657
+ adSets: z133.array(z133.object({
31658
+ tempId: z133.string().min(1).max(80),
31659
+ name: z133.string().min(1).max(100),
31660
+ dailyBudget: z133.number().int().positive().optional(),
31661
+ creativeIds: z133.array(z133.string().min(1)).min(1)
31143
31662
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
31144
31663
  /**
31145
31664
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -31147,17 +31666,17 @@ var GroupedCampaignConfigBase = z132.object({
31147
31666
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
31148
31667
  * the API since #849 — unreachable from this tool.
31149
31668
  */
31150
- destination: z132.discriminatedUnion("type", [
31151
- z132.object({
31152
- type: z132.literal("landing"),
31153
- landingUrl: z132.string().url()
31669
+ destination: z133.discriminatedUnion("type", [
31670
+ z133.object({
31671
+ type: z133.literal("landing"),
31672
+ landingUrl: z133.string().url()
31154
31673
  }),
31155
- z132.object({
31156
- type: z132.literal("whatsapp"),
31157
- phoneNumber: z132.string().min(8).max(32)
31674
+ z133.object({
31675
+ type: z133.literal("whatsapp"),
31676
+ phoneNumber: z133.string().min(8).max(32)
31158
31677
  })
31159
31678
  ]),
31160
- saveAsDefault: z132.boolean().default(false),
31679
+ saveAsDefault: z133.boolean().default(false),
31161
31680
  budgetPolicy: MetaBudgetPolicy.optional()
31162
31681
  });
31163
31682
  function resolveBudgetMode(value) {
@@ -31171,7 +31690,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
31171
31690
  const budgetMode = resolveBudgetMode(value);
31172
31691
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
31173
31692
  ctx.addIssue({
31174
- code: z132.ZodIssueCode.custom,
31693
+ code: z133.ZodIssueCode.custom,
31175
31694
  path: [
31176
31695
  "campaignDailyBudget"
31177
31696
  ],
@@ -31182,7 +31701,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
31182
31701
  value.adSets.forEach((adSet, index) => {
31183
31702
  if (adSet.dailyBudget === void 0) {
31184
31703
  ctx.addIssue({
31185
- code: z132.ZodIssueCode.custom,
31704
+ code: z133.ZodIssueCode.custom,
31186
31705
  path: [
31187
31706
  "adSets",
31188
31707
  index,
@@ -31197,25 +31716,25 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
31197
31716
  ...value,
31198
31717
  budgetMode: resolveBudgetMode(value)
31199
31718
  }));
31200
- var PublishCreativesToMetaInputBase = z132.object({
31201
- creatives: z132.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
31719
+ var PublishCreativesToMetaInputBase = z133.object({
31720
+ creatives: z133.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
31202
31721
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
31203
- portfolioId: z132.string().trim().min(1),
31722
+ portfolioId: z133.string().trim().min(1),
31204
31723
  /** Exact Facebook Page selected from `list_meta_destinations`. */
31205
- pageId: z132.string().trim().min(1),
31724
+ pageId: z133.string().trim().min(1),
31206
31725
  adAccountId: McpAdAccountId,
31207
- pixelId: z132.string().min(1).optional(),
31726
+ pixelId: z133.string().min(1).optional(),
31208
31727
  /** Required unless `campaignConfig.destination` is whatsapp or a creative
31209
31728
  * comes from a task (the API then lands on the published service landing
31210
31729
  * of its service tasks) — see the superRefine below. Mirrors the API's
31211
31730
  * `FacebookCreateCampaignFromTasksBodySchema`. */
31212
- landingUrl: z132.string().url().optional(),
31731
+ landingUrl: z133.string().url().optional(),
31213
31732
  /** ISO-2 code or resolvable country name — mirrors the API contract
31214
31733
  * (CountryIso2Schema), which normalizes names to alpha-2 at validation.
31215
31734
  * Omitted: the brand country of its service tasks (the API answers
31216
31735
  * META_NO_TARGET_COUNTRY when it has none); "US" for products. */
31217
31736
  targetCountry: CountryIso2Schema.optional(),
31218
- campaignName: z132.string().trim().min(1).max(100),
31737
+ campaignName: z133.string().trim().min(1).max(100),
31219
31738
  campaignConfig: GroupedCampaignConfig.optional()
31220
31739
  });
31221
31740
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
@@ -31223,7 +31742,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
31223
31742
  const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
31224
31743
  if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl && !hasTaskCreative) {
31225
31744
  ctx.addIssue({
31226
- code: z132.ZodIssueCode.custom,
31745
+ code: z133.ZodIssueCode.custom,
31227
31746
  path: [
31228
31747
  "landingUrl"
31229
31748
  ],
@@ -31232,7 +31751,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
31232
31751
  }
31233
31752
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
31234
31753
  ctx.addIssue({
31235
- code: z132.ZodIssueCode.custom,
31754
+ code: z133.ZodIssueCode.custom,
31236
31755
  path: [
31237
31756
  "campaignConfig",
31238
31757
  "destination",
@@ -31251,16 +31770,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
31251
31770
  }
31252
31771
  return value;
31253
31772
  });
31254
- var PresignUploadResponseSchema = z132.object({
31255
- uploadUrl: z132.string().url().refine((value) => {
31773
+ var PresignUploadResponseSchema = z133.object({
31774
+ uploadUrl: z133.string().url().refine((value) => {
31256
31775
  const url = new URL(value);
31257
31776
  return !url.username && !url.password && url.protocol === "https:";
31258
31777
  }, "presigned upload URL must be HTTPS without embedded credentials"),
31259
- publicUrl: z132.string().url().refine((value) => {
31778
+ publicUrl: z133.string().url().refine((value) => {
31260
31779
  const url = new URL(value);
31261
31780
  return !url.username && !url.password;
31262
31781
  }, "public media URL must not contain embedded credentials"),
31263
- stagingAssetId: z132.string().uuid()
31782
+ stagingAssetId: z133.string().uuid()
31264
31783
  });
31265
31784
  async function uploadResolvedMedia(api, media, assetRole) {
31266
31785
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -31286,14 +31805,14 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
31286
31805
  }
31287
31806
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
31288
31807
  var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
31289
- dailyBudgetUsd: z132.number().finite().positive().optional().describe("Legacy USD amount, supported only for USD advertiser accounts. No FX conversion."),
31290
- dailyBudget: z132.number().finite().positive().optional().describe("Daily budget in the selected advertiser currency major units; pass budgetCurrency together."),
31808
+ dailyBudgetUsd: z133.number().finite().positive().optional().describe("Legacy USD amount, supported only for USD advertiser accounts. No FX conversion."),
31809
+ dailyBudget: z133.number().finite().positive().optional().describe("Daily budget in the selected advertiser currency major units; pass budgetCurrency together."),
31291
31810
  budgetCurrency: TikTokBudgetCurrencySchema.optional(),
31292
31811
  destination: TikTokCampaignDestinationSchema.optional()
31293
31812
  }).superRefine((value, ctx) => {
31294
31813
  if (value.dailyBudgetUsd !== void 0 && (value.dailyBudget !== void 0 || value.budgetCurrency !== void 0)) {
31295
31814
  ctx.addIssue({
31296
- code: z132.ZodIssueCode.custom,
31815
+ code: z133.ZodIssueCode.custom,
31297
31816
  path: [
31298
31817
  "dailyBudgetUsd"
31299
31818
  ],
@@ -31302,7 +31821,7 @@ var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
31302
31821
  }
31303
31822
  if (value.dailyBudget !== void 0 !== (value.budgetCurrency !== void 0)) {
31304
31823
  ctx.addIssue({
31305
- code: z132.ZodIssueCode.custom,
31824
+ code: z133.ZodIssueCode.custom,
31306
31825
  path: [
31307
31826
  "budgetCurrency"
31308
31827
  ],
@@ -31310,16 +31829,16 @@ var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
31310
31829
  });
31311
31830
  }
31312
31831
  });
31313
- var TikTokInput = z132.object({
31314
- taskId: z132.string().min(1),
31315
- advertiserId: z132.string().min(1),
31316
- pixelId: z132.string().min(1).optional(),
31317
- landingUrl: z132.string().url().optional(),
31318
- angleIndexes: z132.array(z132.number().int().nonnegative()).optional(),
31832
+ var TikTokInput = z133.object({
31833
+ taskId: z133.string().min(1),
31834
+ advertiserId: z133.string().min(1),
31835
+ pixelId: z133.string().min(1).optional(),
31836
+ landingUrl: z133.string().url().optional(),
31837
+ angleIndexes: z133.array(z133.number().int().nonnegative()).optional(),
31319
31838
  campaignConfig: TikTokMcpCampaignConfig.optional(),
31320
31839
  /** Override the ad's description (TikTok's body copy). If omitted,
31321
31840
  * ProductMaker uses the auto-generated copy attached to the task. */
31322
- primaryText: z132.string().trim().min(1).max(500).optional()
31841
+ primaryText: z133.string().trim().min(1).max(500).optional()
31323
31842
  });
31324
31843
  function registerPublishTools(server, api, opts = {}) {
31325
31844
  const transport = opts.transport ?? "http";
@@ -31678,39 +32197,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
31678
32197
 
31679
32198
  // src/tools/meta-upload.ts
31680
32199
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
31681
- import { z as z133 } from "zod";
32200
+ import { z as z134 } from "zod";
31682
32201
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
31683
- var UploadSessionInputBase = z133.object({
31684
- mediaKind: z133.enum([
32202
+ var UploadSessionInputBase = z134.object({
32203
+ mediaKind: z134.enum([
31685
32204
  "image",
31686
32205
  "video",
31687
32206
  "mixed"
31688
32207
  ]).default("mixed").describe("The kind of file the user will select. Use image for product references and landing pages, video for a single video, and mixed only when the consumer supports both."),
31689
- assetRole: z133.enum([
32208
+ assetRole: z134.enum([
31690
32209
  "media",
31691
32210
  "thumbnail"
31692
32211
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
31693
- uploadPurpose: z133.enum([
32212
+ uploadPurpose: z134.enum([
31694
32213
  "product_reference",
31695
32214
  "creative",
31696
32215
  "generic"
31697
32216
  ]).default("generic").describe("The user's purpose for these files. Use product_reference for a product photo used by tasks or landings, creative for media that will become an ad or creative, and generic only when neither applies."),
31698
- maxFiles: z133.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
32217
+ maxFiles: z134.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
31699
32218
  });
31700
- var OpenAiFileReference = z133.object({
31701
- download_url: z133.string().url().describe("Required by ChatGPT's openai/fileParams schema. The App prefers getFileDownloadUrl(file_id) for a fresh URL, and the server never fetches this value."),
31702
- file_id: z133.string().min(1),
31703
- mime_type: z133.string().min(1).optional(),
31704
- file_name: z133.string().min(1).optional()
32219
+ var OpenAiFileReference = z134.object({
32220
+ download_url: z134.string().url().describe("Required by ChatGPT's openai/fileParams schema. The App prefers getFileDownloadUrl(file_id) for a fresh URL, and the server never fetches this value."),
32221
+ file_id: z134.string().min(1),
32222
+ mime_type: z134.string().min(1).optional(),
32223
+ file_name: z134.string().min(1).optional()
31705
32224
  });
31706
32225
  var UploadSessionToolInputShape = {
31707
32226
  ...UploadSessionInputBase.shape,
31708
- files: z133.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.")
32227
+ files: z134.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.")
31709
32228
  };
31710
- var UploadSessionToolInput = z133.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
32229
+ var UploadSessionToolInput = z134.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
31711
32230
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
31712
32231
  ctx.addIssue({
31713
- code: z133.ZodIssueCode.custom,
32232
+ code: z134.ZodIssueCode.custom,
31714
32233
  path: [
31715
32234
  "mediaKind"
31716
32235
  ],
@@ -31719,7 +32238,7 @@ var UploadSessionToolInput = z133.object(UploadSessionToolInputShape).superRefin
31719
32238
  }
31720
32239
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
31721
32240
  ctx.addIssue({
31722
- code: z133.ZodIssueCode.custom,
32241
+ code: z134.ZodIssueCode.custom,
31723
32242
  path: [
31724
32243
  "maxFiles"
31725
32244
  ],
@@ -31728,7 +32247,7 @@ var UploadSessionToolInput = z133.object(UploadSessionToolInputShape).superRefin
31728
32247
  }
31729
32248
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
31730
32249
  ctx.addIssue({
31731
- code: z133.ZodIssueCode.custom,
32250
+ code: z134.ZodIssueCode.custom,
31732
32251
  path: [
31733
32252
  "maxFiles"
31734
32253
  ],
@@ -31736,38 +32255,38 @@ var UploadSessionToolInput = z133.object(UploadSessionToolInputShape).superRefin
31736
32255
  });
31737
32256
  }
31738
32257
  });
31739
- var UploadSessionResponse = z133.object({
31740
- sessionId: z133.string().uuid(),
31741
- uploadPageUrl: z133.string().url(),
31742
- mediaKind: z133.enum([
32258
+ var UploadSessionResponse = z134.object({
32259
+ sessionId: z134.string().uuid(),
32260
+ uploadPageUrl: z134.string().url(),
32261
+ mediaKind: z134.enum([
31743
32262
  "image",
31744
32263
  "video",
31745
32264
  "mixed"
31746
32265
  ]),
31747
- assetRole: z133.enum([
32266
+ assetRole: z134.enum([
31748
32267
  "media",
31749
32268
  "thumbnail"
31750
32269
  ]),
31751
- maxFiles: z133.number().int().positive(),
31752
- expiresAt: z133.string().datetime()
32270
+ maxFiles: z134.number().int().positive(),
32271
+ expiresAt: z134.string().datetime()
31753
32272
  });
31754
- var UploadStatusInput = z133.object({
31755
- sessionId: z133.string().uuid().describe("The sessionId returned by request_media_upload.")
32273
+ var UploadStatusInput = z134.object({
32274
+ sessionId: z134.string().uuid().describe("The sessionId returned by request_media_upload.")
31756
32275
  });
31757
- var UniversalUploadStatusResponse = z133.discriminatedUnion("status", [
31758
- z133.object({
31759
- status: z133.literal("pending"),
31760
- assets: z133.array(z133.never()).length(0)
32276
+ var UniversalUploadStatusResponse = z134.discriminatedUnion("status", [
32277
+ z134.object({
32278
+ status: z134.literal("pending"),
32279
+ assets: z134.array(z134.never()).length(0)
31761
32280
  }),
31762
- z133.object({
31763
- status: z133.literal("uploaded"),
31764
- assets: z133.array(z133.object({
31765
- assetId: z133.string().uuid(),
31766
- mediaKind: z133.enum([
32281
+ z134.object({
32282
+ status: z134.literal("uploaded"),
32283
+ assets: z134.array(z134.object({
32284
+ assetId: z134.string().uuid(),
32285
+ mediaKind: z134.enum([
31767
32286
  "image",
31768
32287
  "video"
31769
32288
  ]),
31770
- assetRole: z133.enum([
32289
+ assetRole: z134.enum([
31771
32290
  "media",
31772
32291
  "thumbnail"
31773
32292
  ])
@@ -31775,13 +32294,13 @@ var UniversalUploadStatusResponse = z133.discriminatedUnion("status", [
31775
32294
  })
31776
32295
  ]);
31777
32296
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
31778
- uploadPurpose: z133.enum([
32297
+ uploadPurpose: z134.enum([
31779
32298
  "product_reference",
31780
32299
  "creative",
31781
32300
  "generic"
31782
32301
  ]),
31783
- checkToolName: z133.literal("check_media_upload"),
31784
- resolveEndpoint: z133.string().url()
32302
+ checkToolName: z134.literal("check_media_upload"),
32303
+ resolveEndpoint: z134.string().url()
31785
32304
  });
31786
32305
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
31787
32306
  const url = new URL(uploadPageUrl);
@@ -31872,15 +32391,15 @@ function registerMediaUploadTools(server, api) {
31872
32391
  __name(registerMediaUploadTools, "registerMediaUploadTools");
31873
32392
 
31874
32393
  // src/tools/campaigns.ts
31875
- import { z as z134 } from "zod";
32394
+ import { z as z135 } from "zod";
31876
32395
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
31877
32396
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
31878
- var MetaStatusInput = z134.object({
31879
- campaignId: z134.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
32397
+ var MetaStatusInput = z135.object({
32398
+ campaignId: z135.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
31880
32399
  });
31881
- var TikTokStatusInput = z134.object({
31882
- campaignId: z134.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
31883
- advertiserId: z134.string().min(1).describe("The same advertiserId used to publish the campaign.")
32400
+ var TikTokStatusInput = z135.object({
32401
+ campaignId: z135.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
32402
+ advertiserId: z135.string().min(1).describe("The same advertiserId used to publish the campaign.")
31884
32403
  });
31885
32404
  function registerCampaignTools(server, api) {
31886
32405
  server.registerTool("get_meta_campaign_status", {
@@ -31985,10 +32504,10 @@ function renderTikTokStatusMarkdown(r) {
31985
32504
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
31986
32505
 
31987
32506
  // ../../packages/product-economics/src/product-costing.ts
31988
- import { z as z136 } from "zod";
32507
+ import { z as z137 } from "zod";
31989
32508
 
31990
32509
  // ../../packages/product-economics/src/product-costing-countries.ts
31991
- import { z as z135 } from "zod";
32510
+ import { z as z136 } from "zod";
31992
32511
 
31993
32512
  // ../../packages/product-economics/src/product-costing-shipping-references.json
31994
32513
  var product_costing_shipping_references_default = {
@@ -32052,21 +32571,21 @@ var product_costing_shipping_references_default = {
32052
32571
  };
32053
32572
 
32054
32573
  // ../../packages/product-economics/src/product-costing-countries.ts
32055
- var ShippingReferenceSchema = z135.object({
32056
- reference: z135.number().positive(),
32057
- min: z135.number().nonnegative(),
32058
- max: z135.number().positive(),
32059
- updatedAt: z135.string().date(),
32060
- confidence: z135.enum([
32574
+ var ShippingReferenceSchema = z136.object({
32575
+ reference: z136.number().positive(),
32576
+ min: z136.number().nonnegative(),
32577
+ max: z136.number().positive(),
32578
+ updatedAt: z136.string().date(),
32579
+ confidence: z136.enum([
32061
32580
  "high",
32062
32581
  "medium",
32063
32582
  "medium-low"
32064
32583
  ]),
32065
- sources: z135.array(z135.string().url().startsWith("https://")).min(1).max(3)
32584
+ sources: z136.array(z136.string().url().startsWith("https://")).min(1).max(3)
32066
32585
  }).superRefine(({ reference, min, max }, context) => {
32067
32586
  if (min > reference || reference > max) {
32068
32587
  context.addIssue({
32069
- code: z135.ZodIssueCode.custom,
32588
+ code: z136.ZodIssueCode.custom,
32070
32589
  message: "shipping_reference_outside_range",
32071
32590
  path: [
32072
32591
  "reference"
@@ -32074,7 +32593,7 @@ var ShippingReferenceSchema = z135.object({
32074
32593
  });
32075
32594
  }
32076
32595
  });
32077
- var SHIPPING_REFERENCES = z135.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
32596
+ var SHIPPING_REFERENCES = z136.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
32078
32597
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
32079
32598
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
32080
32599
  "MX",
@@ -32256,18 +32775,18 @@ function getProductCostingCountryName(country) {
32256
32775
  __name(getProductCostingCountryName, "getProductCostingCountryName");
32257
32776
 
32258
32777
  // ../../packages/product-economics/src/product-costing.ts
32259
- var ProductCostingInputSchema = z136.object({
32260
- country: z136.string().refine(isProductCostingCountryCode, "unsupported_country"),
32261
- supplierCost: z136.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
32262
- shippingCost: z136.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
32263
- returnRate: z136.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
32264
- cancellationRate: z136.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
32265
- adsManagerCpa: z136.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
32266
- desiredMargin: z136.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
32778
+ var ProductCostingInputSchema = z137.object({
32779
+ country: z137.string().refine(isProductCostingCountryCode, "unsupported_country"),
32780
+ supplierCost: z137.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
32781
+ shippingCost: z137.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
32782
+ returnRate: z137.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
32783
+ cancellationRate: z137.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
32784
+ adsManagerCpa: z137.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
32785
+ desiredMargin: z137.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
32267
32786
  }).superRefine(({ returnRate, cancellationRate }, context) => {
32268
32787
  if (returnRate + cancellationRate >= 1) {
32269
32788
  context.addIssue({
32270
- code: z136.ZodIssueCode.custom,
32789
+ code: z137.ZodIssueCode.custom,
32271
32790
  message: "delivery_rate_positive",
32272
32791
  path: [
32273
32792
  "cancellationRate"
@@ -32364,15 +32883,15 @@ function calculateProductCosting(rawInput) {
32364
32883
  __name(calculateProductCosting, "calculateProductCosting");
32365
32884
 
32366
32885
  // src/tools/product-costing.ts
32367
- import { z as z137 } from "zod";
32886
+ import { z as z138 } from "zod";
32368
32887
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
32369
- var optionalAmount = /* @__PURE__ */ __name((description) => z137.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
32370
- var optionalPercent = /* @__PURE__ */ __name((description) => z137.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
32371
- var ProductCostingToolInput = z137.object({
32372
- country: z137.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
32888
+ var optionalAmount = /* @__PURE__ */ __name((description) => z138.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
32889
+ var optionalPercent = /* @__PURE__ */ __name((description) => z138.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
32890
+ var ProductCostingToolInput = z138.object({
32891
+ country: z138.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
32373
32892
  message: "Pa\xEDs no soportado por ProductMaker."
32374
32893
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
32375
- supplierCost: z137.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."),
32894
+ supplierCost: z138.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."),
32376
32895
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
32377
32896
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
32378
32897
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -32535,7 +33054,7 @@ function formatPercent(value) {
32535
33054
  __name(formatPercent, "formatPercent");
32536
33055
 
32537
33056
  // src/tools/product-research.ts
32538
- import { z as z138 } from "zod";
33057
+ import { z as z139 } from "zod";
32539
33058
 
32540
33059
  // src/tools/product-research-idempotency.ts
32541
33060
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -32906,17 +33425,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
32906
33425
  ]);
32907
33426
  var POLL_INTERVAL_MS = 5e3;
32908
33427
  var MAX_WAIT_SECONDS = 120;
32909
- var FindInput = z138.object({
33428
+ var FindInput = z139.object({
32910
33429
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
32911
33430
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
32912
- confirmed: z138.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
32913
- waitSeconds: z138.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
33431
+ confirmed: z139.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
33432
+ waitSeconds: z139.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
32914
33433
  });
32915
- var GetInput = z138.object({
32916
- runId: z138.string().uuid().describe("ID del run devuelto por find_winning_products.")
33434
+ var GetInput = z139.object({
33435
+ runId: z139.string().uuid().describe("ID del run devuelto por find_winning_products.")
32917
33436
  });
32918
- var ListInput = z138.object({
32919
- limit: z138.number().int().min(1).max(20).default(10)
33437
+ var ListInput = z139.object({
33438
+ limit: z139.number().int().min(1).max(20).default(10)
32920
33439
  });
32921
33440
  function textResult(text3) {
32922
33441
  return {
@@ -33055,17 +33574,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
33055
33574
  __name(registerProductResearchTools, "registerProductResearchTools");
33056
33575
 
33057
33576
  // src/tools/dropshipping-projects.ts
33058
- import { z as z139 } from "zod";
33577
+ import { z as z140 } from "zod";
33059
33578
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
33060
33579
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
33061
33580
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
33062
- var ProjectId = z139.string().uuid();
33063
- var DropshippingProjectStatus = z139.enum([
33581
+ var ProjectId = z140.string().uuid();
33582
+ var DropshippingProjectStatus = z140.enum([
33064
33583
  "active",
33065
33584
  "completed",
33066
33585
  "archived"
33067
33586
  ]);
33068
- var DropshippingProjectPhase = z139.enum([
33587
+ var DropshippingProjectPhase = z140.enum([
33069
33588
  "research",
33070
33589
  "costing",
33071
33590
  "media",
@@ -33074,21 +33593,21 @@ var DropshippingProjectPhase = z139.enum([
33074
33593
  "advertising",
33075
33594
  "complete"
33076
33595
  ]);
33077
- var DropshippingRewardMilestone = z139.enum([
33596
+ var DropshippingRewardMilestone = z140.enum([
33078
33597
  "product_selected",
33079
33598
  "costing_saved",
33080
33599
  "product_media_ready",
33081
33600
  "creatives_completed",
33082
33601
  "campaign_created"
33083
33602
  ]);
33084
- var TargetCountry = z139.enum([
33603
+ var TargetCountry = z140.enum([
33085
33604
  "CO",
33086
33605
  "MX",
33087
33606
  "PE",
33088
33607
  "EC",
33089
33608
  "CL"
33090
33609
  ]);
33091
- var ResearchCategory = z139.enum([
33610
+ var ResearchCategory = z140.enum([
33092
33611
  "auto",
33093
33612
  "automotive",
33094
33613
  "kitchen",
@@ -33103,7 +33622,7 @@ var ResearchCategory = z139.enum([
33103
33622
  "garden",
33104
33623
  "cleaning"
33105
33624
  ]);
33106
- var HttpUrl3 = z139.string().url().max(2e3).refine((value) => {
33625
+ var HttpUrl3 = z140.string().url().max(2e3).refine((value) => {
33107
33626
  try {
33108
33627
  return [
33109
33628
  "http:",
@@ -33113,45 +33632,45 @@ var HttpUrl3 = z139.string().url().max(2e3).refine((value) => {
33113
33632
  return false;
33114
33633
  }
33115
33634
  }, "URL must use HTTP(S)");
33116
- var ResearchCandidateOrigin = z139.object({
33117
- type: z139.literal("research_candidate"),
33635
+ var ResearchCandidateOrigin = z140.object({
33636
+ type: z140.literal("research_candidate"),
33118
33637
  runId: ProjectId,
33119
- candidateSourceId: z139.string().min(1).max(160)
33638
+ candidateSourceId: z140.string().min(1).max(160)
33120
33639
  });
33121
- var TaskOrigin = z139.object({
33122
- type: z139.literal("task"),
33640
+ var TaskOrigin = z140.object({
33641
+ type: z140.literal("task"),
33123
33642
  taskId: ProjectId
33124
33643
  });
33125
- var ManualOrigin = z139.object({
33126
- type: z139.literal("manual"),
33644
+ var ManualOrigin = z140.object({
33645
+ type: z140.literal("manual"),
33127
33646
  clientRequestId: ProjectId,
33128
- country: z139.string().min(2).max(3).optional()
33647
+ country: z140.string().min(2).max(3).optional()
33129
33648
  });
33130
- var StartProjectInput = z139.object({
33131
- origin: z139.discriminatedUnion("type", [
33649
+ var StartProjectInput = z140.object({
33650
+ origin: z140.discriminatedUnion("type", [
33132
33651
  ResearchCandidateOrigin,
33133
33652
  TaskOrigin,
33134
33653
  ManualOrigin
33135
33654
  ]),
33136
- productName: z139.string().trim().min(1).max(240).optional(),
33655
+ productName: z140.string().trim().min(1).max(240).optional(),
33137
33656
  productUrl: HttpUrl3.optional(),
33138
- country: z139.string().min(2).max(3).optional(),
33139
- languageCode: z139.string().min(2).max(16).optional()
33657
+ country: z140.string().min(2).max(3).optional(),
33658
+ languageCode: z140.string().min(2).max(16).optional()
33140
33659
  }).strict();
33141
- var CostProjectInput = z139.object({
33660
+ var CostProjectInput = z140.object({
33142
33661
  projectId: ProjectId,
33143
- version: z139.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
33144
- country: z139.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
33662
+ version: z140.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
33663
+ country: z140.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
33145
33664
  message: "Pa\xEDs no soportado por ProductMaker."
33146
33665
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
33147
- supplierCost: z139.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
33148
- shippingCost: z139.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
33149
- returnRate: z139.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
33150
- cancellationRate: z139.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
33151
- adsManagerCpa: z139.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
33152
- desiredMargin: z139.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
33153
- });
33154
- var GuideInput = z139.object({
33666
+ supplierCost: z140.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
33667
+ shippingCost: z140.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
33668
+ returnRate: z140.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
33669
+ cancellationRate: z140.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
33670
+ adsManagerCpa: z140.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
33671
+ desiredMargin: z140.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
33672
+ });
33673
+ var GuideInput = z140.object({
33155
33674
  projectId: ProjectId.optional()
33156
33675
  }).strict();
33157
33676
  var NEXT_ACTION_KINDS = [
@@ -33169,29 +33688,29 @@ var NEXT_ACTION_KINDS = [
33169
33688
  "repair_meta_campaign",
33170
33689
  "review_paused_campaign"
33171
33690
  ];
33172
- var DropshippingProjectNextAction = z139.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z139.object({
33173
- kind: z139.literal(kind),
33174
- href: z139.string().min(1)
33691
+ var DropshippingProjectNextAction = z140.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z140.object({
33692
+ kind: z140.literal(kind),
33693
+ href: z140.string().min(1)
33175
33694
  })));
33176
- var CostingInputSchema = z139.object({
33177
- country: z139.string().min(2).max(3),
33178
- supplierCost: z139.number().finite().positive(),
33179
- shippingCost: z139.number().finite().nonnegative(),
33180
- returnRate: z139.number().finite().min(0).lt(1),
33181
- cancellationRate: z139.number().finite().min(0).lt(1),
33182
- adsManagerCpa: z139.number().finite().nonnegative(),
33183
- desiredMargin: z139.number().finite().min(0).lt(1)
33695
+ var CostingInputSchema = z140.object({
33696
+ country: z140.string().min(2).max(3),
33697
+ supplierCost: z140.number().finite().positive(),
33698
+ shippingCost: z140.number().finite().nonnegative(),
33699
+ returnRate: z140.number().finite().min(0).lt(1),
33700
+ cancellationRate: z140.number().finite().min(0).lt(1),
33701
+ adsManagerCpa: z140.number().finite().nonnegative(),
33702
+ desiredMargin: z140.number().finite().min(0).lt(1)
33184
33703
  }).superRefine(({ returnRate, cancellationRate }, context) => {
33185
33704
  if (returnRate + cancellationRate >= 1) context.addIssue({
33186
- code: z139.ZodIssueCode.custom,
33705
+ code: z140.ZodIssueCode.custom,
33187
33706
  path: [
33188
33707
  "cancellationRate"
33189
33708
  ]
33190
33709
  });
33191
33710
  });
33192
- var FiniteCostingNumber = z139.number().finite();
33193
- var CostingResultSchema = z139.object({
33194
- country: z139.string().min(2).max(3),
33711
+ var FiniteCostingNumber = z140.number().finite();
33712
+ var CostingResultSchema = z140.object({
33713
+ country: z140.string().min(2).max(3),
33195
33714
  deliveryRate: FiniteCostingNumber,
33196
33715
  adjustedShippingCost: FiniteCostingNumber,
33197
33716
  adjustedCpa: FiniteCostingNumber,
@@ -33204,45 +33723,45 @@ var CostingResultSchema = z139.object({
33204
33723
  estimatedProfit: FiniteCostingNumber,
33205
33724
  actualMargin: FiniteCostingNumber,
33206
33725
  breakEvenAdsManagerCpa: FiniteCostingNumber,
33207
- wasPriceAutoAdjusted: z139.boolean(),
33208
- profitabilityStatus: z139.literal("healthy")
33209
- });
33210
- var RewardProgressSchema = z139.object({
33211
- campaignKey: z139.literal("dropshipping-launch-v1"),
33212
- totalCredits: z139.number().int().positive(),
33213
- earnedCredits: z139.number().int().nonnegative(),
33214
- milestones: z139.array(z139.object({
33726
+ wasPriceAutoAdjusted: z140.boolean(),
33727
+ profitabilityStatus: z140.literal("healthy")
33728
+ });
33729
+ var RewardProgressSchema = z140.object({
33730
+ campaignKey: z140.literal("dropshipping-launch-v1"),
33731
+ totalCredits: z140.number().int().positive(),
33732
+ earnedCredits: z140.number().int().nonnegative(),
33733
+ milestones: z140.array(z140.object({
33215
33734
  milestone: DropshippingRewardMilestone,
33216
- credits: z139.number().int().positive(),
33217
- available: z139.boolean().optional(),
33218
- earned: z139.boolean(),
33735
+ credits: z140.number().int().positive(),
33736
+ available: z140.boolean().optional(),
33737
+ earned: z140.boolean(),
33219
33738
  grantId: ProjectId.nullable(),
33220
- grantedAt: z139.string().datetime().nullable()
33739
+ grantedAt: z140.string().datetime().nullable()
33221
33740
  })).length(DropshippingRewardMilestone.options.length)
33222
33741
  });
33223
- var ProjectResponseSchema = z139.object({
33742
+ var ProjectResponseSchema = z140.object({
33224
33743
  id: ProjectId,
33225
33744
  taskId: ProjectId.nullable(),
33226
33745
  status: DropshippingProjectStatus,
33227
- originKey: z139.string().min(1),
33746
+ originKey: z140.string().min(1),
33228
33747
  researchRunId: ProjectId.nullable(),
33229
- candidateSourceId: z139.string().nullable(),
33230
- productName: z139.string().nullable(),
33748
+ candidateSourceId: z140.string().nullable(),
33749
+ productName: z140.string().nullable(),
33231
33750
  productUrl: HttpUrl3.nullable(),
33232
33751
  referenceImageUrl: HttpUrl3.nullable(),
33233
- targetCountry: z139.string().nullable(),
33234
- languageCode: z139.string().nullable(),
33235
- hasReferenceImage: z139.boolean(),
33236
- hasWinnerReferenceImage: z139.boolean(),
33752
+ targetCountry: z140.string().nullable(),
33753
+ languageCode: z140.string().nullable(),
33754
+ hasReferenceImage: z140.boolean(),
33755
+ hasWinnerReferenceImage: z140.boolean(),
33237
33756
  costingInput: CostingInputSchema.nullable(),
33238
33757
  costingResult: CostingResultSchema.nullable(),
33239
- costingVersion: z139.number().int().positive().nullable(),
33240
- version: z139.number().int().positive(),
33758
+ costingVersion: z140.number().int().positive().nullable(),
33759
+ version: z140.number().int().positive(),
33241
33760
  phase: DropshippingProjectPhase,
33242
33761
  nextAction: DropshippingProjectNextAction.nullable(),
33243
33762
  rewards: RewardProgressSchema,
33244
- createdAt: z139.string().datetime(),
33245
- updatedAt: z139.string().datetime()
33763
+ createdAt: z140.string().datetime(),
33764
+ updatedAt: z140.string().datetime()
33246
33765
  }).passthrough();
33247
33766
  var NEXT_ACTION_GUIDANCE = {
33248
33767
  cost_product: "Llama `cost_dropshipping_project` con el costo real del proveedor. Nunca lo inventes: p\xEDdeselo al usuario. Es el \xDANICO dato que debes pedirle: omite env\xEDo, devoluciones, cancelaciones, CPA y margen para que ProductMaker use los valores gu\xEDa del pa\xEDs, y luego dile al usuario cu\xE1les us\xF3 por si quiere corregirlos.",
@@ -33362,58 +33881,58 @@ function registerDropshippingProjectTools(server, api) {
33362
33881
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
33363
33882
 
33364
33883
  // src/tools/daily-control.ts
33365
- import { z as z140 } from "zod";
33884
+ import { z as z141 } from "zod";
33366
33885
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
33367
33886
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
33368
33887
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
33369
- var ProviderCampaignIdentifier = z140.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
33370
- var DateOnly = z140.string().regex(/^\d{4}-\d{2}-\d{2}$/);
33371
- var DailyControlInput = z140.object({
33888
+ var ProviderCampaignIdentifier = z141.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
33889
+ var DateOnly = z141.string().regex(/^\d{4}-\d{2}-\d{2}$/);
33890
+ var DailyControlInput = z141.object({
33372
33891
  date: DateOnly.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, la ventana termina AYER en UTC \u2014 nunca hoy, porque el d\xEDa en curso est\xE1 incompleto \u2014 y el servidor puede correrla un d\xEDa m\xE1s atr\xE1s si en la zona horaria de la tienda ese d\xEDa todav\xEDa no ha cerrado."),
33373
- days: z140.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
33374
- projectId: z140.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
33892
+ days: z141.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
33893
+ projectId: z141.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
33375
33894
  }).strict();
33376
- var LinkCampaignInput = z140.object({
33377
- projectId: z140.string().uuid(),
33378
- provider: z140.enum([
33895
+ var LinkCampaignInput = z141.object({
33896
+ projectId: z141.string().uuid(),
33897
+ provider: z141.enum([
33379
33898
  "meta",
33380
33899
  "tiktok"
33381
33900
  ]),
33382
33901
  accountId: ProviderCampaignIdentifier.describe("Cuenta publicitaria del proveedor. Para Meta el servidor la IGNORA y deriva la cuenta real de la campa\xF1a \u2014 se sigue pidiendo aqu\xED solo porque TikTok s\xED la necesita para resolver la campa\xF1a."),
33383
33902
  campaignId: ProviderCampaignIdentifier
33384
33903
  }).strict();
33385
- var ReportReturnsInput = z140.object({
33386
- projectId: z140.string().uuid(),
33904
+ var ReportReturnsInput = z141.object({
33905
+ projectId: z141.string().uuid(),
33387
33906
  date: DateOnly,
33388
- returnedOrders: z140.number().int().min(0).max(1e5),
33389
- note: z140.string().trim().max(280).optional()
33390
- }).strict();
33391
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z140.string());
33392
- var DailyControlLightMirror = DailyControlLightEnum.or(z140.string());
33393
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z140.string());
33394
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z140.string());
33395
- var DailyControlDayMirror = z140.object({
33396
- date: z140.string(),
33397
- returnedOrders: z140.number(),
33907
+ returnedOrders: z141.number().int().min(0).max(1e5),
33908
+ note: z141.string().trim().max(280).optional()
33909
+ }).strict();
33910
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z141.string());
33911
+ var DailyControlLightMirror = DailyControlLightEnum.or(z141.string());
33912
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z141.string());
33913
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z141.string());
33914
+ var DailyControlDayMirror = z141.object({
33915
+ date: z141.string(),
33916
+ returnedOrders: z141.number(),
33398
33917
  returnedSource: DailyControlSourceMirror,
33399
33918
  cancelledSource: DailyControlSourceMirror,
33400
- hasEstimates: z140.boolean(),
33919
+ hasEstimates: z141.boolean(),
33401
33920
  light: DailyControlLightMirror
33402
33921
  }).passthrough();
33403
- var DailyControlProductMirror = z140.object({
33404
- projectId: z140.string().uuid(),
33405
- productName: z140.string().nullable(),
33922
+ var DailyControlProductMirror = z141.object({
33923
+ projectId: z141.string().uuid(),
33924
+ productName: z141.string().nullable(),
33406
33925
  status: DailyControlStatusMirror,
33407
- statusMessage: z140.string().nullable(),
33408
- days: z140.array(DailyControlDayMirror),
33926
+ statusMessage: z141.string().nullable(),
33927
+ days: z141.array(DailyControlDayMirror),
33409
33928
  verdict: DailyControlVerdictMirror.nullable(),
33410
- rationale: z140.string().nullable()
33929
+ rationale: z141.string().nullable()
33411
33930
  }).passthrough();
33412
- var DailyControlResponseMirror = z140.object({
33413
- since: z140.string(),
33414
- until: z140.string(),
33415
- products: z140.array(DailyControlProductMirror),
33416
- archivedProjectSpend: z140.array(z140.unknown())
33931
+ var DailyControlResponseMirror = z141.object({
33932
+ since: z141.string(),
33933
+ until: z141.string(),
33934
+ products: z141.array(DailyControlProductMirror),
33935
+ archivedProjectSpend: z141.array(z141.unknown())
33417
33936
  }).passthrough();
33418
33937
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
33419
33938
  function withWarnings(response) {
@@ -33488,7 +34007,7 @@ __name(registerDailyControlTools, "registerDailyControlTools");
33488
34007
  // src/tools/product-control.ts
33489
34008
  import { readFile, stat } from "fs/promises";
33490
34009
  import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
33491
- import { z as z141 } from "zod";
34010
+ import { z as z142 } from "zod";
33492
34011
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
33493
34012
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
33494
34013
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
@@ -33501,36 +34020,36 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
33501
34020
  var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
33502
34021
  var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
33503
34022
  var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
33504
- var DateOnly2 = z141.string().regex(/^\d{4}-\d{2}-\d{2}$/);
34023
+ var DateOnly2 = z142.string().regex(/^\d{4}-\d{2}-\d{2}$/);
33505
34024
  var IMPORT_BATCH_MAX2 = 50;
33506
- var ProductControlListInput = z141.object({
33507
- days: z141.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
34025
+ var ProductControlListInput = z142.object({
34026
+ days: z142.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
33508
34027
  date: DateOnly2.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, termina en el \xFAltimo d\xEDa cerrado \u2014 nunca hoy, que est\xE1 incompleto."),
33509
- shopDomain: z141.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
34028
+ shopDomain: z142.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
33510
34029
  }).strict();
33511
- var ImportableProductsInput = z141.object({
33512
- q: z141.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
33513
- after: z141.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
33514
- shopDomain: z141.string().min(1).optional()
34030
+ var ImportableProductsInput = z142.object({
34031
+ q: z142.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
34032
+ after: z142.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
34033
+ shopDomain: z142.string().min(1).optional()
33515
34034
  }).strict();
33516
- var ImportProductControlsInput = z141.object({
33517
- shopifyProductIds: z141.array(z141.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
34035
+ var ImportProductControlsInput = z142.object({
34036
+ shopifyProductIds: z142.array(z142.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
33518
34037
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
33519
34038
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
33520
- shopDomain: z141.string().min(1)
33521
- }).strict();
33522
- var SetProductCostingInput = z141.object({
33523
- shopDomain: z141.string().min(1),
33524
- shopifyProductId: z141.string().min(1).max(64),
33525
- targetCountry: z141.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
33526
- supplierCost: z141.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
33527
- shippingCost: z141.number().finite().nonnegative(),
33528
- returnRate: z141.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
33529
- cancellationRate: z141.number().finite().min(0).lt(1)
33530
- }).strict();
33531
- var Count = z141.number().int().min(0).max(1e5).nullable().optional();
33532
- var ReportProductCountsInput = z141.object({
33533
- productControlId: z141.string().uuid().describe("El identificador que devuelve get_product_control."),
34039
+ shopDomain: z142.string().min(1)
34040
+ }).strict();
34041
+ var SetProductCostingInput = z142.object({
34042
+ shopDomain: z142.string().min(1),
34043
+ shopifyProductId: z142.string().min(1).max(64),
34044
+ targetCountry: z142.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
34045
+ supplierCost: z142.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
34046
+ shippingCost: z142.number().finite().nonnegative(),
34047
+ returnRate: z142.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
34048
+ cancellationRate: z142.number().finite().min(0).lt(1)
34049
+ }).strict();
34050
+ var Count = z142.number().int().min(0).max(1e5).nullable().optional();
34051
+ var ReportProductCountsInput = z142.object({
34052
+ productControlId: z142.string().uuid().describe("El identificador que devuelve get_product_control."),
33534
34053
  date: DateOnly2,
33535
34054
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
33536
34055
  cancelledOrders: Count,
@@ -33540,36 +34059,36 @@ var ReportProductCountsInput = z141.object({
33540
34059
  }).strict();
33541
34060
  var MAX_ORDERS_FILE_BYTES = 8 * 1024 * 1024;
33542
34061
  var SyncShopifyOrdersInput = SyncShopifyOrdersSchema;
33543
- var ImportOrdersFileInput = z141.object({
34062
+ var ImportOrdersFileInput = z142.object({
33544
34063
  /** Ruta ABSOLUTA en la máquina de quien usa el MCP. */
33545
- path: z141.string().min(1),
33546
- operationId: z141.string().uuid().optional(),
34064
+ path: z142.string().min(1),
34065
+ operationId: z142.string().uuid().optional(),
33547
34066
  /** Solo mirar: devuelve el resumen y no escribe nada. */
33548
- dryRun: z141.boolean().optional()
34067
+ dryRun: z142.boolean().optional()
33549
34068
  }).strict();
33550
- var CreateOperationInput = z141.object({
33551
- countryCode: z141.string().length(2),
33552
- label: z141.string().trim().min(1).max(60).optional()
34069
+ var CreateOperationInput = z142.object({
34070
+ countryCode: z142.string().length(2),
34071
+ label: z142.string().trim().min(1).max(60).optional()
33553
34072
  }).strict();
33554
- var MergeProductsInput = z141.object({
33555
- sourceId: z141.string().uuid(),
33556
- targetId: z141.string().uuid()
34073
+ var MergeProductsInput = z142.object({
34074
+ sourceId: z142.string().uuid(),
34075
+ targetId: z142.string().uuid()
33557
34076
  }).strict();
33558
- var SetMonthlyExpenseInput = z141.object({
33559
- month: z141.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
34077
+ var SetMonthlyExpenseInput = z142.object({
34078
+ month: z142.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
33560
34079
  label: SaveMonthlyExpenseSchema.shape.label,
33561
- amount: z141.number().finite().min(0),
33562
- operationId: z141.string().uuid().optional()
34080
+ amount: z142.number().finite().min(0),
34081
+ operationId: z142.string().uuid().optional()
33563
34082
  }).strict();
33564
- var SetAdSpendInput = z141.object({
33565
- month: z141.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
33566
- operationId: z141.string().uuid().optional(),
34083
+ var SetAdSpendInput = z142.object({
34084
+ month: z142.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
34085
+ operationId: z142.string().uuid().optional(),
33567
34086
  /** null RETIRA la corrección; cero afirma que no pautó. */
33568
- amount: z141.number().finite().min(0).nullable()
34087
+ amount: z142.number().finite().min(0).nullable()
33569
34088
  }).strict();
33570
- var GetFinancesInput = z141.object({
33571
- month: z141.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional().describe("Mes en YYYY-MM. Si se omite, el mes en curso. Solo mes calendario."),
33572
- operationId: z141.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
34089
+ var GetFinancesInput = z142.object({
34090
+ month: z142.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional().describe("Mes en YYYY-MM. Si se omite, el mes en curso. Solo mes calendario."),
34091
+ operationId: z142.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
33573
34092
  }).strict();
33574
34093
  function registerProductControlTools(server, api, { transport = "http" } = {}) {
33575
34094
  server.registerTool("get_product_control", {
@@ -33761,28 +34280,28 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
33761
34280
  __name(registerProductControlTools, "registerProductControlTools");
33762
34281
 
33763
34282
  // src/tools/market-study-estimate.ts
33764
- import { z as z142 } from "zod";
34283
+ import { z as z143 } from "zod";
33765
34284
  var estimateMarketStudyGuidance = getProductMakerCapabilityModelGuidance("estimate_market_study_cost");
33766
- var ProductTaskOutputEnum = z142.enum([
34285
+ var ProductTaskOutputEnum = z143.enum([
33767
34286
  "landing",
33768
34287
  "video",
33769
34288
  "image"
33770
34289
  ]);
33771
- var EstimateMarketStudyInput = z142.object({
33772
- kind: z142.enum([
34290
+ var EstimateMarketStudyInput = z143.object({
34291
+ kind: z143.enum([
33773
34292
  "video",
33774
34293
  "product_task"
33775
34294
  ]).describe('"video" para generate_video_creative; "product_task" para create_product_task.'),
33776
- videoAngleCount: z142.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
33777
- durationSeconds: z142.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
34295
+ videoAngleCount: z143.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
34296
+ durationSeconds: z143.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
33778
34297
  videoStructure: VideoStructureEnum.default("single_take"),
33779
34298
  videoQuality: VideoQualityEnum.default("economy"),
33780
34299
  videoResolution: VideoResolutionEnum.default("480p"),
33781
- productImageCount: z142.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
34300
+ productImageCount: z143.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
33782
34301
  outputs: ProductTaskOutputEnum.array().min(1).max(3).optional().describe('Solo para kind="product_task": los mismos outputs de create_product_task. Default: todos.'),
33783
- generateAiMusic: z142.boolean().optional(),
34302
+ generateAiMusic: z143.boolean().optional(),
33784
34303
  generateAiEdit: AiEditRequestSchema.optional(),
33785
- replicateWinnerWhenFound: z142.boolean().optional().describe("La misma preferencia que enviar\xE1s al crear. false excluye la reserva de r\xE9plica del ganador de la cotizaci\xF3n con estudio.")
34304
+ replicateWinnerWhenFound: z143.boolean().optional().describe("La misma preferencia que enviar\xE1s al crear. false excluye la reserva de r\xE9plica del ganador de la cotizaci\xF3n con estudio.")
33786
34305
  }).strict();
33787
34306
  function buildMarketStudyEstimateRequests(input) {
33788
34307
  const quotesVideo = input.kind === "video" || (input.outputs ?? [
@@ -33981,6 +34500,7 @@ function createServer(opts) {
33981
34500
  });
33982
34501
  registerProductMakerPrompts(server);
33983
34502
  registerMediaUploadAppResource(server, api.publicUrl("/v1/uploaded-assets/sessions/resolve"));
34503
+ registerTaskResultsAppResource(server, proxyBaseUrl);
33984
34504
  registerProductCostingTools(server);
33985
34505
  registerProductResearchTools(server, api);
33986
34506
  registerDropshippingProjectTools(server, api);