@productmaker/mcp 11.3.2 → 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +11 -0
  2. package/dist/http.js +1068 -844
  3. package/dist/stdio.js +1057 -833
  4. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -9676,13 +9676,23 @@ var FacebookCreateCampaignFromTasksBodySchema = z51.object({
9676
9676
  portfolioId: z51.string().min(1),
9677
9677
  pageId: z51.string().min(1),
9678
9678
  pixelId: z51.string().optional(),
9679
+ /**
9680
+ * Omitted: a campaign with task creatives lands on the published service
9681
+ * landing of its service tasks (resolved server side, META_NO_LANDING_URL
9682
+ * when there is none); a media-only campaign must name it.
9683
+ */
9679
9684
  landingUrl: HttpUrl2.optional(),
9680
- targetCountry: CountryIso2Schema.default("US"),
9685
+ /**
9686
+ * Omitted: the brand country of its service tasks; a product-only campaign
9687
+ * keeps "US". Never a hardcoded country for a service (META_NO_TARGET_COUNTRY).
9688
+ */
9689
+ targetCountry: CountryIso2Schema.optional(),
9681
9690
  campaignName: z51.string().min(1).max(100),
9682
9691
  campaignConfig: MetaCampaignConfig.optional()
9683
9692
  }).superRefine((value, ctx) => {
9684
9693
  const isWhatsapp = value.campaignConfig?.destination?.type === "whatsapp";
9685
- if (!isWhatsapp && !value.landingUrl) {
9694
+ const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
9695
+ if (!isWhatsapp && !value.landingUrl && !hasTaskCreative) {
9686
9696
  ctx.addIssue({
9687
9697
  code: z51.ZodIssueCode.custom,
9688
9698
  path: [
@@ -18759,7 +18769,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
18759
18769
  ], [
18760
18770
  "tiktok_advertiser"
18761
18771
  ]),
18762
- defineCapability("publish_creatives_to_meta", "554d977e26e824490ffe3e027f34889b1e29d5969e6e9c0320f79e7c5a03584c", "external_mutation", "publishing", [
18772
+ defineCapability("publish_creatives_to_meta", "dff962c84ed7d0393444dcbe86cb6f4016b5928c1d0005f78ce9a365f1923ac3", "external_mutation", "publishing", [
18763
18773
  "external_mutation",
18764
18774
  "state_change"
18765
18775
  ], [
@@ -21600,8 +21610,33 @@ var ServicePageGenerateRequestSchema = z100.object({
21600
21610
  instruction: ServicePageEditInstructionSchema.optional(),
21601
21611
  attachmentRefs: ServicePageAttachmentRefsSchema.optional()
21602
21612
  }).strict();
21613
+ var SERVICE_PAGE_CREATION_MAX_ATTEMPTS = 3;
21614
+ var ServicePageCreationMarkerSchema = z100.object({
21615
+ rootOperationId: z100.string().uuid().optional(),
21616
+ attempt: z100.number().int().min(1).max(SERVICE_PAGE_CREATION_MAX_ATTEMPTS)
21617
+ }).strict();
21618
+ var ServicePageCreationEstimateRequestSchema = z100.object({
21619
+ textCharacters: z100.number().int().min(0).max(1e6),
21620
+ documentBytes: z100.number().int().min(0).max(1e8),
21621
+ imageCount: z100.number().int().min(0).max(50),
21622
+ instagram: z100.boolean()
21623
+ }).strict();
21624
+ var ServicePageCreationEstimateResponseSchema = z100.object({
21625
+ estimatedMinCostCredits: z100.number().int().nonnegative(),
21626
+ estimatedMaxCostCredits: z100.number().int().nonnegative()
21627
+ }).strict();
21628
+ var ServicePageCreationStatusSchema = z100.object({
21629
+ status: z100.enum([
21630
+ "idle",
21631
+ "running",
21632
+ "failed"
21633
+ ]),
21634
+ errorCode: z100.string().max(64).optional()
21635
+ }).strict();
21603
21636
  var ServicePageFactExtractionRequestSchema = ServicePageGenerateRequestSchema.omit({
21604
21637
  instruction: true
21638
+ }).extend({
21639
+ continueWith: z100.literal("generation").optional()
21605
21640
  });
21606
21641
  var ServicePageOperationStatusSchema = z100.enum([
21607
21642
  "queued",
@@ -22084,19 +22119,37 @@ var ServiceImageContextSchema = z106.object({
22084
22119
  referenceKeys: z106.array(z106.string()).max(10)
22085
22120
  }).strict();
22086
22121
 
22087
- // ../../packages/types/src/service-website-capture.ts
22122
+ // ../../packages/types/src/task-ad-defaults.ts
22088
22123
  import { z as z107 } from "zod";
22124
+ var AD_HEADLINE_MAX_CHARS = 255;
22125
+ var TaskAdDefaultsSchema = z107.object({
22126
+ subjectKind: z107.enum([
22127
+ "product",
22128
+ "service"
22129
+ ]),
22130
+ landingUrl: z107.string().url().nullable(),
22131
+ landingSource: z107.enum([
22132
+ "shopify",
22133
+ "service_page"
22134
+ ]).nullable(),
22135
+ headline: z107.string().min(1).max(AD_HEADLINE_MAX_CHARS).nullable(),
22136
+ /** ISO 3166-1 alpha-2 when known. */
22137
+ country: z107.string().min(2).nullable()
22138
+ });
22139
+
22140
+ // ../../packages/types/src/service-website-capture.ts
22141
+ import { z as z108 } from "zod";
22089
22142
  var WEBSITE_CAPTURE_MAX_RESEARCH_BYTES = 1024 * 1024;
22090
22143
  var WEBSITE_CAPTURE_MAX_FILES = 100;
22091
22144
  var WEBSITE_CAPTURE_MAX_FILE_BYTES = 8 * 1024 * 1024;
22092
22145
  var WEBSITE_CAPTURE_MAX_BUNDLE_BYTES = 30 * 1024 * 1024;
22093
- var WebsiteCaptureCauseSchema = z107.enum([
22146
+ var WebsiteCaptureCauseSchema = z108.enum([
22094
22147
  "site_blocked",
22095
22148
  "site_unreachable",
22096
22149
  "not_enough_content",
22097
22150
  "internal"
22098
22151
  ]);
22099
- var WebsiteCaptureStatusSchema = z107.enum([
22152
+ var WebsiteCaptureStatusSchema = z108.enum([
22100
22153
  "queued",
22101
22154
  "capturing",
22102
22155
  "ready",
@@ -22118,133 +22171,286 @@ function normalizeWebsiteCaptureUrl(value) {
22118
22171
  }
22119
22172
  }
22120
22173
  __name(normalizeWebsiteCaptureUrl, "normalizeWebsiteCaptureUrl");
22121
- var WebsiteCaptureRequestSchema = z107.object({
22122
- url: z107.string().trim().max(2048).url().refine((value) => normalizeWebsiteCaptureUrl(value) !== null, "Use an HTTP(S) URL without credentials").transform((value) => normalizeWebsiteCaptureUrl(value)),
22174
+ var WebsiteCaptureRequestSchema = z108.object({
22175
+ url: z108.string().trim().max(2048).url().refine((value) => normalizeWebsiteCaptureUrl(value) !== null, "Use an HTTP(S) URL without credentials").transform((value) => normalizeWebsiteCaptureUrl(value)),
22123
22176
  language: MotionGraphicsLanguageSchema
22124
22177
  }).strict();
22125
- var WebsiteCaptureResponseSchema = z107.object({
22126
- captureId: z107.string().uuid(),
22178
+ var WebsiteCaptureResponseSchema = z108.object({
22179
+ captureId: z108.string().uuid(),
22127
22180
  status: WebsiteCaptureStatusSchema,
22128
- expiresAt: z107.string().datetime(),
22129
- previewUrl: z107.string().url().optional(),
22181
+ expiresAt: z108.string().datetime(),
22182
+ previewUrl: z108.string().url().optional(),
22130
22183
  cause: WebsiteCaptureCauseSchema.optional()
22131
22184
  });
22132
22185
  var WebsiteCaptureJobSchema = WebsiteCaptureRequestSchema.extend({
22133
- captureId: z107.string().uuid(),
22134
- attempt: z107.number().int().positive(),
22135
- leaseUntil: z107.string().datetime()
22186
+ captureId: z108.string().uuid(),
22187
+ attempt: z108.number().int().positive(),
22188
+ leaseUntil: z108.string().datetime()
22136
22189
  });
22137
- var WebsiteCaptureClaimResponseSchema = z107.object({
22190
+ var WebsiteCaptureClaimResponseSchema = z108.object({
22138
22191
  capture: WebsiteCaptureJobSchema.nullable()
22139
22192
  });
22140
22193
  var attempt = {
22141
- attempt: z107.number().int().positive()
22194
+ attempt: z108.number().int().positive()
22142
22195
  };
22143
- var digest = z107.string().regex(/^[a-f0-9]{64}$/);
22144
- var WebsiteCaptureUploadRequestSchema = z107.object({
22196
+ var digest = z108.string().regex(/^[a-f0-9]{64}$/);
22197
+ var WebsiteCaptureUploadRequestSchema = z108.object({
22145
22198
  ...attempt,
22146
- contentLength: z107.number().int().positive().max(WEBSITE_CAPTURE_MAX_BUNDLE_BYTES),
22199
+ contentLength: z108.number().int().positive().max(WEBSITE_CAPTURE_MAX_BUNDLE_BYTES),
22147
22200
  sha256: digest
22148
22201
  }).strict();
22149
- var WebsiteCaptureDoneRequestSchema = z107.object({
22202
+ var WebsiteCaptureDoneRequestSchema = z108.object({
22150
22203
  ...attempt,
22151
22204
  sha256: digest
22152
22205
  }).strict();
22153
- var WebsiteCaptureFailedRequestSchema = z107.object({
22206
+ var WebsiteCaptureFailedRequestSchema = z108.object({
22154
22207
  ...attempt,
22155
22208
  cause: WebsiteCaptureCauseSchema
22156
22209
  }).strict();
22157
- var WebsiteCaptureBundleSchema = z107.object({
22158
- version: z107.literal(1),
22159
- files: z107.array(z107.object({
22160
- path: z107.string().max(140).regex(/^research\/(?:page\.json|(?:desktop|mobile)-[1-9]\d*\.jpg|logo\.(?:png|svg)|image-[1-9]\d*\.(?:png|jpg|jpeg|webp|svg|avif)|font-[1-9]\d*\.(?:woff2?|ttf|otf))$/),
22161
- base64: z107.string().max(Math.ceil(WEBSITE_CAPTURE_MAX_FILE_BYTES / 3) * 4).regex(/^[A-Za-z0-9+/]*={0,2}$/).refine((value) => value.length % 4 === 0),
22210
+ var WebsiteCaptureBundleSchema = z108.object({
22211
+ version: z108.literal(1),
22212
+ files: z108.array(z108.object({
22213
+ path: z108.string().max(140).regex(/^research\/(?:page\.json|(?:desktop|mobile)-[1-9]\d*\.jpg|logo\.(?:png|svg)|image-[1-9]\d*\.(?:png|jpg|jpeg|webp|svg|avif)|font-[1-9]\d*\.(?:woff2?|ttf|otf))$/),
22214
+ base64: z108.string().max(Math.ceil(WEBSITE_CAPTURE_MAX_FILE_BYTES / 3) * 4).regex(/^[A-Za-z0-9+/]*={0,2}$/).refine((value) => value.length % 4 === 0),
22162
22215
  sha256: digest
22163
22216
  }).strict()).min(1).max(WEBSITE_CAPTURE_MAX_FILES)
22164
22217
  }).strict().refine((bundle) => new Set(bundle.files.map((file) => file.path)).size === bundle.files.length, "Duplicate capture file");
22165
- var WebsiteCaptureScreenshotSchema = z107.object({
22166
- file: z107.string(),
22167
- scrollTop: z107.number()
22168
- });
22169
- var WebsiteCaptureAccessSchema = z107.object({
22170
- publicContentText: z107.string().max(8e3),
22171
- passwordGate: z107.boolean(),
22172
- challengeGate: z107.boolean(),
22173
- blockingOverlay: z107.boolean(),
22218
+ var WebsiteCaptureScreenshotSchema = z108.object({
22219
+ file: z108.string(),
22220
+ scrollTop: z108.number()
22221
+ });
22222
+ var WebsiteCaptureAccessSchema = z108.object({
22223
+ publicContentText: z108.string().max(8e3),
22224
+ passwordGate: z108.boolean(),
22225
+ challengeGate: z108.boolean(),
22226
+ blockingOverlay: z108.boolean(),
22174
22227
  // Decoded, substantial images visible outside access walls and page chrome.
22175
22228
  // Optional for compatibility with already captured text-led research.
22176
- publicImageUrls: z107.array(z107.string().url().max(8192)).max(20).optional()
22177
- });
22178
- var WebsiteCaptureResearchSchema = z107.object({
22179
- requestedUrl: z107.string().url(),
22180
- capturedAt: z107.string().datetime(),
22181
- locale: z107.string(),
22182
- bodyTextTruncated: z107.boolean(),
22183
- finalUrl: z107.string().url(),
22184
- lang: z107.string().nullable(),
22185
- title: z107.string(),
22186
- description: z107.string(),
22187
- openGraph: z107.object({
22188
- title: z107.string(),
22189
- description: z107.string(),
22190
- image: z107.string(),
22191
- siteName: z107.string()
22229
+ publicImageUrls: z108.array(z108.string().url().max(8192)).max(20).optional()
22230
+ });
22231
+ var WebsiteCaptureResearchSchema = z108.object({
22232
+ requestedUrl: z108.string().url(),
22233
+ capturedAt: z108.string().datetime(),
22234
+ locale: z108.string(),
22235
+ bodyTextTruncated: z108.boolean(),
22236
+ finalUrl: z108.string().url(),
22237
+ lang: z108.string().nullable(),
22238
+ title: z108.string(),
22239
+ description: z108.string(),
22240
+ openGraph: z108.object({
22241
+ title: z108.string(),
22242
+ description: z108.string(),
22243
+ image: z108.string(),
22244
+ siteName: z108.string()
22192
22245
  }),
22193
- themeColor: z107.string(),
22194
- headings: z107.object({
22195
- h1: z107.array(z107.string()),
22196
- h2: z107.array(z107.string()),
22197
- h3: z107.array(z107.string())
22246
+ themeColor: z108.string(),
22247
+ headings: z108.object({
22248
+ h1: z108.array(z108.string()),
22249
+ h2: z108.array(z108.string()),
22250
+ h3: z108.array(z108.string())
22198
22251
  }),
22199
- callsToAction: z107.array(z107.string()),
22200
- listItems: z107.array(z107.string()),
22201
- bodyText: z107.string(),
22252
+ callsToAction: z108.array(z108.string()),
22253
+ listItems: z108.array(z108.string()),
22254
+ bodyText: z108.string(),
22202
22255
  access: WebsiteCaptureAccessSchema.optional(),
22203
- consent: z107.object({
22204
- pressed: z107.string().nullable(),
22205
- removed: z107.number().nonnegative()
22256
+ consent: z108.object({
22257
+ pressed: z108.string().nullable(),
22258
+ removed: z108.number().nonnegative()
22206
22259
  }).optional(),
22207
- overlaysDismissed: z107.number().int().nonnegative().optional(),
22208
- style: z107.object({
22209
- bodyBackground: z107.string(),
22210
- bodyColor: z107.string(),
22211
- bodyFont: z107.string(),
22212
- headingFont: z107.string().nullable(),
22213
- headingColor: z107.string().nullable(),
22214
- actionColors: z107.array(z107.object({
22215
- color: z107.string(),
22216
- uses: z107.number()
22260
+ overlaysDismissed: z108.number().int().nonnegative().optional(),
22261
+ style: z108.object({
22262
+ bodyBackground: z108.string(),
22263
+ bodyColor: z108.string(),
22264
+ bodyFont: z108.string(),
22265
+ headingFont: z108.string().nullable(),
22266
+ headingColor: z108.string().nullable(),
22267
+ actionColors: z108.array(z108.object({
22268
+ color: z108.string(),
22269
+ uses: z108.number()
22217
22270
  }))
22218
22271
  }),
22219
- images: z107.array(z107.object({
22220
- file: z107.string(),
22221
- src: z107.string(),
22222
- alt: z107.string(),
22223
- width: z107.number().nullable(),
22224
- height: z107.number().nullable(),
22225
- isOpenGraph: z107.boolean()
22272
+ images: z108.array(z108.object({
22273
+ file: z108.string(),
22274
+ src: z108.string(),
22275
+ alt: z108.string(),
22276
+ width: z108.number().nullable(),
22277
+ height: z108.number().nullable(),
22278
+ isOpenGraph: z108.boolean()
22226
22279
  })),
22227
- logo: z107.object({
22228
- file: z107.literal("logo.png"),
22229
- svg: z107.literal("logo.svg").optional(),
22230
- width: z107.number(),
22231
- height: z107.number()
22280
+ logo: z108.object({
22281
+ file: z108.literal("logo.png"),
22282
+ svg: z108.literal("logo.svg").optional(),
22283
+ width: z108.number(),
22284
+ height: z108.number()
22232
22285
  }).nullable(),
22233
- fonts: z107.array(z107.object({
22234
- family: z107.string(),
22235
- weight: z107.string(),
22236
- style: z107.string(),
22237
- unicodeRange: z107.string().nullable(),
22238
- file: z107.string().optional()
22286
+ fonts: z108.array(z108.object({
22287
+ family: z108.string(),
22288
+ weight: z108.string(),
22289
+ style: z108.string(),
22290
+ unicodeRange: z108.string().nullable(),
22291
+ file: z108.string().optional()
22239
22292
  }).transform((font) => ({
22240
22293
  ...font,
22241
22294
  file: font.file
22242
22295
  }))),
22243
- screenshots: z107.object({
22244
- desktop: z107.array(WebsiteCaptureScreenshotSchema),
22245
- mobile: z107.array(WebsiteCaptureScreenshotSchema)
22296
+ screenshots: z108.object({
22297
+ desktop: z108.array(WebsiteCaptureScreenshotSchema),
22298
+ mobile: z108.array(WebsiteCaptureScreenshotSchema)
22299
+ })
22300
+ });
22301
+
22302
+ // ../../packages/types/src/demo-mode.ts
22303
+ import { z as z109 } from "zod";
22304
+ var DEMO_MODE_FLOWS = [
22305
+ "brand",
22306
+ "servicePage",
22307
+ "motion",
22308
+ "image"
22309
+ ];
22310
+ var DemoModeFlowSchema = z109.enum(DEMO_MODE_FLOWS);
22311
+ var DEMO_MODE_STEPS = [
22312
+ "running",
22313
+ "research",
22314
+ "design",
22315
+ "render_0",
22316
+ "render_33",
22317
+ "render_66",
22318
+ "render_100",
22319
+ "review",
22320
+ "final",
22321
+ "watchdog"
22322
+ ];
22323
+ var DemoModeStepSchema = z109.enum(DEMO_MODE_STEPS);
22324
+ var DEMO_MODE_WAIT_SECONDS = {
22325
+ min: 30,
22326
+ max: 450,
22327
+ default: 150
22328
+ };
22329
+ var centsSchema = z109.number().int().min(0).max(1e5);
22330
+ var emailSchema = z109.string().trim().toLowerCase().email();
22331
+ var DemoModeTemplatesSchema = z109.object({
22332
+ brandId: z109.string().uuid(),
22333
+ servicePageId: z109.string().uuid(),
22334
+ motionTaskId: z109.string().uuid(),
22335
+ imageTaskId: z109.string().uuid()
22336
+ });
22337
+ var DemoModeEditableSchema = z109.object({
22338
+ enabled: z109.boolean(),
22339
+ emails: z109.array(emailSchema).max(50).transform((list) => [
22340
+ ...new Set(list)
22341
+ ]),
22342
+ waitSeconds: z109.number().int().min(DEMO_MODE_WAIT_SECONDS.min).max(DEMO_MODE_WAIT_SECONDS.max),
22343
+ chargeCents: z109.object({
22344
+ brand: centsSchema,
22345
+ servicePage: centsSchema,
22346
+ motion: centsSchema,
22347
+ image: centsSchema
22348
+ }),
22349
+ templates: DemoModeTemplatesSchema
22350
+ });
22351
+ var nullableString = z109.string().nullable();
22352
+ var DemoModeSnapshotSchema = z109.object({
22353
+ brand: z109.object({
22354
+ /** Columnas de identidad de `Brand` listas para un `update` (sin id/userId/slug/estado/fechas). */
22355
+ identity: z109.record(z109.unknown()),
22356
+ productSamples: z109.array(z109.object({
22357
+ name: z109.string(),
22358
+ priceCents: z109.number().int().nullable(),
22359
+ currency: nullableString,
22360
+ imageKey: z109.string(),
22361
+ productUrl: nullableString,
22362
+ position: z109.number().int()
22363
+ })),
22364
+ personas: z109.array(z109.object({
22365
+ name: z109.string(),
22366
+ demographics: nullableString,
22367
+ painPoints: nullableString,
22368
+ motivations: nullableString,
22369
+ objections: nullableString,
22370
+ gender: nullableString,
22371
+ isDefault: z109.boolean()
22372
+ }))
22373
+ }),
22374
+ servicePage: z109.object({
22375
+ facts: z109.unknown(),
22376
+ review: z109.unknown(),
22377
+ artifact: z109.unknown()
22378
+ }),
22379
+ motion: z109.object({
22380
+ outputs: MotionGraphicsOutputsSchema,
22381
+ /**
22382
+ * La captura REAL de la web de la plantilla (nunca una fabricada por la
22383
+ * demo). Null cuando la plantilla no tiene ninguna: la captura demo nunca
22384
+ * va live, así que el servicio usa `DEMO_MODE_PLACEHOLDER_CAPTURE`.
22385
+ */
22386
+ capture: z109.object({
22387
+ bundleKey: z109.string(),
22388
+ sha256: z109.string(),
22389
+ uploadBytes: z109.number().int().nullable(),
22390
+ previewKey: nullableString
22391
+ }).nullable()
22392
+ }),
22393
+ image: z109.object({
22394
+ provider: z109.string(),
22395
+ model: z109.string(),
22396
+ prompt: z109.string(),
22397
+ imageUrl: z109.string(),
22398
+ width: z109.number().int(),
22399
+ height: z109.number().int(),
22400
+ adCopy: nullableString,
22401
+ rawResponse: z109.unknown()
22246
22402
  })
22247
22403
  });
22404
+ var DemoModeConfigSchema = DemoModeEditableSchema.extend({
22405
+ snapshot: DemoModeSnapshotSchema.nullable(),
22406
+ snapshotAt: z109.string().datetime().nullable()
22407
+ });
22408
+ var DemoModeAdminViewSchema = DemoModeEditableSchema.extend({
22409
+ // Sin configurar, la API devuelve ids vacíos ("" no es uuid): la vista los
22410
+ // admite; el PUT sí exige uuid (`DemoModeEditableSchema`).
22411
+ templates: z109.object({
22412
+ brandId: z109.string(),
22413
+ servicePageId: z109.string(),
22414
+ motionTaskId: z109.string(),
22415
+ imageTaskId: z109.string()
22416
+ }),
22417
+ snapshotAt: z109.string().nullable()
22418
+ });
22419
+ var DEMO_MODE_TEMPLATE_PROBLEMS = [
22420
+ "not_found",
22421
+ "brand_not_ready",
22422
+ "no_artifact",
22423
+ "artifact_invalid",
22424
+ "task_not_done",
22425
+ "no_video",
22426
+ "no_creative"
22427
+ ];
22428
+ var DemoModeTemplateVerdictSchema = z109.discriminatedUnion("ok", [
22429
+ z109.object({
22430
+ ok: z109.literal(true)
22431
+ }),
22432
+ z109.object({
22433
+ ok: z109.literal(false),
22434
+ problem: z109.enum(DEMO_MODE_TEMPLATE_PROBLEMS)
22435
+ })
22436
+ ]);
22437
+ var DemoModeValidationSchema = z109.object({
22438
+ brandId: DemoModeTemplateVerdictSchema,
22439
+ servicePageId: DemoModeTemplateVerdictSchema,
22440
+ motionTaskId: DemoModeTemplateVerdictSchema,
22441
+ imageTaskId: DemoModeTemplateVerdictSchema
22442
+ });
22443
+ var DemoModeJobSchema = z109.object({
22444
+ flow: DemoModeFlowSchema,
22445
+ step: DemoModeStepSchema,
22446
+ /** brandId | servicePageOperationId | taskId según el flujo. */
22447
+ targetId: z109.string().uuid(),
22448
+ userId: z109.string().min(1),
22449
+ /** Solo marca: la generación de extracción que el guion completa. */
22450
+ generation: z109.number().int().positive().optional(),
22451
+ /** Solo `final`/`watchdog`: la parte del snapshot de ESTE flujo, congelada al empezar. */
22452
+ result: z109.unknown().optional()
22453
+ });
22248
22454
 
22249
22455
  // src/http.ts
22250
22456
  import express4 from "express";
@@ -22755,23 +22961,23 @@ import { InsufficientScopeError, InvalidTokenError } from "@modelcontextprotocol
22755
22961
  import { createRemoteJWKSet as createRemoteJWKSet2, jwtVerify as jwtVerify2 } from "jose";
22756
22962
 
22757
22963
  // src/auth/oauth-config.ts
22758
- import { z as z108 } from "zod";
22964
+ import { z as z110 } from "zod";
22759
22965
  var MCP_RESOURCE = new URL("https://mcp.productmaker.app/mcp");
22760
22966
  var MCP_SCOPE = "mcp:access";
22761
22967
  var REFRESH_SCOPE = "offline_access";
22762
22968
  var STATIC_CLIENT_ISSUER = new URL(MCP_RESOURCE.origin);
22763
- var oauthEnvSchema = z108.object({
22764
- MCP_REMOTE_AUTH_MODE: z108.literal("oauth"),
22765
- MCP_AUTH0_ISSUER: z108.string().trim().min(1),
22766
- MCP_AUTH0_AUDIENCE: z108.string().trim().refine((value) => value === MCP_RESOURCE.href, {
22969
+ var oauthEnvSchema = z110.object({
22970
+ MCP_REMOTE_AUTH_MODE: z110.literal("oauth"),
22971
+ MCP_AUTH0_ISSUER: z110.string().trim().min(1),
22972
+ MCP_AUTH0_AUDIENCE: z110.string().trim().refine((value) => value === MCP_RESOURCE.href, {
22767
22973
  message: `must equal ${MCP_RESOURCE.href}`
22768
22974
  }),
22769
- MCP_AUTH0_CLIENT_ID: z108.string().trim().min(1),
22770
- MCP_AUTH0_CLIENT_SECRET: z108.string().trim().min(1),
22771
- PM_API_AUDIENCE: z108.string().trim().min(1),
22772
- AUTH0_AUDIENCE: z108.string().trim().min(1),
22773
- MCP_STATIC_CLIENT_ID: z108.string().trim().min(1).optional(),
22774
- MCP_STATIC_CLIENT_SECRET: z108.string().trim().min(1).optional()
22975
+ MCP_AUTH0_CLIENT_ID: z110.string().trim().min(1),
22976
+ MCP_AUTH0_CLIENT_SECRET: z110.string().trim().min(1),
22977
+ PM_API_AUDIENCE: z110.string().trim().min(1),
22978
+ AUTH0_AUDIENCE: z110.string().trim().min(1),
22979
+ MCP_STATIC_CLIENT_ID: z110.string().trim().min(1).optional(),
22980
+ MCP_STATIC_CLIENT_SECRET: z110.string().trim().min(1).optional()
22775
22981
  });
22776
22982
  function formatZodIssues(error) {
22777
22983
  return error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
@@ -23927,7 +24133,7 @@ var ApiClient = class {
23927
24133
  };
23928
24134
 
23929
24135
  // src/index.ts
23930
- var MCP_VERSION = "11.3.2";
24136
+ var MCP_VERSION = "11.4.0";
23931
24137
 
23932
24138
  // src/meta-upload-app.ts
23933
24139
  import { readFileSync } from "fs";
@@ -23999,7 +24205,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
23999
24205
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
24000
24206
 
24001
24207
  // src/tools/tasks.ts
24002
- import { z as z113 } from "zod";
24208
+ import { z as z115 } from "zod";
24003
24209
 
24004
24210
  // src/resolve-image.ts
24005
24211
  import { lookup as dnsLookup } from "dns/promises";
@@ -24560,9 +24766,9 @@ async function resolveMediaRef(ref, opts) {
24560
24766
  __name(resolveMediaRef, "resolveMediaRef");
24561
24767
 
24562
24768
  // src/tools/shared.ts
24563
- import { z as z109 } from "zod";
24564
- var Lang = z109.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);
24565
- var Country = z109.string().min(2).max(3);
24769
+ import { z as z111 } from "zod";
24770
+ var Lang = z111.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);
24771
+ var Country = z111.string().min(2).max(3);
24566
24772
  var LandingStrategyEnum = LandingStrategySchema;
24567
24773
  var LandingImageFormatEnum = LandingImageFormatSchema;
24568
24774
  var VideoPresetEnum = VideoPreset.extract([
@@ -24666,7 +24872,7 @@ function animationStyleApplies(videoPreset, angleNarratives) {
24666
24872
  return ANIMATED_VIDEO_PRESETS.has(videoPreset ?? "") || (angleNarratives ?? []).some((n) => ANIMATED_NARRATIVE_STYLES.has(n));
24667
24873
  }
24668
24874
  __name(animationStyleApplies, "animationStyleApplies");
24669
- var VideoTierEnum = z109.enum([
24875
+ var VideoTierEnum = z111.enum([
24670
24876
  "basic"
24671
24877
  ]);
24672
24878
  function resolveVideoTier(_tier) {
@@ -24724,10 +24930,10 @@ var ImageCreativeStyleEnum = ImageCreativeStyle;
24724
24930
  var ImageCreativeArchetypeEnum = ImageCreativeArchetype;
24725
24931
  var ImageCreativeVisualTreatmentEnum = ImageCreativeVisualTreatment;
24726
24932
  var ImageCreativeAspectRatioEnum = ImageCreativeAspectRatio;
24727
- var ImageRefSchema = z109.object({
24728
- url: z109.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.'),
24729
- path: z109.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`.'),
24730
- assetId: z109.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.")
24933
+ var ImageRefSchema = z111.object({
24934
+ url: z111.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.'),
24935
+ path: z111.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`.'),
24936
+ assetId: z111.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.")
24731
24937
  }).refine((v) => [
24732
24938
  v.url,
24733
24939
  v.path,
@@ -24735,11 +24941,11 @@ var ImageRefSchema = z109.object({
24735
24941
  ].filter(Boolean).length === 1, {
24736
24942
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
24737
24943
  });
24738
- var ImagesInput = z109.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
24944
+ var ImagesInput = z111.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
24739
24945
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
24740
24946
  if (assetCount > 0 && assetCount !== images.length) {
24741
24947
  ctx.addIssue({
24742
- code: z109.ZodIssueCode.custom,
24948
+ code: z111.ZodIssueCode.custom,
24743
24949
  message: "all image entries must use assetId, or all must use URL/path sources"
24744
24950
  });
24745
24951
  }
@@ -24789,16 +24995,24 @@ async function submitCreative(api, opts) {
24789
24995
  ...img,
24790
24996
  filename: `image-${i}.png`
24791
24997
  }));
24792
- const r = await api.postMultipart(opts.path, {
24793
- images: parts
24794
- }, flatten({
24795
- ...rest,
24796
- ...assetIds ? {
24797
- assetIds
24798
- } : {}
24799
- }), opts.idempotencyKey ? {
24800
- idempotencyKey: opts.idempotencyKey
24801
- } : void 0);
24998
+ const r = await api.postMultipart(
24999
+ opts.path,
25000
+ {
25001
+ images: parts
25002
+ },
25003
+ // assetIds stays an array so postMultipart appends one `assetIds` field per
25004
+ // id: `flatten` would comma-join them into a single non-UUID value and the
25005
+ // API rejects every multi-photo upload with "assetId must be a valid UUID".
25006
+ {
25007
+ ...flatten(rest),
25008
+ ...assetIds ? {
25009
+ assetIds
25010
+ } : {}
25011
+ },
25012
+ opts.idempotencyKey ? {
25013
+ idempotencyKey: opts.idempotencyKey
25014
+ } : void 0
25015
+ );
24802
25016
  const taskId = r.taskId ?? r.jobId;
24803
25017
  return asText({
24804
25018
  taskId,
@@ -24812,14 +25026,14 @@ async function submitCreative(api, opts) {
24812
25026
  });
24813
25027
  }
24814
25028
  __name(submitCreative, "submitCreative");
24815
- var ResearchTargetCountryEnum = z109.enum([
25029
+ var ResearchTargetCountryEnum = z111.enum([
24816
25030
  "CO",
24817
25031
  "MX",
24818
25032
  "PE",
24819
25033
  "EC",
24820
25034
  "CL"
24821
25035
  ]);
24822
- var ResearchCategoryEnum = z109.enum([
25036
+ var ResearchCategoryEnum = z111.enum([
24823
25037
  "auto",
24824
25038
  "automotive",
24825
25039
  "kitchen",
@@ -24949,6 +25163,7 @@ var McpErrorCode = {
24949
25163
  CAMPAIGN_NOT_FOUND: "CAMPAIGN_NOT_FOUND",
24950
25164
  CAMPAIGN_TASK_NOT_FOUND: "CAMPAIGN_TASK_NOT_FOUND",
24951
25165
  CAMPAIGN_MISSING_LANDING_URL: "CAMPAIGN_MISSING_LANDING_URL",
25166
+ CAMPAIGN_MISSING_TARGET_COUNTRY: "CAMPAIGN_MISSING_TARGET_COUNTRY",
24952
25167
  CAMPAIGN_NO_CREATIVES: "CAMPAIGN_NO_CREATIVES",
24953
25168
  CAMPAIGN_MISSING_THUMBNAILS: "CAMPAIGN_MISSING_THUMBNAILS",
24954
25169
  CAMPAIGN_RECONCILIATION_REQUIRED: "CAMPAIGN_RECONCILIATION_REQUIRED",
@@ -24988,6 +25203,7 @@ var McpErrorCode = {
24988
25203
  META_NO_ASSETS_READY: "META_NO_ASSETS_READY",
24989
25204
  META_NO_THUMBNAIL_SOURCE: "META_NO_THUMBNAIL_SOURCE",
24990
25205
  META_NO_LANDING_URL: "META_NO_LANDING_URL",
25206
+ META_NO_TARGET_COUNTRY: "META_NO_TARGET_COUNTRY",
24991
25207
  META_TASK_NOT_FOUND: "META_TASK_NOT_FOUND",
24992
25208
  META_INVALID_DATA: "META_INVALID_DATA",
24993
25209
  META_INVALID_AD_ACCOUNT: "META_INVALID_AD_ACCOUNT",
@@ -25075,7 +25291,8 @@ var CODE_MESSAGES = {
25075
25291
  META_NO_ADS_CREATED: "No ads could be created. Most likely: the Meta Ads account has no payment method, no Facebook Page is linked, or the Facebook app lost permissions. Verify all three at https://business.facebook.com.",
25076
25292
  META_NO_ASSETS_READY: "The task has no videos or ad creative ready to publish yet. Wait for generation to finish or regenerate the assets.",
25077
25293
  META_NO_THUMBNAIL_SOURCE: "No image is available to use as the video thumbnail. Upload a product image or generate the ad creative before publishing.",
25078
- META_NO_LANDING_URL: "Missing landing URL. Pass it in `landingUrl` or publish to Shopify first with `publish_to_shopify`.",
25294
+ META_NO_LANDING_URL: "Missing landing URL. Pass it in `landingUrl`, or publish first: a product to Shopify with `publish_to_shopify`, a service to its service landing.",
25295
+ META_NO_TARGET_COUNTRY: "This service ad has no target country (its brand sets none). Ask the user which country and pass it in `campaignConfig.targetCountries`; never assume one.",
25079
25296
  META_TASK_NOT_FOUND: "Task not found or does not belong to this user. Verify the `taskId`.",
25080
25297
  META_INVALID_DATA: "Meta rejected the request due to invalid data. Verify that `adAccountId` and `pixelId` are correct.",
25081
25298
  META_INVALID_AD_ACCOUNT: "Ad account not found or no access. Confirm the `adAccountId` with `list_meta_ad_accounts`.",
@@ -25114,7 +25331,8 @@ var CODE_MESSAGES = {
25114
25331
  // Campaign (shared)
25115
25332
  CAMPAIGN_NOT_FOUND: "Campaign not found or does not belong to this user. Verify the `campaignId`.",
25116
25333
  CAMPAIGN_TASK_NOT_FOUND: "Campaign task not found. Verify the `taskId`.",
25117
- CAMPAIGN_MISSING_LANDING_URL: "Missing landing URL for the campaign. Publish to Shopify first or pass `landingUrl` explicitly.",
25334
+ CAMPAIGN_MISSING_LANDING_URL: "Missing landing URL for the campaign. Publish first (a product to Shopify, a service to its service landing) or pass `landingUrl` explicitly.",
25335
+ CAMPAIGN_MISSING_TARGET_COUNTRY: "This service ad has no target country (its brand sets none). Ask the user which country and pass it in `campaignConfig.targetCountries`; never assume one.",
25118
25336
  CAMPAIGN_NO_CREATIVES: "The task has no creatives (video/image) ready for the campaign. Wait for generation to finish.",
25119
25337
  CAMPAIGN_MISSING_THUMBNAILS: "Missing thumbnails for the videos. Verify that image/video generation has finished.",
25120
25338
  CAMPAIGN_RECONCILIATION_REQUIRED: "A campaign may already have been created. Do not retry creation; reopen the project and reconcile it or contact support.",
@@ -25206,8 +25424,10 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
25206
25424
  McpErrorCode.TIKTOK_ADVERTISER_REQUIRED,
25207
25425
  McpErrorCode.TIKTOK_PIXEL_NOT_FOUND,
25208
25426
  McpErrorCode.CAMPAIGN_MISSING_LANDING_URL,
25427
+ McpErrorCode.CAMPAIGN_MISSING_TARGET_COUNTRY,
25209
25428
  McpErrorCode.CAMPAIGN_RECONCILIATION_REQUIRED,
25210
25429
  McpErrorCode.META_NO_LANDING_URL,
25430
+ McpErrorCode.META_NO_TARGET_COUNTRY,
25211
25431
  McpErrorCode.META_PORTFOLIO_MISMATCH,
25212
25432
  McpErrorCode.META_PAGE_SELECTION_REQUIRED,
25213
25433
  McpErrorCode.META_INVALID_PAGE,
@@ -25318,6 +25538,7 @@ var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
25318
25538
  McpErrorCode.META_NO_ASSETS_READY,
25319
25539
  McpErrorCode.META_NO_THUMBNAIL_SOURCE,
25320
25540
  McpErrorCode.META_NO_LANDING_URL,
25541
+ McpErrorCode.META_NO_TARGET_COUNTRY,
25321
25542
  McpErrorCode.META_TASK_NOT_FOUND,
25322
25543
  McpErrorCode.META_INVALID_DATA,
25323
25544
  McpErrorCode.META_INVALID_AD_ACCOUNT,
@@ -25365,6 +25586,7 @@ var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
25365
25586
  McpErrorCode.CAMPAIGN_NOT_FOUND,
25366
25587
  McpErrorCode.CAMPAIGN_TASK_NOT_FOUND,
25367
25588
  McpErrorCode.CAMPAIGN_MISSING_LANDING_URL,
25589
+ McpErrorCode.CAMPAIGN_MISSING_TARGET_COUNTRY,
25368
25590
  McpErrorCode.CAMPAIGN_NO_CREATIVES,
25369
25591
  McpErrorCode.CAMPAIGN_MISSING_THUMBNAILS,
25370
25592
  McpErrorCode.CAMPAIGN_RECONCILIATION_REQUIRED,
@@ -26131,29 +26353,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
26131
26353
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
26132
26354
 
26133
26355
  // src/tools/media-presentation.ts
26134
- import { z as z110 } from "zod";
26135
- var HttpsPresentationUrlSchema = z110.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
26356
+ import { z as z112 } from "zod";
26357
+ var HttpsPresentationUrlSchema = z112.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
26136
26358
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
26137
26359
  const hostname = new URL(value).hostname.toLowerCase();
26138
26360
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
26139
26361
  }, "preview URL must be owned by ProductMaker");
26140
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z110.number().int().positive().max(maximum), "positiveIntAtMost");
26141
- var PresentationImageSchema = z110.object({
26142
- kind: z110.literal("image"),
26362
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z112.number().int().positive().max(maximum), "positiveIntAtMost");
26363
+ var PresentationImageSchema = z112.object({
26364
+ kind: z112.literal("image"),
26143
26365
  url: HttpsPresentationUrlSchema,
26144
- mimeType: z110.enum([
26366
+ mimeType: z112.enum([
26145
26367
  "image/jpeg",
26146
26368
  "image/png"
26147
26369
  ]),
26148
26370
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
26149
26371
  width: positiveIntAtMost(16384),
26150
26372
  height: positiveIntAtMost(16384),
26151
- alt: z110.string().trim().min(1).max(240)
26373
+ alt: z112.string().trim().min(1).max(240)
26152
26374
  }).strict();
26153
26375
  var McpMediaPresentationSchema = PresentationImageSchema;
26154
- var GalleryImageSchema = z110.object({
26376
+ var GalleryImageSchema = z112.object({
26155
26377
  url: ProductMakerPreviewUrlSchema,
26156
- alt: z110.string().trim().min(1).max(240)
26378
+ alt: z112.string().trim().min(1).max(240)
26157
26379
  });
26158
26380
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
26159
26381
  async function imageBlocks(image, transport) {
@@ -26210,12 +26432,12 @@ async function buildMcpMediaPresentationContent(rawPresentation, transport = "ht
26210
26432
  ];
26211
26433
  }
26212
26434
  __name(buildMcpMediaPresentationContent, "buildMcpMediaPresentationContent");
26213
- var OwnedImagePreviewSchema = z110.object({
26435
+ var OwnedImagePreviewSchema = z112.object({
26214
26436
  url: HttpsPresentationUrlSchema.refine((value) => {
26215
26437
  const url = new URL(value);
26216
26438
  return !url.username && !url.password && !isPrivateHost(url.hostname);
26217
26439
  }, "Preview URL must be public HTTPS without credentials"),
26218
- alt: z110.string().trim().min(1).max(240)
26440
+ alt: z112.string().trim().min(1).max(240)
26219
26441
  });
26220
26442
  async function buildMcpImagePreviewContent(rawPreview, transport = "http") {
26221
26443
  const preview2 = OwnedImagePreviewSchema.safeParse(rawPreview);
@@ -26298,7 +26520,7 @@ async function buildMcpImageGalleryContent(rawItems, transport = "http") {
26298
26520
  __name(buildMcpImageGalleryContent, "buildMcpImageGalleryContent");
26299
26521
 
26300
26522
  // src/tools/animated-video.ts
26301
- import { z as z111 } from "zod";
26523
+ import { z as z113 } from "zod";
26302
26524
 
26303
26525
  // src/tools/paid-confirmation.ts
26304
26526
  function describeMarketStudyChoice(enabled) {
@@ -26548,27 +26770,27 @@ function hookVariantsLabel(count) {
26548
26770
  return count === 1 ? "1 versi\xF3n del gancho" : `${count} versiones del gancho`;
26549
26771
  }
26550
26772
  __name(hookVariantsLabel, "hookVariantsLabel");
26551
- var DurationInput = z111.union(MOTION_GRAPHICS_DURATIONS.map((d) => z111.literal(d)));
26552
- var CreateAnimatedVideoInput = z111.object({
26553
- action: z111.enum([
26773
+ var DurationInput = z113.union(MOTION_GRAPHICS_DURATIONS.map((d) => z113.literal(d)));
26774
+ var CreateAnimatedVideoInput = z113.object({
26775
+ action: z113.enum([
26554
26776
  "prepare",
26555
26777
  "status",
26556
26778
  "cancel",
26557
26779
  "generate"
26558
26780
  ]).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."),
26559
- websiteCaptureId: z111.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
26560
- generationRequestId: z111.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."),
26561
- confirmed: z111.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."),
26781
+ websiteCaptureId: z113.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
26782
+ generationRequestId: z113.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."),
26783
+ confirmed: z113.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."),
26562
26784
  // Plain text, not `.url()`: users type «cal.com», and the web accepts it.
26563
26785
  // normalizeWebAddress (shared with the web) adds https:// and refuses
26564
26786
  // anything that is not a public http(s) address.
26565
- landingUrl: z111.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."),
26787
+ landingUrl: z113.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."),
26566
26788
  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.'),
26567
26789
  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.`),
26568
26790
  language: MotionGraphicsLanguageSchema.optional().describe('Idioma de los textos del video: "es", "en" o "pt".'),
26569
- notes: z111.string().trim().max(MOTION_GRAPHICS_NOTES_MAX_CHARS).optional().describe("Opcional. Indicaciones para el video en lenguaje natural (ej. enf\xF3cate en los precios, tono m\xE1s formal, menciona la prueba gratis)."),
26791
+ notes: z113.string().trim().max(MOTION_GRAPHICS_NOTES_MAX_CHARS).optional().describe("Opcional. Indicaciones para el video en lenguaje natural (ej. enf\xF3cate en los precios, tono m\xE1s formal, menciona la prueba gratis)."),
26570
26792
  hookVariants: MotionGraphicsHookVariantsSchema.optional().describe(`Opcional. Versiones del gancho: el mismo video con distintas aperturas para probar cu\xE1l funciona mejor, de 1 a ${MOTION_GRAPHICS_HOOK_VARIANTS_MAX} (por defecto 1). Cada versi\xF3n extra tiene precio (ver la descripci\xF3n de la herramienta); \xFAsalo solo si el usuario lo pide.`),
26571
- music: z111.boolean().optional().describe("Opcional. M\xFAsica de fondo (por defecto true). false hace el video sin m\xFAsica, m\xE1s crudo, estilo UGC: quedan la voz y los efectos de sonido. Mismo precio. \xDAsalo solo si el usuario lo pide.")
26793
+ music: z113.boolean().optional().describe("Opcional. M\xFAsica de fondo (por defecto true). false hace el video sin m\xFAsica, m\xE1s crudo, estilo UGC: quedan la voz y los efectos de sonido. Mismo precio. \xDAsalo solo si el usuario lo pide.")
26572
26794
  }).strict();
26573
26795
  function captureNextAction(capture) {
26574
26796
  if (capture.status === "ready") return "Muestra la vista previa al usuario y confirma formato, duraci\xF3n, idioma y precio. Solo despu\xE9s llama create_animated_video con action=generate, este websiteCaptureId y confirmed=true.";
@@ -26601,43 +26823,43 @@ var FORMAT_LABELS = {
26601
26823
  square: "cuadrado 1:1",
26602
26824
  horizontal: "horizontal 16:9"
26603
26825
  };
26604
- var AnimatedVideoResultSchema = z111.object({
26605
- status: z111.enum([
26826
+ var AnimatedVideoResultSchema = z113.object({
26827
+ status: z113.enum([
26606
26828
  "pending",
26607
26829
  "done",
26608
26830
  "error"
26609
26831
  ]),
26610
- serviceMode: z111.literal("motion_graphics"),
26611
- finalMp4Url: z111.string().optional(),
26612
- error: z111.string().optional(),
26613
- motionGraphics: z111.object({
26832
+ serviceMode: z113.literal("motion_graphics"),
26833
+ finalMp4Url: z113.string().optional(),
26834
+ error: z113.string().optional(),
26835
+ motionGraphics: z113.object({
26614
26836
  stage: MotionGraphicsStageSchema,
26615
26837
  format: MotionGraphicsFormatSchema,
26616
- durationSec: z111.number(),
26617
- width: z111.number().optional(),
26618
- height: z111.number().optional(),
26838
+ durationSec: z113.number(),
26839
+ width: z113.number().optional(),
26840
+ height: z113.number().optional(),
26619
26841
  language: MotionGraphicsLanguageSchema.optional(),
26620
- queuedAt: z111.string().optional(),
26621
- jobsAhead: z111.number().int().nonnegative().optional(),
26622
- stageStartedAt: z111.string().optional(),
26623
- renderProgress: z111.number().optional(),
26842
+ queuedAt: z113.string().optional(),
26843
+ jobsAhead: z113.number().int().nonnegative().optional(),
26844
+ stageStartedAt: z113.string().optional(),
26845
+ renderProgress: z113.number().optional(),
26624
26846
  // AI clip fields (absent on a video paid before clips, or from an API
26625
26847
  // that predates them). Lenient: an unreadable value is dropped
26626
26848
  // instead of hiding the status.
26627
- clipCount: z111.number().int().nonnegative().optional().catch(void 0),
26628
- clipsUsed: z111.number().int().nonnegative().optional().catch(void 0),
26629
- clipPriceCents: z111.number().finite().nonnegative().optional().catch(void 0),
26630
- clipsRefunded: z111.number().int().nonnegative().optional().catch(void 0),
26849
+ clipCount: z113.number().int().nonnegative().optional().catch(void 0),
26850
+ clipsUsed: z113.number().int().nonnegative().optional().catch(void 0),
26851
+ clipPriceCents: z113.number().finite().nonnegative().optional().catch(void 0),
26852
+ clipsRefunded: z113.number().int().nonnegative().optional().catch(void 0),
26631
26853
  // Hook versions (absent from an API or a video before them): the
26632
26854
  // count ordered and, once done, the signed URLs of the EXTRA versions
26633
26855
  // (hook 2, hook 3); `finalMp4Url` is hook 1.
26634
- hookVariants: z111.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
26635
- variantUrls: z111.array(z111.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
26856
+ hookVariants: z113.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
26857
+ variantUrls: z113.array(z113.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
26636
26858
  // Extra hook versions given back, as the task recorded it once the
26637
26859
  // refunds landed (absent until then, and from an API before it).
26638
- variantsRefunded: z111.number().int().nonnegative().optional().catch(void 0),
26639
- activity: z111.array(MotionGraphicsActivitySchema).optional().catch(void 0),
26640
- previewUrl: z111.string().optional()
26860
+ variantsRefunded: z113.number().int().nonnegative().optional().catch(void 0),
26861
+ activity: z113.array(MotionGraphicsActivitySchema).optional().catch(void 0),
26862
+ previewUrl: z113.string().optional()
26641
26863
  }).passthrough()
26642
26864
  }).passthrough();
26643
26865
  function parseAnimatedVideoResult(value) {
@@ -26893,10 +27115,10 @@ function registerAnimatedVideoTools(server, api) {
26893
27115
  __name(registerAnimatedVideoTools, "registerAnimatedVideoTools");
26894
27116
 
26895
27117
  // src/tools/winning-product-image.ts
26896
- import { z as z112 } from "zod";
26897
- var WinnerReferenceInput = z112.object({
26898
- runId: z112.string().uuid(),
26899
- candidateSourceId: z112.string().trim().min(1).max(160)
27118
+ import { z as z114 } from "zod";
27119
+ var WinnerReferenceInput = z114.object({
27120
+ runId: z114.string().uuid(),
27121
+ candidateSourceId: z114.string().trim().min(1).max(160)
26900
27122
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
26901
27123
  async function resolveWinnerImages(api, winnerReference, images) {
26902
27124
  if (!winnerReference) return images;
@@ -26933,62 +27155,62 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
26933
27155
  var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
26934
27156
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
26935
27157
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
26936
- var CreateProductTaskInput = z113.object({
27158
+ var CreateProductTaskInput = z115.object({
26937
27159
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
26938
27160
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
26939
- projectId: z113.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
26940
- productUrl: z113.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."),
27161
+ projectId: z115.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
27162
+ productUrl: z115.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."),
26941
27163
  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.'),
26942
27164
  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.'),
26943
- price: z113.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.'),
26944
- compareAtPrice: z113.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".'),
26945
- offer: z113.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.'),
26946
- paymentMethods: z113.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.'),
26947
- productContext: z113.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."),
26948
- productLabel: z113.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.'),
27165
+ price: z115.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.'),
27166
+ compareAtPrice: z115.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".'),
27167
+ offer: z115.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.'),
27168
+ paymentMethods: z115.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.'),
27169
+ productContext: z115.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."),
27170
+ productLabel: z115.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.'),
26949
27171
  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.'),
26950
27172
  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.'),
26951
- durationSeconds: z113.union([
26952
- z113.literal(15),
26953
- z113.literal(30)
27173
+ durationSeconds: z115.union([
27174
+ z115.literal(15),
27175
+ z115.literal(30)
26954
27176
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
26955
- pauseForAngleReview: z113.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."),
26956
- aiDecidesAll: z113.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."),
27177
+ pauseForAngleReview: z115.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."),
27178
+ aiDecidesAll: z115.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."),
26957
27179
  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.'),
26958
27180
  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.'),
26959
27181
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
26960
27182
  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).'),
26961
- videoAngleCount: z113.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."),
27183
+ videoAngleCount: z115.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."),
26962
27184
  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.'),
26963
- outputs: z113.array(z113.enum([
27185
+ outputs: z115.array(z115.enum([
26964
27186
  "landing",
26965
27187
  "video",
26966
27188
  "image"
26967
27189
  ])).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}`),
26968
- includeInitialLandingGif: z113.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."),
26969
- competitorScanEnabled: z113.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."),
27190
+ includeInitialLandingGif: z115.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."),
27191
+ competitorScanEnabled: z115.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."),
26970
27192
  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.'),
26971
- replicateWinnerWhenFound: z113.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."),
26972
- brandId: z113.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."),
26973
- actorId: z113.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."),
27193
+ replicateWinnerWhenFound: z115.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."),
27194
+ brandId: z115.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."),
27195
+ actorId: z115.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."),
26974
27196
  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.'),
26975
- creativeDirection: z113.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.'),
26976
- headline: z113.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."),
26977
- subheadline: z113.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."),
27197
+ creativeDirection: z115.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.'),
27198
+ headline: z115.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."),
27199
+ subheadline: z115.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."),
26978
27200
  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".'),
26979
27201
  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".')
26980
27202
  }).strict();
26981
- var CreateServiceVideoInput = z113.object({
26982
- landingUrl: z113.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
26983
- additionalContext: z113.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
27203
+ var CreateServiceVideoInput = z115.object({
27204
+ landingUrl: z115.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
27205
+ additionalContext: z115.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
26984
27206
  language: Lang.describe("Idioma del video: es, en o pt."),
26985
- voiceId: z113.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.'),
26986
- brandId: z113.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
26987
- reviewMode: z113.enum([
27207
+ voiceId: z115.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.'),
27208
+ brandId: z115.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
27209
+ reviewMode: z115.enum([
26988
27210
  "automatic",
26989
27211
  "guided"
26990
27212
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
26991
- videoPreset: z113.enum([
27213
+ videoPreset: z115.enum([
26992
27214
  "auto",
26993
27215
  "ugc_dynamic",
26994
27216
  "ugc_how_to",
@@ -26998,128 +27220,128 @@ var CreateServiceVideoInput = z113.object({
26998
27220
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
26999
27221
  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.')
27000
27222
  }).strict();
27001
- var GetTaskStatusInput = z113.object({
27002
- taskId: z113.string().min(1),
27003
- waitSeconds: z113.number().int().min(0).max(120).optional()
27223
+ var GetTaskStatusInput = z115.object({
27224
+ taskId: z115.string().min(1),
27225
+ waitSeconds: z115.number().int().min(0).max(120).optional()
27004
27226
  });
27005
- var ListTasksInput = z113.object({
27006
- limit: z113.number().int().min(1).max(50).optional(),
27007
- offset: z113.number().int().min(0).optional(),
27008
- search: z113.string().optional()
27227
+ var ListTasksInput = z115.object({
27228
+ limit: z115.number().int().min(1).max(50).optional(),
27229
+ offset: z115.number().int().min(0).optional(),
27230
+ search: z115.string().optional()
27009
27231
  });
27010
27232
  var MCP_REVIEW_LIST_FIELD_MAX = IMAGE_WIZARD_LIST_FIELD_MAX;
27011
27233
  var MCP_REVIEW_FEATURE_ITEM_MAX = IMAGE_FEATURE_ITEM_MAX;
27012
- var EditTaskDraftInput = z113.object({
27013
- taskId: z113.string().min(1),
27014
- angleIndex: z113.number().int().min(0),
27015
- angle: z113.object({
27016
- angle: z113.string().min(1).max(480),
27017
- buyerPersona: z113.string().min(1).max(360),
27018
- actor: z113.string().min(1).max(360).optional(),
27019
- actorId: z113.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."),
27020
- gender: z113.enum([
27234
+ var EditTaskDraftInput = z115.object({
27235
+ taskId: z115.string().min(1),
27236
+ angleIndex: z115.number().int().min(0),
27237
+ angle: z115.object({
27238
+ angle: z115.string().min(1).max(480),
27239
+ buyerPersona: z115.string().min(1).max(360),
27240
+ actor: z115.string().min(1).max(360).optional(),
27241
+ actorId: z115.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."),
27242
+ gender: z115.enum([
27021
27243
  "female",
27022
27244
  "male"
27023
27245
  ]).optional(),
27024
- scriptNotes: z113.string().max(2e3).optional()
27246
+ scriptNotes: z115.string().max(2e3).optional()
27025
27247
  })
27026
27248
  });
27027
- var PendingActionPayload = z113.discriminatedUnion("kind", [
27028
- z113.object({
27029
- kind: z113.literal("product_reference_set_approval"),
27249
+ var PendingActionPayload = z115.discriminatedUnion("kind", [
27250
+ z115.object({
27251
+ kind: z115.literal("product_reference_set_approval"),
27030
27252
  scope: ProductReferenceScopeEnum.optional(),
27031
- scopeKey: z113.string().min(1).max(120).optional(),
27032
- scopeSnapshotId: z113.string().uuid().optional(),
27033
- expectedScopeHash: z113.string().min(1).max(128).optional(),
27253
+ scopeKey: z115.string().min(1).max(120).optional(),
27254
+ scopeSnapshotId: z115.string().uuid().optional(),
27255
+ expectedScopeHash: z115.string().min(1).max(128).optional(),
27034
27256
  decision: ProductReferenceResolutionDecisionEnum,
27035
27257
  reason: ProductReferenceRejectionReasonEnum.optional(),
27036
- affectedRefKeys: z113.array(z113.string().min(1).max(200)).min(1).optional(),
27037
- affectedPhotoNumbers: z113.array(z113.number().int().positive()).min(1).optional(),
27038
- recoveryAction: z113.enum([
27258
+ affectedRefKeys: z115.array(z115.string().min(1).max(200)).min(1).optional(),
27259
+ affectedPhotoNumbers: z115.array(z115.number().int().positive()).min(1).optional(),
27260
+ recoveryAction: z115.enum([
27039
27261
  "remove",
27040
27262
  "replace",
27041
27263
  "upload",
27042
27264
  "return_to_selection"
27043
27265
  ]).optional()
27044
27266
  }),
27045
- z113.object({
27046
- kind: z113.literal("product_reference_confirmation"),
27047
- selectedPhotoNumbers: z113.array(z113.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."),
27267
+ z115.object({
27268
+ kind: z115.literal("product_reference_confirmation"),
27269
+ selectedPhotoNumbers: z115.array(z115.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."),
27048
27270
  userChoice: ProductReferenceUserChoiceEnum.optional(),
27049
- confirmedProductNames: z113.array(z113.string().min(1).max(120)).min(2).max(8).optional(),
27271
+ confirmedProductNames: z115.array(z115.string().min(1).max(120)).min(2).max(8).optional(),
27050
27272
  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."),
27051
27273
  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."),
27052
- useMultiSceneShowcase: z113.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
27274
+ useMultiSceneShowcase: z115.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
27053
27275
  }),
27054
- z113.object({
27055
- kind: z113.literal("angle_review_approval"),
27276
+ z115.object({
27277
+ kind: z115.literal("angle_review_approval"),
27056
27278
  // All edits are optional — empty action body just approves the
27057
27279
  // backend-generated draft as-is. Field shapes mirror the angle-review
27058
27280
  // request contracts in @packages/types/wizard.ts; the handler routes to
27059
27281
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
27060
- customAngle: z113.string().min(1).max(480).optional(),
27282
+ customAngle: z115.string().min(1).max(480).optional(),
27061
27283
  // Keep the shared MCP action within the strictest downstream contract:
27062
27284
  // autopilot/image resume endpoints cap these fields at 1500 characters.
27063
- painPoints: z113.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
27064
- benefits: z113.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
27285
+ painPoints: z115.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
27286
+ benefits: z115.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
27065
27287
  // Same policy as the two fields above: the strictest downstream contract
27066
27288
  // wins. The image endpoint caps each feature at 240 while landing/video
27067
27289
  // accept 300, and this single action routes to whichever the task is — so
27068
27290
  // accepting 300 here turns a 250-character feature on an image task into
27069
27291
  // an opaque HTTP 400 after the model already believed it had been saved.
27070
- features: z113.array(z113.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
27071
- buyerPersona: z113.string().min(1).max(360).optional(),
27292
+ features: z115.array(z115.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
27293
+ buyerPersona: z115.string().min(1).max(360).optional(),
27072
27294
  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.'),
27073
- actor: z113.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."),
27074
- actorId: z113.string().max(120).nullable().optional(),
27075
- creativeDirection: z113.string().max(2e3).optional(),
27076
- selectedAngleNumbers: z113.array(z113.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."),
27077
- angleEdits: z113.array(z113.object({
27078
- angleNumber: z113.number().int().positive(),
27079
- narrativeSelection: z113.enum([
27295
+ actor: z115.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."),
27296
+ actorId: z115.string().max(120).nullable().optional(),
27297
+ creativeDirection: z115.string().max(2e3).optional(),
27298
+ selectedAngleNumbers: z115.array(z115.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."),
27299
+ angleEdits: z115.array(z115.object({
27300
+ angleNumber: z115.number().int().positive(),
27301
+ narrativeSelection: z115.enum([
27080
27302
  "market",
27081
27303
  "guided"
27082
27304
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
27083
- angle: z113.string().min(1).max(480).optional(),
27084
- buyerPersona: z113.string().min(1).max(360).optional(),
27305
+ angle: z115.string().min(1).max(480).optional(),
27306
+ buyerPersona: z115.string().min(1).max(360).optional(),
27085
27307
  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.'),
27086
- actor: z113.string().min(1).max(360).optional(),
27087
- actorId: z113.string().max(120).nullable().optional(),
27088
- creativeDirection: z113.string().max(2e3).optional()
27308
+ actor: z115.string().min(1).max(360).optional(),
27309
+ actorId: z115.string().max(120).nullable().optional(),
27310
+ creativeDirection: z115.string().max(2e3).optional()
27089
27311
  }).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)."),
27090
- gapDurationSeconds: z113.union([
27091
- z113.literal(15),
27092
- z113.literal(30)
27312
+ gapDurationSeconds: z115.union([
27313
+ z115.literal(15),
27314
+ z115.literal(30)
27093
27315
  ]).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.")
27094
27316
  }),
27095
- z113.object({
27096
- kind: z113.literal("service_angle_approval"),
27097
- angleId: z113.string().uuid().optional(),
27098
- angleNumber: z113.number().int().positive().optional(),
27099
- content: z113.string().min(1).max(480).optional(),
27100
- creativeDirection: z113.string().min(1).max(1500).optional(),
27101
- actor: z113.string().min(1).max(360).optional()
27317
+ z115.object({
27318
+ kind: z115.literal("service_angle_approval"),
27319
+ angleId: z115.string().uuid().optional(),
27320
+ angleNumber: z115.number().int().positive().optional(),
27321
+ content: z115.string().min(1).max(480).optional(),
27322
+ creativeDirection: z115.string().min(1).max(1500).optional(),
27323
+ actor: z115.string().min(1).max(360).optional()
27102
27324
  }),
27103
- z113.object({
27104
- kind: z113.literal("service_script_approval"),
27105
- voiceovers: z113.record(z113.string(), z113.string().min(1).max(600)).optional(),
27106
- visualDirections: z113.record(z113.string(), z113.string().min(1).max(1200)).optional(),
27107
- voiceoversByScene: z113.record(z113.string(), z113.string().min(1).max(600)).optional(),
27108
- visualDirectionsByScene: z113.record(z113.string(), z113.string().min(1).max(1200)).optional()
27325
+ z115.object({
27326
+ kind: z115.literal("service_script_approval"),
27327
+ voiceovers: z115.record(z115.string(), z115.string().min(1).max(600)).optional(),
27328
+ visualDirections: z115.record(z115.string(), z115.string().min(1).max(1200)).optional(),
27329
+ voiceoversByScene: z115.record(z115.string(), z115.string().min(1).max(600)).optional(),
27330
+ visualDirectionsByScene: z115.record(z115.string(), z115.string().min(1).max(1200)).optional()
27109
27331
  })
27110
27332
  ]);
27111
- var ResolvePendingActionInput = z113.object({
27112
- taskId: z113.string().min(1),
27333
+ var ResolvePendingActionInput = z115.object({
27334
+ taskId: z115.string().min(1),
27113
27335
  action: PendingActionPayload
27114
27336
  }).strict();
27115
27337
  function resolveVariantConfirmVideoTier(action) {
27116
27338
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
27117
27339
  }
27118
27340
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
27119
- var StatusForResolveSchema = z113.object({
27341
+ var StatusForResolveSchema = z115.object({
27120
27342
  // Metadata used to select the backend resume contract. Older API responses
27121
27343
  // may omit these fields, so the resolver keeps the generic fallback.
27122
- kind: z113.enum([
27344
+ kind: z115.enum([
27123
27345
  "autopilot",
27124
27346
  "video",
27125
27347
  "image",
@@ -27127,18 +27349,18 @@ var StatusForResolveSchema = z113.object({
27127
27349
  "mix",
27128
27350
  "service"
27129
27351
  ]).optional(),
27130
- selectedOutputs: z113.array(z113.enum([
27352
+ selectedOutputs: z115.array(z115.enum([
27131
27353
  "landing",
27132
27354
  "video",
27133
27355
  "image"
27134
27356
  ])).optional(),
27135
- videoAngleCount: z113.number().int().min(1).max(3).optional(),
27136
- ugcFormat: z113.enum([
27357
+ videoAngleCount: z115.number().int().min(1).max(3).optional(),
27358
+ ugcFormat: z115.enum([
27137
27359
  "single_8s",
27138
27360
  "single_15s",
27139
27361
  "double_30s"
27140
27362
  ]).optional(),
27141
- videoStyle: z113.enum([
27363
+ videoStyle: z115.enum([
27142
27364
  "ugc",
27143
27365
  "cartoon_3d",
27144
27366
  "product_only",
@@ -27148,13 +27370,13 @@ var StatusForResolveSchema = z113.object({
27148
27370
  videoQuality: VideoQualityEnum.optional(),
27149
27371
  videoRouteId: VideoRouteIdEnum.optional(),
27150
27372
  videoModel: TaskVideoModelEnum.optional(),
27151
- videoTier: z113.enum([
27373
+ videoTier: z115.enum([
27152
27374
  "legacy",
27153
27375
  "standard",
27154
27376
  "pro",
27155
27377
  "single_call"
27156
27378
  ]).optional(),
27157
- videoResolution: z113.enum([
27379
+ videoResolution: z115.enum([
27158
27380
  "480p",
27159
27381
  "720p"
27160
27382
  ]).optional(),
@@ -27162,60 +27384,60 @@ var StatusForResolveSchema = z113.object({
27162
27384
  // A task created before a narrative was blocked/hidden must still parse,
27163
27385
  // or resolve_pending_action could never approve it.
27164
27386
  narrativeStyle: NarrativeStyle.optional(),
27165
- pauseForVideoScriptReview: z113.boolean().optional(),
27166
- pendingUserAction: z113.object({
27167
- kind: z113.string(),
27168
- candidateGrouping: z113.string().optional(),
27169
- selectedImageUrls: z113.array(z113.string()).optional(),
27170
- proposedProductNames: z113.array(z113.string()).optional(),
27387
+ pauseForVideoScriptReview: z115.boolean().optional(),
27388
+ pendingUserAction: z115.object({
27389
+ kind: z115.string(),
27390
+ candidateGrouping: z115.string().optional(),
27391
+ selectedImageUrls: z115.array(z115.string()).optional(),
27392
+ proposedProductNames: z115.array(z115.string()).optional(),
27171
27393
  // Adaptive reference questions are server-owned. Echo only the evidence
27172
27394
  // identity and the choices shown by the current snapshot; never accept a
27173
27395
  // client-supplied reference set as authorization.
27174
- options: z113.array(ProductReferenceUserChoiceEnum).max(4).optional(),
27175
- mode: z113.enum([
27396
+ options: z115.array(ProductReferenceUserChoiceEnum).max(4).optional(),
27397
+ mode: z115.enum([
27176
27398
  "question",
27177
27399
  "visual_recovery"
27178
27400
  ]).optional(),
27179
27401
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
27180
- canKeepSelection: z113.boolean().optional(),
27181
- decisionKey: z113.string().optional(),
27182
- questionOrdinal: z113.number().int().min(1).max(5).optional(),
27183
- questionCeiling: z113.union([
27184
- z113.literal(3),
27185
- z113.literal(5)
27402
+ canKeepSelection: z115.boolean().optional(),
27403
+ decisionKey: z115.string().optional(),
27404
+ questionOrdinal: z115.number().int().min(1).max(5).optional(),
27405
+ questionCeiling: z115.union([
27406
+ z115.literal(3),
27407
+ z115.literal(5)
27186
27408
  ]).optional(),
27187
- referenceEvidenceVersion: z113.number().int().positive().optional(),
27188
- expectedEvidenceHash: z113.string().optional(),
27189
- question: z113.object({
27190
- prompt: z113.string().min(1).max(240),
27191
- helpText: z113.string().min(1).max(300).optional(),
27192
- options: z113.array(z113.object({
27409
+ referenceEvidenceVersion: z115.number().int().positive().optional(),
27410
+ expectedEvidenceHash: z115.string().optional(),
27411
+ question: z115.object({
27412
+ prompt: z115.string().min(1).max(240),
27413
+ helpText: z115.string().min(1).max(300).optional(),
27414
+ options: z115.array(z115.object({
27193
27415
  value: ProductReferenceUserChoiceEnum,
27194
- label: z113.string().min(1).max(120),
27195
- description: z113.string().min(1).max(240).optional()
27416
+ label: z115.string().min(1).max(120),
27417
+ description: z115.string().min(1).max(240).optional()
27196
27418
  })).min(2).max(4)
27197
27419
  }).optional(),
27198
27420
  scope: ProductReferenceScopeEnum.optional(),
27199
- scopeKey: z113.string().optional(),
27200
- scopeSnapshotId: z113.string().uuid().optional(),
27201
- scopeHash: z113.string().optional(),
27202
- baseReferenceSetHash: z113.string().optional(),
27203
- phase: z113.enum([
27421
+ scopeKey: z115.string().optional(),
27422
+ scopeSnapshotId: z115.string().uuid().optional(),
27423
+ scopeHash: z115.string().optional(),
27424
+ baseReferenceSetHash: z115.string().optional(),
27425
+ phase: z115.enum([
27204
27426
  "preparation",
27205
27427
  "final"
27206
27428
  ]).optional(),
27207
- selectedRefKeys: z113.array(z113.string().min(1).max(200)).optional(),
27208
- allowedDecisions: z113.array(ProductReferenceResolutionDecisionEnum).optional(),
27209
- previews: z113.array(z113.object({
27210
- refKey: z113.string().min(1).max(200)
27429
+ selectedRefKeys: z115.array(z115.string().min(1).max(200)).optional(),
27430
+ allowedDecisions: z115.array(ProductReferenceResolutionDecisionEnum).optional(),
27431
+ previews: z115.array(z115.object({
27432
+ refKey: z115.string().min(1).max(200)
27211
27433
  }).passthrough()).optional(),
27212
- customAngleDraft: z113.string().optional(),
27213
- painPointsDraft: z113.string().optional(),
27214
- benefitsDraft: z113.string().optional(),
27215
- featuresDraft: z113.array(z113.string()).optional(),
27216
- angleOptions: z113.array(z113.object({
27217
- index: z113.number().int().nonnegative(),
27218
- angle: z113.string().min(1)
27434
+ customAngleDraft: z115.string().optional(),
27435
+ painPointsDraft: z115.string().optional(),
27436
+ benefitsDraft: z115.string().optional(),
27437
+ featuresDraft: z115.array(z115.string()).optional(),
27438
+ angleOptions: z115.array(z115.object({
27439
+ index: z115.number().int().nonnegative(),
27440
+ angle: z115.string().min(1)
27219
27441
  }).passthrough()).min(1).max(5).optional(),
27220
27442
  // Recommendation consumed only when the caller explicitly sends
27221
27443
  // gapDurationSeconds: 30 in the angle approval action.
@@ -27225,17 +27447,17 @@ var StatusForResolveSchema = z113.object({
27225
27447
  // keys. `actorId` (the saved custom actor the picker stored) was silently
27226
27448
  // dropped here, so the approval handler below could not echo it back on the
27227
27449
  // PATCH — the selection looked accepted and reached no render.
27228
- angles: z113.array(z113.object({
27229
- id: z113.string().uuid(),
27230
- content: z113.string(),
27231
- creativeDirection: z113.string(),
27232
- actor: z113.string(),
27233
- actorId: z113.string().nullable().optional()
27450
+ angles: z115.array(z115.object({
27451
+ id: z115.string().uuid(),
27452
+ content: z115.string(),
27453
+ creativeDirection: z115.string(),
27454
+ actor: z115.string(),
27455
+ actorId: z115.string().nullable().optional()
27234
27456
  }).passthrough()).optional(),
27235
- panels: z113.array(z113.object({
27236
- beatId: z113.string(),
27237
- voiceover: z113.string(),
27238
- visualDirection: z113.string()
27457
+ panels: z115.array(z115.object({
27458
+ beatId: z115.string(),
27459
+ voiceover: z115.string(),
27460
+ visualDirection: z115.string()
27239
27461
  }).passthrough()).optional()
27240
27462
  }).optional()
27241
27463
  }).passthrough();
@@ -27587,8 +27809,8 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
27587
27809
  server.registerTool("verify_landing_commerce", {
27588
27810
  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.",
27589
27811
  inputSchema: {
27590
- taskId: z113.string().uuid(),
27591
- editId: z113.string().uuid()
27812
+ taskId: z115.string().uuid(),
27813
+ editId: z115.string().uuid()
27592
27814
  },
27593
27815
  annotations: OVERWRITES_EXTERNAL
27594
27816
  }, async (input) => {
@@ -28234,25 +28456,25 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
28234
28456
  __name(registerTaskTools, "registerTaskTools");
28235
28457
 
28236
28458
  // src/tools/brands.ts
28237
- import { z as z114 } from "zod";
28459
+ import { z as z116 } from "zod";
28238
28460
  var guidance2 = getProductMakerCapabilityModelGuidance("create_brand");
28239
28461
  var BRAND_START_REPLAY_WINDOW_MS = 15 * 60 * 1e3;
28240
28462
  var BRAND_NOTES_MAX_CHARS = 2e4;
28241
- var CreateBrandInput = z114.object({
28242
- action: z114.enum([
28463
+ var CreateBrandInput = z116.object({
28464
+ action: z116.enum([
28243
28465
  "start",
28244
28466
  "status",
28245
28467
  "list"
28246
28468
  ]).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."),
28247
- sourceUrl: z114.string().trim().min(1).max(500).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."),
28248
- businessNotes: z114.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."),
28249
- language: z114.enum([
28469
+ sourceUrl: z116.string().trim().min(1).max(500).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."),
28470
+ businessNotes: z116.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."),
28471
+ language: z116.enum([
28250
28472
  "es",
28251
28473
  "en",
28252
28474
  "pt"
28253
28475
  ]).optional().describe("Idioma de la conversaci\xF3n. Solo se usa si la p\xE1gina del negocio no deja claro su idioma."),
28254
- confirmed: z114.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
28255
- brandId: z114.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
28476
+ confirmed: z116.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
28477
+ brandId: z116.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
28256
28478
  }).strict();
28257
28479
  function normalizeBrandSourceUrl(raw) {
28258
28480
  const value = raw.trim();
@@ -28492,24 +28714,24 @@ __name(registerBrandTools, "registerBrandTools");
28492
28714
 
28493
28715
  // src/tools/service-landing.ts
28494
28716
  import { createHash as createHash4 } from "crypto";
28495
- import { z as z115 } from "zod";
28717
+ import { z as z117 } from "zod";
28496
28718
  var guidance3 = getProductMakerCapabilityModelGuidance("create_service_landing");
28497
28719
  var SERVICE_LANDING_KEY_NAMESPACE = "6f1d8c2a-3b4e-5f60-8a7b-9c0d1e2f3a4b";
28498
28720
  var SERVICE_LANDING_INFO_MAX_CHARS = 2e4;
28499
- var CreateServiceLandingInput = z115.object({
28500
- action: z115.enum([
28721
+ var CreateServiceLandingInput = z117.object({
28722
+ action: z117.enum([
28501
28723
  "prepare",
28502
28724
  "build",
28503
28725
  "status",
28504
28726
  "publish"
28505
28727
  ]).default("prepare").describe("prepare (gratis) crea o retoma la landing de la marca y da el precio; build (pagado, confirmed=true) lee los datos del negocio y luego crea la p\xE1gina; status sigue el avance; publish la publica y devuelve su enlace."),
28506
- brandId: z115.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
28507
- servicePageId: z115.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
28508
- businessInfo: z115.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."),
28509
- confirmed: z115.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
28510
- maxCredits: z115.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."),
28511
- operationId: z115.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
28512
- slug: z115.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.")
28728
+ brandId: z117.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
28729
+ servicePageId: z117.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
28730
+ businessInfo: z117.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."),
28731
+ confirmed: z117.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
28732
+ maxCredits: z117.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."),
28733
+ operationId: z117.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
28734
+ slug: z117.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.")
28513
28735
  }).strict();
28514
28736
  var SERVICE_LANDING_MAX_BUILD_ATTEMPTS = 10;
28515
28737
  function serviceKey(...parts) {
@@ -28731,9 +28953,6 @@ function registerServiceLandingTools(server, api) {
28731
28953
  let operation2 = null;
28732
28954
  if (input.operationId) {
28733
28955
  operation2 = await api.getJson(`/v1/service-pages/operations/${encodeURIComponent(input.operationId)}`);
28734
- if (operation2.recoverable && (operation2.status === "failed" || operation2.status === "requires_reconciliation")) {
28735
- operation2 = await api.postJson(`${pagePath(input.servicePageId)}/operations/${encodeURIComponent(operation2.opId)}/recover`, {});
28736
- }
28737
28956
  if (operation2.status === "queued" || operation2.status === "running") {
28738
28957
  return asText({
28739
28958
  servicePageId: input.servicePageId,
@@ -28750,7 +28969,7 @@ function registerServiceLandingTools(server, api) {
28750
28969
  status: "in_review",
28751
28970
  // Unknown on purpose: the charge is exactly what is being
28752
28971
  // confirmed. Settlement only charges a completed step.
28753
- nextAction: "Esta etapa qued\xF3 en revisi\xF3n por un problema temporal: estamos confirmando si se complet\xF3. Si no se complet\xF3, no se cobra. Dile al usuario que sus datos est\xE1n guardados; vuelve a llamar action=status con el mismo operationId en unos minutos (si no se complet\xF3, pasa a fallida y la reintentas con build). No inicies otra etapa mientras tanto."
28972
+ nextAction: "Esta etapa qued\xF3 en revisi\xF3n por un problema temporal: el servidor est\xE1 confirmando si se complet\xF3 y la resuelve solo. Si no se completa, se devuelve lo cobrado. Dile al usuario que sus datos est\xE1n guardados; vuelve a llamar action=status con el mismo operationId en unos minutos (si no se complet\xF3, pasa a fallida y la reintentas con build). No inicies otra etapa mientras tanto."
28754
28973
  });
28755
28974
  }
28756
28975
  if (operation2.status !== "succeeded") {
@@ -28845,7 +29064,7 @@ function registerServiceLandingTools(server, api) {
28845
29064
  __name(registerServiceLandingTools, "registerServiceLandingTools");
28846
29065
 
28847
29066
  // src/tools/service-images.ts
28848
- import { z as z116 } from "zod";
29067
+ import { z as z118 } from "zod";
28849
29068
  var guidance4 = getProductMakerCapabilityModelGuidance("create_service_images");
28850
29069
  var SERVICE_IMAGE_FORMATS = [
28851
29070
  "4:5",
@@ -28858,23 +29077,23 @@ var LANGUAGE_TAGS = {
28858
29077
  en: "en-US",
28859
29078
  pt: "pt-BR"
28860
29079
  };
28861
- var CreateServiceImagesInput = z116.object({
28862
- brandId: z116.string().uuid().optional().describe("ID de la marca (de create_brand). Recomendado: da nombre, colores, tono y servicios. Nunca un taskId de producto."),
28863
- instruction: z116.string().trim().max(4e3).optional().describe("Qu\xE9 servicio o promoci\xF3n mostrar, con las palabras del usuario (ej. \xABcorte + barba a $35.000 los martes\xBB). Si el usuario deja que la IA decida, om\xEDtelo y usa delegateToAi=true."),
28864
- delegateToAi: z116.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su marca."),
28865
- format: z116.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
28866
- count: z116.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
28867
- quality: z116.enum([
29080
+ var CreateServiceImagesInput = z118.object({
29081
+ brandId: z118.string().uuid().optional().describe("ID de la marca (de create_brand). Recomendado: da nombre, colores, tono y servicios. Nunca un taskId de producto."),
29082
+ instruction: z118.string().trim().max(4e3).optional().describe("Qu\xE9 servicio o promoci\xF3n mostrar, con las palabras del usuario (ej. \xABcorte + barba a $35.000 los martes\xBB). Si el usuario deja que la IA decida, om\xEDtelo y usa delegateToAi=true."),
29083
+ delegateToAi: z118.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su marca."),
29084
+ format: z118.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
29085
+ count: z118.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
29086
+ quality: z118.enum([
28868
29087
  "standard",
28869
29088
  "high"
28870
29089
  ]).optional().describe('Calidad: "standard" (por defecto) o "high" (m\xE1s cara; no disponible en 4:5).'),
28871
- language: z116.enum([
29090
+ language: z118.enum([
28872
29091
  "es",
28873
29092
  "en",
28874
29093
  "pt"
28875
29094
  ]).optional().describe("Idioma de los textos de la imagen (por defecto es)."),
28876
- adCopy: z116.boolean().optional().describe("Opcional. true agrega textos para el anuncio (titular y descripci\xF3n). Por defecto false."),
28877
- confirmed: z116.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
29095
+ adCopy: z118.boolean().optional().describe("Opcional. true agrega textos para el anuncio (titular y descripci\xF3n). Por defecto false."),
29096
+ confirmed: z118.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
28878
29097
  }).strict();
28879
29098
  function serviceImageModel(quality) {
28880
29099
  return quality === "high" ? AD_CREATIVE_MODELS.PREMIUM : AD_CREATIVE_MODELS.STANDARD;
@@ -28985,7 +29204,7 @@ function registerServiceImageTools(server, api, options = {}) {
28985
29204
  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."
28986
29205
  });
28987
29206
  } catch (error) {
28988
- if (error instanceof z116.ZodError) throw invalidInputFromZod(error);
29207
+ if (error instanceof z118.ZodError) throw invalidInputFromZod(error);
28989
29208
  throw translateError(error);
28990
29209
  }
28991
29210
  });
@@ -28993,7 +29212,7 @@ function registerServiceImageTools(server, api, options = {}) {
28993
29212
  __name(registerServiceImageTools, "registerServiceImageTools");
28994
29213
 
28995
29214
  // src/tools/creatives.ts
28996
- import { z as z117 } from "zod";
29215
+ import { z as z119 } from "zod";
28997
29216
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
28998
29217
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
28999
29218
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -29004,72 +29223,72 @@ var CreativeRefs = {
29004
29223
  images: ImagesInput,
29005
29224
  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.'),
29006
29225
  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.'),
29007
- price: z117.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.'),
29008
- offer: z117.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.'),
29009
- compareAtPrice: z117.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
29010
- productContext: z117.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."),
29011
- productLabel: z117.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.'),
29012
- buyerPersona: z117.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.'),
29013
- isCombo: z117.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
29014
- competitorScanEnabled: z117.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."),
29015
- brandId: z117.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.")
29226
+ price: z119.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.'),
29227
+ offer: z119.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.'),
29228
+ compareAtPrice: z119.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
29229
+ productContext: z119.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."),
29230
+ productLabel: z119.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.'),
29231
+ buyerPersona: z119.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.'),
29232
+ isCombo: z119.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
29233
+ competitorScanEnabled: z119.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."),
29234
+ brandId: z119.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.")
29016
29235
  };
29017
- var VideoPresenter = z117.discriminatedUnion("mode", [
29018
- z117.object({
29019
- mode: z117.literal("none")
29236
+ var VideoPresenter = z119.discriminatedUnion("mode", [
29237
+ z119.object({
29238
+ mode: z119.literal("none")
29020
29239
  }).strict(),
29021
- z117.object({
29022
- mode: z117.literal("saved_actor"),
29023
- actorId: z117.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
29240
+ z119.object({
29241
+ mode: z119.literal("saved_actor"),
29242
+ actorId: z119.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
29024
29243
  }).strict(),
29025
- z117.object({
29026
- mode: z117.literal("described"),
29027
- description: z117.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
29244
+ z119.object({
29245
+ mode: z119.literal("described"),
29246
+ description: z119.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
29028
29247
  }).strict()
29029
29248
  ]);
29030
- var VideoCreativeSetup = z117.discriminatedUnion("mode", [
29031
- z117.object({
29032
- mode: z117.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
29249
+ var VideoCreativeSetup = z119.discriminatedUnion("mode", [
29250
+ z119.object({
29251
+ mode: z119.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
29033
29252
  }).strict(),
29034
- z117.object({
29035
- mode: z117.literal("guided"),
29253
+ z119.object({
29254
+ mode: z119.literal("guided"),
29036
29255
  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.'),
29037
- buyerPersona: z117.string().trim().min(1).max(360),
29256
+ buyerPersona: z119.string().trim().min(1).max(360),
29038
29257
  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.'),
29039
29258
  presenter: VideoPresenter,
29040
- creativeDirection: z117.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
29259
+ creativeDirection: z119.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
29041
29260
  }).strict()
29042
29261
  ]);
29043
- var VideoInput = z117.object({
29262
+ var VideoInput = z119.object({
29044
29263
  images: CreativeRefs.images.optional(),
29045
29264
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
29046
- title: z117.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
29047
- primaryAngle: z117.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".'),
29265
+ title: z119.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
29266
+ primaryAngle: z119.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".'),
29048
29267
  language: CreativeRefs.language,
29049
29268
  country: CreativeRefs.country,
29050
- aspectRatio: z117.enum([
29269
+ aspectRatio: z119.enum([
29051
29270
  "9:16",
29052
29271
  "16:9",
29053
29272
  "Auto"
29054
29273
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
29055
29274
  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.'),
29056
- durationSeconds: z117.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."),
29057
- videoAngleCount: z117.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."),
29275
+ durationSeconds: z119.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."),
29276
+ videoAngleCount: z119.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."),
29058
29277
  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.'),
29059
29278
  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."),
29060
29279
  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.'),
29061
29280
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
29062
29281
  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.'),
29063
- features: z117.array(z117.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
29282
+ features: z119.array(z119.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
29064
29283
  price: CreativeRefs.price,
29065
29284
  offer: CreativeRefs.offer,
29066
29285
  productContext: CreativeRefs.productContext,
29067
29286
  productLabel: CreativeRefs.productLabel,
29068
- cta: z117.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.'),
29069
- scriptNotes: z117.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.'),
29287
+ cta: z119.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.'),
29288
+ scriptNotes: z119.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.'),
29070
29289
  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.'),
29071
29290
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
29072
- replicateWinnerWhenFound: z117.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."),
29291
+ replicateWinnerWhenFound: z119.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."),
29073
29292
  brandId: CreativeRefs.brandId
29074
29293
  }).strict();
29075
29294
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -29087,7 +29306,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
29087
29306
  length: 29
29088
29307
  }, (_, index) => index + 2)
29089
29308
  };
29090
- var FreeVideoModelIdEnum = z117.enum([
29309
+ var FreeVideoModelIdEnum = z119.enum([
29091
29310
  "grok-imagine-video-1-5-preview",
29092
29311
  "minimax-h3/reference-to-video",
29093
29312
  "wan/3-0-video",
@@ -29098,66 +29317,66 @@ var FREE_SELECTABLE_MODEL_IDS = [
29098
29317
  "minimax-h3/reference-to-video",
29099
29318
  "wan/3-0-video"
29100
29319
  ];
29101
- var FreeVideoInput = z117.object({
29320
+ var FreeVideoInput = z119.object({
29102
29321
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
29103
- rawPrompt: z117.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."),
29322
+ rawPrompt: z119.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."),
29104
29323
  language: CreativeRefs.language,
29105
29324
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
29106
29325
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
29107
29326
  // parsed ONLY so the handler can reject it with a message naming its
29108
29327
  // replacement — dropping it silently would turn a caller's explicit
29109
29328
  // Pro++ pick into a quiet fallback to Wan.
29110
- freeProModel: z117.enum([
29329
+ freeProModel: z119.enum([
29111
29330
  "wan",
29112
29331
  "seedance"
29113
29332
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
29114
29333
  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.'),
29115
- durationSeconds: z117.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."),
29334
+ durationSeconds: z119.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."),
29116
29335
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
29117
- generateAiMusic: z117.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.'),
29336
+ generateAiMusic: z119.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.'),
29118
29337
  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.'),
29119
- addSubtitles: z117.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
29120
- idempotencyKey: z117.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.")
29338
+ addSubtitles: z119.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
29339
+ idempotencyKey: z119.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.")
29121
29340
  }).strict();
29122
29341
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
29123
- var ImageCreativeSetup = z117.discriminatedUnion("mode", [
29124
- z117.object({
29125
- mode: z117.literal("automatic")
29342
+ var ImageCreativeSetup = z119.discriminatedUnion("mode", [
29343
+ z119.object({
29344
+ mode: z119.literal("automatic")
29126
29345
  }).strict(),
29127
- z117.object({
29128
- mode: z117.literal("guided"),
29129
- creativeArchetype: z117.union([
29346
+ z119.object({
29347
+ mode: z119.literal("guided"),
29348
+ creativeArchetype: z119.union([
29130
29349
  ImageCreativeArchetypeEnum,
29131
- z117.literal("ai_decides")
29350
+ z119.literal("ai_decides")
29132
29351
  ]),
29133
- visualTreatment: z117.union([
29352
+ visualTreatment: z119.union([
29134
29353
  ImageCreativeVisualTreatmentEnum,
29135
- z117.literal("ai_decides")
29354
+ z119.literal("ai_decides")
29136
29355
  ]),
29137
29356
  aspectRatio: ImageCreativeAspectRatioEnum,
29138
- nVariants: z117.union([
29139
- z117.literal(1),
29140
- z117.literal(2),
29141
- z117.literal(3),
29142
- z117.literal(4),
29143
- z117.literal(6)
29357
+ nVariants: z119.union([
29358
+ z119.literal(1),
29359
+ z119.literal(2),
29360
+ z119.literal(3),
29361
+ z119.literal(4),
29362
+ z119.literal(6)
29144
29363
  ]),
29145
- imageModel: z117.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.'),
29146
- styleMix: z117.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
29147
- generateAdCopy: z117.boolean(),
29148
- competitorScanEnabled: z117.boolean(),
29149
- productContext: z117.string().trim().min(1).max(3e3).nullable(),
29150
- creativeDirection: z117.string().trim().min(1).max(500).nullable(),
29151
- brandColors: z117.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.'),
29152
- headline: z117.string().trim().min(1).max(120).nullable(),
29153
- subheadline: z117.string().trim().min(1).max(160).nullable()
29364
+ imageModel: z119.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.'),
29365
+ styleMix: z119.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
29366
+ generateAdCopy: z119.boolean(),
29367
+ competitorScanEnabled: z119.boolean(),
29368
+ productContext: z119.string().trim().min(1).max(3e3).nullable(),
29369
+ creativeDirection: z119.string().trim().min(1).max(500).nullable(),
29370
+ brandColors: z119.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.'),
29371
+ headline: z119.string().trim().min(1).max(120).nullable(),
29372
+ subheadline: z119.string().trim().min(1).max(160).nullable()
29154
29373
  }).strict()
29155
29374
  ]).superRefine((setup, context) => {
29156
29375
  if (setup.mode !== "guided") return;
29157
29376
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
29158
29377
  if (needsStyleMix && setup.styleMix === null) {
29159
29378
  context.addIssue({
29160
- code: z117.ZodIssueCode.custom,
29379
+ code: z119.ZodIssueCode.custom,
29161
29380
  path: [
29162
29381
  "styleMix"
29163
29382
  ],
@@ -29166,7 +29385,7 @@ var ImageCreativeSetup = z117.discriminatedUnion("mode", [
29166
29385
  }
29167
29386
  if (!needsStyleMix && setup.styleMix !== null) {
29168
29387
  context.addIssue({
29169
- code: z117.ZodIssueCode.custom,
29388
+ code: z119.ZodIssueCode.custom,
29170
29389
  path: [
29171
29390
  "styleMix"
29172
29391
  ],
@@ -29175,7 +29394,7 @@ var ImageCreativeSetup = z117.discriminatedUnion("mode", [
29175
29394
  }
29176
29395
  if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
29177
29396
  context.addIssue({
29178
- code: z117.ZodIssueCode.custom,
29397
+ code: z119.ZodIssueCode.custom,
29179
29398
  path: [
29180
29399
  "aspectRatio"
29181
29400
  ],
@@ -29183,55 +29402,55 @@ var ImageCreativeSetup = z117.discriminatedUnion("mode", [
29183
29402
  });
29184
29403
  }
29185
29404
  });
29186
- var LandingCreativeSetup = z117.discriminatedUnion("mode", [
29187
- z117.object({
29188
- mode: z117.literal("automatic")
29405
+ var LandingCreativeSetup = z119.discriminatedUnion("mode", [
29406
+ z119.object({
29407
+ mode: z119.literal("automatic")
29189
29408
  }).strict(),
29190
- z117.object({
29191
- mode: z117.literal("guided"),
29409
+ z119.object({
29410
+ mode: z119.literal("guided"),
29192
29411
  landingStrategy: LandingStrategyEnum,
29193
29412
  landingImageFormat: LandingImageFormatEnum,
29194
- competitorScanEnabled: z117.boolean(),
29195
- paymentMethods: z117.string().trim().min(1).max(240).nullable(),
29196
- productContext: z117.string().trim().min(1).max(3e3).nullable(),
29197
- creativeDirection: z117.string().trim().min(1).max(500).nullable(),
29198
- headline: z117.string().trim().min(1).max(120).nullable(),
29199
- subheadline: z117.string().trim().min(1).max(160).nullable()
29413
+ competitorScanEnabled: z119.boolean(),
29414
+ paymentMethods: z119.string().trim().min(1).max(240).nullable(),
29415
+ productContext: z119.string().trim().min(1).max(3e3).nullable(),
29416
+ creativeDirection: z119.string().trim().min(1).max(500).nullable(),
29417
+ headline: z119.string().trim().min(1).max(120).nullable(),
29418
+ subheadline: z119.string().trim().min(1).max(160).nullable()
29200
29419
  }).strict()
29201
29420
  ]);
29202
- var ImageInput = z117.object({
29421
+ var ImageInput = z119.object({
29203
29422
  images: CreativeRefs.images.optional(),
29204
29423
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
29205
- productTitle: z117.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
29206
- primaryAngle: z117.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.'),
29424
+ productTitle: z119.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
29425
+ primaryAngle: z119.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.'),
29207
29426
  buyerPersona: CreativeRefs.buyerPersona,
29208
29427
  language: CreativeRefs.language,
29209
29428
  country: CreativeRefs.country,
29210
29429
  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."),
29211
29430
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
29212
- features: z117.array(z117.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
29431
+ features: z119.array(z119.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
29213
29432
  price: CreativeRefs.price,
29214
- omitPrice: z117.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."),
29433
+ omitPrice: z119.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."),
29215
29434
  compareAtPrice: CreativeRefs.compareAtPrice,
29216
29435
  offer: CreativeRefs.offer,
29217
29436
  productLabel: CreativeRefs.productLabel,
29218
29437
  isCombo: CreativeRefs.isCombo,
29219
29438
  brandId: CreativeRefs.brandId
29220
29439
  });
29221
- var EditImageCreativeInput = z117.object({
29222
- taskId: z117.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
29223
- variantIndex: z117.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
29224
- clientRequestId: z117.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."),
29225
- instruction: z117.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".')
29440
+ var EditImageCreativeInput = z119.object({
29441
+ taskId: z119.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
29442
+ variantIndex: z119.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
29443
+ clientRequestId: z119.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."),
29444
+ instruction: z119.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".')
29226
29445
  });
29227
- var LandingInput = z117.object({
29228
- includeInitialLandingGif: z117.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."),
29446
+ var LandingInput = z119.object({
29447
+ includeInitialLandingGif: z119.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."),
29229
29448
  images: CreativeRefs.images.optional(),
29230
29449
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
29231
29450
  language: CreativeRefs.language,
29232
29451
  country: CreativeRefs.country,
29233
29452
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
29234
- salesAngle: z117.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.'),
29453
+ salesAngle: z119.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.'),
29235
29454
  buyerPersona: CreativeRefs.buyerPersona,
29236
29455
  price: CreativeRefs.price,
29237
29456
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -29513,8 +29732,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
29513
29732
  server.registerTool("get_image_edit_status", {
29514
29733
  description: imageEditStatusGuidance.summary,
29515
29734
  inputSchema: {
29516
- taskId: z117.string().uuid(),
29517
- operationId: z117.string().uuid()
29735
+ taskId: z119.string().uuid(),
29736
+ operationId: z119.string().uuid()
29518
29737
  },
29519
29738
  annotations: READS_INTERNAL
29520
29739
  }, async (input) => {
@@ -29571,10 +29790,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
29571
29790
  __name(registerCreativeTools, "registerCreativeTools");
29572
29791
 
29573
29792
  // src/tools/creative-variants.ts
29574
- import { z as z118 } from "zod";
29793
+ import { z as z120 } from "zod";
29575
29794
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
29576
29795
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
29577
- var LandingSectionKeyEnum = z118.enum([
29796
+ var LandingSectionKeyEnum = z120.enum([
29578
29797
  "problem_hook",
29579
29798
  "problem_cost",
29580
29799
  "solution_mechanism",
@@ -29614,24 +29833,24 @@ var LandingSectionKeyEnum = z118.enum([
29614
29833
  "lifestyle_fit",
29615
29834
  "join_lifestyle"
29616
29835
  ]);
29617
- var CreativeVariantKindEnum = z118.enum([
29836
+ var CreativeVariantKindEnum = z120.enum([
29618
29837
  "video",
29619
29838
  "image",
29620
29839
  "landing"
29621
29840
  ]);
29622
- var EstimateCreativeVariantInputBase = z118.object({
29623
- sourceTaskId: z118.string().uuid().describe("ID de la tarea original completada."),
29841
+ var EstimateCreativeVariantInputBase = z120.object({
29842
+ sourceTaskId: z120.string().uuid().describe("ID de la tarea original completada."),
29624
29843
  kind: CreativeVariantKindEnum,
29625
29844
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
29626
29845
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
29627
- nVariants: z118.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
29846
+ nVariants: z120.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
29628
29847
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
29629
- instructions: z118.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.")
29848
+ instructions: z120.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.")
29630
29849
  }).strict();
29631
29850
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
29632
29851
  if (input.kind === "video" && input.nVariants !== void 0) {
29633
29852
  ctx.addIssue({
29634
- code: z118.ZodIssueCode.custom,
29853
+ code: z120.ZodIssueCode.custom,
29635
29854
  path: [
29636
29855
  "nVariants"
29637
29856
  ],
@@ -29641,7 +29860,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
29641
29860
  if (input.kind !== "video") {
29642
29861
  if (input.videoPreset !== void 0) {
29643
29862
  ctx.addIssue({
29644
- code: z118.ZodIssueCode.custom,
29863
+ code: z120.ZodIssueCode.custom,
29645
29864
  path: [
29646
29865
  "videoPreset"
29647
29866
  ],
@@ -29650,7 +29869,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
29650
29869
  }
29651
29870
  if (input.videoResolution !== void 0) {
29652
29871
  ctx.addIssue({
29653
- code: z118.ZodIssueCode.custom,
29872
+ code: z120.ZodIssueCode.custom,
29654
29873
  path: [
29655
29874
  "videoResolution"
29656
29875
  ],
@@ -29660,7 +29879,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
29660
29879
  }
29661
29880
  if (input.kind !== "image" && input.nVariants !== void 0) {
29662
29881
  ctx.addIssue({
29663
- code: z118.ZodIssueCode.custom,
29882
+ code: z120.ZodIssueCode.custom,
29664
29883
  path: [
29665
29884
  "nVariants"
29666
29885
  ],
@@ -29670,7 +29889,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
29670
29889
  if (input.kind !== "landing") {
29671
29890
  if (input.sectionKey !== void 0) {
29672
29891
  ctx.addIssue({
29673
- code: z118.ZodIssueCode.custom,
29892
+ code: z120.ZodIssueCode.custom,
29674
29893
  path: [
29675
29894
  "sectionKey"
29676
29895
  ],
@@ -29679,7 +29898,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
29679
29898
  }
29680
29899
  if (input.instructions !== void 0) {
29681
29900
  ctx.addIssue({
29682
- code: z118.ZodIssueCode.custom,
29901
+ code: z120.ZodIssueCode.custom,
29683
29902
  path: [
29684
29903
  "instructions"
29685
29904
  ],
@@ -29688,31 +29907,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
29688
29907
  }
29689
29908
  }
29690
29909
  });
29691
- var CreateCreativeVariantInputBase = z118.object({
29692
- sourceTaskId: z118.string().uuid().describe("ID de la tarea original completada."),
29910
+ var CreateCreativeVariantInputBase = z120.object({
29911
+ sourceTaskId: z120.string().uuid().describe("ID de la tarea original completada."),
29693
29912
  kind: CreativeVariantKindEnum,
29694
- confirm: z118.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
29695
- clientRequestId: z118.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."),
29696
- angle: z118.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
29697
- buyerPersona: z118.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
29698
- scriptNotes: z118.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
29699
- creativeDirection: z118.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
29913
+ confirm: z120.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
29914
+ clientRequestId: z120.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."),
29915
+ angle: z120.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
29916
+ buyerPersona: z120.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
29917
+ scriptNotes: z120.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
29918
+ creativeDirection: z120.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
29700
29919
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
29701
29920
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
29702
- generateAiMusic: z118.boolean().optional().describe("Opcional para video."),
29703
- nVariants: z118.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
29921
+ generateAiMusic: z120.boolean().optional().describe("Opcional para video."),
29922
+ nVariants: z120.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
29704
29923
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
29705
29924
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
29706
29925
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
29707
29926
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
29708
- styleMix: z118.boolean().optional().describe("Opcional para imagen."),
29927
+ styleMix: z120.boolean().optional().describe("Opcional para imagen."),
29709
29928
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
29710
- instructions: z118.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.")
29929
+ instructions: z120.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.")
29711
29930
  }).strict();
29712
29931
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
29713
29932
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
29714
29933
  ctx.addIssue({
29715
- code: z118.ZodIssueCode.custom,
29934
+ code: z120.ZodIssueCode.custom,
29716
29935
  path: [
29717
29936
  "angle"
29718
29937
  ],
@@ -29721,7 +29940,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
29721
29940
  }
29722
29941
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
29723
29942
  ctx.addIssue({
29724
- code: z118.ZodIssueCode.custom,
29943
+ code: z120.ZodIssueCode.custom,
29725
29944
  path: [
29726
29945
  "instructions"
29727
29946
  ],
@@ -29767,7 +29986,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
29767
29986
  for (const field of fieldsByKind[input.kind]) {
29768
29987
  if (input[field] !== void 0) {
29769
29988
  ctx.addIssue({
29770
- code: z118.ZodIssueCode.custom,
29989
+ code: z120.ZodIssueCode.custom,
29771
29990
  path: [
29772
29991
  field
29773
29992
  ],
@@ -29900,13 +30119,13 @@ function registerCreativeVariantTools(server, api) {
29900
30119
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
29901
30120
 
29902
30121
  // src/tools/script-review.ts
29903
- import { z as z119 } from "zod";
30122
+ import { z as z121 } from "zod";
29904
30123
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
29905
30124
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
29906
30125
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
29907
- var GetVideoScriptInput = z119.object({
29908
- taskId: z119.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
29909
- angleKey: z119.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
30126
+ var GetVideoScriptInput = z121.object({
30127
+ taskId: z121.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
30128
+ angleKey: z121.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
29910
30129
  }).strict();
29911
30130
  var ApproveVideoScriptInput = ApproveVideoScriptCapabilityRequest;
29912
30131
  var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
@@ -29989,7 +30208,7 @@ function registerScriptReviewTools(server, api) {
29989
30208
  __name(registerScriptReviewTools, "registerScriptReviewTools");
29990
30209
 
29991
30210
  // src/tools/connections.ts
29992
- import { z as z120 } from "zod";
30211
+ import { z as z122 } from "zod";
29993
30212
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
29994
30213
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
29995
30214
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
@@ -29998,7 +30217,7 @@ var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list
29998
30217
  function registerConnectionTools(server, api) {
29999
30218
  server.registerTool("list_shopify_shops", {
30000
30219
  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.",
30001
- inputSchema: z120.object({}).shape,
30220
+ inputSchema: z122.object({}).shape,
30002
30221
  annotations: READS_INTERNAL
30003
30222
  }, async () => {
30004
30223
  try {
@@ -30010,10 +30229,10 @@ function registerConnectionTools(server, api) {
30010
30229
  });
30011
30230
  server.registerTool("list_shopify_products", {
30012
30231
  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.',
30013
- inputSchema: z120.object({
30014
- shopDomain: z120.string().min(3).max(120),
30015
- query: z120.string().trim().max(120).optional(),
30016
- taskId: z120.string().uuid().optional()
30232
+ inputSchema: z122.object({
30233
+ shopDomain: z122.string().min(3).max(120),
30234
+ query: z122.string().trim().max(120).optional(),
30235
+ taskId: z122.string().uuid().optional()
30017
30236
  }).shape,
30018
30237
  annotations: READS_EXTERNAL
30019
30238
  }, async ({ shopDomain, query, taskId }) => {
@@ -30031,7 +30250,7 @@ function registerConnectionTools(server, api) {
30031
30250
  });
30032
30251
  server.registerTool("list_meta_ad_accounts", {
30033
30252
  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.",
30034
- inputSchema: z120.object({}).shape,
30253
+ inputSchema: z122.object({}).shape,
30035
30254
  annotations: READS_EXTERNAL
30036
30255
  }, async () => {
30037
30256
  try {
@@ -30043,7 +30262,7 @@ function registerConnectionTools(server, api) {
30043
30262
  });
30044
30263
  server.registerTool("list_meta_destinations", {
30045
30264
  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.",
30046
- inputSchema: z120.object({}).shape,
30265
+ inputSchema: z122.object({}).shape,
30047
30266
  annotations: READS_EXTERNAL,
30048
30267
  _meta: {
30049
30268
  "openai/widgetAccessible": true
@@ -30058,7 +30277,7 @@ function registerConnectionTools(server, api) {
30058
30277
  });
30059
30278
  server.registerTool("list_tiktok_advertisers", {
30060
30279
  description: listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.",
30061
- inputSchema: z120.object({}).shape,
30280
+ inputSchema: z122.object({}).shape,
30062
30281
  annotations: READS_EXTERNAL
30063
30282
  }, async () => {
30064
30283
  try {
@@ -30072,7 +30291,7 @@ function registerConnectionTools(server, api) {
30072
30291
  __name(registerConnectionTools, "registerConnectionTools");
30073
30292
 
30074
30293
  // src/tools/actors.ts
30075
- import { z as z121 } from "zod";
30294
+ import { z as z123 } from "zod";
30076
30295
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
30077
30296
  var actorVoiceGuidance = {
30078
30297
  capabilities: getProductMakerCapabilityModelGuidance("get_actor_voice_capabilities"),
@@ -30112,7 +30331,7 @@ function sanitizeVoiceResult(value) {
30112
30331
  __name(sanitizeVoiceResult, "sanitizeVoiceResult");
30113
30332
  function registerActorTools(server, api) {
30114
30333
  const actor = {
30115
- actorId: z121.string().min(1).max(64)
30334
+ actorId: z123.string().min(1).max(64)
30116
30335
  };
30117
30336
  const safe = /* @__PURE__ */ __name(async (request) => {
30118
30337
  try {
@@ -30141,8 +30360,8 @@ function registerActorTools(server, api) {
30141
30360
  inputSchema: {
30142
30361
  ...actor,
30143
30362
  draft: ActorVoiceDraftSchema,
30144
- requestKey: z121.string().trim().min(1).max(128),
30145
- acceptedQuoteId: z121.string().trim().min(1).max(128)
30363
+ requestKey: z123.string().trim().min(1).max(128),
30364
+ acceptedQuoteId: z123.string().trim().min(1).max(128)
30146
30365
  },
30147
30366
  annotations: CREATES_PAID
30148
30367
  }, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/previews`, body)));
@@ -30150,7 +30369,7 @@ function registerActorTools(server, api) {
30150
30369
  description: actorVoiceGuidance.get.summary,
30151
30370
  inputSchema: {
30152
30371
  ...actor,
30153
- candidateId: z121.string().min(1).max(64)
30372
+ candidateId: z123.string().min(1).max(64)
30154
30373
  },
30155
30374
  // Polling can resume the first paid submission of an accepted quote.
30156
30375
  // The immutable candidate/operation key keeps recovery idempotent.
@@ -30163,16 +30382,16 @@ function registerActorTools(server, api) {
30163
30382
  description: actorVoiceGuidance.approve.summary,
30164
30383
  inputSchema: {
30165
30384
  ...actor,
30166
- candidateId: z121.string().min(1).max(64),
30167
- expectedRevision: z121.number().int().positive(),
30168
- expectedApprovedRevision: z121.number().int().positive().nullable().optional()
30385
+ candidateId: z123.string().min(1).max(64),
30386
+ expectedRevision: z123.number().int().positive(),
30387
+ expectedApprovedRevision: z123.number().int().positive().nullable().optional()
30169
30388
  },
30170
30389
  // Replaces the selected voice and withdraws the old catalog grants.
30171
30390
  annotations: OVERWRITES_INTERNAL
30172
30391
  }, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/approve`, body)));
30173
30392
  server.registerTool("list_actors", {
30174
30393
  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.",
30175
- inputSchema: z121.object({}).shape,
30394
+ inputSchema: z123.object({}).shape,
30176
30395
  annotations: READS_INTERNAL
30177
30396
  }, async () => {
30178
30397
  try {
@@ -30205,7 +30424,7 @@ function registerActorTools(server, api) {
30205
30424
  __name(registerActorTools, "registerActorTools");
30206
30425
 
30207
30426
  // src/tools/publish.ts
30208
- import { z as z122 } from "zod";
30427
+ import { z as z124 } from "zod";
30209
30428
 
30210
30429
  // src/tools/meta-publish-attempt-id.ts
30211
30430
  var META_PUBLISH_NAMESPACE = "7b19c9ac-b4eb-4db1-970e-c2f24ce30b98";
@@ -30244,40 +30463,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
30244
30463
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
30245
30464
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
30246
30465
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
30247
- var ShopifyInput = z122.object({
30248
- taskId: z122.string().min(1),
30249
- shopDomain: z122.string().min(1),
30466
+ var ShopifyInput = z124.object({
30467
+ taskId: z124.string().min(1),
30468
+ shopDomain: z124.string().min(1),
30250
30469
  /** Override: number of landing images to include. Default = ALL images the
30251
30470
  * task generated (the MCP fetches /v1/results first to count). Bounded
30252
30471
  * generously here; the backend validates each index against
30253
30472
  * landing.images.length and rejects out-of-range. */
30254
- numLandingImages: z122.number().int().min(1).max(20).optional(),
30255
- variantIndex: z122.number().int().min(0).optional(),
30473
+ numLandingImages: z124.number().int().min(1).max(20).optional(),
30474
+ variantIndex: z124.number().int().min(0).optional(),
30256
30475
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
30257
30476
  * When true, the landing renders variant-picker pills; when false, it ships
30258
30477
  * a single-option product page. Defaults to false. */
30259
- showVariantPicker: z122.boolean().optional(),
30478
+ showVariantPicker: z124.boolean().optional(),
30260
30479
  /** Default `auto` updates the product previously published for this task and
30261
30480
  * shop. Use `existing` with targetProductId to choose another product, or
30262
30481
  * `new` only when the user explicitly wants a duplicate/new listing. */
30263
- publicationMode: z122.enum([
30482
+ publicationMode: z124.enum([
30264
30483
  "auto",
30265
30484
  "existing",
30266
30485
  "new"
30267
30486
  ]).optional(),
30268
30487
  /** Shopify product GID, numeric id, or admin product URL. Required when
30269
30488
  * publicationMode is `existing`. */
30270
- targetProductId: z122.string().trim().min(1).max(300).optional(),
30489
+ targetProductId: z124.string().trim().min(1).max(300).optional(),
30271
30490
  /** Add an announcement bar text above add-to-cart (optional). */
30272
- announcementBarEnabled: z122.boolean().optional(),
30273
- announcementBarText: z122.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
30491
+ announcementBarEnabled: z124.boolean().optional(),
30492
+ announcementBarText: z124.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
30274
30493
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
30275
- confirmed: z122.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
30494
+ confirmed: z124.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
30276
30495
  });
30277
30496
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
30278
30497
  if (value.commerceCorrection && value.confirmed !== true) {
30279
30498
  ctx.addIssue({
30280
- code: z122.ZodIssueCode.custom,
30499
+ code: z124.ZodIssueCode.custom,
30281
30500
  path: [
30282
30501
  "confirmed"
30283
30502
  ],
@@ -30286,7 +30505,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
30286
30505
  }
30287
30506
  if (value.announcementBarEnabled && !value.announcementBarText) {
30288
30507
  ctx.addIssue({
30289
- code: z122.ZodIssueCode.custom,
30508
+ code: z124.ZodIssueCode.custom,
30290
30509
  path: [
30291
30510
  "announcementBarText"
30292
30511
  ],
@@ -30295,7 +30514,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
30295
30514
  }
30296
30515
  if (!value.announcementBarEnabled && value.announcementBarText) {
30297
30516
  ctx.addIssue({
30298
- code: z122.ZodIssueCode.custom,
30517
+ code: z124.ZodIssueCode.custom,
30299
30518
  path: [
30300
30519
  "announcementBarText"
30301
30520
  ],
@@ -30309,91 +30528,91 @@ function parseShopifyInput(rawInput) {
30309
30528
  return parsed.data;
30310
30529
  }
30311
30530
  __name(parseShopifyInput, "parseShopifyInput");
30312
- var McpCampaignConfig = z122.object({
30531
+ var McpCampaignConfig = z124.object({
30313
30532
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
30314
30533
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
30315
30534
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
30316
- dailyBudgetUsd: z122.number().positive().optional(),
30535
+ dailyBudgetUsd: z124.number().positive().optional(),
30317
30536
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
30318
30537
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
30319
30538
  * TikTok takes only the first entry. */
30320
- targetCountries: z122.array(CountryIso2Schema).max(1).optional(),
30321
- campaignName: z122.string().trim().min(1).max(100).optional()
30539
+ targetCountries: z124.array(CountryIso2Schema).max(1).optional(),
30540
+ campaignName: z124.string().trim().min(1).max(100).optional()
30322
30541
  });
30323
30542
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
30324
- var MetaInput = z122.object({
30325
- taskId: z122.string().min(1),
30543
+ var MetaInput = z124.object({
30544
+ taskId: z124.string().min(1),
30326
30545
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
30327
- portfolioId: z122.string().trim().min(1),
30546
+ portfolioId: z124.string().trim().min(1),
30328
30547
  /** Exact Facebook Page selected from `list_meta_destinations`. */
30329
- pageId: z122.string().trim().min(1),
30548
+ pageId: z124.string().trim().min(1),
30330
30549
  adAccountId: McpAdAccountId,
30331
- pixelId: z122.string().min(1).optional(),
30332
- landingUrl: z122.string().url().optional(),
30550
+ pixelId: z124.string().min(1).optional(),
30551
+ landingUrl: z124.string().url().optional(),
30333
30552
  /** Select which angles to publish by 0-based index. Omit to publish all
30334
30553
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
30335
- angleIndexes: z122.array(z122.number().int().nonnegative()).optional(),
30554
+ angleIndexes: z124.array(z124.number().int().nonnegative()).optional(),
30336
30555
  campaignConfig: McpCampaignConfig.optional(),
30337
30556
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
30338
30557
  * uses the auto-generated copy attached to the task. Capped at 500 chars
30339
30558
  * (Meta's primary-text limit). */
30340
- primaryText: z122.string().trim().min(1).max(500).optional(),
30559
+ primaryText: z124.string().trim().min(1).max(500).optional(),
30341
30560
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
30342
30561
  * (wa.me) instead of a landing page. */
30343
- phoneNumber: z122.string().min(8).max(32).optional()
30562
+ phoneNumber: z124.string().min(8).max(32).optional()
30344
30563
  });
30345
- var GroupedTaskSource = z122.object({
30346
- type: z122.literal("task"),
30347
- taskId: z122.string().min(1),
30348
- angleIndex: z122.number().int().min(0).optional(),
30349
- videoVariant: z122.enum([
30564
+ var GroupedTaskSource = z124.object({
30565
+ type: z124.literal("task"),
30566
+ taskId: z124.string().min(1),
30567
+ angleIndex: z124.number().int().min(0).optional(),
30568
+ videoVariant: z124.enum([
30350
30569
  "with_subtitles",
30351
30570
  "without_subtitles"
30352
30571
  ]).optional(),
30353
- imageVariantIndex: z122.number().int().min(0).optional()
30354
- });
30355
- var GroupedMediaSource = z122.object({
30356
- type: z122.literal("media"),
30357
- url: z122.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
30358
- path: z122.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".'),
30359
- thumbnailUrl: z122.string().url().optional(),
30360
- thumbnailPath: z122.string().min(1).optional()
30572
+ imageVariantIndex: z124.number().int().min(0).optional()
30573
+ });
30574
+ var GroupedMediaSource = z124.object({
30575
+ type: z124.literal("media"),
30576
+ url: z124.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
30577
+ path: z124.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".'),
30578
+ thumbnailUrl: z124.string().url().optional(),
30579
+ thumbnailPath: z124.string().min(1).optional()
30361
30580
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
30362
30581
  message: "media source needs exactly one of `url` or `path`"
30363
30582
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
30364
30583
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
30365
30584
  });
30366
- var GroupedUploadedAssetSource = z122.object({
30367
- type: z122.literal("asset"),
30585
+ var GroupedUploadedAssetSource = z124.object({
30586
+ type: z124.literal("asset"),
30368
30587
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
30369
- assetId: z122.string().uuid(),
30370
- thumbnailAssetId: z122.string().uuid().optional()
30588
+ assetId: z124.string().uuid(),
30589
+ thumbnailAssetId: z124.string().uuid().optional()
30371
30590
  });
30372
- var GroupedCreative = z122.object({
30373
- type: z122.enum([
30591
+ var GroupedCreative = z124.object({
30592
+ type: z124.enum([
30374
30593
  "image",
30375
30594
  "video"
30376
30595
  ]),
30377
- source: z122.union([
30596
+ source: z124.union([
30378
30597
  GroupedTaskSource,
30379
30598
  GroupedMediaSource,
30380
30599
  GroupedUploadedAssetSource
30381
30600
  ]),
30382
- title: z122.string().max(120).optional(),
30383
- description: z122.string().max(500).optional(),
30601
+ title: z124.string().max(120).optional(),
30602
+ description: z124.string().max(500).optional(),
30384
30603
  cta: MetaCtaType.optional(),
30385
- creativeId: z122.string().min(1).optional()
30604
+ creativeId: z124.string().min(1).optional()
30386
30605
  });
30387
- var GroupedCampaignConfigBase = z122.object({
30606
+ var GroupedCampaignConfigBase = z124.object({
30388
30607
  campaignType: MetaCampaignType.default("sales"),
30389
30608
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
30390
30609
  budgetMode: MetaBudgetMode.optional(),
30391
- campaignDailyBudget: z122.number().int().positive().optional(),
30392
- adSets: z122.array(z122.object({
30393
- tempId: z122.string().min(1).max(80),
30394
- name: z122.string().min(1).max(100),
30395
- dailyBudget: z122.number().int().positive().optional(),
30396
- creativeIds: z122.array(z122.string().min(1)).min(1)
30610
+ campaignDailyBudget: z124.number().int().positive().optional(),
30611
+ adSets: z124.array(z124.object({
30612
+ tempId: z124.string().min(1).max(80),
30613
+ name: z124.string().min(1).max(100),
30614
+ dailyBudget: z124.number().int().positive().optional(),
30615
+ creativeIds: z124.array(z124.string().min(1)).min(1)
30397
30616
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
30398
30617
  /**
30399
30618
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -30401,17 +30620,17 @@ var GroupedCampaignConfigBase = z122.object({
30401
30620
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
30402
30621
  * the API since #849 — unreachable from this tool.
30403
30622
  */
30404
- destination: z122.discriminatedUnion("type", [
30405
- z122.object({
30406
- type: z122.literal("landing"),
30407
- landingUrl: z122.string().url()
30623
+ destination: z124.discriminatedUnion("type", [
30624
+ z124.object({
30625
+ type: z124.literal("landing"),
30626
+ landingUrl: z124.string().url()
30408
30627
  }),
30409
- z122.object({
30410
- type: z122.literal("whatsapp"),
30411
- phoneNumber: z122.string().min(8).max(32)
30628
+ z124.object({
30629
+ type: z124.literal("whatsapp"),
30630
+ phoneNumber: z124.string().min(8).max(32)
30412
30631
  })
30413
30632
  ]),
30414
- saveAsDefault: z122.boolean().default(false),
30633
+ saveAsDefault: z124.boolean().default(false),
30415
30634
  budgetPolicy: MetaBudgetPolicy.optional()
30416
30635
  });
30417
30636
  function resolveBudgetMode(value) {
@@ -30425,7 +30644,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
30425
30644
  const budgetMode = resolveBudgetMode(value);
30426
30645
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
30427
30646
  ctx.addIssue({
30428
- code: z122.ZodIssueCode.custom,
30647
+ code: z124.ZodIssueCode.custom,
30429
30648
  path: [
30430
30649
  "campaignDailyBudget"
30431
30650
  ],
@@ -30436,7 +30655,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
30436
30655
  value.adSets.forEach((adSet, index) => {
30437
30656
  if (adSet.dailyBudget === void 0) {
30438
30657
  ctx.addIssue({
30439
- code: z122.ZodIssueCode.custom,
30658
+ code: z124.ZodIssueCode.custom,
30440
30659
  path: [
30441
30660
  "adSets",
30442
30661
  index,
@@ -30451,28 +30670,33 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
30451
30670
  ...value,
30452
30671
  budgetMode: resolveBudgetMode(value)
30453
30672
  }));
30454
- var PublishCreativesToMetaInputBase = z122.object({
30455
- creatives: z122.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
30673
+ var PublishCreativesToMetaInputBase = z124.object({
30674
+ creatives: z124.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
30456
30675
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
30457
- portfolioId: z122.string().trim().min(1),
30676
+ portfolioId: z124.string().trim().min(1),
30458
30677
  /** Exact Facebook Page selected from `list_meta_destinations`. */
30459
- pageId: z122.string().trim().min(1),
30678
+ pageId: z124.string().trim().min(1),
30460
30679
  adAccountId: McpAdAccountId,
30461
- pixelId: z122.string().min(1).optional(),
30462
- /** Required unless `campaignConfig.destination` is whatsapp — see the
30463
- * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
30464
- landingUrl: z122.string().url().optional(),
30680
+ pixelId: z124.string().min(1).optional(),
30681
+ /** Required unless `campaignConfig.destination` is whatsapp or a creative
30682
+ * comes from a task (the API then lands on the published service landing
30683
+ * of its service tasks) — see the superRefine below. Mirrors the API's
30684
+ * `FacebookCreateCampaignFromTasksBodySchema`. */
30685
+ landingUrl: z124.string().url().optional(),
30465
30686
  /** ISO-2 code or resolvable country name — mirrors the API contract
30466
- * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
30467
- targetCountry: CountryIso2Schema,
30468
- campaignName: z122.string().trim().min(1).max(100),
30687
+ * (CountryIso2Schema), which normalizes names to alpha-2 at validation.
30688
+ * Omitted: the brand country of its service tasks (the API answers
30689
+ * META_NO_TARGET_COUNTRY when it has none); "US" for products. */
30690
+ targetCountry: CountryIso2Schema.optional(),
30691
+ campaignName: z124.string().trim().min(1).max(100),
30469
30692
  campaignConfig: GroupedCampaignConfig.optional()
30470
30693
  });
30471
30694
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
30472
30695
  const destination = value.campaignConfig?.destination;
30473
- if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
30696
+ const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
30697
+ if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl && !hasTaskCreative) {
30474
30698
  ctx.addIssue({
30475
- code: z122.ZodIssueCode.custom,
30699
+ code: z124.ZodIssueCode.custom,
30476
30700
  path: [
30477
30701
  "landingUrl"
30478
30702
  ],
@@ -30481,7 +30705,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
30481
30705
  }
30482
30706
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
30483
30707
  ctx.addIssue({
30484
- code: z122.ZodIssueCode.custom,
30708
+ code: z124.ZodIssueCode.custom,
30485
30709
  path: [
30486
30710
  "campaignConfig",
30487
30711
  "destination",
@@ -30500,16 +30724,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
30500
30724
  }
30501
30725
  return value;
30502
30726
  });
30503
- var PresignUploadResponseSchema = z122.object({
30504
- uploadUrl: z122.string().url().refine((value) => {
30727
+ var PresignUploadResponseSchema = z124.object({
30728
+ uploadUrl: z124.string().url().refine((value) => {
30505
30729
  const url = new URL(value);
30506
30730
  return !url.username && !url.password && url.protocol === "https:";
30507
30731
  }, "presigned upload URL must be HTTPS without embedded credentials"),
30508
- publicUrl: z122.string().url().refine((value) => {
30732
+ publicUrl: z124.string().url().refine((value) => {
30509
30733
  const url = new URL(value);
30510
30734
  return !url.username && !url.password;
30511
30735
  }, "public media URL must not contain embedded credentials"),
30512
- stagingAssetId: z122.string().uuid()
30736
+ stagingAssetId: z124.string().uuid()
30513
30737
  });
30514
30738
  async function uploadResolvedMedia(api, media, assetRole) {
30515
30739
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -30534,16 +30758,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
30534
30758
  return uploadResolvedMedia(api, media, assetRole);
30535
30759
  }
30536
30760
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
30537
- var TikTokInput = z122.object({
30538
- taskId: z122.string().min(1),
30539
- advertiserId: z122.string().min(1),
30540
- pixelId: z122.string().min(1).optional(),
30541
- landingUrl: z122.string().url().optional(),
30542
- angleIndexes: z122.array(z122.number().int().nonnegative()).optional(),
30761
+ var TikTokInput = z124.object({
30762
+ taskId: z124.string().min(1),
30763
+ advertiserId: z124.string().min(1),
30764
+ pixelId: z124.string().min(1).optional(),
30765
+ landingUrl: z124.string().url().optional(),
30766
+ angleIndexes: z124.array(z124.number().int().nonnegative()).optional(),
30543
30767
  campaignConfig: McpCampaignConfig.optional(),
30544
30768
  /** Override the ad's description (TikTok's body copy). If omitted,
30545
30769
  * ProductMaker uses the auto-generated copy attached to the task. */
30546
- primaryText: z122.string().trim().min(1).max(500).optional()
30770
+ primaryText: z124.string().trim().min(1).max(500).optional()
30547
30771
  });
30548
30772
  function registerPublishTools(server, api, opts = {}) {
30549
30773
  const transport = opts.transport ?? "http";
@@ -30665,7 +30889,7 @@ function registerPublishTools(server, api, opts = {}) {
30665
30889
  }
30666
30890
  });
30667
30891
  server.registerTool("publish_creatives_to_meta", {
30668
- description: publishCreativesToMetaGuidance.summary + ' Publica tus creativos en Meta sin gastar cr\xE9ditos de ProductMaker. El presupuesto de anuncios se paga directamente desde tu cuenta de Meta. Crear creativos o copy con IA sigue usando cr\xE9ditos. Si la petici\xF3n natural adjunta o menciona archivos locales, llama primero `request_media_upload`; tras OK usa cada resultado como `source.type="asset"` con su `assetId` y el `type` que coincide con `mediaKind`. No pidas path ni URL. Despu\xE9s llama `list_meta_destinations` y pregunta en el chat por el `portfolioId`, `adAccountId` y `pageId` exactos; el App es solo para archivos. Si la carga fue parcial, conserva los assets confirmados, procesa s\xF3lo los pendientes y publica \xFAnicamente assets confirmados; nunca inventes assets ni superes diez creativos. Las rutas locales s\xF3lo funcionan con MCP stdio. Los medios propios se eliminan despu\xE9s de publicar correctamente; si falla antes de enviar una mutaci\xF3n a Meta, quedan durante el TTL. Para videos la miniatura es opcional y ProductMaker puede generarla con FFmpeg. `campaignConfig.destination` acepta landing o WhatsApp. Para landing basta `campaignConfig.destination.landingUrl`; no dupliques la URL arriba. Si omites `budgetMode`, se infiere `ad_set` cuando cada ad set trae `dailyBudget`, o `campaign` cuando env\xEDas `campaignDailyBudget`. No actives la campa\xF1a autom\xE1ticamente. Si el resultado es ambiguo, NO reenv\xEDes: revisa Meta Ads Manager.',
30892
+ description: publishCreativesToMetaGuidance.summary + ' Publica tus creativos en Meta sin gastar cr\xE9ditos de ProductMaker. El presupuesto de anuncios se paga directamente desde tu cuenta de Meta. Crear creativos o copy con IA sigue usando cr\xE9ditos. Si la petici\xF3n natural adjunta o menciona archivos locales, llama primero `request_media_upload`; tras OK usa cada resultado como `source.type="asset"` con su `assetId` y el `type` que coincide con `mediaKind`. No pidas path ni URL. Despu\xE9s llama `list_meta_destinations` y pregunta en el chat por el `portfolioId`, `adAccountId` y `pageId` exactos; el App es solo para archivos. Si la carga fue parcial, conserva los assets confirmados, procesa s\xF3lo los pendientes y publica \xFAnicamente assets confirmados; nunca inventes assets ni superes diez creativos. Las rutas locales s\xF3lo funcionan con MCP stdio. Los medios propios se eliminan despu\xE9s de publicar correctamente; si falla antes de enviar una mutaci\xF3n a Meta, quedan durante el TTL. Para videos la miniatura es opcional y ProductMaker puede generarla con FFmpeg. `campaignConfig.destination` acepta landing o WhatsApp. Para landing basta `campaignConfig.destination.landingUrl`; no dupliques la URL arriba. Con creativos de tarea de servicio puedes omitir `landingUrl` y `targetCountry`: se usan su landing de servicio publicada y el pa\xEDs de su marca; si falta alguno, pregunta al usuario (nunca asumas un pa\xEDs). Si omites `budgetMode`, se infiere `ad_set` cuando cada ad set trae `dailyBudget`, o `campaign` cuando env\xEDas `campaignDailyBudget`. No actives la campa\xF1a autom\xE1ticamente. Si el resultado es ambiguo, NO reenv\xEDes: revisa Meta Ads Manager.',
30669
30893
  inputSchema: PublishCreativesToMetaInputBase.shape,
30670
30894
  annotations: CREATES_EXTERNAL
30671
30895
  }, async (rawInput, extra) => {
@@ -30895,39 +31119,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
30895
31119
 
30896
31120
  // src/tools/meta-upload.ts
30897
31121
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
30898
- import { z as z123 } from "zod";
31122
+ import { z as z125 } from "zod";
30899
31123
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
30900
- var UploadSessionInputBase = z123.object({
30901
- mediaKind: z123.enum([
31124
+ var UploadSessionInputBase = z125.object({
31125
+ mediaKind: z125.enum([
30902
31126
  "image",
30903
31127
  "video",
30904
31128
  "mixed"
30905
31129
  ]).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."),
30906
- assetRole: z123.enum([
31130
+ assetRole: z125.enum([
30907
31131
  "media",
30908
31132
  "thumbnail"
30909
31133
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
30910
- uploadPurpose: z123.enum([
31134
+ uploadPurpose: z125.enum([
30911
31135
  "product_reference",
30912
31136
  "creative",
30913
31137
  "generic"
30914
31138
  ]).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."),
30915
- maxFiles: z123.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
31139
+ maxFiles: z125.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
30916
31140
  });
30917
- var OpenAiFileReference = z123.object({
30918
- download_url: z123.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."),
30919
- file_id: z123.string().min(1),
30920
- mime_type: z123.string().min(1).optional(),
30921
- file_name: z123.string().min(1).optional()
31141
+ var OpenAiFileReference = z125.object({
31142
+ download_url: z125.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."),
31143
+ file_id: z125.string().min(1),
31144
+ mime_type: z125.string().min(1).optional(),
31145
+ file_name: z125.string().min(1).optional()
30922
31146
  });
30923
31147
  var UploadSessionToolInputShape = {
30924
31148
  ...UploadSessionInputBase.shape,
30925
- files: z123.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.")
31149
+ files: z125.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.")
30926
31150
  };
30927
- var UploadSessionToolInput = z123.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
31151
+ var UploadSessionToolInput = z125.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
30928
31152
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
30929
31153
  ctx.addIssue({
30930
- code: z123.ZodIssueCode.custom,
31154
+ code: z125.ZodIssueCode.custom,
30931
31155
  path: [
30932
31156
  "mediaKind"
30933
31157
  ],
@@ -30936,7 +31160,7 @@ var UploadSessionToolInput = z123.object(UploadSessionToolInputShape).superRefin
30936
31160
  }
30937
31161
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
30938
31162
  ctx.addIssue({
30939
- code: z123.ZodIssueCode.custom,
31163
+ code: z125.ZodIssueCode.custom,
30940
31164
  path: [
30941
31165
  "maxFiles"
30942
31166
  ],
@@ -30945,7 +31169,7 @@ var UploadSessionToolInput = z123.object(UploadSessionToolInputShape).superRefin
30945
31169
  }
30946
31170
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
30947
31171
  ctx.addIssue({
30948
- code: z123.ZodIssueCode.custom,
31172
+ code: z125.ZodIssueCode.custom,
30949
31173
  path: [
30950
31174
  "maxFiles"
30951
31175
  ],
@@ -30953,38 +31177,38 @@ var UploadSessionToolInput = z123.object(UploadSessionToolInputShape).superRefin
30953
31177
  });
30954
31178
  }
30955
31179
  });
30956
- var UploadSessionResponse = z123.object({
30957
- sessionId: z123.string().uuid(),
30958
- uploadPageUrl: z123.string().url(),
30959
- mediaKind: z123.enum([
31180
+ var UploadSessionResponse = z125.object({
31181
+ sessionId: z125.string().uuid(),
31182
+ uploadPageUrl: z125.string().url(),
31183
+ mediaKind: z125.enum([
30960
31184
  "image",
30961
31185
  "video",
30962
31186
  "mixed"
30963
31187
  ]),
30964
- assetRole: z123.enum([
31188
+ assetRole: z125.enum([
30965
31189
  "media",
30966
31190
  "thumbnail"
30967
31191
  ]),
30968
- maxFiles: z123.number().int().positive(),
30969
- expiresAt: z123.string().datetime()
31192
+ maxFiles: z125.number().int().positive(),
31193
+ expiresAt: z125.string().datetime()
30970
31194
  });
30971
- var UploadStatusInput = z123.object({
30972
- sessionId: z123.string().uuid().describe("The sessionId returned by request_media_upload.")
31195
+ var UploadStatusInput = z125.object({
31196
+ sessionId: z125.string().uuid().describe("The sessionId returned by request_media_upload.")
30973
31197
  });
30974
- var UniversalUploadStatusResponse = z123.discriminatedUnion("status", [
30975
- z123.object({
30976
- status: z123.literal("pending"),
30977
- assets: z123.array(z123.never()).length(0)
31198
+ var UniversalUploadStatusResponse = z125.discriminatedUnion("status", [
31199
+ z125.object({
31200
+ status: z125.literal("pending"),
31201
+ assets: z125.array(z125.never()).length(0)
30978
31202
  }),
30979
- z123.object({
30980
- status: z123.literal("uploaded"),
30981
- assets: z123.array(z123.object({
30982
- assetId: z123.string().uuid(),
30983
- mediaKind: z123.enum([
31203
+ z125.object({
31204
+ status: z125.literal("uploaded"),
31205
+ assets: z125.array(z125.object({
31206
+ assetId: z125.string().uuid(),
31207
+ mediaKind: z125.enum([
30984
31208
  "image",
30985
31209
  "video"
30986
31210
  ]),
30987
- assetRole: z123.enum([
31211
+ assetRole: z125.enum([
30988
31212
  "media",
30989
31213
  "thumbnail"
30990
31214
  ])
@@ -30992,13 +31216,13 @@ var UniversalUploadStatusResponse = z123.discriminatedUnion("status", [
30992
31216
  })
30993
31217
  ]);
30994
31218
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
30995
- uploadPurpose: z123.enum([
31219
+ uploadPurpose: z125.enum([
30996
31220
  "product_reference",
30997
31221
  "creative",
30998
31222
  "generic"
30999
31223
  ]),
31000
- checkToolName: z123.literal("check_media_upload"),
31001
- resolveEndpoint: z123.string().url()
31224
+ checkToolName: z125.literal("check_media_upload"),
31225
+ resolveEndpoint: z125.string().url()
31002
31226
  });
31003
31227
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
31004
31228
  const url = new URL(uploadPageUrl);
@@ -31089,15 +31313,15 @@ function registerMediaUploadTools(server, api) {
31089
31313
  __name(registerMediaUploadTools, "registerMediaUploadTools");
31090
31314
 
31091
31315
  // src/tools/campaigns.ts
31092
- import { z as z124 } from "zod";
31316
+ import { z as z126 } from "zod";
31093
31317
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
31094
31318
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
31095
- var MetaStatusInput = z124.object({
31096
- campaignId: z124.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
31319
+ var MetaStatusInput = z126.object({
31320
+ campaignId: z126.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
31097
31321
  });
31098
- var TikTokStatusInput = z124.object({
31099
- campaignId: z124.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
31100
- advertiserId: z124.string().min(1).describe("The same advertiserId used to publish the campaign.")
31322
+ var TikTokStatusInput = z126.object({
31323
+ campaignId: z126.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
31324
+ advertiserId: z126.string().min(1).describe("The same advertiserId used to publish the campaign.")
31101
31325
  });
31102
31326
  function registerCampaignTools(server, api) {
31103
31327
  server.registerTool("get_meta_campaign_status", {
@@ -31202,10 +31426,10 @@ function renderTikTokStatusMarkdown(r) {
31202
31426
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
31203
31427
 
31204
31428
  // ../../packages/product-economics/src/product-costing.ts
31205
- import { z as z126 } from "zod";
31429
+ import { z as z128 } from "zod";
31206
31430
 
31207
31431
  // ../../packages/product-economics/src/product-costing-countries.ts
31208
- import { z as z125 } from "zod";
31432
+ import { z as z127 } from "zod";
31209
31433
 
31210
31434
  // ../../packages/product-economics/src/product-costing-shipping-references.json
31211
31435
  var product_costing_shipping_references_default = {
@@ -31269,21 +31493,21 @@ var product_costing_shipping_references_default = {
31269
31493
  };
31270
31494
 
31271
31495
  // ../../packages/product-economics/src/product-costing-countries.ts
31272
- var ShippingReferenceSchema = z125.object({
31273
- reference: z125.number().positive(),
31274
- min: z125.number().nonnegative(),
31275
- max: z125.number().positive(),
31276
- updatedAt: z125.string().date(),
31277
- confidence: z125.enum([
31496
+ var ShippingReferenceSchema = z127.object({
31497
+ reference: z127.number().positive(),
31498
+ min: z127.number().nonnegative(),
31499
+ max: z127.number().positive(),
31500
+ updatedAt: z127.string().date(),
31501
+ confidence: z127.enum([
31278
31502
  "high",
31279
31503
  "medium",
31280
31504
  "medium-low"
31281
31505
  ]),
31282
- sources: z125.array(z125.string().url().startsWith("https://")).min(1).max(3)
31506
+ sources: z127.array(z127.string().url().startsWith("https://")).min(1).max(3)
31283
31507
  }).superRefine(({ reference, min, max }, context) => {
31284
31508
  if (min > reference || reference > max) {
31285
31509
  context.addIssue({
31286
- code: z125.ZodIssueCode.custom,
31510
+ code: z127.ZodIssueCode.custom,
31287
31511
  message: "shipping_reference_outside_range",
31288
31512
  path: [
31289
31513
  "reference"
@@ -31291,7 +31515,7 @@ var ShippingReferenceSchema = z125.object({
31291
31515
  });
31292
31516
  }
31293
31517
  });
31294
- var SHIPPING_REFERENCES = z125.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
31518
+ var SHIPPING_REFERENCES = z127.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
31295
31519
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
31296
31520
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
31297
31521
  "MX",
@@ -31473,18 +31697,18 @@ function getProductCostingCountryName(country) {
31473
31697
  __name(getProductCostingCountryName, "getProductCostingCountryName");
31474
31698
 
31475
31699
  // ../../packages/product-economics/src/product-costing.ts
31476
- var ProductCostingInputSchema = z126.object({
31477
- country: z126.string().refine(isProductCostingCountryCode, "unsupported_country"),
31478
- supplierCost: z126.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
31479
- shippingCost: z126.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
31480
- returnRate: z126.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
31481
- cancellationRate: z126.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
31482
- adsManagerCpa: z126.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
31483
- desiredMargin: z126.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
31700
+ var ProductCostingInputSchema = z128.object({
31701
+ country: z128.string().refine(isProductCostingCountryCode, "unsupported_country"),
31702
+ supplierCost: z128.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
31703
+ shippingCost: z128.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
31704
+ returnRate: z128.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
31705
+ cancellationRate: z128.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
31706
+ adsManagerCpa: z128.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
31707
+ desiredMargin: z128.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
31484
31708
  }).superRefine(({ returnRate, cancellationRate }, context) => {
31485
31709
  if (returnRate + cancellationRate >= 1) {
31486
31710
  context.addIssue({
31487
- code: z126.ZodIssueCode.custom,
31711
+ code: z128.ZodIssueCode.custom,
31488
31712
  message: "delivery_rate_positive",
31489
31713
  path: [
31490
31714
  "cancellationRate"
@@ -31581,15 +31805,15 @@ function calculateProductCosting(rawInput) {
31581
31805
  __name(calculateProductCosting, "calculateProductCosting");
31582
31806
 
31583
31807
  // src/tools/product-costing.ts
31584
- import { z as z127 } from "zod";
31808
+ import { z as z129 } from "zod";
31585
31809
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
31586
- var optionalAmount = /* @__PURE__ */ __name((description) => z127.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
31587
- var optionalPercent = /* @__PURE__ */ __name((description) => z127.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
31588
- var ProductCostingToolInput = z127.object({
31589
- country: z127.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
31810
+ var optionalAmount = /* @__PURE__ */ __name((description) => z129.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
31811
+ var optionalPercent = /* @__PURE__ */ __name((description) => z129.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
31812
+ var ProductCostingToolInput = z129.object({
31813
+ country: z129.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
31590
31814
  message: "Pa\xEDs no soportado por ProductMaker."
31591
31815
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
31592
- supplierCost: z127.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."),
31816
+ supplierCost: z129.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."),
31593
31817
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
31594
31818
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
31595
31819
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -31752,7 +31976,7 @@ function formatPercent(value) {
31752
31976
  __name(formatPercent, "formatPercent");
31753
31977
 
31754
31978
  // src/tools/product-research.ts
31755
- import { z as z128 } from "zod";
31979
+ import { z as z130 } from "zod";
31756
31980
 
31757
31981
  // src/tools/product-research-idempotency.ts
31758
31982
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -32123,17 +32347,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
32123
32347
  ]);
32124
32348
  var POLL_INTERVAL_MS = 5e3;
32125
32349
  var MAX_WAIT_SECONDS = 120;
32126
- var FindInput = z128.object({
32350
+ var FindInput = z130.object({
32127
32351
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
32128
32352
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
32129
- confirmed: z128.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
32130
- waitSeconds: z128.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
32353
+ confirmed: z130.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
32354
+ waitSeconds: z130.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
32131
32355
  });
32132
- var GetInput = z128.object({
32133
- runId: z128.string().uuid().describe("ID del run devuelto por find_winning_products.")
32356
+ var GetInput = z130.object({
32357
+ runId: z130.string().uuid().describe("ID del run devuelto por find_winning_products.")
32134
32358
  });
32135
- var ListInput = z128.object({
32136
- limit: z128.number().int().min(1).max(20).default(10)
32359
+ var ListInput = z130.object({
32360
+ limit: z130.number().int().min(1).max(20).default(10)
32137
32361
  });
32138
32362
  function textResult(text2) {
32139
32363
  return {
@@ -32272,17 +32496,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
32272
32496
  __name(registerProductResearchTools, "registerProductResearchTools");
32273
32497
 
32274
32498
  // src/tools/dropshipping-projects.ts
32275
- import { z as z129 } from "zod";
32499
+ import { z as z131 } from "zod";
32276
32500
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
32277
32501
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
32278
32502
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
32279
- var ProjectId = z129.string().uuid();
32280
- var DropshippingProjectStatus = z129.enum([
32503
+ var ProjectId = z131.string().uuid();
32504
+ var DropshippingProjectStatus = z131.enum([
32281
32505
  "active",
32282
32506
  "completed",
32283
32507
  "archived"
32284
32508
  ]);
32285
- var DropshippingProjectPhase = z129.enum([
32509
+ var DropshippingProjectPhase = z131.enum([
32286
32510
  "research",
32287
32511
  "costing",
32288
32512
  "media",
@@ -32291,21 +32515,21 @@ var DropshippingProjectPhase = z129.enum([
32291
32515
  "advertising",
32292
32516
  "complete"
32293
32517
  ]);
32294
- var DropshippingRewardMilestone = z129.enum([
32518
+ var DropshippingRewardMilestone = z131.enum([
32295
32519
  "product_selected",
32296
32520
  "costing_saved",
32297
32521
  "product_media_ready",
32298
32522
  "creatives_completed",
32299
32523
  "campaign_created"
32300
32524
  ]);
32301
- var TargetCountry = z129.enum([
32525
+ var TargetCountry = z131.enum([
32302
32526
  "CO",
32303
32527
  "MX",
32304
32528
  "PE",
32305
32529
  "EC",
32306
32530
  "CL"
32307
32531
  ]);
32308
- var ResearchCategory = z129.enum([
32532
+ var ResearchCategory = z131.enum([
32309
32533
  "auto",
32310
32534
  "automotive",
32311
32535
  "kitchen",
@@ -32320,7 +32544,7 @@ var ResearchCategory = z129.enum([
32320
32544
  "garden",
32321
32545
  "cleaning"
32322
32546
  ]);
32323
- var HttpUrl3 = z129.string().url().max(2e3).refine((value) => {
32547
+ var HttpUrl3 = z131.string().url().max(2e3).refine((value) => {
32324
32548
  try {
32325
32549
  return [
32326
32550
  "http:",
@@ -32330,45 +32554,45 @@ var HttpUrl3 = z129.string().url().max(2e3).refine((value) => {
32330
32554
  return false;
32331
32555
  }
32332
32556
  }, "URL must use HTTP(S)");
32333
- var ResearchCandidateOrigin = z129.object({
32334
- type: z129.literal("research_candidate"),
32557
+ var ResearchCandidateOrigin = z131.object({
32558
+ type: z131.literal("research_candidate"),
32335
32559
  runId: ProjectId,
32336
- candidateSourceId: z129.string().min(1).max(160)
32560
+ candidateSourceId: z131.string().min(1).max(160)
32337
32561
  });
32338
- var TaskOrigin = z129.object({
32339
- type: z129.literal("task"),
32562
+ var TaskOrigin = z131.object({
32563
+ type: z131.literal("task"),
32340
32564
  taskId: ProjectId
32341
32565
  });
32342
- var ManualOrigin = z129.object({
32343
- type: z129.literal("manual"),
32566
+ var ManualOrigin = z131.object({
32567
+ type: z131.literal("manual"),
32344
32568
  clientRequestId: ProjectId,
32345
- country: z129.string().min(2).max(3).optional()
32569
+ country: z131.string().min(2).max(3).optional()
32346
32570
  });
32347
- var StartProjectInput = z129.object({
32348
- origin: z129.discriminatedUnion("type", [
32571
+ var StartProjectInput = z131.object({
32572
+ origin: z131.discriminatedUnion("type", [
32349
32573
  ResearchCandidateOrigin,
32350
32574
  TaskOrigin,
32351
32575
  ManualOrigin
32352
32576
  ]),
32353
- productName: z129.string().trim().min(1).max(240).optional(),
32577
+ productName: z131.string().trim().min(1).max(240).optional(),
32354
32578
  productUrl: HttpUrl3.optional(),
32355
- country: z129.string().min(2).max(3).optional(),
32356
- languageCode: z129.string().min(2).max(16).optional()
32579
+ country: z131.string().min(2).max(3).optional(),
32580
+ languageCode: z131.string().min(2).max(16).optional()
32357
32581
  }).strict();
32358
- var CostProjectInput = z129.object({
32582
+ var CostProjectInput = z131.object({
32359
32583
  projectId: ProjectId,
32360
- version: z129.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
32361
- country: z129.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
32584
+ version: z131.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
32585
+ country: z131.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
32362
32586
  message: "Pa\xEDs no soportado por ProductMaker."
32363
32587
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
32364
- supplierCost: z129.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."),
32365
- shippingCost: z129.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
32366
- returnRate: z129.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."),
32367
- cancellationRate: z129.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."),
32368
- adsManagerCpa: z129.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
32369
- desiredMargin: z129.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
32370
- });
32371
- var GuideInput = z129.object({
32588
+ supplierCost: z131.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."),
32589
+ shippingCost: z131.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
32590
+ returnRate: z131.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."),
32591
+ cancellationRate: z131.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."),
32592
+ adsManagerCpa: z131.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
32593
+ desiredMargin: z131.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
32594
+ });
32595
+ var GuideInput = z131.object({
32372
32596
  projectId: ProjectId.optional()
32373
32597
  }).strict();
32374
32598
  var NEXT_ACTION_KINDS = [
@@ -32386,29 +32610,29 @@ var NEXT_ACTION_KINDS = [
32386
32610
  "repair_meta_campaign",
32387
32611
  "review_paused_campaign"
32388
32612
  ];
32389
- var DropshippingProjectNextAction = z129.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z129.object({
32390
- kind: z129.literal(kind),
32391
- href: z129.string().min(1)
32613
+ var DropshippingProjectNextAction = z131.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z131.object({
32614
+ kind: z131.literal(kind),
32615
+ href: z131.string().min(1)
32392
32616
  })));
32393
- var CostingInputSchema = z129.object({
32394
- country: z129.string().min(2).max(3),
32395
- supplierCost: z129.number().finite().positive(),
32396
- shippingCost: z129.number().finite().nonnegative(),
32397
- returnRate: z129.number().finite().min(0).lt(1),
32398
- cancellationRate: z129.number().finite().min(0).lt(1),
32399
- adsManagerCpa: z129.number().finite().nonnegative(),
32400
- desiredMargin: z129.number().finite().min(0).lt(1)
32617
+ var CostingInputSchema = z131.object({
32618
+ country: z131.string().min(2).max(3),
32619
+ supplierCost: z131.number().finite().positive(),
32620
+ shippingCost: z131.number().finite().nonnegative(),
32621
+ returnRate: z131.number().finite().min(0).lt(1),
32622
+ cancellationRate: z131.number().finite().min(0).lt(1),
32623
+ adsManagerCpa: z131.number().finite().nonnegative(),
32624
+ desiredMargin: z131.number().finite().min(0).lt(1)
32401
32625
  }).superRefine(({ returnRate, cancellationRate }, context) => {
32402
32626
  if (returnRate + cancellationRate >= 1) context.addIssue({
32403
- code: z129.ZodIssueCode.custom,
32627
+ code: z131.ZodIssueCode.custom,
32404
32628
  path: [
32405
32629
  "cancellationRate"
32406
32630
  ]
32407
32631
  });
32408
32632
  });
32409
- var FiniteCostingNumber = z129.number().finite();
32410
- var CostingResultSchema = z129.object({
32411
- country: z129.string().min(2).max(3),
32633
+ var FiniteCostingNumber = z131.number().finite();
32634
+ var CostingResultSchema = z131.object({
32635
+ country: z131.string().min(2).max(3),
32412
32636
  deliveryRate: FiniteCostingNumber,
32413
32637
  adjustedShippingCost: FiniteCostingNumber,
32414
32638
  adjustedCpa: FiniteCostingNumber,
@@ -32421,45 +32645,45 @@ var CostingResultSchema = z129.object({
32421
32645
  estimatedProfit: FiniteCostingNumber,
32422
32646
  actualMargin: FiniteCostingNumber,
32423
32647
  breakEvenAdsManagerCpa: FiniteCostingNumber,
32424
- wasPriceAutoAdjusted: z129.boolean(),
32425
- profitabilityStatus: z129.literal("healthy")
32426
- });
32427
- var RewardProgressSchema = z129.object({
32428
- campaignKey: z129.literal("dropshipping-launch-v1"),
32429
- totalCredits: z129.number().int().positive(),
32430
- earnedCredits: z129.number().int().nonnegative(),
32431
- milestones: z129.array(z129.object({
32648
+ wasPriceAutoAdjusted: z131.boolean(),
32649
+ profitabilityStatus: z131.literal("healthy")
32650
+ });
32651
+ var RewardProgressSchema = z131.object({
32652
+ campaignKey: z131.literal("dropshipping-launch-v1"),
32653
+ totalCredits: z131.number().int().positive(),
32654
+ earnedCredits: z131.number().int().nonnegative(),
32655
+ milestones: z131.array(z131.object({
32432
32656
  milestone: DropshippingRewardMilestone,
32433
- credits: z129.number().int().positive(),
32434
- available: z129.boolean().optional(),
32435
- earned: z129.boolean(),
32657
+ credits: z131.number().int().positive(),
32658
+ available: z131.boolean().optional(),
32659
+ earned: z131.boolean(),
32436
32660
  grantId: ProjectId.nullable(),
32437
- grantedAt: z129.string().datetime().nullable()
32661
+ grantedAt: z131.string().datetime().nullable()
32438
32662
  })).length(DropshippingRewardMilestone.options.length)
32439
32663
  });
32440
- var ProjectResponseSchema = z129.object({
32664
+ var ProjectResponseSchema = z131.object({
32441
32665
  id: ProjectId,
32442
32666
  taskId: ProjectId.nullable(),
32443
32667
  status: DropshippingProjectStatus,
32444
- originKey: z129.string().min(1),
32668
+ originKey: z131.string().min(1),
32445
32669
  researchRunId: ProjectId.nullable(),
32446
- candidateSourceId: z129.string().nullable(),
32447
- productName: z129.string().nullable(),
32670
+ candidateSourceId: z131.string().nullable(),
32671
+ productName: z131.string().nullable(),
32448
32672
  productUrl: HttpUrl3.nullable(),
32449
32673
  referenceImageUrl: HttpUrl3.nullable(),
32450
- targetCountry: z129.string().nullable(),
32451
- languageCode: z129.string().nullable(),
32452
- hasReferenceImage: z129.boolean(),
32453
- hasWinnerReferenceImage: z129.boolean(),
32674
+ targetCountry: z131.string().nullable(),
32675
+ languageCode: z131.string().nullable(),
32676
+ hasReferenceImage: z131.boolean(),
32677
+ hasWinnerReferenceImage: z131.boolean(),
32454
32678
  costingInput: CostingInputSchema.nullable(),
32455
32679
  costingResult: CostingResultSchema.nullable(),
32456
- costingVersion: z129.number().int().positive().nullable(),
32457
- version: z129.number().int().positive(),
32680
+ costingVersion: z131.number().int().positive().nullable(),
32681
+ version: z131.number().int().positive(),
32458
32682
  phase: DropshippingProjectPhase,
32459
32683
  nextAction: DropshippingProjectNextAction.nullable(),
32460
32684
  rewards: RewardProgressSchema,
32461
- createdAt: z129.string().datetime(),
32462
- updatedAt: z129.string().datetime()
32685
+ createdAt: z131.string().datetime(),
32686
+ updatedAt: z131.string().datetime()
32463
32687
  }).passthrough();
32464
32688
  var NEXT_ACTION_GUIDANCE = {
32465
32689
  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.",
@@ -32579,58 +32803,58 @@ function registerDropshippingProjectTools(server, api) {
32579
32803
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
32580
32804
 
32581
32805
  // src/tools/daily-control.ts
32582
- import { z as z130 } from "zod";
32806
+ import { z as z132 } from "zod";
32583
32807
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
32584
32808
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
32585
32809
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
32586
- var ProviderCampaignIdentifier = z130.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
32587
- var DateOnly = z130.string().regex(/^\d{4}-\d{2}-\d{2}$/);
32588
- var DailyControlInput = z130.object({
32810
+ var ProviderCampaignIdentifier = z132.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
32811
+ var DateOnly = z132.string().regex(/^\d{4}-\d{2}-\d{2}$/);
32812
+ var DailyControlInput = z132.object({
32589
32813
  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."),
32590
- days: z130.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
32591
- projectId: z130.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
32814
+ days: z132.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
32815
+ projectId: z132.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
32592
32816
  }).strict();
32593
- var LinkCampaignInput = z130.object({
32594
- projectId: z130.string().uuid(),
32595
- provider: z130.enum([
32817
+ var LinkCampaignInput = z132.object({
32818
+ projectId: z132.string().uuid(),
32819
+ provider: z132.enum([
32596
32820
  "meta",
32597
32821
  "tiktok"
32598
32822
  ]),
32599
32823
  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."),
32600
32824
  campaignId: ProviderCampaignIdentifier
32601
32825
  }).strict();
32602
- var ReportReturnsInput = z130.object({
32603
- projectId: z130.string().uuid(),
32826
+ var ReportReturnsInput = z132.object({
32827
+ projectId: z132.string().uuid(),
32604
32828
  date: DateOnly,
32605
- returnedOrders: z130.number().int().min(0).max(1e5),
32606
- note: z130.string().trim().max(280).optional()
32829
+ returnedOrders: z132.number().int().min(0).max(1e5),
32830
+ note: z132.string().trim().max(280).optional()
32607
32831
  }).strict();
32608
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z130.string());
32609
- var DailyControlLightMirror = DailyControlLightEnum.or(z130.string());
32610
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z130.string());
32611
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z130.string());
32612
- var DailyControlDayMirror = z130.object({
32613
- date: z130.string(),
32614
- returnedOrders: z130.number(),
32832
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z132.string());
32833
+ var DailyControlLightMirror = DailyControlLightEnum.or(z132.string());
32834
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z132.string());
32835
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z132.string());
32836
+ var DailyControlDayMirror = z132.object({
32837
+ date: z132.string(),
32838
+ returnedOrders: z132.number(),
32615
32839
  returnedSource: DailyControlSourceMirror,
32616
32840
  cancelledSource: DailyControlSourceMirror,
32617
- hasEstimates: z130.boolean(),
32841
+ hasEstimates: z132.boolean(),
32618
32842
  light: DailyControlLightMirror
32619
32843
  }).passthrough();
32620
- var DailyControlProductMirror = z130.object({
32621
- projectId: z130.string().uuid(),
32622
- productName: z130.string().nullable(),
32844
+ var DailyControlProductMirror = z132.object({
32845
+ projectId: z132.string().uuid(),
32846
+ productName: z132.string().nullable(),
32623
32847
  status: DailyControlStatusMirror,
32624
- statusMessage: z130.string().nullable(),
32625
- days: z130.array(DailyControlDayMirror),
32848
+ statusMessage: z132.string().nullable(),
32849
+ days: z132.array(DailyControlDayMirror),
32626
32850
  verdict: DailyControlVerdictMirror.nullable(),
32627
- rationale: z130.string().nullable()
32851
+ rationale: z132.string().nullable()
32628
32852
  }).passthrough();
32629
- var DailyControlResponseMirror = z130.object({
32630
- since: z130.string(),
32631
- until: z130.string(),
32632
- products: z130.array(DailyControlProductMirror),
32633
- archivedProjectSpend: z130.array(z130.unknown())
32853
+ var DailyControlResponseMirror = z132.object({
32854
+ since: z132.string(),
32855
+ until: z132.string(),
32856
+ products: z132.array(DailyControlProductMirror),
32857
+ archivedProjectSpend: z132.array(z132.unknown())
32634
32858
  }).passthrough();
32635
32859
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
32636
32860
  function withWarnings(response) {
@@ -32705,7 +32929,7 @@ __name(registerDailyControlTools, "registerDailyControlTools");
32705
32929
  // src/tools/product-control.ts
32706
32930
  import { readFile, stat } from "fs/promises";
32707
32931
  import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
32708
- import { z as z131 } from "zod";
32932
+ import { z as z133 } from "zod";
32709
32933
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
32710
32934
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
32711
32935
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
@@ -32718,36 +32942,36 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
32718
32942
  var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
32719
32943
  var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
32720
32944
  var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
32721
- var DateOnly2 = z131.string().regex(/^\d{4}-\d{2}-\d{2}$/);
32945
+ var DateOnly2 = z133.string().regex(/^\d{4}-\d{2}-\d{2}$/);
32722
32946
  var IMPORT_BATCH_MAX2 = 50;
32723
- var ProductControlListInput = z131.object({
32724
- days: z131.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
32947
+ var ProductControlListInput = z133.object({
32948
+ days: z133.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
32725
32949
  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."),
32726
- shopDomain: z131.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
32950
+ shopDomain: z133.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
32727
32951
  }).strict();
32728
- var ImportableProductsInput = z131.object({
32729
- q: z131.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
32730
- after: z131.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
32731
- shopDomain: z131.string().min(1).optional()
32952
+ var ImportableProductsInput = z133.object({
32953
+ q: z133.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
32954
+ after: z133.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
32955
+ shopDomain: z133.string().min(1).optional()
32732
32956
  }).strict();
32733
- var ImportProductControlsInput = z131.object({
32734
- shopifyProductIds: z131.array(z131.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."),
32957
+ var ImportProductControlsInput = z133.object({
32958
+ shopifyProductIds: z133.array(z133.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."),
32735
32959
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
32736
32960
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
32737
- shopDomain: z131.string().min(1)
32961
+ shopDomain: z133.string().min(1)
32738
32962
  }).strict();
32739
- var SetProductCostingInput = z131.object({
32740
- shopDomain: z131.string().min(1),
32741
- shopifyProductId: z131.string().min(1).max(64),
32742
- targetCountry: z131.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
32743
- supplierCost: z131.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
32744
- shippingCost: z131.number().finite().nonnegative(),
32745
- returnRate: z131.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
32746
- cancellationRate: z131.number().finite().min(0).lt(1)
32963
+ var SetProductCostingInput = z133.object({
32964
+ shopDomain: z133.string().min(1),
32965
+ shopifyProductId: z133.string().min(1).max(64),
32966
+ targetCountry: z133.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
32967
+ supplierCost: z133.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
32968
+ shippingCost: z133.number().finite().nonnegative(),
32969
+ returnRate: z133.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
32970
+ cancellationRate: z133.number().finite().min(0).lt(1)
32747
32971
  }).strict();
32748
- var Count = z131.number().int().min(0).max(1e5).nullable().optional();
32749
- var ReportProductCountsInput = z131.object({
32750
- productControlId: z131.string().uuid().describe("El identificador que devuelve get_product_control."),
32972
+ var Count = z133.number().int().min(0).max(1e5).nullable().optional();
32973
+ var ReportProductCountsInput = z133.object({
32974
+ productControlId: z133.string().uuid().describe("El identificador que devuelve get_product_control."),
32751
32975
  date: DateOnly2,
32752
32976
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
32753
32977
  cancelledOrders: Count,
@@ -32757,36 +32981,36 @@ var ReportProductCountsInput = z131.object({
32757
32981
  }).strict();
32758
32982
  var MAX_ORDERS_FILE_BYTES = 8 * 1024 * 1024;
32759
32983
  var SyncShopifyOrdersInput = SyncShopifyOrdersSchema;
32760
- var ImportOrdersFileInput = z131.object({
32984
+ var ImportOrdersFileInput = z133.object({
32761
32985
  /** Ruta ABSOLUTA en la máquina de quien usa el MCP. */
32762
- path: z131.string().min(1),
32763
- operationId: z131.string().uuid().optional(),
32986
+ path: z133.string().min(1),
32987
+ operationId: z133.string().uuid().optional(),
32764
32988
  /** Solo mirar: devuelve el resumen y no escribe nada. */
32765
- dryRun: z131.boolean().optional()
32989
+ dryRun: z133.boolean().optional()
32766
32990
  }).strict();
32767
- var CreateOperationInput = z131.object({
32768
- countryCode: z131.string().length(2),
32769
- label: z131.string().trim().min(1).max(60).optional()
32991
+ var CreateOperationInput = z133.object({
32992
+ countryCode: z133.string().length(2),
32993
+ label: z133.string().trim().min(1).max(60).optional()
32770
32994
  }).strict();
32771
- var MergeProductsInput = z131.object({
32772
- sourceId: z131.string().uuid(),
32773
- targetId: z131.string().uuid()
32995
+ var MergeProductsInput = z133.object({
32996
+ sourceId: z133.string().uuid(),
32997
+ targetId: z133.string().uuid()
32774
32998
  }).strict();
32775
- var SetMonthlyExpenseInput = z131.object({
32776
- month: z131.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
32999
+ var SetMonthlyExpenseInput = z133.object({
33000
+ month: z133.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
32777
33001
  label: SaveMonthlyExpenseSchema.shape.label,
32778
- amount: z131.number().finite().min(0),
32779
- operationId: z131.string().uuid().optional()
33002
+ amount: z133.number().finite().min(0),
33003
+ operationId: z133.string().uuid().optional()
32780
33004
  }).strict();
32781
- var SetAdSpendInput = z131.object({
32782
- month: z131.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
32783
- operationId: z131.string().uuid().optional(),
33005
+ var SetAdSpendInput = z133.object({
33006
+ month: z133.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
33007
+ operationId: z133.string().uuid().optional(),
32784
33008
  /** null RETIRA la corrección; cero afirma que no pautó. */
32785
- amount: z131.number().finite().min(0).nullable()
33009
+ amount: z133.number().finite().min(0).nullable()
32786
33010
  }).strict();
32787
- var GetFinancesInput = z131.object({
32788
- month: z131.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."),
32789
- operationId: z131.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
33011
+ var GetFinancesInput = z133.object({
33012
+ month: z133.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."),
33013
+ operationId: z133.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
32790
33014
  }).strict();
32791
33015
  function registerProductControlTools(server, api, { transport = "http" } = {}) {
32792
33016
  server.registerTool("get_product_control", {
@@ -32978,28 +33202,28 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
32978
33202
  __name(registerProductControlTools, "registerProductControlTools");
32979
33203
 
32980
33204
  // src/tools/market-study-estimate.ts
32981
- import { z as z132 } from "zod";
33205
+ import { z as z134 } from "zod";
32982
33206
  var estimateMarketStudyGuidance = getProductMakerCapabilityModelGuidance("estimate_market_study_cost");
32983
- var ProductTaskOutputEnum = z132.enum([
33207
+ var ProductTaskOutputEnum = z134.enum([
32984
33208
  "landing",
32985
33209
  "video",
32986
33210
  "image"
32987
33211
  ]);
32988
- var EstimateMarketStudyInput = z132.object({
32989
- kind: z132.enum([
33212
+ var EstimateMarketStudyInput = z134.object({
33213
+ kind: z134.enum([
32990
33214
  "video",
32991
33215
  "product_task"
32992
33216
  ]).describe('"video" para generate_video_creative; "product_task" para create_product_task.'),
32993
- videoAngleCount: z132.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
32994
- durationSeconds: z132.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
33217
+ videoAngleCount: z134.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
33218
+ durationSeconds: z134.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
32995
33219
  videoStructure: VideoStructureEnum.default("single_take"),
32996
33220
  videoQuality: VideoQualityEnum.default("economy"),
32997
33221
  videoResolution: VideoResolutionEnum.default("480p"),
32998
- productImageCount: z132.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
33222
+ productImageCount: z134.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
32999
33223
  outputs: ProductTaskOutputEnum.array().min(1).max(3).optional().describe('Solo para kind="product_task": los mismos outputs de create_product_task. Default: todos.'),
33000
- generateAiMusic: z132.boolean().optional(),
33224
+ generateAiMusic: z134.boolean().optional(),
33001
33225
  generateAiEdit: AiEditRequestSchema.optional(),
33002
- replicateWinnerWhenFound: z132.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.")
33226
+ replicateWinnerWhenFound: z134.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.")
33003
33227
  }).strict();
33004
33228
  function buildMarketStudyEstimateRequests(input) {
33005
33229
  const quotesVideo = input.kind === "video" || (input.outputs ?? [