@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/stdio.js CHANGED
@@ -9698,13 +9698,23 @@ var FacebookCreateCampaignFromTasksBodySchema = z51.object({
9698
9698
  portfolioId: z51.string().min(1),
9699
9699
  pageId: z51.string().min(1),
9700
9700
  pixelId: z51.string().optional(),
9701
+ /**
9702
+ * Omitted: a campaign with task creatives lands on the published service
9703
+ * landing of its service tasks (resolved server side, META_NO_LANDING_URL
9704
+ * when there is none); a media-only campaign must name it.
9705
+ */
9701
9706
  landingUrl: HttpUrl2.optional(),
9702
- targetCountry: CountryIso2Schema.default("US"),
9707
+ /**
9708
+ * Omitted: the brand country of its service tasks; a product-only campaign
9709
+ * keeps "US". Never a hardcoded country for a service (META_NO_TARGET_COUNTRY).
9710
+ */
9711
+ targetCountry: CountryIso2Schema.optional(),
9703
9712
  campaignName: z51.string().min(1).max(100),
9704
9713
  campaignConfig: MetaCampaignConfig.optional()
9705
9714
  }).superRefine((value, ctx) => {
9706
9715
  const isWhatsapp = value.campaignConfig?.destination?.type === "whatsapp";
9707
- if (!isWhatsapp && !value.landingUrl) {
9716
+ const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
9717
+ if (!isWhatsapp && !value.landingUrl && !hasTaskCreative) {
9708
9718
  ctx.addIssue({
9709
9719
  code: z51.ZodIssueCode.custom,
9710
9720
  path: [
@@ -18781,7 +18791,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
18781
18791
  ], [
18782
18792
  "tiktok_advertiser"
18783
18793
  ]),
18784
- defineCapability("publish_creatives_to_meta", "554d977e26e824490ffe3e027f34889b1e29d5969e6e9c0320f79e7c5a03584c", "external_mutation", "publishing", [
18794
+ defineCapability("publish_creatives_to_meta", "dff962c84ed7d0393444dcbe86cb6f4016b5928c1d0005f78ce9a365f1923ac3", "external_mutation", "publishing", [
18785
18795
  "external_mutation",
18786
18796
  "state_change"
18787
18797
  ], [
@@ -21368,8 +21378,33 @@ var ServicePageGenerateRequestSchema = z100.object({
21368
21378
  instruction: ServicePageEditInstructionSchema.optional(),
21369
21379
  attachmentRefs: ServicePageAttachmentRefsSchema.optional()
21370
21380
  }).strict();
21381
+ var SERVICE_PAGE_CREATION_MAX_ATTEMPTS = 3;
21382
+ var ServicePageCreationMarkerSchema = z100.object({
21383
+ rootOperationId: z100.string().uuid().optional(),
21384
+ attempt: z100.number().int().min(1).max(SERVICE_PAGE_CREATION_MAX_ATTEMPTS)
21385
+ }).strict();
21386
+ var ServicePageCreationEstimateRequestSchema = z100.object({
21387
+ textCharacters: z100.number().int().min(0).max(1e6),
21388
+ documentBytes: z100.number().int().min(0).max(1e8),
21389
+ imageCount: z100.number().int().min(0).max(50),
21390
+ instagram: z100.boolean()
21391
+ }).strict();
21392
+ var ServicePageCreationEstimateResponseSchema = z100.object({
21393
+ estimatedMinCostCredits: z100.number().int().nonnegative(),
21394
+ estimatedMaxCostCredits: z100.number().int().nonnegative()
21395
+ }).strict();
21396
+ var ServicePageCreationStatusSchema = z100.object({
21397
+ status: z100.enum([
21398
+ "idle",
21399
+ "running",
21400
+ "failed"
21401
+ ]),
21402
+ errorCode: z100.string().max(64).optional()
21403
+ }).strict();
21371
21404
  var ServicePageFactExtractionRequestSchema = ServicePageGenerateRequestSchema.omit({
21372
21405
  instruction: true
21406
+ }).extend({
21407
+ continueWith: z100.literal("generation").optional()
21373
21408
  });
21374
21409
  var ServicePageOperationStatusSchema = z100.enum([
21375
21410
  "queued",
@@ -21852,19 +21887,37 @@ var ServiceImageContextSchema = z106.object({
21852
21887
  referenceKeys: z106.array(z106.string()).max(10)
21853
21888
  }).strict();
21854
21889
 
21855
- // ../../packages/types/src/service-website-capture.ts
21890
+ // ../../packages/types/src/task-ad-defaults.ts
21856
21891
  import { z as z107 } from "zod";
21892
+ var AD_HEADLINE_MAX_CHARS = 255;
21893
+ var TaskAdDefaultsSchema = z107.object({
21894
+ subjectKind: z107.enum([
21895
+ "product",
21896
+ "service"
21897
+ ]),
21898
+ landingUrl: z107.string().url().nullable(),
21899
+ landingSource: z107.enum([
21900
+ "shopify",
21901
+ "service_page"
21902
+ ]).nullable(),
21903
+ headline: z107.string().min(1).max(AD_HEADLINE_MAX_CHARS).nullable(),
21904
+ /** ISO 3166-1 alpha-2 when known. */
21905
+ country: z107.string().min(2).nullable()
21906
+ });
21907
+
21908
+ // ../../packages/types/src/service-website-capture.ts
21909
+ import { z as z108 } from "zod";
21857
21910
  var WEBSITE_CAPTURE_MAX_RESEARCH_BYTES = 1024 * 1024;
21858
21911
  var WEBSITE_CAPTURE_MAX_FILES = 100;
21859
21912
  var WEBSITE_CAPTURE_MAX_FILE_BYTES = 8 * 1024 * 1024;
21860
21913
  var WEBSITE_CAPTURE_MAX_BUNDLE_BYTES = 30 * 1024 * 1024;
21861
- var WebsiteCaptureCauseSchema = z107.enum([
21914
+ var WebsiteCaptureCauseSchema = z108.enum([
21862
21915
  "site_blocked",
21863
21916
  "site_unreachable",
21864
21917
  "not_enough_content",
21865
21918
  "internal"
21866
21919
  ]);
21867
- var WebsiteCaptureStatusSchema = z107.enum([
21920
+ var WebsiteCaptureStatusSchema = z108.enum([
21868
21921
  "queued",
21869
21922
  "capturing",
21870
21923
  "ready",
@@ -21886,134 +21939,287 @@ function normalizeWebsiteCaptureUrl(value) {
21886
21939
  }
21887
21940
  }
21888
21941
  __name(normalizeWebsiteCaptureUrl, "normalizeWebsiteCaptureUrl");
21889
- var WebsiteCaptureRequestSchema = z107.object({
21890
- url: z107.string().trim().max(2048).url().refine((value) => normalizeWebsiteCaptureUrl(value) !== null, "Use an HTTP(S) URL without credentials").transform((value) => normalizeWebsiteCaptureUrl(value)),
21942
+ var WebsiteCaptureRequestSchema = z108.object({
21943
+ url: z108.string().trim().max(2048).url().refine((value) => normalizeWebsiteCaptureUrl(value) !== null, "Use an HTTP(S) URL without credentials").transform((value) => normalizeWebsiteCaptureUrl(value)),
21891
21944
  language: MotionGraphicsLanguageSchema
21892
21945
  }).strict();
21893
- var WebsiteCaptureResponseSchema = z107.object({
21894
- captureId: z107.string().uuid(),
21946
+ var WebsiteCaptureResponseSchema = z108.object({
21947
+ captureId: z108.string().uuid(),
21895
21948
  status: WebsiteCaptureStatusSchema,
21896
- expiresAt: z107.string().datetime(),
21897
- previewUrl: z107.string().url().optional(),
21949
+ expiresAt: z108.string().datetime(),
21950
+ previewUrl: z108.string().url().optional(),
21898
21951
  cause: WebsiteCaptureCauseSchema.optional()
21899
21952
  });
21900
21953
  var WebsiteCaptureJobSchema = WebsiteCaptureRequestSchema.extend({
21901
- captureId: z107.string().uuid(),
21902
- attempt: z107.number().int().positive(),
21903
- leaseUntil: z107.string().datetime()
21954
+ captureId: z108.string().uuid(),
21955
+ attempt: z108.number().int().positive(),
21956
+ leaseUntil: z108.string().datetime()
21904
21957
  });
21905
- var WebsiteCaptureClaimResponseSchema = z107.object({
21958
+ var WebsiteCaptureClaimResponseSchema = z108.object({
21906
21959
  capture: WebsiteCaptureJobSchema.nullable()
21907
21960
  });
21908
21961
  var attempt = {
21909
- attempt: z107.number().int().positive()
21962
+ attempt: z108.number().int().positive()
21910
21963
  };
21911
- var digest = z107.string().regex(/^[a-f0-9]{64}$/);
21912
- var WebsiteCaptureUploadRequestSchema = z107.object({
21964
+ var digest = z108.string().regex(/^[a-f0-9]{64}$/);
21965
+ var WebsiteCaptureUploadRequestSchema = z108.object({
21913
21966
  ...attempt,
21914
- contentLength: z107.number().int().positive().max(WEBSITE_CAPTURE_MAX_BUNDLE_BYTES),
21967
+ contentLength: z108.number().int().positive().max(WEBSITE_CAPTURE_MAX_BUNDLE_BYTES),
21915
21968
  sha256: digest
21916
21969
  }).strict();
21917
- var WebsiteCaptureDoneRequestSchema = z107.object({
21970
+ var WebsiteCaptureDoneRequestSchema = z108.object({
21918
21971
  ...attempt,
21919
21972
  sha256: digest
21920
21973
  }).strict();
21921
- var WebsiteCaptureFailedRequestSchema = z107.object({
21974
+ var WebsiteCaptureFailedRequestSchema = z108.object({
21922
21975
  ...attempt,
21923
21976
  cause: WebsiteCaptureCauseSchema
21924
21977
  }).strict();
21925
- var WebsiteCaptureBundleSchema = z107.object({
21926
- version: z107.literal(1),
21927
- files: z107.array(z107.object({
21928
- 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))$/),
21929
- 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),
21978
+ var WebsiteCaptureBundleSchema = z108.object({
21979
+ version: z108.literal(1),
21980
+ files: z108.array(z108.object({
21981
+ 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))$/),
21982
+ 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),
21930
21983
  sha256: digest
21931
21984
  }).strict()).min(1).max(WEBSITE_CAPTURE_MAX_FILES)
21932
21985
  }).strict().refine((bundle) => new Set(bundle.files.map((file) => file.path)).size === bundle.files.length, "Duplicate capture file");
21933
- var WebsiteCaptureScreenshotSchema = z107.object({
21934
- file: z107.string(),
21935
- scrollTop: z107.number()
21936
- });
21937
- var WebsiteCaptureAccessSchema = z107.object({
21938
- publicContentText: z107.string().max(8e3),
21939
- passwordGate: z107.boolean(),
21940
- challengeGate: z107.boolean(),
21941
- blockingOverlay: z107.boolean(),
21986
+ var WebsiteCaptureScreenshotSchema = z108.object({
21987
+ file: z108.string(),
21988
+ scrollTop: z108.number()
21989
+ });
21990
+ var WebsiteCaptureAccessSchema = z108.object({
21991
+ publicContentText: z108.string().max(8e3),
21992
+ passwordGate: z108.boolean(),
21993
+ challengeGate: z108.boolean(),
21994
+ blockingOverlay: z108.boolean(),
21942
21995
  // Decoded, substantial images visible outside access walls and page chrome.
21943
21996
  // Optional for compatibility with already captured text-led research.
21944
- publicImageUrls: z107.array(z107.string().url().max(8192)).max(20).optional()
21945
- });
21946
- var WebsiteCaptureResearchSchema = z107.object({
21947
- requestedUrl: z107.string().url(),
21948
- capturedAt: z107.string().datetime(),
21949
- locale: z107.string(),
21950
- bodyTextTruncated: z107.boolean(),
21951
- finalUrl: z107.string().url(),
21952
- lang: z107.string().nullable(),
21953
- title: z107.string(),
21954
- description: z107.string(),
21955
- openGraph: z107.object({
21956
- title: z107.string(),
21957
- description: z107.string(),
21958
- image: z107.string(),
21959
- siteName: z107.string()
21997
+ publicImageUrls: z108.array(z108.string().url().max(8192)).max(20).optional()
21998
+ });
21999
+ var WebsiteCaptureResearchSchema = z108.object({
22000
+ requestedUrl: z108.string().url(),
22001
+ capturedAt: z108.string().datetime(),
22002
+ locale: z108.string(),
22003
+ bodyTextTruncated: z108.boolean(),
22004
+ finalUrl: z108.string().url(),
22005
+ lang: z108.string().nullable(),
22006
+ title: z108.string(),
22007
+ description: z108.string(),
22008
+ openGraph: z108.object({
22009
+ title: z108.string(),
22010
+ description: z108.string(),
22011
+ image: z108.string(),
22012
+ siteName: z108.string()
21960
22013
  }),
21961
- themeColor: z107.string(),
21962
- headings: z107.object({
21963
- h1: z107.array(z107.string()),
21964
- h2: z107.array(z107.string()),
21965
- h3: z107.array(z107.string())
22014
+ themeColor: z108.string(),
22015
+ headings: z108.object({
22016
+ h1: z108.array(z108.string()),
22017
+ h2: z108.array(z108.string()),
22018
+ h3: z108.array(z108.string())
21966
22019
  }),
21967
- callsToAction: z107.array(z107.string()),
21968
- listItems: z107.array(z107.string()),
21969
- bodyText: z107.string(),
22020
+ callsToAction: z108.array(z108.string()),
22021
+ listItems: z108.array(z108.string()),
22022
+ bodyText: z108.string(),
21970
22023
  access: WebsiteCaptureAccessSchema.optional(),
21971
- consent: z107.object({
21972
- pressed: z107.string().nullable(),
21973
- removed: z107.number().nonnegative()
22024
+ consent: z108.object({
22025
+ pressed: z108.string().nullable(),
22026
+ removed: z108.number().nonnegative()
21974
22027
  }).optional(),
21975
- overlaysDismissed: z107.number().int().nonnegative().optional(),
21976
- style: z107.object({
21977
- bodyBackground: z107.string(),
21978
- bodyColor: z107.string(),
21979
- bodyFont: z107.string(),
21980
- headingFont: z107.string().nullable(),
21981
- headingColor: z107.string().nullable(),
21982
- actionColors: z107.array(z107.object({
21983
- color: z107.string(),
21984
- uses: z107.number()
22028
+ overlaysDismissed: z108.number().int().nonnegative().optional(),
22029
+ style: z108.object({
22030
+ bodyBackground: z108.string(),
22031
+ bodyColor: z108.string(),
22032
+ bodyFont: z108.string(),
22033
+ headingFont: z108.string().nullable(),
22034
+ headingColor: z108.string().nullable(),
22035
+ actionColors: z108.array(z108.object({
22036
+ color: z108.string(),
22037
+ uses: z108.number()
21985
22038
  }))
21986
22039
  }),
21987
- images: z107.array(z107.object({
21988
- file: z107.string(),
21989
- src: z107.string(),
21990
- alt: z107.string(),
21991
- width: z107.number().nullable(),
21992
- height: z107.number().nullable(),
21993
- isOpenGraph: z107.boolean()
22040
+ images: z108.array(z108.object({
22041
+ file: z108.string(),
22042
+ src: z108.string(),
22043
+ alt: z108.string(),
22044
+ width: z108.number().nullable(),
22045
+ height: z108.number().nullable(),
22046
+ isOpenGraph: z108.boolean()
21994
22047
  })),
21995
- logo: z107.object({
21996
- file: z107.literal("logo.png"),
21997
- svg: z107.literal("logo.svg").optional(),
21998
- width: z107.number(),
21999
- height: z107.number()
22048
+ logo: z108.object({
22049
+ file: z108.literal("logo.png"),
22050
+ svg: z108.literal("logo.svg").optional(),
22051
+ width: z108.number(),
22052
+ height: z108.number()
22000
22053
  }).nullable(),
22001
- fonts: z107.array(z107.object({
22002
- family: z107.string(),
22003
- weight: z107.string(),
22004
- style: z107.string(),
22005
- unicodeRange: z107.string().nullable(),
22006
- file: z107.string().optional()
22054
+ fonts: z108.array(z108.object({
22055
+ family: z108.string(),
22056
+ weight: z108.string(),
22057
+ style: z108.string(),
22058
+ unicodeRange: z108.string().nullable(),
22059
+ file: z108.string().optional()
22007
22060
  }).transform((font) => ({
22008
22061
  ...font,
22009
22062
  file: font.file
22010
22063
  }))),
22011
- screenshots: z107.object({
22012
- desktop: z107.array(WebsiteCaptureScreenshotSchema),
22013
- mobile: z107.array(WebsiteCaptureScreenshotSchema)
22064
+ screenshots: z108.object({
22065
+ desktop: z108.array(WebsiteCaptureScreenshotSchema),
22066
+ mobile: z108.array(WebsiteCaptureScreenshotSchema)
22014
22067
  })
22015
22068
  });
22016
22069
 
22070
+ // ../../packages/types/src/demo-mode.ts
22071
+ import { z as z109 } from "zod";
22072
+ var DEMO_MODE_FLOWS = [
22073
+ "brand",
22074
+ "servicePage",
22075
+ "motion",
22076
+ "image"
22077
+ ];
22078
+ var DemoModeFlowSchema = z109.enum(DEMO_MODE_FLOWS);
22079
+ var DEMO_MODE_STEPS = [
22080
+ "running",
22081
+ "research",
22082
+ "design",
22083
+ "render_0",
22084
+ "render_33",
22085
+ "render_66",
22086
+ "render_100",
22087
+ "review",
22088
+ "final",
22089
+ "watchdog"
22090
+ ];
22091
+ var DemoModeStepSchema = z109.enum(DEMO_MODE_STEPS);
22092
+ var DEMO_MODE_WAIT_SECONDS = {
22093
+ min: 30,
22094
+ max: 450,
22095
+ default: 150
22096
+ };
22097
+ var centsSchema = z109.number().int().min(0).max(1e5);
22098
+ var emailSchema = z109.string().trim().toLowerCase().email();
22099
+ var DemoModeTemplatesSchema = z109.object({
22100
+ brandId: z109.string().uuid(),
22101
+ servicePageId: z109.string().uuid(),
22102
+ motionTaskId: z109.string().uuid(),
22103
+ imageTaskId: z109.string().uuid()
22104
+ });
22105
+ var DemoModeEditableSchema = z109.object({
22106
+ enabled: z109.boolean(),
22107
+ emails: z109.array(emailSchema).max(50).transform((list) => [
22108
+ ...new Set(list)
22109
+ ]),
22110
+ waitSeconds: z109.number().int().min(DEMO_MODE_WAIT_SECONDS.min).max(DEMO_MODE_WAIT_SECONDS.max),
22111
+ chargeCents: z109.object({
22112
+ brand: centsSchema,
22113
+ servicePage: centsSchema,
22114
+ motion: centsSchema,
22115
+ image: centsSchema
22116
+ }),
22117
+ templates: DemoModeTemplatesSchema
22118
+ });
22119
+ var nullableString = z109.string().nullable();
22120
+ var DemoModeSnapshotSchema = z109.object({
22121
+ brand: z109.object({
22122
+ /** Columnas de identidad de `Brand` listas para un `update` (sin id/userId/slug/estado/fechas). */
22123
+ identity: z109.record(z109.unknown()),
22124
+ productSamples: z109.array(z109.object({
22125
+ name: z109.string(),
22126
+ priceCents: z109.number().int().nullable(),
22127
+ currency: nullableString,
22128
+ imageKey: z109.string(),
22129
+ productUrl: nullableString,
22130
+ position: z109.number().int()
22131
+ })),
22132
+ personas: z109.array(z109.object({
22133
+ name: z109.string(),
22134
+ demographics: nullableString,
22135
+ painPoints: nullableString,
22136
+ motivations: nullableString,
22137
+ objections: nullableString,
22138
+ gender: nullableString,
22139
+ isDefault: z109.boolean()
22140
+ }))
22141
+ }),
22142
+ servicePage: z109.object({
22143
+ facts: z109.unknown(),
22144
+ review: z109.unknown(),
22145
+ artifact: z109.unknown()
22146
+ }),
22147
+ motion: z109.object({
22148
+ outputs: MotionGraphicsOutputsSchema,
22149
+ /**
22150
+ * La captura REAL de la web de la plantilla (nunca una fabricada por la
22151
+ * demo). Null cuando la plantilla no tiene ninguna: la captura demo nunca
22152
+ * va live, así que el servicio usa `DEMO_MODE_PLACEHOLDER_CAPTURE`.
22153
+ */
22154
+ capture: z109.object({
22155
+ bundleKey: z109.string(),
22156
+ sha256: z109.string(),
22157
+ uploadBytes: z109.number().int().nullable(),
22158
+ previewKey: nullableString
22159
+ }).nullable()
22160
+ }),
22161
+ image: z109.object({
22162
+ provider: z109.string(),
22163
+ model: z109.string(),
22164
+ prompt: z109.string(),
22165
+ imageUrl: z109.string(),
22166
+ width: z109.number().int(),
22167
+ height: z109.number().int(),
22168
+ adCopy: nullableString,
22169
+ rawResponse: z109.unknown()
22170
+ })
22171
+ });
22172
+ var DemoModeConfigSchema = DemoModeEditableSchema.extend({
22173
+ snapshot: DemoModeSnapshotSchema.nullable(),
22174
+ snapshotAt: z109.string().datetime().nullable()
22175
+ });
22176
+ var DemoModeAdminViewSchema = DemoModeEditableSchema.extend({
22177
+ // Sin configurar, la API devuelve ids vacíos ("" no es uuid): la vista los
22178
+ // admite; el PUT sí exige uuid (`DemoModeEditableSchema`).
22179
+ templates: z109.object({
22180
+ brandId: z109.string(),
22181
+ servicePageId: z109.string(),
22182
+ motionTaskId: z109.string(),
22183
+ imageTaskId: z109.string()
22184
+ }),
22185
+ snapshotAt: z109.string().nullable()
22186
+ });
22187
+ var DEMO_MODE_TEMPLATE_PROBLEMS = [
22188
+ "not_found",
22189
+ "brand_not_ready",
22190
+ "no_artifact",
22191
+ "artifact_invalid",
22192
+ "task_not_done",
22193
+ "no_video",
22194
+ "no_creative"
22195
+ ];
22196
+ var DemoModeTemplateVerdictSchema = z109.discriminatedUnion("ok", [
22197
+ z109.object({
22198
+ ok: z109.literal(true)
22199
+ }),
22200
+ z109.object({
22201
+ ok: z109.literal(false),
22202
+ problem: z109.enum(DEMO_MODE_TEMPLATE_PROBLEMS)
22203
+ })
22204
+ ]);
22205
+ var DemoModeValidationSchema = z109.object({
22206
+ brandId: DemoModeTemplateVerdictSchema,
22207
+ servicePageId: DemoModeTemplateVerdictSchema,
22208
+ motionTaskId: DemoModeTemplateVerdictSchema,
22209
+ imageTaskId: DemoModeTemplateVerdictSchema
22210
+ });
22211
+ var DemoModeJobSchema = z109.object({
22212
+ flow: DemoModeFlowSchema,
22213
+ step: DemoModeStepSchema,
22214
+ /** brandId | servicePageOperationId | taskId según el flujo. */
22215
+ targetId: z109.string().uuid(),
22216
+ userId: z109.string().min(1),
22217
+ /** Solo marca: la generación de extracción que el guion completa. */
22218
+ generation: z109.number().int().positive().optional(),
22219
+ /** Solo `final`/`watchdog`: la parte del snapshot de ESTE flujo, congelada al empezar. */
22220
+ result: z109.unknown().optional()
22221
+ });
22222
+
22017
22223
  // src/response-body.ts
22018
22224
  var ResponseBodyTooLargeError = class extends Error {
22019
22225
  static {
@@ -22256,7 +22462,7 @@ var ApiClient = class {
22256
22462
  };
22257
22463
 
22258
22464
  // src/index.ts
22259
- var MCP_VERSION = "11.3.2";
22465
+ var MCP_VERSION = "11.4.0";
22260
22466
 
22261
22467
  // src/meta-upload-app.ts
22262
22468
  import { readFileSync } from "fs";
@@ -22328,7 +22534,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
22328
22534
  __name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
22329
22535
 
22330
22536
  // src/tools/tasks.ts
22331
- import { z as z112 } from "zod";
22537
+ import { z as z114 } from "zod";
22332
22538
 
22333
22539
  // src/resolve-image.ts
22334
22540
  import { lookup as dnsLookup } from "dns/promises";
@@ -22889,9 +23095,9 @@ async function resolveMediaRef(ref, opts) {
22889
23095
  __name(resolveMediaRef, "resolveMediaRef");
22890
23096
 
22891
23097
  // src/tools/shared.ts
22892
- import { z as z108 } from "zod";
22893
- var Lang = z108.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);
22894
- var Country = z108.string().min(2).max(3);
23098
+ import { z as z110 } from "zod";
23099
+ var Lang = z110.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);
23100
+ var Country = z110.string().min(2).max(3);
22895
23101
  var LandingStrategyEnum = LandingStrategySchema;
22896
23102
  var LandingImageFormatEnum = LandingImageFormatSchema;
22897
23103
  var VideoPresetEnum = VideoPreset.extract([
@@ -22995,7 +23201,7 @@ function animationStyleApplies(videoPreset, angleNarratives) {
22995
23201
  return ANIMATED_VIDEO_PRESETS.has(videoPreset ?? "") || (angleNarratives ?? []).some((n) => ANIMATED_NARRATIVE_STYLES.has(n));
22996
23202
  }
22997
23203
  __name(animationStyleApplies, "animationStyleApplies");
22998
- var VideoTierEnum = z108.enum([
23204
+ var VideoTierEnum = z110.enum([
22999
23205
  "basic"
23000
23206
  ]);
23001
23207
  function resolveVideoTier(_tier) {
@@ -23053,10 +23259,10 @@ var ImageCreativeStyleEnum = ImageCreativeStyle;
23053
23259
  var ImageCreativeArchetypeEnum = ImageCreativeArchetype;
23054
23260
  var ImageCreativeVisualTreatmentEnum = ImageCreativeVisualTreatment;
23055
23261
  var ImageCreativeAspectRatioEnum = ImageCreativeAspectRatio;
23056
- var ImageRefSchema = z108.object({
23057
- url: z108.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.'),
23058
- path: z108.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`.'),
23059
- assetId: z108.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.")
23262
+ var ImageRefSchema = z110.object({
23263
+ url: z110.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.'),
23264
+ path: z110.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`.'),
23265
+ assetId: z110.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.")
23060
23266
  }).refine((v) => [
23061
23267
  v.url,
23062
23268
  v.path,
@@ -23064,11 +23270,11 @@ var ImageRefSchema = z108.object({
23064
23270
  ].filter(Boolean).length === 1, {
23065
23271
  message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
23066
23272
  });
23067
- var ImagesInput = z108.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
23273
+ var ImagesInput = z110.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
23068
23274
  const assetCount = images.filter((image) => Boolean(image.assetId)).length;
23069
23275
  if (assetCount > 0 && assetCount !== images.length) {
23070
23276
  ctx.addIssue({
23071
- code: z108.ZodIssueCode.custom,
23277
+ code: z110.ZodIssueCode.custom,
23072
23278
  message: "all image entries must use assetId, or all must use URL/path sources"
23073
23279
  });
23074
23280
  }
@@ -23118,16 +23324,24 @@ async function submitCreative(api, opts) {
23118
23324
  ...img,
23119
23325
  filename: `image-${i}.png`
23120
23326
  }));
23121
- const r = await api.postMultipart(opts.path, {
23122
- images: parts
23123
- }, flatten({
23124
- ...rest,
23125
- ...assetIds ? {
23126
- assetIds
23127
- } : {}
23128
- }), opts.idempotencyKey ? {
23129
- idempotencyKey: opts.idempotencyKey
23130
- } : void 0);
23327
+ const r = await api.postMultipart(
23328
+ opts.path,
23329
+ {
23330
+ images: parts
23331
+ },
23332
+ // assetIds stays an array so postMultipart appends one `assetIds` field per
23333
+ // id: `flatten` would comma-join them into a single non-UUID value and the
23334
+ // API rejects every multi-photo upload with "assetId must be a valid UUID".
23335
+ {
23336
+ ...flatten(rest),
23337
+ ...assetIds ? {
23338
+ assetIds
23339
+ } : {}
23340
+ },
23341
+ opts.idempotencyKey ? {
23342
+ idempotencyKey: opts.idempotencyKey
23343
+ } : void 0
23344
+ );
23131
23345
  const taskId = r.taskId ?? r.jobId;
23132
23346
  return asText({
23133
23347
  taskId,
@@ -23141,14 +23355,14 @@ async function submitCreative(api, opts) {
23141
23355
  });
23142
23356
  }
23143
23357
  __name(submitCreative, "submitCreative");
23144
- var ResearchTargetCountryEnum = z108.enum([
23358
+ var ResearchTargetCountryEnum = z110.enum([
23145
23359
  "CO",
23146
23360
  "MX",
23147
23361
  "PE",
23148
23362
  "EC",
23149
23363
  "CL"
23150
23364
  ]);
23151
- var ResearchCategoryEnum = z108.enum([
23365
+ var ResearchCategoryEnum = z110.enum([
23152
23366
  "auto",
23153
23367
  "automotive",
23154
23368
  "kitchen",
@@ -23278,6 +23492,7 @@ var McpErrorCode = {
23278
23492
  CAMPAIGN_NOT_FOUND: "CAMPAIGN_NOT_FOUND",
23279
23493
  CAMPAIGN_TASK_NOT_FOUND: "CAMPAIGN_TASK_NOT_FOUND",
23280
23494
  CAMPAIGN_MISSING_LANDING_URL: "CAMPAIGN_MISSING_LANDING_URL",
23495
+ CAMPAIGN_MISSING_TARGET_COUNTRY: "CAMPAIGN_MISSING_TARGET_COUNTRY",
23281
23496
  CAMPAIGN_NO_CREATIVES: "CAMPAIGN_NO_CREATIVES",
23282
23497
  CAMPAIGN_MISSING_THUMBNAILS: "CAMPAIGN_MISSING_THUMBNAILS",
23283
23498
  CAMPAIGN_RECONCILIATION_REQUIRED: "CAMPAIGN_RECONCILIATION_REQUIRED",
@@ -23317,6 +23532,7 @@ var McpErrorCode = {
23317
23532
  META_NO_ASSETS_READY: "META_NO_ASSETS_READY",
23318
23533
  META_NO_THUMBNAIL_SOURCE: "META_NO_THUMBNAIL_SOURCE",
23319
23534
  META_NO_LANDING_URL: "META_NO_LANDING_URL",
23535
+ META_NO_TARGET_COUNTRY: "META_NO_TARGET_COUNTRY",
23320
23536
  META_TASK_NOT_FOUND: "META_TASK_NOT_FOUND",
23321
23537
  META_INVALID_DATA: "META_INVALID_DATA",
23322
23538
  META_INVALID_AD_ACCOUNT: "META_INVALID_AD_ACCOUNT",
@@ -23404,7 +23620,8 @@ var CODE_MESSAGES = {
23404
23620
  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.",
23405
23621
  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.",
23406
23622
  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.",
23407
- META_NO_LANDING_URL: "Missing landing URL. Pass it in `landingUrl` or publish to Shopify first with `publish_to_shopify`.",
23623
+ 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.",
23624
+ 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.",
23408
23625
  META_TASK_NOT_FOUND: "Task not found or does not belong to this user. Verify the `taskId`.",
23409
23626
  META_INVALID_DATA: "Meta rejected the request due to invalid data. Verify that `adAccountId` and `pixelId` are correct.",
23410
23627
  META_INVALID_AD_ACCOUNT: "Ad account not found or no access. Confirm the `adAccountId` with `list_meta_ad_accounts`.",
@@ -23443,7 +23660,8 @@ var CODE_MESSAGES = {
23443
23660
  // Campaign (shared)
23444
23661
  CAMPAIGN_NOT_FOUND: "Campaign not found or does not belong to this user. Verify the `campaignId`.",
23445
23662
  CAMPAIGN_TASK_NOT_FOUND: "Campaign task not found. Verify the `taskId`.",
23446
- CAMPAIGN_MISSING_LANDING_URL: "Missing landing URL for the campaign. Publish to Shopify first or pass `landingUrl` explicitly.",
23663
+ 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.",
23664
+ 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.",
23447
23665
  CAMPAIGN_NO_CREATIVES: "The task has no creatives (video/image) ready for the campaign. Wait for generation to finish.",
23448
23666
  CAMPAIGN_MISSING_THUMBNAILS: "Missing thumbnails for the videos. Verify that image/video generation has finished.",
23449
23667
  CAMPAIGN_RECONCILIATION_REQUIRED: "A campaign may already have been created. Do not retry creation; reopen the project and reconcile it or contact support.",
@@ -23535,8 +23753,10 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
23535
23753
  McpErrorCode.TIKTOK_ADVERTISER_REQUIRED,
23536
23754
  McpErrorCode.TIKTOK_PIXEL_NOT_FOUND,
23537
23755
  McpErrorCode.CAMPAIGN_MISSING_LANDING_URL,
23756
+ McpErrorCode.CAMPAIGN_MISSING_TARGET_COUNTRY,
23538
23757
  McpErrorCode.CAMPAIGN_RECONCILIATION_REQUIRED,
23539
23758
  McpErrorCode.META_NO_LANDING_URL,
23759
+ McpErrorCode.META_NO_TARGET_COUNTRY,
23540
23760
  McpErrorCode.META_PORTFOLIO_MISMATCH,
23541
23761
  McpErrorCode.META_PAGE_SELECTION_REQUIRED,
23542
23762
  McpErrorCode.META_INVALID_PAGE,
@@ -23647,6 +23867,7 @@ var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
23647
23867
  McpErrorCode.META_NO_ASSETS_READY,
23648
23868
  McpErrorCode.META_NO_THUMBNAIL_SOURCE,
23649
23869
  McpErrorCode.META_NO_LANDING_URL,
23870
+ McpErrorCode.META_NO_TARGET_COUNTRY,
23650
23871
  McpErrorCode.META_TASK_NOT_FOUND,
23651
23872
  McpErrorCode.META_INVALID_DATA,
23652
23873
  McpErrorCode.META_INVALID_AD_ACCOUNT,
@@ -23694,6 +23915,7 @@ var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
23694
23915
  McpErrorCode.CAMPAIGN_NOT_FOUND,
23695
23916
  McpErrorCode.CAMPAIGN_TASK_NOT_FOUND,
23696
23917
  McpErrorCode.CAMPAIGN_MISSING_LANDING_URL,
23918
+ McpErrorCode.CAMPAIGN_MISSING_TARGET_COUNTRY,
23697
23919
  McpErrorCode.CAMPAIGN_NO_CREATIVES,
23698
23920
  McpErrorCode.CAMPAIGN_MISSING_THUMBNAILS,
23699
23921
  McpErrorCode.CAMPAIGN_RECONCILIATION_REQUIRED,
@@ -24513,29 +24735,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
24513
24735
  __name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
24514
24736
 
24515
24737
  // src/tools/media-presentation.ts
24516
- import { z as z109 } from "zod";
24517
- var HttpsPresentationUrlSchema = z109.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
24738
+ import { z as z111 } from "zod";
24739
+ var HttpsPresentationUrlSchema = z111.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
24518
24740
  var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
24519
24741
  const hostname = new URL(value).hostname.toLowerCase();
24520
24742
  return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
24521
24743
  }, "preview URL must be owned by ProductMaker");
24522
- var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z109.number().int().positive().max(maximum), "positiveIntAtMost");
24523
- var PresentationImageSchema = z109.object({
24524
- kind: z109.literal("image"),
24744
+ var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z111.number().int().positive().max(maximum), "positiveIntAtMost");
24745
+ var PresentationImageSchema = z111.object({
24746
+ kind: z111.literal("image"),
24525
24747
  url: HttpsPresentationUrlSchema,
24526
- mimeType: z109.enum([
24748
+ mimeType: z111.enum([
24527
24749
  "image/jpeg",
24528
24750
  "image/png"
24529
24751
  ]),
24530
24752
  byteSize: positiveIntAtMost(5 * 1024 * 1024),
24531
24753
  width: positiveIntAtMost(16384),
24532
24754
  height: positiveIntAtMost(16384),
24533
- alt: z109.string().trim().min(1).max(240)
24755
+ alt: z111.string().trim().min(1).max(240)
24534
24756
  }).strict();
24535
24757
  var McpMediaPresentationSchema = PresentationImageSchema;
24536
- var GalleryImageSchema = z109.object({
24758
+ var GalleryImageSchema = z111.object({
24537
24759
  url: ProductMakerPreviewUrlSchema,
24538
- alt: z109.string().trim().min(1).max(240)
24760
+ alt: z111.string().trim().min(1).max(240)
24539
24761
  });
24540
24762
  var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
24541
24763
  async function imageBlocks(image, transport) {
@@ -24592,12 +24814,12 @@ async function buildMcpMediaPresentationContent(rawPresentation, transport = "ht
24592
24814
  ];
24593
24815
  }
24594
24816
  __name(buildMcpMediaPresentationContent, "buildMcpMediaPresentationContent");
24595
- var OwnedImagePreviewSchema = z109.object({
24817
+ var OwnedImagePreviewSchema = z111.object({
24596
24818
  url: HttpsPresentationUrlSchema.refine((value) => {
24597
24819
  const url = new URL(value);
24598
24820
  return !url.username && !url.password && !isPrivateHost(url.hostname);
24599
24821
  }, "Preview URL must be public HTTPS without credentials"),
24600
- alt: z109.string().trim().min(1).max(240)
24822
+ alt: z111.string().trim().min(1).max(240)
24601
24823
  });
24602
24824
  async function buildMcpImagePreviewContent(rawPreview, transport = "http") {
24603
24825
  const preview2 = OwnedImagePreviewSchema.safeParse(rawPreview);
@@ -24680,7 +24902,7 @@ async function buildMcpImageGalleryContent(rawItems, transport = "http") {
24680
24902
  __name(buildMcpImageGalleryContent, "buildMcpImageGalleryContent");
24681
24903
 
24682
24904
  // src/tools/animated-video.ts
24683
- import { z as z110 } from "zod";
24905
+ import { z as z112 } from "zod";
24684
24906
 
24685
24907
  // src/tools/paid-confirmation.ts
24686
24908
  function describeMarketStudyChoice(enabled) {
@@ -24930,27 +25152,27 @@ function hookVariantsLabel(count) {
24930
25152
  return count === 1 ? "1 versi\xF3n del gancho" : `${count} versiones del gancho`;
24931
25153
  }
24932
25154
  __name(hookVariantsLabel, "hookVariantsLabel");
24933
- var DurationInput = z110.union(MOTION_GRAPHICS_DURATIONS.map((d) => z110.literal(d)));
24934
- var CreateAnimatedVideoInput = z110.object({
24935
- action: z110.enum([
25155
+ var DurationInput = z112.union(MOTION_GRAPHICS_DURATIONS.map((d) => z112.literal(d)));
25156
+ var CreateAnimatedVideoInput = z112.object({
25157
+ action: z112.enum([
24936
25158
  "prepare",
24937
25159
  "status",
24938
25160
  "cancel",
24939
25161
  "generate"
24940
25162
  ]).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."),
24941
- websiteCaptureId: z110.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
24942
- generationRequestId: z110.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."),
24943
- confirmed: z110.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."),
25163
+ websiteCaptureId: z112.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
25164
+ generationRequestId: z112.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."),
25165
+ confirmed: z112.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."),
24944
25166
  // Plain text, not `.url()`: users type «cal.com», and the web accepts it.
24945
25167
  // normalizeWebAddress (shared with the web) adds https:// and refuses
24946
25168
  // anything that is not a public http(s) address.
24947
- landingUrl: z110.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."),
25169
+ landingUrl: z112.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."),
24948
25170
  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.'),
24949
25171
  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.`),
24950
25172
  language: MotionGraphicsLanguageSchema.optional().describe('Idioma de los textos del video: "es", "en" o "pt".'),
24951
- notes: z110.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)."),
25173
+ notes: z112.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)."),
24952
25174
  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.`),
24953
- music: z110.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.")
25175
+ music: z112.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.")
24954
25176
  }).strict();
24955
25177
  function captureNextAction(capture) {
24956
25178
  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.";
@@ -24983,43 +25205,43 @@ var FORMAT_LABELS = {
24983
25205
  square: "cuadrado 1:1",
24984
25206
  horizontal: "horizontal 16:9"
24985
25207
  };
24986
- var AnimatedVideoResultSchema = z110.object({
24987
- status: z110.enum([
25208
+ var AnimatedVideoResultSchema = z112.object({
25209
+ status: z112.enum([
24988
25210
  "pending",
24989
25211
  "done",
24990
25212
  "error"
24991
25213
  ]),
24992
- serviceMode: z110.literal("motion_graphics"),
24993
- finalMp4Url: z110.string().optional(),
24994
- error: z110.string().optional(),
24995
- motionGraphics: z110.object({
25214
+ serviceMode: z112.literal("motion_graphics"),
25215
+ finalMp4Url: z112.string().optional(),
25216
+ error: z112.string().optional(),
25217
+ motionGraphics: z112.object({
24996
25218
  stage: MotionGraphicsStageSchema,
24997
25219
  format: MotionGraphicsFormatSchema,
24998
- durationSec: z110.number(),
24999
- width: z110.number().optional(),
25000
- height: z110.number().optional(),
25220
+ durationSec: z112.number(),
25221
+ width: z112.number().optional(),
25222
+ height: z112.number().optional(),
25001
25223
  language: MotionGraphicsLanguageSchema.optional(),
25002
- queuedAt: z110.string().optional(),
25003
- jobsAhead: z110.number().int().nonnegative().optional(),
25004
- stageStartedAt: z110.string().optional(),
25005
- renderProgress: z110.number().optional(),
25224
+ queuedAt: z112.string().optional(),
25225
+ jobsAhead: z112.number().int().nonnegative().optional(),
25226
+ stageStartedAt: z112.string().optional(),
25227
+ renderProgress: z112.number().optional(),
25006
25228
  // AI clip fields (absent on a video paid before clips, or from an API
25007
25229
  // that predates them). Lenient: an unreadable value is dropped
25008
25230
  // instead of hiding the status.
25009
- clipCount: z110.number().int().nonnegative().optional().catch(void 0),
25010
- clipsUsed: z110.number().int().nonnegative().optional().catch(void 0),
25011
- clipPriceCents: z110.number().finite().nonnegative().optional().catch(void 0),
25012
- clipsRefunded: z110.number().int().nonnegative().optional().catch(void 0),
25231
+ clipCount: z112.number().int().nonnegative().optional().catch(void 0),
25232
+ clipsUsed: z112.number().int().nonnegative().optional().catch(void 0),
25233
+ clipPriceCents: z112.number().finite().nonnegative().optional().catch(void 0),
25234
+ clipsRefunded: z112.number().int().nonnegative().optional().catch(void 0),
25013
25235
  // Hook versions (absent from an API or a video before them): the
25014
25236
  // count ordered and, once done, the signed URLs of the EXTRA versions
25015
25237
  // (hook 2, hook 3); `finalMp4Url` is hook 1.
25016
- hookVariants: z110.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
25017
- variantUrls: z110.array(z110.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
25238
+ hookVariants: z112.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
25239
+ variantUrls: z112.array(z112.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
25018
25240
  // Extra hook versions given back, as the task recorded it once the
25019
25241
  // refunds landed (absent until then, and from an API before it).
25020
- variantsRefunded: z110.number().int().nonnegative().optional().catch(void 0),
25021
- activity: z110.array(MotionGraphicsActivitySchema).optional().catch(void 0),
25022
- previewUrl: z110.string().optional()
25242
+ variantsRefunded: z112.number().int().nonnegative().optional().catch(void 0),
25243
+ activity: z112.array(MotionGraphicsActivitySchema).optional().catch(void 0),
25244
+ previewUrl: z112.string().optional()
25023
25245
  }).passthrough()
25024
25246
  }).passthrough();
25025
25247
  function parseAnimatedVideoResult(value) {
@@ -25275,10 +25497,10 @@ function registerAnimatedVideoTools(server, api) {
25275
25497
  __name(registerAnimatedVideoTools, "registerAnimatedVideoTools");
25276
25498
 
25277
25499
  // src/tools/winning-product-image.ts
25278
- import { z as z111 } from "zod";
25279
- var WinnerReferenceInput = z111.object({
25280
- runId: z111.string().uuid(),
25281
- candidateSourceId: z111.string().trim().min(1).max(160)
25500
+ import { z as z113 } from "zod";
25501
+ var WinnerReferenceInput = z113.object({
25502
+ runId: z113.string().uuid(),
25503
+ candidateSourceId: z113.string().trim().min(1).max(160)
25282
25504
  }).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
25283
25505
  async function resolveWinnerImages(api, winnerReference, images) {
25284
25506
  if (!winnerReference) return images;
@@ -25315,62 +25537,62 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
25315
25537
  var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
25316
25538
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
25317
25539
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
25318
- var CreateProductTaskInput = z112.object({
25540
+ var CreateProductTaskInput = z114.object({
25319
25541
  images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
25320
25542
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
25321
- projectId: z112.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
25322
- productUrl: z112.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."),
25543
+ projectId: z114.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
25544
+ productUrl: z114.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."),
25323
25545
  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.'),
25324
25546
  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.'),
25325
- price: z112.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.'),
25326
- compareAtPrice: z112.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".'),
25327
- offer: z112.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.'),
25328
- paymentMethods: z112.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.'),
25329
- productContext: z112.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."),
25330
- productLabel: z112.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.'),
25547
+ price: z114.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.'),
25548
+ compareAtPrice: z114.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".'),
25549
+ offer: z114.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.'),
25550
+ paymentMethods: z114.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.'),
25551
+ productContext: z114.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."),
25552
+ productLabel: z114.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.'),
25331
25553
  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.'),
25332
25554
  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.'),
25333
- durationSeconds: z112.union([
25334
- z112.literal(15),
25335
- z112.literal(30)
25555
+ durationSeconds: z114.union([
25556
+ z114.literal(15),
25557
+ z114.literal(30)
25336
25558
  ]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
25337
- pauseForAngleReview: z112.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."),
25338
- aiDecidesAll: z112.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."),
25559
+ pauseForAngleReview: z114.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."),
25560
+ aiDecidesAll: z114.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."),
25339
25561
  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.'),
25340
25562
  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.'),
25341
25563
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
25342
25564
  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).'),
25343
- videoAngleCount: z112.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."),
25565
+ videoAngleCount: z114.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."),
25344
25566
  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.'),
25345
- outputs: z112.array(z112.enum([
25567
+ outputs: z114.array(z114.enum([
25346
25568
  "landing",
25347
25569
  "video",
25348
25570
  "image"
25349
25571
  ])).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}`),
25350
- includeInitialLandingGif: z112.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."),
25351
- competitorScanEnabled: z112.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."),
25572
+ includeInitialLandingGif: z114.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."),
25573
+ competitorScanEnabled: z114.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."),
25352
25574
  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.'),
25353
- replicateWinnerWhenFound: z112.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."),
25354
- brandId: z112.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."),
25355
- actorId: z112.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."),
25575
+ replicateWinnerWhenFound: z114.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."),
25576
+ brandId: z114.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."),
25577
+ actorId: z114.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."),
25356
25578
  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.'),
25357
- creativeDirection: z112.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.'),
25358
- headline: z112.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."),
25359
- subheadline: z112.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."),
25579
+ creativeDirection: z114.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.'),
25580
+ headline: z114.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."),
25581
+ subheadline: z114.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."),
25360
25582
  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".'),
25361
25583
  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".')
25362
25584
  }).strict();
25363
- var CreateServiceVideoInput = z112.object({
25364
- landingUrl: z112.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
25365
- additionalContext: z112.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
25585
+ var CreateServiceVideoInput = z114.object({
25586
+ landingUrl: z114.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
25587
+ additionalContext: z114.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
25366
25588
  language: Lang.describe("Idioma del video: es, en o pt."),
25367
- voiceId: z112.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.'),
25368
- brandId: z112.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
25369
- reviewMode: z112.enum([
25589
+ voiceId: z114.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.'),
25590
+ brandId: z114.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
25591
+ reviewMode: z114.enum([
25370
25592
  "automatic",
25371
25593
  "guided"
25372
25594
  ]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
25373
- videoPreset: z112.enum([
25595
+ videoPreset: z114.enum([
25374
25596
  "auto",
25375
25597
  "ugc_dynamic",
25376
25598
  "ugc_how_to",
@@ -25380,128 +25602,128 @@ var CreateServiceVideoInput = z112.object({
25380
25602
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
25381
25603
  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.')
25382
25604
  }).strict();
25383
- var GetTaskStatusInput = z112.object({
25384
- taskId: z112.string().min(1),
25385
- waitSeconds: z112.number().int().min(0).max(120).optional()
25605
+ var GetTaskStatusInput = z114.object({
25606
+ taskId: z114.string().min(1),
25607
+ waitSeconds: z114.number().int().min(0).max(120).optional()
25386
25608
  });
25387
- var ListTasksInput = z112.object({
25388
- limit: z112.number().int().min(1).max(50).optional(),
25389
- offset: z112.number().int().min(0).optional(),
25390
- search: z112.string().optional()
25609
+ var ListTasksInput = z114.object({
25610
+ limit: z114.number().int().min(1).max(50).optional(),
25611
+ offset: z114.number().int().min(0).optional(),
25612
+ search: z114.string().optional()
25391
25613
  });
25392
25614
  var MCP_REVIEW_LIST_FIELD_MAX = IMAGE_WIZARD_LIST_FIELD_MAX;
25393
25615
  var MCP_REVIEW_FEATURE_ITEM_MAX = IMAGE_FEATURE_ITEM_MAX;
25394
- var EditTaskDraftInput = z112.object({
25395
- taskId: z112.string().min(1),
25396
- angleIndex: z112.number().int().min(0),
25397
- angle: z112.object({
25398
- angle: z112.string().min(1).max(480),
25399
- buyerPersona: z112.string().min(1).max(360),
25400
- actor: z112.string().min(1).max(360).optional(),
25401
- actorId: z112.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."),
25402
- gender: z112.enum([
25616
+ var EditTaskDraftInput = z114.object({
25617
+ taskId: z114.string().min(1),
25618
+ angleIndex: z114.number().int().min(0),
25619
+ angle: z114.object({
25620
+ angle: z114.string().min(1).max(480),
25621
+ buyerPersona: z114.string().min(1).max(360),
25622
+ actor: z114.string().min(1).max(360).optional(),
25623
+ actorId: z114.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."),
25624
+ gender: z114.enum([
25403
25625
  "female",
25404
25626
  "male"
25405
25627
  ]).optional(),
25406
- scriptNotes: z112.string().max(2e3).optional()
25628
+ scriptNotes: z114.string().max(2e3).optional()
25407
25629
  })
25408
25630
  });
25409
- var PendingActionPayload = z112.discriminatedUnion("kind", [
25410
- z112.object({
25411
- kind: z112.literal("product_reference_set_approval"),
25631
+ var PendingActionPayload = z114.discriminatedUnion("kind", [
25632
+ z114.object({
25633
+ kind: z114.literal("product_reference_set_approval"),
25412
25634
  scope: ProductReferenceScopeEnum.optional(),
25413
- scopeKey: z112.string().min(1).max(120).optional(),
25414
- scopeSnapshotId: z112.string().uuid().optional(),
25415
- expectedScopeHash: z112.string().min(1).max(128).optional(),
25635
+ scopeKey: z114.string().min(1).max(120).optional(),
25636
+ scopeSnapshotId: z114.string().uuid().optional(),
25637
+ expectedScopeHash: z114.string().min(1).max(128).optional(),
25416
25638
  decision: ProductReferenceResolutionDecisionEnum,
25417
25639
  reason: ProductReferenceRejectionReasonEnum.optional(),
25418
- affectedRefKeys: z112.array(z112.string().min(1).max(200)).min(1).optional(),
25419
- affectedPhotoNumbers: z112.array(z112.number().int().positive()).min(1).optional(),
25420
- recoveryAction: z112.enum([
25640
+ affectedRefKeys: z114.array(z114.string().min(1).max(200)).min(1).optional(),
25641
+ affectedPhotoNumbers: z114.array(z114.number().int().positive()).min(1).optional(),
25642
+ recoveryAction: z114.enum([
25421
25643
  "remove",
25422
25644
  "replace",
25423
25645
  "upload",
25424
25646
  "return_to_selection"
25425
25647
  ]).optional()
25426
25648
  }),
25427
- z112.object({
25428
- kind: z112.literal("product_reference_confirmation"),
25429
- selectedPhotoNumbers: z112.array(z112.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."),
25649
+ z114.object({
25650
+ kind: z114.literal("product_reference_confirmation"),
25651
+ selectedPhotoNumbers: z114.array(z114.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."),
25430
25652
  userChoice: ProductReferenceUserChoiceEnum.optional(),
25431
- confirmedProductNames: z112.array(z112.string().min(1).max(120)).min(2).max(8).optional(),
25653
+ confirmedProductNames: z114.array(z114.string().min(1).max(120)).min(2).max(8).optional(),
25432
25654
  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."),
25433
25655
  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."),
25434
- useMultiSceneShowcase: z112.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
25656
+ useMultiSceneShowcase: z114.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
25435
25657
  }),
25436
- z112.object({
25437
- kind: z112.literal("angle_review_approval"),
25658
+ z114.object({
25659
+ kind: z114.literal("angle_review_approval"),
25438
25660
  // All edits are optional — empty action body just approves the
25439
25661
  // backend-generated draft as-is. Field shapes mirror the angle-review
25440
25662
  // request contracts in @packages/types/wizard.ts; the handler routes to
25441
25663
  // the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
25442
- customAngle: z112.string().min(1).max(480).optional(),
25664
+ customAngle: z114.string().min(1).max(480).optional(),
25443
25665
  // Keep the shared MCP action within the strictest downstream contract:
25444
25666
  // autopilot/image resume endpoints cap these fields at 1500 characters.
25445
- painPoints: z112.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
25446
- benefits: z112.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
25667
+ painPoints: z114.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
25668
+ benefits: z114.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
25447
25669
  // Same policy as the two fields above: the strictest downstream contract
25448
25670
  // wins. The image endpoint caps each feature at 240 while landing/video
25449
25671
  // accept 300, and this single action routes to whichever the task is — so
25450
25672
  // accepting 300 here turns a 250-character feature on an image task into
25451
25673
  // an opaque HTTP 400 after the model already believed it had been saved.
25452
- features: z112.array(z112.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
25453
- buyerPersona: z112.string().min(1).max(360).optional(),
25674
+ features: z114.array(z114.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
25675
+ buyerPersona: z114.string().min(1).max(360).optional(),
25454
25676
  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.'),
25455
- actor: z112.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."),
25456
- actorId: z112.string().max(120).nullable().optional(),
25457
- creativeDirection: z112.string().max(2e3).optional(),
25458
- selectedAngleNumbers: z112.array(z112.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."),
25459
- angleEdits: z112.array(z112.object({
25460
- angleNumber: z112.number().int().positive(),
25461
- narrativeSelection: z112.enum([
25677
+ actor: z114.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."),
25678
+ actorId: z114.string().max(120).nullable().optional(),
25679
+ creativeDirection: z114.string().max(2e3).optional(),
25680
+ selectedAngleNumbers: z114.array(z114.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."),
25681
+ angleEdits: z114.array(z114.object({
25682
+ angleNumber: z114.number().int().positive(),
25683
+ narrativeSelection: z114.enum([
25462
25684
  "market",
25463
25685
  "guided"
25464
25686
  ]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
25465
- angle: z112.string().min(1).max(480).optional(),
25466
- buyerPersona: z112.string().min(1).max(360).optional(),
25687
+ angle: z114.string().min(1).max(480).optional(),
25688
+ buyerPersona: z114.string().min(1).max(360).optional(),
25467
25689
  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.'),
25468
- actor: z112.string().min(1).max(360).optional(),
25469
- actorId: z112.string().max(120).nullable().optional(),
25470
- creativeDirection: z112.string().max(2e3).optional()
25690
+ actor: z114.string().min(1).max(360).optional(),
25691
+ actorId: z114.string().max(120).nullable().optional(),
25692
+ creativeDirection: z114.string().max(2e3).optional()
25471
25693
  }).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)."),
25472
- gapDurationSeconds: z112.union([
25473
- z112.literal(15),
25474
- z112.literal(30)
25694
+ gapDurationSeconds: z114.union([
25695
+ z114.literal(15),
25696
+ z114.literal(30)
25475
25697
  ]).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.")
25476
25698
  }),
25477
- z112.object({
25478
- kind: z112.literal("service_angle_approval"),
25479
- angleId: z112.string().uuid().optional(),
25480
- angleNumber: z112.number().int().positive().optional(),
25481
- content: z112.string().min(1).max(480).optional(),
25482
- creativeDirection: z112.string().min(1).max(1500).optional(),
25483
- actor: z112.string().min(1).max(360).optional()
25699
+ z114.object({
25700
+ kind: z114.literal("service_angle_approval"),
25701
+ angleId: z114.string().uuid().optional(),
25702
+ angleNumber: z114.number().int().positive().optional(),
25703
+ content: z114.string().min(1).max(480).optional(),
25704
+ creativeDirection: z114.string().min(1).max(1500).optional(),
25705
+ actor: z114.string().min(1).max(360).optional()
25484
25706
  }),
25485
- z112.object({
25486
- kind: z112.literal("service_script_approval"),
25487
- voiceovers: z112.record(z112.string(), z112.string().min(1).max(600)).optional(),
25488
- visualDirections: z112.record(z112.string(), z112.string().min(1).max(1200)).optional(),
25489
- voiceoversByScene: z112.record(z112.string(), z112.string().min(1).max(600)).optional(),
25490
- visualDirectionsByScene: z112.record(z112.string(), z112.string().min(1).max(1200)).optional()
25707
+ z114.object({
25708
+ kind: z114.literal("service_script_approval"),
25709
+ voiceovers: z114.record(z114.string(), z114.string().min(1).max(600)).optional(),
25710
+ visualDirections: z114.record(z114.string(), z114.string().min(1).max(1200)).optional(),
25711
+ voiceoversByScene: z114.record(z114.string(), z114.string().min(1).max(600)).optional(),
25712
+ visualDirectionsByScene: z114.record(z114.string(), z114.string().min(1).max(1200)).optional()
25491
25713
  })
25492
25714
  ]);
25493
- var ResolvePendingActionInput = z112.object({
25494
- taskId: z112.string().min(1),
25715
+ var ResolvePendingActionInput = z114.object({
25716
+ taskId: z114.string().min(1),
25495
25717
  action: PendingActionPayload
25496
25718
  }).strict();
25497
25719
  function resolveVariantConfirmVideoTier(action) {
25498
25720
  return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
25499
25721
  }
25500
25722
  __name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
25501
- var StatusForResolveSchema = z112.object({
25723
+ var StatusForResolveSchema = z114.object({
25502
25724
  // Metadata used to select the backend resume contract. Older API responses
25503
25725
  // may omit these fields, so the resolver keeps the generic fallback.
25504
- kind: z112.enum([
25726
+ kind: z114.enum([
25505
25727
  "autopilot",
25506
25728
  "video",
25507
25729
  "image",
@@ -25509,18 +25731,18 @@ var StatusForResolveSchema = z112.object({
25509
25731
  "mix",
25510
25732
  "service"
25511
25733
  ]).optional(),
25512
- selectedOutputs: z112.array(z112.enum([
25734
+ selectedOutputs: z114.array(z114.enum([
25513
25735
  "landing",
25514
25736
  "video",
25515
25737
  "image"
25516
25738
  ])).optional(),
25517
- videoAngleCount: z112.number().int().min(1).max(3).optional(),
25518
- ugcFormat: z112.enum([
25739
+ videoAngleCount: z114.number().int().min(1).max(3).optional(),
25740
+ ugcFormat: z114.enum([
25519
25741
  "single_8s",
25520
25742
  "single_15s",
25521
25743
  "double_30s"
25522
25744
  ]).optional(),
25523
- videoStyle: z112.enum([
25745
+ videoStyle: z114.enum([
25524
25746
  "ugc",
25525
25747
  "cartoon_3d",
25526
25748
  "product_only",
@@ -25530,13 +25752,13 @@ var StatusForResolveSchema = z112.object({
25530
25752
  videoQuality: VideoQualityEnum.optional(),
25531
25753
  videoRouteId: VideoRouteIdEnum.optional(),
25532
25754
  videoModel: TaskVideoModelEnum.optional(),
25533
- videoTier: z112.enum([
25755
+ videoTier: z114.enum([
25534
25756
  "legacy",
25535
25757
  "standard",
25536
25758
  "pro",
25537
25759
  "single_call"
25538
25760
  ]).optional(),
25539
- videoResolution: z112.enum([
25761
+ videoResolution: z114.enum([
25540
25762
  "480p",
25541
25763
  "720p"
25542
25764
  ]).optional(),
@@ -25544,60 +25766,60 @@ var StatusForResolveSchema = z112.object({
25544
25766
  // A task created before a narrative was blocked/hidden must still parse,
25545
25767
  // or resolve_pending_action could never approve it.
25546
25768
  narrativeStyle: NarrativeStyle.optional(),
25547
- pauseForVideoScriptReview: z112.boolean().optional(),
25548
- pendingUserAction: z112.object({
25549
- kind: z112.string(),
25550
- candidateGrouping: z112.string().optional(),
25551
- selectedImageUrls: z112.array(z112.string()).optional(),
25552
- proposedProductNames: z112.array(z112.string()).optional(),
25769
+ pauseForVideoScriptReview: z114.boolean().optional(),
25770
+ pendingUserAction: z114.object({
25771
+ kind: z114.string(),
25772
+ candidateGrouping: z114.string().optional(),
25773
+ selectedImageUrls: z114.array(z114.string()).optional(),
25774
+ proposedProductNames: z114.array(z114.string()).optional(),
25553
25775
  // Adaptive reference questions are server-owned. Echo only the evidence
25554
25776
  // identity and the choices shown by the current snapshot; never accept a
25555
25777
  // client-supplied reference set as authorization.
25556
- options: z112.array(ProductReferenceUserChoiceEnum).max(4).optional(),
25557
- mode: z112.enum([
25778
+ options: z114.array(ProductReferenceUserChoiceEnum).max(4).optional(),
25779
+ mode: z114.enum([
25558
25780
  "question",
25559
25781
  "visual_recovery"
25560
25782
  ]).optional(),
25561
25783
  /** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
25562
- canKeepSelection: z112.boolean().optional(),
25563
- decisionKey: z112.string().optional(),
25564
- questionOrdinal: z112.number().int().min(1).max(5).optional(),
25565
- questionCeiling: z112.union([
25566
- z112.literal(3),
25567
- z112.literal(5)
25784
+ canKeepSelection: z114.boolean().optional(),
25785
+ decisionKey: z114.string().optional(),
25786
+ questionOrdinal: z114.number().int().min(1).max(5).optional(),
25787
+ questionCeiling: z114.union([
25788
+ z114.literal(3),
25789
+ z114.literal(5)
25568
25790
  ]).optional(),
25569
- referenceEvidenceVersion: z112.number().int().positive().optional(),
25570
- expectedEvidenceHash: z112.string().optional(),
25571
- question: z112.object({
25572
- prompt: z112.string().min(1).max(240),
25573
- helpText: z112.string().min(1).max(300).optional(),
25574
- options: z112.array(z112.object({
25791
+ referenceEvidenceVersion: z114.number().int().positive().optional(),
25792
+ expectedEvidenceHash: z114.string().optional(),
25793
+ question: z114.object({
25794
+ prompt: z114.string().min(1).max(240),
25795
+ helpText: z114.string().min(1).max(300).optional(),
25796
+ options: z114.array(z114.object({
25575
25797
  value: ProductReferenceUserChoiceEnum,
25576
- label: z112.string().min(1).max(120),
25577
- description: z112.string().min(1).max(240).optional()
25798
+ label: z114.string().min(1).max(120),
25799
+ description: z114.string().min(1).max(240).optional()
25578
25800
  })).min(2).max(4)
25579
25801
  }).optional(),
25580
25802
  scope: ProductReferenceScopeEnum.optional(),
25581
- scopeKey: z112.string().optional(),
25582
- scopeSnapshotId: z112.string().uuid().optional(),
25583
- scopeHash: z112.string().optional(),
25584
- baseReferenceSetHash: z112.string().optional(),
25585
- phase: z112.enum([
25803
+ scopeKey: z114.string().optional(),
25804
+ scopeSnapshotId: z114.string().uuid().optional(),
25805
+ scopeHash: z114.string().optional(),
25806
+ baseReferenceSetHash: z114.string().optional(),
25807
+ phase: z114.enum([
25586
25808
  "preparation",
25587
25809
  "final"
25588
25810
  ]).optional(),
25589
- selectedRefKeys: z112.array(z112.string().min(1).max(200)).optional(),
25590
- allowedDecisions: z112.array(ProductReferenceResolutionDecisionEnum).optional(),
25591
- previews: z112.array(z112.object({
25592
- refKey: z112.string().min(1).max(200)
25811
+ selectedRefKeys: z114.array(z114.string().min(1).max(200)).optional(),
25812
+ allowedDecisions: z114.array(ProductReferenceResolutionDecisionEnum).optional(),
25813
+ previews: z114.array(z114.object({
25814
+ refKey: z114.string().min(1).max(200)
25593
25815
  }).passthrough()).optional(),
25594
- customAngleDraft: z112.string().optional(),
25595
- painPointsDraft: z112.string().optional(),
25596
- benefitsDraft: z112.string().optional(),
25597
- featuresDraft: z112.array(z112.string()).optional(),
25598
- angleOptions: z112.array(z112.object({
25599
- index: z112.number().int().nonnegative(),
25600
- angle: z112.string().min(1)
25816
+ customAngleDraft: z114.string().optional(),
25817
+ painPointsDraft: z114.string().optional(),
25818
+ benefitsDraft: z114.string().optional(),
25819
+ featuresDraft: z114.array(z114.string()).optional(),
25820
+ angleOptions: z114.array(z114.object({
25821
+ index: z114.number().int().nonnegative(),
25822
+ angle: z114.string().min(1)
25601
25823
  }).passthrough()).min(1).max(5).optional(),
25602
25824
  // Recommendation consumed only when the caller explicitly sends
25603
25825
  // gapDurationSeconds: 30 in the angle approval action.
@@ -25607,17 +25829,17 @@ var StatusForResolveSchema = z112.object({
25607
25829
  // keys. `actorId` (the saved custom actor the picker stored) was silently
25608
25830
  // dropped here, so the approval handler below could not echo it back on the
25609
25831
  // PATCH — the selection looked accepted and reached no render.
25610
- angles: z112.array(z112.object({
25611
- id: z112.string().uuid(),
25612
- content: z112.string(),
25613
- creativeDirection: z112.string(),
25614
- actor: z112.string(),
25615
- actorId: z112.string().nullable().optional()
25832
+ angles: z114.array(z114.object({
25833
+ id: z114.string().uuid(),
25834
+ content: z114.string(),
25835
+ creativeDirection: z114.string(),
25836
+ actor: z114.string(),
25837
+ actorId: z114.string().nullable().optional()
25616
25838
  }).passthrough()).optional(),
25617
- panels: z112.array(z112.object({
25618
- beatId: z112.string(),
25619
- voiceover: z112.string(),
25620
- visualDirection: z112.string()
25839
+ panels: z114.array(z114.object({
25840
+ beatId: z114.string(),
25841
+ voiceover: z114.string(),
25842
+ visualDirection: z114.string()
25621
25843
  }).passthrough()).optional()
25622
25844
  }).optional()
25623
25845
  }).passthrough();
@@ -25969,8 +26191,8 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
25969
26191
  server.registerTool("verify_landing_commerce", {
25970
26192
  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.",
25971
26193
  inputSchema: {
25972
- taskId: z112.string().uuid(),
25973
- editId: z112.string().uuid()
26194
+ taskId: z114.string().uuid(),
26195
+ editId: z114.string().uuid()
25974
26196
  },
25975
26197
  annotations: OVERWRITES_EXTERNAL
25976
26198
  }, async (input) => {
@@ -26616,25 +26838,25 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
26616
26838
  __name(registerTaskTools, "registerTaskTools");
26617
26839
 
26618
26840
  // src/tools/brands.ts
26619
- import { z as z113 } from "zod";
26841
+ import { z as z115 } from "zod";
26620
26842
  var guidance2 = getProductMakerCapabilityModelGuidance("create_brand");
26621
26843
  var BRAND_START_REPLAY_WINDOW_MS = 15 * 60 * 1e3;
26622
26844
  var BRAND_NOTES_MAX_CHARS = 2e4;
26623
- var CreateBrandInput = z113.object({
26624
- action: z113.enum([
26845
+ var CreateBrandInput = z115.object({
26846
+ action: z115.enum([
26625
26847
  "start",
26626
26848
  "status",
26627
26849
  "list"
26628
26850
  ]).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."),
26629
- sourceUrl: z113.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."),
26630
- businessNotes: z113.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."),
26631
- language: z113.enum([
26851
+ sourceUrl: z115.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."),
26852
+ businessNotes: z115.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."),
26853
+ language: z115.enum([
26632
26854
  "es",
26633
26855
  "en",
26634
26856
  "pt"
26635
26857
  ]).optional().describe("Idioma de la conversaci\xF3n. Solo se usa si la p\xE1gina del negocio no deja claro su idioma."),
26636
- confirmed: z113.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
26637
- brandId: z113.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
26858
+ confirmed: z115.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
26859
+ brandId: z115.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
26638
26860
  }).strict();
26639
26861
  function normalizeBrandSourceUrl(raw) {
26640
26862
  const value = raw.trim();
@@ -26874,24 +27096,24 @@ __name(registerBrandTools, "registerBrandTools");
26874
27096
 
26875
27097
  // src/tools/service-landing.ts
26876
27098
  import { createHash as createHash3 } from "crypto";
26877
- import { z as z114 } from "zod";
27099
+ import { z as z116 } from "zod";
26878
27100
  var guidance3 = getProductMakerCapabilityModelGuidance("create_service_landing");
26879
27101
  var SERVICE_LANDING_KEY_NAMESPACE = "6f1d8c2a-3b4e-5f60-8a7b-9c0d1e2f3a4b";
26880
27102
  var SERVICE_LANDING_INFO_MAX_CHARS = 2e4;
26881
- var CreateServiceLandingInput = z114.object({
26882
- action: z114.enum([
27103
+ var CreateServiceLandingInput = z116.object({
27104
+ action: z116.enum([
26883
27105
  "prepare",
26884
27106
  "build",
26885
27107
  "status",
26886
27108
  "publish"
26887
27109
  ]).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."),
26888
- brandId: z114.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
26889
- servicePageId: z114.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
26890
- businessInfo: z114.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."),
26891
- confirmed: z114.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
26892
- maxCredits: z114.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."),
26893
- operationId: z114.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
26894
- slug: z114.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.")
27110
+ brandId: z116.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
27111
+ servicePageId: z116.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
27112
+ businessInfo: z116.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."),
27113
+ confirmed: z116.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
27114
+ maxCredits: z116.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."),
27115
+ operationId: z116.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
27116
+ slug: z116.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.")
26895
27117
  }).strict();
26896
27118
  var SERVICE_LANDING_MAX_BUILD_ATTEMPTS = 10;
26897
27119
  function serviceKey(...parts) {
@@ -27113,9 +27335,6 @@ function registerServiceLandingTools(server, api) {
27113
27335
  let operation2 = null;
27114
27336
  if (input.operationId) {
27115
27337
  operation2 = await api.getJson(`/v1/service-pages/operations/${encodeURIComponent(input.operationId)}`);
27116
- if (operation2.recoverable && (operation2.status === "failed" || operation2.status === "requires_reconciliation")) {
27117
- operation2 = await api.postJson(`${pagePath(input.servicePageId)}/operations/${encodeURIComponent(operation2.opId)}/recover`, {});
27118
- }
27119
27338
  if (operation2.status === "queued" || operation2.status === "running") {
27120
27339
  return asText({
27121
27340
  servicePageId: input.servicePageId,
@@ -27132,7 +27351,7 @@ function registerServiceLandingTools(server, api) {
27132
27351
  status: "in_review",
27133
27352
  // Unknown on purpose: the charge is exactly what is being
27134
27353
  // confirmed. Settlement only charges a completed step.
27135
- 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."
27354
+ 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."
27136
27355
  });
27137
27356
  }
27138
27357
  if (operation2.status !== "succeeded") {
@@ -27227,7 +27446,7 @@ function registerServiceLandingTools(server, api) {
27227
27446
  __name(registerServiceLandingTools, "registerServiceLandingTools");
27228
27447
 
27229
27448
  // src/tools/service-images.ts
27230
- import { z as z115 } from "zod";
27449
+ import { z as z117 } from "zod";
27231
27450
  var guidance4 = getProductMakerCapabilityModelGuidance("create_service_images");
27232
27451
  var SERVICE_IMAGE_FORMATS = [
27233
27452
  "4:5",
@@ -27240,23 +27459,23 @@ var LANGUAGE_TAGS = {
27240
27459
  en: "en-US",
27241
27460
  pt: "pt-BR"
27242
27461
  };
27243
- var CreateServiceImagesInput = z115.object({
27244
- brandId: z115.string().uuid().optional().describe("ID de la marca (de create_brand). Recomendado: da nombre, colores, tono y servicios. Nunca un taskId de producto."),
27245
- instruction: z115.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."),
27246
- delegateToAi: z115.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su marca."),
27247
- format: z115.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
27248
- count: z115.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
27249
- quality: z115.enum([
27462
+ var CreateServiceImagesInput = z117.object({
27463
+ brandId: z117.string().uuid().optional().describe("ID de la marca (de create_brand). Recomendado: da nombre, colores, tono y servicios. Nunca un taskId de producto."),
27464
+ instruction: z117.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."),
27465
+ delegateToAi: z117.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su marca."),
27466
+ format: z117.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
27467
+ count: z117.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
27468
+ quality: z117.enum([
27250
27469
  "standard",
27251
27470
  "high"
27252
27471
  ]).optional().describe('Calidad: "standard" (por defecto) o "high" (m\xE1s cara; no disponible en 4:5).'),
27253
- language: z115.enum([
27472
+ language: z117.enum([
27254
27473
  "es",
27255
27474
  "en",
27256
27475
  "pt"
27257
27476
  ]).optional().describe("Idioma de los textos de la imagen (por defecto es)."),
27258
- adCopy: z115.boolean().optional().describe("Opcional. true agrega textos para el anuncio (titular y descripci\xF3n). Por defecto false."),
27259
- confirmed: z115.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
27477
+ adCopy: z117.boolean().optional().describe("Opcional. true agrega textos para el anuncio (titular y descripci\xF3n). Por defecto false."),
27478
+ confirmed: z117.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
27260
27479
  }).strict();
27261
27480
  function serviceImageModel(quality) {
27262
27481
  return quality === "high" ? AD_CREATIVE_MODELS.PREMIUM : AD_CREATIVE_MODELS.STANDARD;
@@ -27367,7 +27586,7 @@ function registerServiceImageTools(server, api, options = {}) {
27367
27586
  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."
27368
27587
  });
27369
27588
  } catch (error) {
27370
- if (error instanceof z115.ZodError) throw invalidInputFromZod(error);
27589
+ if (error instanceof z117.ZodError) throw invalidInputFromZod(error);
27371
27590
  throw translateError(error);
27372
27591
  }
27373
27592
  });
@@ -27375,7 +27594,7 @@ function registerServiceImageTools(server, api, options = {}) {
27375
27594
  __name(registerServiceImageTools, "registerServiceImageTools");
27376
27595
 
27377
27596
  // src/tools/creatives.ts
27378
- import { z as z116 } from "zod";
27597
+ import { z as z118 } from "zod";
27379
27598
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
27380
27599
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
27381
27600
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
@@ -27386,72 +27605,72 @@ var CreativeRefs = {
27386
27605
  images: ImagesInput,
27387
27606
  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.'),
27388
27607
  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.'),
27389
- price: z116.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.'),
27390
- offer: z116.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.'),
27391
- compareAtPrice: z116.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
27392
- productContext: z116.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."),
27393
- productLabel: z116.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.'),
27394
- buyerPersona: z116.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.'),
27395
- isCombo: z116.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
27396
- competitorScanEnabled: z116.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."),
27397
- brandId: z116.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.")
27608
+ price: z118.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.'),
27609
+ offer: z118.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.'),
27610
+ compareAtPrice: z118.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
27611
+ productContext: z118.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."),
27612
+ productLabel: z118.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.'),
27613
+ buyerPersona: z118.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.'),
27614
+ isCombo: z118.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
27615
+ competitorScanEnabled: z118.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."),
27616
+ brandId: z118.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.")
27398
27617
  };
27399
- var VideoPresenter = z116.discriminatedUnion("mode", [
27400
- z116.object({
27401
- mode: z116.literal("none")
27618
+ var VideoPresenter = z118.discriminatedUnion("mode", [
27619
+ z118.object({
27620
+ mode: z118.literal("none")
27402
27621
  }).strict(),
27403
- z116.object({
27404
- mode: z116.literal("saved_actor"),
27405
- actorId: z116.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
27622
+ z118.object({
27623
+ mode: z118.literal("saved_actor"),
27624
+ actorId: z118.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
27406
27625
  }).strict(),
27407
- z116.object({
27408
- mode: z116.literal("described"),
27409
- description: z116.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
27626
+ z118.object({
27627
+ mode: z118.literal("described"),
27628
+ description: z118.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
27410
27629
  }).strict()
27411
27630
  ]);
27412
- var VideoCreativeSetup = z116.discriminatedUnion("mode", [
27413
- z116.object({
27414
- mode: z116.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
27631
+ var VideoCreativeSetup = z118.discriminatedUnion("mode", [
27632
+ z118.object({
27633
+ mode: z118.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
27415
27634
  }).strict(),
27416
- z116.object({
27417
- mode: z116.literal("guided"),
27635
+ z118.object({
27636
+ mode: z118.literal("guided"),
27418
27637
  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.'),
27419
- buyerPersona: z116.string().trim().min(1).max(360),
27638
+ buyerPersona: z118.string().trim().min(1).max(360),
27420
27639
  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.'),
27421
27640
  presenter: VideoPresenter,
27422
- creativeDirection: z116.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
27641
+ creativeDirection: z118.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
27423
27642
  }).strict()
27424
27643
  ]);
27425
- var VideoInput = z116.object({
27644
+ var VideoInput = z118.object({
27426
27645
  images: CreativeRefs.images.optional(),
27427
27646
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
27428
- title: z116.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
27429
- primaryAngle: z116.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".'),
27647
+ title: z118.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
27648
+ primaryAngle: z118.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".'),
27430
27649
  language: CreativeRefs.language,
27431
27650
  country: CreativeRefs.country,
27432
- aspectRatio: z116.enum([
27651
+ aspectRatio: z118.enum([
27433
27652
  "9:16",
27434
27653
  "16:9",
27435
27654
  "Auto"
27436
27655
  ]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
27437
27656
  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.'),
27438
- durationSeconds: z116.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."),
27439
- videoAngleCount: z116.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."),
27657
+ durationSeconds: z118.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."),
27658
+ videoAngleCount: z118.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."),
27440
27659
  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.'),
27441
27660
  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."),
27442
27661
  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.'),
27443
27662
  videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
27444
27663
  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.'),
27445
- features: z116.array(z116.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
27664
+ features: z118.array(z118.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
27446
27665
  price: CreativeRefs.price,
27447
27666
  offer: CreativeRefs.offer,
27448
27667
  productContext: CreativeRefs.productContext,
27449
27668
  productLabel: CreativeRefs.productLabel,
27450
- cta: z116.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.'),
27451
- scriptNotes: z116.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.'),
27669
+ cta: z118.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.'),
27670
+ scriptNotes: z118.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.'),
27452
27671
  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.'),
27453
27672
  competitorScanEnabled: CreativeRefs.competitorScanEnabled,
27454
- replicateWinnerWhenFound: z116.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."),
27673
+ replicateWinnerWhenFound: z118.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."),
27455
27674
  brandId: CreativeRefs.brandId
27456
27675
  }).strict();
27457
27676
  var FreeVideoQualityEnum = VideoQualityEnum;
@@ -27469,7 +27688,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
27469
27688
  length: 29
27470
27689
  }, (_, index) => index + 2)
27471
27690
  };
27472
- var FreeVideoModelIdEnum = z116.enum([
27691
+ var FreeVideoModelIdEnum = z118.enum([
27473
27692
  "grok-imagine-video-1-5-preview",
27474
27693
  "minimax-h3/reference-to-video",
27475
27694
  "wan/3-0-video",
@@ -27480,66 +27699,66 @@ var FREE_SELECTABLE_MODEL_IDS = [
27480
27699
  "minimax-h3/reference-to-video",
27481
27700
  "wan/3-0-video"
27482
27701
  ];
27483
- var FreeVideoInput = z116.object({
27702
+ var FreeVideoInput = z118.object({
27484
27703
  images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
27485
- rawPrompt: z116.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."),
27704
+ rawPrompt: z118.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."),
27486
27705
  language: CreativeRefs.language,
27487
27706
  quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
27488
27707
  // Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
27489
27708
  // parsed ONLY so the handler can reject it with a message naming its
27490
27709
  // replacement — dropping it silently would turn a caller's explicit
27491
27710
  // Pro++ pick into a quiet fallback to Wan.
27492
- freeProModel: z116.enum([
27711
+ freeProModel: z118.enum([
27493
27712
  "wan",
27494
27713
  "seedance"
27495
27714
  ]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
27496
27715
  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.'),
27497
- durationSeconds: z116.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."),
27716
+ durationSeconds: z118.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."),
27498
27717
  videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
27499
- generateAiMusic: z116.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.'),
27718
+ generateAiMusic: z118.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.'),
27500
27719
  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.'),
27501
- addSubtitles: z116.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
27502
- idempotencyKey: z116.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.")
27720
+ addSubtitles: z118.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
27721
+ idempotencyKey: z118.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.")
27503
27722
  }).strict();
27504
27723
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
27505
- var ImageCreativeSetup = z116.discriminatedUnion("mode", [
27506
- z116.object({
27507
- mode: z116.literal("automatic")
27724
+ var ImageCreativeSetup = z118.discriminatedUnion("mode", [
27725
+ z118.object({
27726
+ mode: z118.literal("automatic")
27508
27727
  }).strict(),
27509
- z116.object({
27510
- mode: z116.literal("guided"),
27511
- creativeArchetype: z116.union([
27728
+ z118.object({
27729
+ mode: z118.literal("guided"),
27730
+ creativeArchetype: z118.union([
27512
27731
  ImageCreativeArchetypeEnum,
27513
- z116.literal("ai_decides")
27732
+ z118.literal("ai_decides")
27514
27733
  ]),
27515
- visualTreatment: z116.union([
27734
+ visualTreatment: z118.union([
27516
27735
  ImageCreativeVisualTreatmentEnum,
27517
- z116.literal("ai_decides")
27736
+ z118.literal("ai_decides")
27518
27737
  ]),
27519
27738
  aspectRatio: ImageCreativeAspectRatioEnum,
27520
- nVariants: z116.union([
27521
- z116.literal(1),
27522
- z116.literal(2),
27523
- z116.literal(3),
27524
- z116.literal(4),
27525
- z116.literal(6)
27739
+ nVariants: z118.union([
27740
+ z118.literal(1),
27741
+ z118.literal(2),
27742
+ z118.literal(3),
27743
+ z118.literal(4),
27744
+ z118.literal(6)
27526
27745
  ]),
27527
- imageModel: z116.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.'),
27528
- styleMix: z116.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
27529
- generateAdCopy: z116.boolean(),
27530
- competitorScanEnabled: z116.boolean(),
27531
- productContext: z116.string().trim().min(1).max(3e3).nullable(),
27532
- creativeDirection: z116.string().trim().min(1).max(500).nullable(),
27533
- brandColors: z116.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.'),
27534
- headline: z116.string().trim().min(1).max(120).nullable(),
27535
- subheadline: z116.string().trim().min(1).max(160).nullable()
27746
+ imageModel: z118.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.'),
27747
+ styleMix: z118.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
27748
+ generateAdCopy: z118.boolean(),
27749
+ competitorScanEnabled: z118.boolean(),
27750
+ productContext: z118.string().trim().min(1).max(3e3).nullable(),
27751
+ creativeDirection: z118.string().trim().min(1).max(500).nullable(),
27752
+ brandColors: z118.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.'),
27753
+ headline: z118.string().trim().min(1).max(120).nullable(),
27754
+ subheadline: z118.string().trim().min(1).max(160).nullable()
27536
27755
  }).strict()
27537
27756
  ]).superRefine((setup, context) => {
27538
27757
  if (setup.mode !== "guided") return;
27539
27758
  const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
27540
27759
  if (needsStyleMix && setup.styleMix === null) {
27541
27760
  context.addIssue({
27542
- code: z116.ZodIssueCode.custom,
27761
+ code: z118.ZodIssueCode.custom,
27543
27762
  path: [
27544
27763
  "styleMix"
27545
27764
  ],
@@ -27548,7 +27767,7 @@ var ImageCreativeSetup = z116.discriminatedUnion("mode", [
27548
27767
  }
27549
27768
  if (!needsStyleMix && setup.styleMix !== null) {
27550
27769
  context.addIssue({
27551
- code: z116.ZodIssueCode.custom,
27770
+ code: z118.ZodIssueCode.custom,
27552
27771
  path: [
27553
27772
  "styleMix"
27554
27773
  ],
@@ -27557,7 +27776,7 @@ var ImageCreativeSetup = z116.discriminatedUnion("mode", [
27557
27776
  }
27558
27777
  if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
27559
27778
  context.addIssue({
27560
- code: z116.ZodIssueCode.custom,
27779
+ code: z118.ZodIssueCode.custom,
27561
27780
  path: [
27562
27781
  "aspectRatio"
27563
27782
  ],
@@ -27565,55 +27784,55 @@ var ImageCreativeSetup = z116.discriminatedUnion("mode", [
27565
27784
  });
27566
27785
  }
27567
27786
  });
27568
- var LandingCreativeSetup = z116.discriminatedUnion("mode", [
27569
- z116.object({
27570
- mode: z116.literal("automatic")
27787
+ var LandingCreativeSetup = z118.discriminatedUnion("mode", [
27788
+ z118.object({
27789
+ mode: z118.literal("automatic")
27571
27790
  }).strict(),
27572
- z116.object({
27573
- mode: z116.literal("guided"),
27791
+ z118.object({
27792
+ mode: z118.literal("guided"),
27574
27793
  landingStrategy: LandingStrategyEnum,
27575
27794
  landingImageFormat: LandingImageFormatEnum,
27576
- competitorScanEnabled: z116.boolean(),
27577
- paymentMethods: z116.string().trim().min(1).max(240).nullable(),
27578
- productContext: z116.string().trim().min(1).max(3e3).nullable(),
27579
- creativeDirection: z116.string().trim().min(1).max(500).nullable(),
27580
- headline: z116.string().trim().min(1).max(120).nullable(),
27581
- subheadline: z116.string().trim().min(1).max(160).nullable()
27795
+ competitorScanEnabled: z118.boolean(),
27796
+ paymentMethods: z118.string().trim().min(1).max(240).nullable(),
27797
+ productContext: z118.string().trim().min(1).max(3e3).nullable(),
27798
+ creativeDirection: z118.string().trim().min(1).max(500).nullable(),
27799
+ headline: z118.string().trim().min(1).max(120).nullable(),
27800
+ subheadline: z118.string().trim().min(1).max(160).nullable()
27582
27801
  }).strict()
27583
27802
  ]);
27584
- var ImageInput = z116.object({
27803
+ var ImageInput = z118.object({
27585
27804
  images: CreativeRefs.images.optional(),
27586
27805
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
27587
- productTitle: z116.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
27588
- primaryAngle: z116.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.'),
27806
+ productTitle: z118.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
27807
+ primaryAngle: z118.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.'),
27589
27808
  buyerPersona: CreativeRefs.buyerPersona,
27590
27809
  language: CreativeRefs.language,
27591
27810
  country: CreativeRefs.country,
27592
27811
  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."),
27593
27812
  imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
27594
- features: z116.array(z116.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
27813
+ features: z118.array(z118.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
27595
27814
  price: CreativeRefs.price,
27596
- omitPrice: z116.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."),
27815
+ omitPrice: z118.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."),
27597
27816
  compareAtPrice: CreativeRefs.compareAtPrice,
27598
27817
  offer: CreativeRefs.offer,
27599
27818
  productLabel: CreativeRefs.productLabel,
27600
27819
  isCombo: CreativeRefs.isCombo,
27601
27820
  brandId: CreativeRefs.brandId
27602
27821
  });
27603
- var EditImageCreativeInput = z116.object({
27604
- taskId: z116.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
27605
- variantIndex: z116.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
27606
- clientRequestId: z116.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."),
27607
- instruction: z116.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".')
27822
+ var EditImageCreativeInput = z118.object({
27823
+ taskId: z118.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
27824
+ variantIndex: z118.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
27825
+ clientRequestId: z118.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."),
27826
+ instruction: z118.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".')
27608
27827
  });
27609
- var LandingInput = z116.object({
27610
- includeInitialLandingGif: z116.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."),
27828
+ var LandingInput = z118.object({
27829
+ includeInitialLandingGif: z118.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."),
27611
27830
  images: CreativeRefs.images.optional(),
27612
27831
  winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
27613
27832
  language: CreativeRefs.language,
27614
27833
  country: CreativeRefs.country,
27615
27834
  creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
27616
- salesAngle: z116.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.'),
27835
+ salesAngle: z118.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.'),
27617
27836
  buyerPersona: CreativeRefs.buyerPersona,
27618
27837
  price: CreativeRefs.price,
27619
27838
  compareAtPrice: CreativeRefs.compareAtPrice,
@@ -27895,8 +28114,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
27895
28114
  server.registerTool("get_image_edit_status", {
27896
28115
  description: imageEditStatusGuidance.summary,
27897
28116
  inputSchema: {
27898
- taskId: z116.string().uuid(),
27899
- operationId: z116.string().uuid()
28117
+ taskId: z118.string().uuid(),
28118
+ operationId: z118.string().uuid()
27900
28119
  },
27901
28120
  annotations: READS_INTERNAL
27902
28121
  }, async (input) => {
@@ -27953,10 +28172,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
27953
28172
  __name(registerCreativeTools, "registerCreativeTools");
27954
28173
 
27955
28174
  // src/tools/creative-variants.ts
27956
- import { z as z117 } from "zod";
28175
+ import { z as z119 } from "zod";
27957
28176
  var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
27958
28177
  var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
27959
- var LandingSectionKeyEnum = z117.enum([
28178
+ var LandingSectionKeyEnum = z119.enum([
27960
28179
  "problem_hook",
27961
28180
  "problem_cost",
27962
28181
  "solution_mechanism",
@@ -27996,24 +28215,24 @@ var LandingSectionKeyEnum = z117.enum([
27996
28215
  "lifestyle_fit",
27997
28216
  "join_lifestyle"
27998
28217
  ]);
27999
- var CreativeVariantKindEnum = z117.enum([
28218
+ var CreativeVariantKindEnum = z119.enum([
28000
28219
  "video",
28001
28220
  "image",
28002
28221
  "landing"
28003
28222
  ]);
28004
- var EstimateCreativeVariantInputBase = z117.object({
28005
- sourceTaskId: z117.string().uuid().describe("ID de la tarea original completada."),
28223
+ var EstimateCreativeVariantInputBase = z119.object({
28224
+ sourceTaskId: z119.string().uuid().describe("ID de la tarea original completada."),
28006
28225
  kind: CreativeVariantKindEnum,
28007
28226
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
28008
28227
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
28009
- nVariants: z117.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
28228
+ nVariants: z119.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
28010
28229
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
28011
- instructions: z117.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.")
28230
+ instructions: z119.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.")
28012
28231
  }).strict();
28013
28232
  var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
28014
28233
  if (input.kind === "video" && input.nVariants !== void 0) {
28015
28234
  ctx.addIssue({
28016
- code: z117.ZodIssueCode.custom,
28235
+ code: z119.ZodIssueCode.custom,
28017
28236
  path: [
28018
28237
  "nVariants"
28019
28238
  ],
@@ -28023,7 +28242,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
28023
28242
  if (input.kind !== "video") {
28024
28243
  if (input.videoPreset !== void 0) {
28025
28244
  ctx.addIssue({
28026
- code: z117.ZodIssueCode.custom,
28245
+ code: z119.ZodIssueCode.custom,
28027
28246
  path: [
28028
28247
  "videoPreset"
28029
28248
  ],
@@ -28032,7 +28251,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
28032
28251
  }
28033
28252
  if (input.videoResolution !== void 0) {
28034
28253
  ctx.addIssue({
28035
- code: z117.ZodIssueCode.custom,
28254
+ code: z119.ZodIssueCode.custom,
28036
28255
  path: [
28037
28256
  "videoResolution"
28038
28257
  ],
@@ -28042,7 +28261,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
28042
28261
  }
28043
28262
  if (input.kind !== "image" && input.nVariants !== void 0) {
28044
28263
  ctx.addIssue({
28045
- code: z117.ZodIssueCode.custom,
28264
+ code: z119.ZodIssueCode.custom,
28046
28265
  path: [
28047
28266
  "nVariants"
28048
28267
  ],
@@ -28052,7 +28271,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
28052
28271
  if (input.kind !== "landing") {
28053
28272
  if (input.sectionKey !== void 0) {
28054
28273
  ctx.addIssue({
28055
- code: z117.ZodIssueCode.custom,
28274
+ code: z119.ZodIssueCode.custom,
28056
28275
  path: [
28057
28276
  "sectionKey"
28058
28277
  ],
@@ -28061,7 +28280,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
28061
28280
  }
28062
28281
  if (input.instructions !== void 0) {
28063
28282
  ctx.addIssue({
28064
- code: z117.ZodIssueCode.custom,
28283
+ code: z119.ZodIssueCode.custom,
28065
28284
  path: [
28066
28285
  "instructions"
28067
28286
  ],
@@ -28070,31 +28289,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
28070
28289
  }
28071
28290
  }
28072
28291
  });
28073
- var CreateCreativeVariantInputBase = z117.object({
28074
- sourceTaskId: z117.string().uuid().describe("ID de la tarea original completada."),
28292
+ var CreateCreativeVariantInputBase = z119.object({
28293
+ sourceTaskId: z119.string().uuid().describe("ID de la tarea original completada."),
28075
28294
  kind: CreativeVariantKindEnum,
28076
- confirm: z117.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
28077
- clientRequestId: z117.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."),
28078
- angle: z117.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
28079
- buyerPersona: z117.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
28080
- scriptNotes: z117.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
28081
- creativeDirection: z117.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
28295
+ confirm: z119.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
28296
+ clientRequestId: z119.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."),
28297
+ angle: z119.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
28298
+ buyerPersona: z119.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
28299
+ scriptNotes: z119.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
28300
+ creativeDirection: z119.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
28082
28301
  videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
28083
28302
  videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
28084
- generateAiMusic: z117.boolean().optional().describe("Opcional para video."),
28085
- nVariants: z117.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
28303
+ generateAiMusic: z119.boolean().optional().describe("Opcional para video."),
28304
+ nVariants: z119.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
28086
28305
  imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
28087
28306
  creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
28088
28307
  visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
28089
28308
  aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
28090
- styleMix: z117.boolean().optional().describe("Opcional para imagen."),
28309
+ styleMix: z119.boolean().optional().describe("Opcional para imagen."),
28091
28310
  sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
28092
- instructions: z117.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.")
28311
+ instructions: z119.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.")
28093
28312
  }).strict();
28094
28313
  var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
28095
28314
  if ((input.kind === "video" || input.kind === "image") && !input.angle) {
28096
28315
  ctx.addIssue({
28097
- code: z117.ZodIssueCode.custom,
28316
+ code: z119.ZodIssueCode.custom,
28098
28317
  path: [
28099
28318
  "angle"
28100
28319
  ],
@@ -28103,7 +28322,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
28103
28322
  }
28104
28323
  if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
28105
28324
  ctx.addIssue({
28106
- code: z117.ZodIssueCode.custom,
28325
+ code: z119.ZodIssueCode.custom,
28107
28326
  path: [
28108
28327
  "instructions"
28109
28328
  ],
@@ -28149,7 +28368,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
28149
28368
  for (const field of fieldsByKind[input.kind]) {
28150
28369
  if (input[field] !== void 0) {
28151
28370
  ctx.addIssue({
28152
- code: z117.ZodIssueCode.custom,
28371
+ code: z119.ZodIssueCode.custom,
28153
28372
  path: [
28154
28373
  field
28155
28374
  ],
@@ -28282,13 +28501,13 @@ function registerCreativeVariantTools(server, api) {
28282
28501
  __name(registerCreativeVariantTools, "registerCreativeVariantTools");
28283
28502
 
28284
28503
  // src/tools/script-review.ts
28285
- import { z as z118 } from "zod";
28504
+ import { z as z120 } from "zod";
28286
28505
  var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
28287
28506
  var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
28288
28507
  var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
28289
- var GetVideoScriptInput = z118.object({
28290
- taskId: z118.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
28291
- angleKey: z118.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.')
28508
+ var GetVideoScriptInput = z120.object({
28509
+ taskId: z120.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
28510
+ angleKey: z120.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.')
28292
28511
  }).strict();
28293
28512
  var ApproveVideoScriptInput = ApproveVideoScriptCapabilityRequest;
28294
28513
  var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
@@ -28371,7 +28590,7 @@ function registerScriptReviewTools(server, api) {
28371
28590
  __name(registerScriptReviewTools, "registerScriptReviewTools");
28372
28591
 
28373
28592
  // src/tools/connections.ts
28374
- import { z as z119 } from "zod";
28593
+ import { z as z121 } from "zod";
28375
28594
  var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
28376
28595
  var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
28377
28596
  var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
@@ -28380,7 +28599,7 @@ var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list
28380
28599
  function registerConnectionTools(server, api) {
28381
28600
  server.registerTool("list_shopify_shops", {
28382
28601
  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.",
28383
- inputSchema: z119.object({}).shape,
28602
+ inputSchema: z121.object({}).shape,
28384
28603
  annotations: READS_INTERNAL
28385
28604
  }, async () => {
28386
28605
  try {
@@ -28392,10 +28611,10 @@ function registerConnectionTools(server, api) {
28392
28611
  });
28393
28612
  server.registerTool("list_shopify_products", {
28394
28613
  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.',
28395
- inputSchema: z119.object({
28396
- shopDomain: z119.string().min(3).max(120),
28397
- query: z119.string().trim().max(120).optional(),
28398
- taskId: z119.string().uuid().optional()
28614
+ inputSchema: z121.object({
28615
+ shopDomain: z121.string().min(3).max(120),
28616
+ query: z121.string().trim().max(120).optional(),
28617
+ taskId: z121.string().uuid().optional()
28399
28618
  }).shape,
28400
28619
  annotations: READS_EXTERNAL
28401
28620
  }, async ({ shopDomain, query, taskId }) => {
@@ -28413,7 +28632,7 @@ function registerConnectionTools(server, api) {
28413
28632
  });
28414
28633
  server.registerTool("list_meta_ad_accounts", {
28415
28634
  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.",
28416
- inputSchema: z119.object({}).shape,
28635
+ inputSchema: z121.object({}).shape,
28417
28636
  annotations: READS_EXTERNAL
28418
28637
  }, async () => {
28419
28638
  try {
@@ -28425,7 +28644,7 @@ function registerConnectionTools(server, api) {
28425
28644
  });
28426
28645
  server.registerTool("list_meta_destinations", {
28427
28646
  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.",
28428
- inputSchema: z119.object({}).shape,
28647
+ inputSchema: z121.object({}).shape,
28429
28648
  annotations: READS_EXTERNAL,
28430
28649
  _meta: {
28431
28650
  "openai/widgetAccessible": true
@@ -28440,7 +28659,7 @@ function registerConnectionTools(server, api) {
28440
28659
  });
28441
28660
  server.registerTool("list_tiktok_advertisers", {
28442
28661
  description: listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.",
28443
- inputSchema: z119.object({}).shape,
28662
+ inputSchema: z121.object({}).shape,
28444
28663
  annotations: READS_EXTERNAL
28445
28664
  }, async () => {
28446
28665
  try {
@@ -28454,7 +28673,7 @@ function registerConnectionTools(server, api) {
28454
28673
  __name(registerConnectionTools, "registerConnectionTools");
28455
28674
 
28456
28675
  // src/tools/actors.ts
28457
- import { z as z120 } from "zod";
28676
+ import { z as z122 } from "zod";
28458
28677
  var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
28459
28678
  var actorVoiceGuidance = {
28460
28679
  capabilities: getProductMakerCapabilityModelGuidance("get_actor_voice_capabilities"),
@@ -28494,7 +28713,7 @@ function sanitizeVoiceResult(value) {
28494
28713
  __name(sanitizeVoiceResult, "sanitizeVoiceResult");
28495
28714
  function registerActorTools(server, api) {
28496
28715
  const actor = {
28497
- actorId: z120.string().min(1).max(64)
28716
+ actorId: z122.string().min(1).max(64)
28498
28717
  };
28499
28718
  const safe = /* @__PURE__ */ __name(async (request) => {
28500
28719
  try {
@@ -28523,8 +28742,8 @@ function registerActorTools(server, api) {
28523
28742
  inputSchema: {
28524
28743
  ...actor,
28525
28744
  draft: ActorVoiceDraftSchema,
28526
- requestKey: z120.string().trim().min(1).max(128),
28527
- acceptedQuoteId: z120.string().trim().min(1).max(128)
28745
+ requestKey: z122.string().trim().min(1).max(128),
28746
+ acceptedQuoteId: z122.string().trim().min(1).max(128)
28528
28747
  },
28529
28748
  annotations: CREATES_PAID
28530
28749
  }, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/previews`, body)));
@@ -28532,7 +28751,7 @@ function registerActorTools(server, api) {
28532
28751
  description: actorVoiceGuidance.get.summary,
28533
28752
  inputSchema: {
28534
28753
  ...actor,
28535
- candidateId: z120.string().min(1).max(64)
28754
+ candidateId: z122.string().min(1).max(64)
28536
28755
  },
28537
28756
  // Polling can resume the first paid submission of an accepted quote.
28538
28757
  // The immutable candidate/operation key keeps recovery idempotent.
@@ -28545,16 +28764,16 @@ function registerActorTools(server, api) {
28545
28764
  description: actorVoiceGuidance.approve.summary,
28546
28765
  inputSchema: {
28547
28766
  ...actor,
28548
- candidateId: z120.string().min(1).max(64),
28549
- expectedRevision: z120.number().int().positive(),
28550
- expectedApprovedRevision: z120.number().int().positive().nullable().optional()
28767
+ candidateId: z122.string().min(1).max(64),
28768
+ expectedRevision: z122.number().int().positive(),
28769
+ expectedApprovedRevision: z122.number().int().positive().nullable().optional()
28551
28770
  },
28552
28771
  // Replaces the selected voice and withdraws the old catalog grants.
28553
28772
  annotations: OVERWRITES_INTERNAL
28554
28773
  }, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/approve`, body)));
28555
28774
  server.registerTool("list_actors", {
28556
28775
  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.",
28557
- inputSchema: z120.object({}).shape,
28776
+ inputSchema: z122.object({}).shape,
28558
28777
  annotations: READS_INTERNAL
28559
28778
  }, async () => {
28560
28779
  try {
@@ -28587,7 +28806,7 @@ function registerActorTools(server, api) {
28587
28806
  __name(registerActorTools, "registerActorTools");
28588
28807
 
28589
28808
  // src/tools/publish.ts
28590
- import { z as z121 } from "zod";
28809
+ import { z as z123 } from "zod";
28591
28810
 
28592
28811
  // src/tools/meta-publish-attempt-id.ts
28593
28812
  var META_PUBLISH_NAMESPACE = "7b19c9ac-b4eb-4db1-970e-c2f24ce30b98";
@@ -28626,40 +28845,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
28626
28845
  var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
28627
28846
  var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
28628
28847
  var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
28629
- var ShopifyInput = z121.object({
28630
- taskId: z121.string().min(1),
28631
- shopDomain: z121.string().min(1),
28848
+ var ShopifyInput = z123.object({
28849
+ taskId: z123.string().min(1),
28850
+ shopDomain: z123.string().min(1),
28632
28851
  /** Override: number of landing images to include. Default = ALL images the
28633
28852
  * task generated (the MCP fetches /v1/results first to count). Bounded
28634
28853
  * generously here; the backend validates each index against
28635
28854
  * landing.images.length and rejects out-of-range. */
28636
- numLandingImages: z121.number().int().min(1).max(20).optional(),
28637
- variantIndex: z121.number().int().min(0).optional(),
28855
+ numLandingImages: z123.number().int().min(1).max(20).optional(),
28856
+ variantIndex: z123.number().int().min(0).optional(),
28638
28857
  /** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
28639
28858
  * When true, the landing renders variant-picker pills; when false, it ships
28640
28859
  * a single-option product page. Defaults to false. */
28641
- showVariantPicker: z121.boolean().optional(),
28860
+ showVariantPicker: z123.boolean().optional(),
28642
28861
  /** Default `auto` updates the product previously published for this task and
28643
28862
  * shop. Use `existing` with targetProductId to choose another product, or
28644
28863
  * `new` only when the user explicitly wants a duplicate/new listing. */
28645
- publicationMode: z121.enum([
28864
+ publicationMode: z123.enum([
28646
28865
  "auto",
28647
28866
  "existing",
28648
28867
  "new"
28649
28868
  ]).optional(),
28650
28869
  /** Shopify product GID, numeric id, or admin product URL. Required when
28651
28870
  * publicationMode is `existing`. */
28652
- targetProductId: z121.string().trim().min(1).max(300).optional(),
28871
+ targetProductId: z123.string().trim().min(1).max(300).optional(),
28653
28872
  /** Add an announcement bar text above add-to-cart (optional). */
28654
- announcementBarEnabled: z121.boolean().optional(),
28655
- announcementBarText: z121.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
28873
+ announcementBarEnabled: z123.boolean().optional(),
28874
+ announcementBarText: z123.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
28656
28875
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
28657
- confirmed: z121.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
28876
+ confirmed: z123.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
28658
28877
  });
28659
28878
  var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
28660
28879
  if (value.commerceCorrection && value.confirmed !== true) {
28661
28880
  ctx.addIssue({
28662
- code: z121.ZodIssueCode.custom,
28881
+ code: z123.ZodIssueCode.custom,
28663
28882
  path: [
28664
28883
  "confirmed"
28665
28884
  ],
@@ -28668,7 +28887,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
28668
28887
  }
28669
28888
  if (value.announcementBarEnabled && !value.announcementBarText) {
28670
28889
  ctx.addIssue({
28671
- code: z121.ZodIssueCode.custom,
28890
+ code: z123.ZodIssueCode.custom,
28672
28891
  path: [
28673
28892
  "announcementBarText"
28674
28893
  ],
@@ -28677,7 +28896,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
28677
28896
  }
28678
28897
  if (!value.announcementBarEnabled && value.announcementBarText) {
28679
28898
  ctx.addIssue({
28680
- code: z121.ZodIssueCode.custom,
28899
+ code: z123.ZodIssueCode.custom,
28681
28900
  path: [
28682
28901
  "announcementBarText"
28683
28902
  ],
@@ -28691,91 +28910,91 @@ function parseShopifyInput(rawInput) {
28691
28910
  return parsed.data;
28692
28911
  }
28693
28912
  __name(parseShopifyInput, "parseShopifyInput");
28694
- var McpCampaignConfig = z121.object({
28913
+ var McpCampaignConfig = z123.object({
28695
28914
  /** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
28696
28915
  * converts to the account currency server-side. Do NOT pre-convert: on a COP
28697
28916
  * account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
28698
- dailyBudgetUsd: z121.number().positive().optional(),
28917
+ dailyBudgetUsd: z123.number().positive().optional(),
28699
28918
  /** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
28700
28919
  * normalizes at validation). Meta accepts max 1 (single-country ad set).
28701
28920
  * TikTok takes only the first entry. */
28702
- targetCountries: z121.array(CountryIso2Schema).max(1).optional(),
28703
- campaignName: z121.string().trim().min(1).max(100).optional()
28921
+ targetCountries: z123.array(CountryIso2Schema).max(1).optional(),
28922
+ campaignName: z123.string().trim().min(1).max(100).optional()
28704
28923
  });
28705
28924
  var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
28706
- var MetaInput = z121.object({
28707
- taskId: z121.string().min(1),
28925
+ var MetaInput = z123.object({
28926
+ taskId: z123.string().min(1),
28708
28927
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
28709
- portfolioId: z121.string().trim().min(1),
28928
+ portfolioId: z123.string().trim().min(1),
28710
28929
  /** Exact Facebook Page selected from `list_meta_destinations`. */
28711
- pageId: z121.string().trim().min(1),
28930
+ pageId: z123.string().trim().min(1),
28712
28931
  adAccountId: McpAdAccountId,
28713
- pixelId: z121.string().min(1).optional(),
28714
- landingUrl: z121.string().url().optional(),
28932
+ pixelId: z123.string().min(1).optional(),
28933
+ landingUrl: z123.string().url().optional(),
28715
28934
  /** Select which angles to publish by 0-based index. Omit to publish all
28716
28935
  * successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
28717
- angleIndexes: z121.array(z121.number().int().nonnegative()).optional(),
28936
+ angleIndexes: z123.array(z123.number().int().nonnegative()).optional(),
28718
28937
  campaignConfig: McpCampaignConfig.optional(),
28719
28938
  /** Override the ad's primary text (body copy). If omitted, ProductMaker
28720
28939
  * uses the auto-generated copy attached to the task. Capped at 500 chars
28721
28940
  * (Meta's primary-text limit). */
28722
- primaryText: z121.string().trim().min(1).max(500).optional(),
28941
+ primaryText: z123.string().trim().min(1).max(500).optional(),
28723
28942
  /** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
28724
28943
  * (wa.me) instead of a landing page. */
28725
- phoneNumber: z121.string().min(8).max(32).optional()
28944
+ phoneNumber: z123.string().min(8).max(32).optional()
28726
28945
  });
28727
- var GroupedTaskSource = z121.object({
28728
- type: z121.literal("task"),
28729
- taskId: z121.string().min(1),
28730
- angleIndex: z121.number().int().min(0).optional(),
28731
- videoVariant: z121.enum([
28946
+ var GroupedTaskSource = z123.object({
28947
+ type: z123.literal("task"),
28948
+ taskId: z123.string().min(1),
28949
+ angleIndex: z123.number().int().min(0).optional(),
28950
+ videoVariant: z123.enum([
28732
28951
  "with_subtitles",
28733
28952
  "without_subtitles"
28734
28953
  ]).optional(),
28735
- imageVariantIndex: z121.number().int().min(0).optional()
28736
- });
28737
- var GroupedMediaSource = z121.object({
28738
- type: z121.literal("media"),
28739
- url: z121.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
28740
- path: z121.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".'),
28741
- thumbnailUrl: z121.string().url().optional(),
28742
- thumbnailPath: z121.string().min(1).optional()
28954
+ imageVariantIndex: z123.number().int().min(0).optional()
28955
+ });
28956
+ var GroupedMediaSource = z123.object({
28957
+ type: z123.literal("media"),
28958
+ url: z123.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
28959
+ path: z123.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".'),
28960
+ thumbnailUrl: z123.string().url().optional(),
28961
+ thumbnailPath: z123.string().min(1).optional()
28743
28962
  }).refine((value) => Boolean(value.url) !== Boolean(value.path), {
28744
28963
  message: "media source needs exactly one of `url` or `path`"
28745
28964
  }).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
28746
28965
  message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
28747
28966
  });
28748
- var GroupedUploadedAssetSource = z121.object({
28749
- type: z121.literal("asset"),
28967
+ var GroupedUploadedAssetSource = z123.object({
28968
+ type: z123.literal("asset"),
28750
28969
  /** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
28751
- assetId: z121.string().uuid(),
28752
- thumbnailAssetId: z121.string().uuid().optional()
28970
+ assetId: z123.string().uuid(),
28971
+ thumbnailAssetId: z123.string().uuid().optional()
28753
28972
  });
28754
- var GroupedCreative = z121.object({
28755
- type: z121.enum([
28973
+ var GroupedCreative = z123.object({
28974
+ type: z123.enum([
28756
28975
  "image",
28757
28976
  "video"
28758
28977
  ]),
28759
- source: z121.union([
28978
+ source: z123.union([
28760
28979
  GroupedTaskSource,
28761
28980
  GroupedMediaSource,
28762
28981
  GroupedUploadedAssetSource
28763
28982
  ]),
28764
- title: z121.string().max(120).optional(),
28765
- description: z121.string().max(500).optional(),
28983
+ title: z123.string().max(120).optional(),
28984
+ description: z123.string().max(500).optional(),
28766
28985
  cta: MetaCtaType.optional(),
28767
- creativeId: z121.string().min(1).optional()
28986
+ creativeId: z123.string().min(1).optional()
28768
28987
  });
28769
- var GroupedCampaignConfigBase = z121.object({
28988
+ var GroupedCampaignConfigBase = z123.object({
28770
28989
  campaignType: MetaCampaignType.default("sales"),
28771
28990
  optimizationMode: MetaOptimizationMode.default("advantage_plus"),
28772
28991
  budgetMode: MetaBudgetMode.optional(),
28773
- campaignDailyBudget: z121.number().int().positive().optional(),
28774
- adSets: z121.array(z121.object({
28775
- tempId: z121.string().min(1).max(80),
28776
- name: z121.string().min(1).max(100),
28777
- dailyBudget: z121.number().int().positive().optional(),
28778
- creativeIds: z121.array(z121.string().min(1)).min(1)
28992
+ campaignDailyBudget: z123.number().int().positive().optional(),
28993
+ adSets: z123.array(z123.object({
28994
+ tempId: z123.string().min(1).max(80),
28995
+ name: z123.string().min(1).max(100),
28996
+ dailyBudget: z123.number().int().positive().optional(),
28997
+ creativeIds: z123.array(z123.string().min(1)).min(1)
28779
28998
  })).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
28780
28999
  /**
28781
29000
  * Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
@@ -28783,17 +29002,17 @@ var GroupedCampaignConfigBase = z121.object({
28783
29002
  * opaque `invalid_literal` and made the WhatsApp destination — supported by
28784
29003
  * the API since #849 — unreachable from this tool.
28785
29004
  */
28786
- destination: z121.discriminatedUnion("type", [
28787
- z121.object({
28788
- type: z121.literal("landing"),
28789
- landingUrl: z121.string().url()
29005
+ destination: z123.discriminatedUnion("type", [
29006
+ z123.object({
29007
+ type: z123.literal("landing"),
29008
+ landingUrl: z123.string().url()
28790
29009
  }),
28791
- z121.object({
28792
- type: z121.literal("whatsapp"),
28793
- phoneNumber: z121.string().min(8).max(32)
29010
+ z123.object({
29011
+ type: z123.literal("whatsapp"),
29012
+ phoneNumber: z123.string().min(8).max(32)
28794
29013
  })
28795
29014
  ]),
28796
- saveAsDefault: z121.boolean().default(false),
29015
+ saveAsDefault: z123.boolean().default(false),
28797
29016
  budgetPolicy: MetaBudgetPolicy.optional()
28798
29017
  });
28799
29018
  function resolveBudgetMode(value) {
@@ -28807,7 +29026,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
28807
29026
  const budgetMode = resolveBudgetMode(value);
28808
29027
  if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
28809
29028
  ctx.addIssue({
28810
- code: z121.ZodIssueCode.custom,
29029
+ code: z123.ZodIssueCode.custom,
28811
29030
  path: [
28812
29031
  "campaignDailyBudget"
28813
29032
  ],
@@ -28818,7 +29037,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
28818
29037
  value.adSets.forEach((adSet, index) => {
28819
29038
  if (adSet.dailyBudget === void 0) {
28820
29039
  ctx.addIssue({
28821
- code: z121.ZodIssueCode.custom,
29040
+ code: z123.ZodIssueCode.custom,
28822
29041
  path: [
28823
29042
  "adSets",
28824
29043
  index,
@@ -28833,28 +29052,33 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
28833
29052
  ...value,
28834
29053
  budgetMode: resolveBudgetMode(value)
28835
29054
  }));
28836
- var PublishCreativesToMetaInputBase = z121.object({
28837
- creatives: z121.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
29055
+ var PublishCreativesToMetaInputBase = z123.object({
29056
+ creatives: z123.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
28838
29057
  /** Exact Meta Business portfolio selected from `list_meta_destinations`. */
28839
- portfolioId: z121.string().trim().min(1),
29058
+ portfolioId: z123.string().trim().min(1),
28840
29059
  /** Exact Facebook Page selected from `list_meta_destinations`. */
28841
- pageId: z121.string().trim().min(1),
29060
+ pageId: z123.string().trim().min(1),
28842
29061
  adAccountId: McpAdAccountId,
28843
- pixelId: z121.string().min(1).optional(),
28844
- /** Required unless `campaignConfig.destination` is whatsapp — see the
28845
- * superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
28846
- landingUrl: z121.string().url().optional(),
29062
+ pixelId: z123.string().min(1).optional(),
29063
+ /** Required unless `campaignConfig.destination` is whatsapp or a creative
29064
+ * comes from a task (the API then lands on the published service landing
29065
+ * of its service tasks) — see the superRefine below. Mirrors the API's
29066
+ * `FacebookCreateCampaignFromTasksBodySchema`. */
29067
+ landingUrl: z123.string().url().optional(),
28847
29068
  /** ISO-2 code or resolvable country name — mirrors the API contract
28848
- * (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
28849
- targetCountry: CountryIso2Schema,
28850
- campaignName: z121.string().trim().min(1).max(100),
29069
+ * (CountryIso2Schema), which normalizes names to alpha-2 at validation.
29070
+ * Omitted: the brand country of its service tasks (the API answers
29071
+ * META_NO_TARGET_COUNTRY when it has none); "US" for products. */
29072
+ targetCountry: CountryIso2Schema.optional(),
29073
+ campaignName: z123.string().trim().min(1).max(100),
28851
29074
  campaignConfig: GroupedCampaignConfig.optional()
28852
29075
  });
28853
29076
  var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
28854
29077
  const destination = value.campaignConfig?.destination;
28855
- if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
29078
+ const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
29079
+ if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl && !hasTaskCreative) {
28856
29080
  ctx.addIssue({
28857
- code: z121.ZodIssueCode.custom,
29081
+ code: z123.ZodIssueCode.custom,
28858
29082
  path: [
28859
29083
  "landingUrl"
28860
29084
  ],
@@ -28863,7 +29087,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
28863
29087
  }
28864
29088
  if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
28865
29089
  ctx.addIssue({
28866
- code: z121.ZodIssueCode.custom,
29090
+ code: z123.ZodIssueCode.custom,
28867
29091
  path: [
28868
29092
  "campaignConfig",
28869
29093
  "destination",
@@ -28882,16 +29106,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
28882
29106
  }
28883
29107
  return value;
28884
29108
  });
28885
- var PresignUploadResponseSchema = z121.object({
28886
- uploadUrl: z121.string().url().refine((value) => {
29109
+ var PresignUploadResponseSchema = z123.object({
29110
+ uploadUrl: z123.string().url().refine((value) => {
28887
29111
  const url = new URL(value);
28888
29112
  return !url.username && !url.password && url.protocol === "https:";
28889
29113
  }, "presigned upload URL must be HTTPS without embedded credentials"),
28890
- publicUrl: z121.string().url().refine((value) => {
29114
+ publicUrl: z123.string().url().refine((value) => {
28891
29115
  const url = new URL(value);
28892
29116
  return !url.username && !url.password;
28893
29117
  }, "public media URL must not contain embedded credentials"),
28894
- stagingAssetId: z121.string().uuid()
29118
+ stagingAssetId: z123.string().uuid()
28895
29119
  });
28896
29120
  async function uploadResolvedMedia(api, media, assetRole) {
28897
29121
  if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
@@ -28916,16 +29140,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
28916
29140
  return uploadResolvedMedia(api, media, assetRole);
28917
29141
  }
28918
29142
  __name(resolveAndUploadMedia, "resolveAndUploadMedia");
28919
- var TikTokInput = z121.object({
28920
- taskId: z121.string().min(1),
28921
- advertiserId: z121.string().min(1),
28922
- pixelId: z121.string().min(1).optional(),
28923
- landingUrl: z121.string().url().optional(),
28924
- angleIndexes: z121.array(z121.number().int().nonnegative()).optional(),
29143
+ var TikTokInput = z123.object({
29144
+ taskId: z123.string().min(1),
29145
+ advertiserId: z123.string().min(1),
29146
+ pixelId: z123.string().min(1).optional(),
29147
+ landingUrl: z123.string().url().optional(),
29148
+ angleIndexes: z123.array(z123.number().int().nonnegative()).optional(),
28925
29149
  campaignConfig: McpCampaignConfig.optional(),
28926
29150
  /** Override the ad's description (TikTok's body copy). If omitted,
28927
29151
  * ProductMaker uses the auto-generated copy attached to the task. */
28928
- primaryText: z121.string().trim().min(1).max(500).optional()
29152
+ primaryText: z123.string().trim().min(1).max(500).optional()
28929
29153
  });
28930
29154
  function registerPublishTools(server, api, opts = {}) {
28931
29155
  const transport = opts.transport ?? "http";
@@ -29047,7 +29271,7 @@ function registerPublishTools(server, api, opts = {}) {
29047
29271
  }
29048
29272
  });
29049
29273
  server.registerTool("publish_creatives_to_meta", {
29050
- 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.',
29274
+ 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.',
29051
29275
  inputSchema: PublishCreativesToMetaInputBase.shape,
29052
29276
  annotations: CREATES_EXTERNAL
29053
29277
  }, async (rawInput, extra) => {
@@ -29277,39 +29501,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
29277
29501
 
29278
29502
  // src/tools/meta-upload.ts
29279
29503
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
29280
- import { z as z122 } from "zod";
29504
+ import { z as z124 } from "zod";
29281
29505
  var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
29282
- var UploadSessionInputBase = z122.object({
29283
- mediaKind: z122.enum([
29506
+ var UploadSessionInputBase = z124.object({
29507
+ mediaKind: z124.enum([
29284
29508
  "image",
29285
29509
  "video",
29286
29510
  "mixed"
29287
29511
  ]).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."),
29288
- assetRole: z122.enum([
29512
+ assetRole: z124.enum([
29289
29513
  "media",
29290
29514
  "thumbnail"
29291
29515
  ]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
29292
- uploadPurpose: z122.enum([
29516
+ uploadPurpose: z124.enum([
29293
29517
  "product_reference",
29294
29518
  "creative",
29295
29519
  "generic"
29296
29520
  ]).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."),
29297
- maxFiles: z122.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
29521
+ maxFiles: z124.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
29298
29522
  });
29299
- var OpenAiFileReference = z122.object({
29300
- download_url: z122.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."),
29301
- file_id: z122.string().min(1),
29302
- mime_type: z122.string().min(1).optional(),
29303
- file_name: z122.string().min(1).optional()
29523
+ var OpenAiFileReference = z124.object({
29524
+ download_url: z124.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."),
29525
+ file_id: z124.string().min(1),
29526
+ mime_type: z124.string().min(1).optional(),
29527
+ file_name: z124.string().min(1).optional()
29304
29528
  });
29305
29529
  var UploadSessionToolInputShape = {
29306
29530
  ...UploadSessionInputBase.shape,
29307
- files: z122.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.")
29531
+ files: z124.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.")
29308
29532
  };
29309
- var UploadSessionToolInput = z122.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
29533
+ var UploadSessionToolInput = z124.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
29310
29534
  if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
29311
29535
  ctx.addIssue({
29312
- code: z122.ZodIssueCode.custom,
29536
+ code: z124.ZodIssueCode.custom,
29313
29537
  path: [
29314
29538
  "mediaKind"
29315
29539
  ],
@@ -29318,7 +29542,7 @@ var UploadSessionToolInput = z122.object(UploadSessionToolInputShape).superRefin
29318
29542
  }
29319
29543
  if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
29320
29544
  ctx.addIssue({
29321
- code: z122.ZodIssueCode.custom,
29545
+ code: z124.ZodIssueCode.custom,
29322
29546
  path: [
29323
29547
  "maxFiles"
29324
29548
  ],
@@ -29327,7 +29551,7 @@ var UploadSessionToolInput = z122.object(UploadSessionToolInputShape).superRefin
29327
29551
  }
29328
29552
  if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
29329
29553
  ctx.addIssue({
29330
- code: z122.ZodIssueCode.custom,
29554
+ code: z124.ZodIssueCode.custom,
29331
29555
  path: [
29332
29556
  "maxFiles"
29333
29557
  ],
@@ -29335,38 +29559,38 @@ var UploadSessionToolInput = z122.object(UploadSessionToolInputShape).superRefin
29335
29559
  });
29336
29560
  }
29337
29561
  });
29338
- var UploadSessionResponse = z122.object({
29339
- sessionId: z122.string().uuid(),
29340
- uploadPageUrl: z122.string().url(),
29341
- mediaKind: z122.enum([
29562
+ var UploadSessionResponse = z124.object({
29563
+ sessionId: z124.string().uuid(),
29564
+ uploadPageUrl: z124.string().url(),
29565
+ mediaKind: z124.enum([
29342
29566
  "image",
29343
29567
  "video",
29344
29568
  "mixed"
29345
29569
  ]),
29346
- assetRole: z122.enum([
29570
+ assetRole: z124.enum([
29347
29571
  "media",
29348
29572
  "thumbnail"
29349
29573
  ]),
29350
- maxFiles: z122.number().int().positive(),
29351
- expiresAt: z122.string().datetime()
29574
+ maxFiles: z124.number().int().positive(),
29575
+ expiresAt: z124.string().datetime()
29352
29576
  });
29353
- var UploadStatusInput = z122.object({
29354
- sessionId: z122.string().uuid().describe("The sessionId returned by request_media_upload.")
29577
+ var UploadStatusInput = z124.object({
29578
+ sessionId: z124.string().uuid().describe("The sessionId returned by request_media_upload.")
29355
29579
  });
29356
- var UniversalUploadStatusResponse = z122.discriminatedUnion("status", [
29357
- z122.object({
29358
- status: z122.literal("pending"),
29359
- assets: z122.array(z122.never()).length(0)
29580
+ var UniversalUploadStatusResponse = z124.discriminatedUnion("status", [
29581
+ z124.object({
29582
+ status: z124.literal("pending"),
29583
+ assets: z124.array(z124.never()).length(0)
29360
29584
  }),
29361
- z122.object({
29362
- status: z122.literal("uploaded"),
29363
- assets: z122.array(z122.object({
29364
- assetId: z122.string().uuid(),
29365
- mediaKind: z122.enum([
29585
+ z124.object({
29586
+ status: z124.literal("uploaded"),
29587
+ assets: z124.array(z124.object({
29588
+ assetId: z124.string().uuid(),
29589
+ mediaKind: z124.enum([
29366
29590
  "image",
29367
29591
  "video"
29368
29592
  ]),
29369
- assetRole: z122.enum([
29593
+ assetRole: z124.enum([
29370
29594
  "media",
29371
29595
  "thumbnail"
29372
29596
  ])
@@ -29374,13 +29598,13 @@ var UniversalUploadStatusResponse = z122.discriminatedUnion("status", [
29374
29598
  })
29375
29599
  ]);
29376
29600
  var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
29377
- uploadPurpose: z122.enum([
29601
+ uploadPurpose: z124.enum([
29378
29602
  "product_reference",
29379
29603
  "creative",
29380
29604
  "generic"
29381
29605
  ]),
29382
- checkToolName: z122.literal("check_media_upload"),
29383
- resolveEndpoint: z122.string().url()
29606
+ checkToolName: z124.literal("check_media_upload"),
29607
+ resolveEndpoint: z124.string().url()
29384
29608
  });
29385
29609
  function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
29386
29610
  const url = new URL(uploadPageUrl);
@@ -29471,15 +29695,15 @@ function registerMediaUploadTools(server, api) {
29471
29695
  __name(registerMediaUploadTools, "registerMediaUploadTools");
29472
29696
 
29473
29697
  // src/tools/campaigns.ts
29474
- import { z as z123 } from "zod";
29698
+ import { z as z125 } from "zod";
29475
29699
  var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
29476
29700
  var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
29477
- var MetaStatusInput = z123.object({
29478
- campaignId: z123.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
29701
+ var MetaStatusInput = z125.object({
29702
+ campaignId: z125.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
29479
29703
  });
29480
- var TikTokStatusInput = z123.object({
29481
- campaignId: z123.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
29482
- advertiserId: z123.string().min(1).describe("The same advertiserId used to publish the campaign.")
29704
+ var TikTokStatusInput = z125.object({
29705
+ campaignId: z125.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
29706
+ advertiserId: z125.string().min(1).describe("The same advertiserId used to publish the campaign.")
29483
29707
  });
29484
29708
  function registerCampaignTools(server, api) {
29485
29709
  server.registerTool("get_meta_campaign_status", {
@@ -29584,10 +29808,10 @@ function renderTikTokStatusMarkdown(r) {
29584
29808
  __name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
29585
29809
 
29586
29810
  // ../../packages/product-economics/src/product-costing.ts
29587
- import { z as z125 } from "zod";
29811
+ import { z as z127 } from "zod";
29588
29812
 
29589
29813
  // ../../packages/product-economics/src/product-costing-countries.ts
29590
- import { z as z124 } from "zod";
29814
+ import { z as z126 } from "zod";
29591
29815
 
29592
29816
  // ../../packages/product-economics/src/product-costing-shipping-references.json
29593
29817
  var product_costing_shipping_references_default = {
@@ -29651,21 +29875,21 @@ var product_costing_shipping_references_default = {
29651
29875
  };
29652
29876
 
29653
29877
  // ../../packages/product-economics/src/product-costing-countries.ts
29654
- var ShippingReferenceSchema = z124.object({
29655
- reference: z124.number().positive(),
29656
- min: z124.number().nonnegative(),
29657
- max: z124.number().positive(),
29658
- updatedAt: z124.string().date(),
29659
- confidence: z124.enum([
29878
+ var ShippingReferenceSchema = z126.object({
29879
+ reference: z126.number().positive(),
29880
+ min: z126.number().nonnegative(),
29881
+ max: z126.number().positive(),
29882
+ updatedAt: z126.string().date(),
29883
+ confidence: z126.enum([
29660
29884
  "high",
29661
29885
  "medium",
29662
29886
  "medium-low"
29663
29887
  ]),
29664
- sources: z124.array(z124.string().url().startsWith("https://")).min(1).max(3)
29888
+ sources: z126.array(z126.string().url().startsWith("https://")).min(1).max(3)
29665
29889
  }).superRefine(({ reference, min, max }, context) => {
29666
29890
  if (min > reference || reference > max) {
29667
29891
  context.addIssue({
29668
- code: z124.ZodIssueCode.custom,
29892
+ code: z126.ZodIssueCode.custom,
29669
29893
  message: "shipping_reference_outside_range",
29670
29894
  path: [
29671
29895
  "reference"
@@ -29673,7 +29897,7 @@ var ShippingReferenceSchema = z124.object({
29673
29897
  });
29674
29898
  }
29675
29899
  });
29676
- var SHIPPING_REFERENCES = z124.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
29900
+ var SHIPPING_REFERENCES = z126.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
29677
29901
  var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
29678
29902
  var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
29679
29903
  "MX",
@@ -29855,18 +30079,18 @@ function getProductCostingCountryName(country) {
29855
30079
  __name(getProductCostingCountryName, "getProductCostingCountryName");
29856
30080
 
29857
30081
  // ../../packages/product-economics/src/product-costing.ts
29858
- var ProductCostingInputSchema = z125.object({
29859
- country: z125.string().refine(isProductCostingCountryCode, "unsupported_country"),
29860
- supplierCost: z125.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
29861
- shippingCost: z125.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
29862
- returnRate: z125.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
29863
- cancellationRate: z125.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
29864
- adsManagerCpa: z125.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
29865
- desiredMargin: z125.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
30082
+ var ProductCostingInputSchema = z127.object({
30083
+ country: z127.string().refine(isProductCostingCountryCode, "unsupported_country"),
30084
+ supplierCost: z127.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
30085
+ shippingCost: z127.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
30086
+ returnRate: z127.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
30087
+ cancellationRate: z127.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
30088
+ adsManagerCpa: z127.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
30089
+ desiredMargin: z127.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
29866
30090
  }).superRefine(({ returnRate, cancellationRate }, context) => {
29867
30091
  if (returnRate + cancellationRate >= 1) {
29868
30092
  context.addIssue({
29869
- code: z125.ZodIssueCode.custom,
30093
+ code: z127.ZodIssueCode.custom,
29870
30094
  message: "delivery_rate_positive",
29871
30095
  path: [
29872
30096
  "cancellationRate"
@@ -29963,15 +30187,15 @@ function calculateProductCosting(rawInput) {
29963
30187
  __name(calculateProductCosting, "calculateProductCosting");
29964
30188
 
29965
30189
  // src/tools/product-costing.ts
29966
- import { z as z126 } from "zod";
30190
+ import { z as z128 } from "zod";
29967
30191
  var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
29968
- var optionalAmount = /* @__PURE__ */ __name((description) => z126.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
29969
- var optionalPercent = /* @__PURE__ */ __name((description) => z126.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
29970
- var ProductCostingToolInput = z126.object({
29971
- country: z126.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
30192
+ var optionalAmount = /* @__PURE__ */ __name((description) => z128.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
30193
+ var optionalPercent = /* @__PURE__ */ __name((description) => z128.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
30194
+ var ProductCostingToolInput = z128.object({
30195
+ country: z128.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
29972
30196
  message: "Pa\xEDs no soportado por ProductMaker."
29973
30197
  }).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
29974
- supplierCost: z126.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."),
30198
+ supplierCost: z128.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."),
29975
30199
  supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
29976
30200
  shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
29977
30201
  shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
@@ -30134,7 +30358,7 @@ function formatPercent(value) {
30134
30358
  __name(formatPercent, "formatPercent");
30135
30359
 
30136
30360
  // src/tools/product-research.ts
30137
- import { z as z127 } from "zod";
30361
+ import { z as z129 } from "zod";
30138
30362
 
30139
30363
  // src/tools/product-research-idempotency.ts
30140
30364
  var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
@@ -30505,17 +30729,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
30505
30729
  ]);
30506
30730
  var POLL_INTERVAL_MS = 5e3;
30507
30731
  var MAX_WAIT_SECONDS = 120;
30508
- var FindInput = z127.object({
30732
+ var FindInput = z129.object({
30509
30733
  targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
30510
30734
  categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
30511
- confirmed: z127.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
30512
- waitSeconds: z127.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
30735
+ confirmed: z129.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
30736
+ waitSeconds: z129.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
30513
30737
  });
30514
- var GetInput = z127.object({
30515
- runId: z127.string().uuid().describe("ID del run devuelto por find_winning_products.")
30738
+ var GetInput = z129.object({
30739
+ runId: z129.string().uuid().describe("ID del run devuelto por find_winning_products.")
30516
30740
  });
30517
- var ListInput = z127.object({
30518
- limit: z127.number().int().min(1).max(20).default(10)
30741
+ var ListInput = z129.object({
30742
+ limit: z129.number().int().min(1).max(20).default(10)
30519
30743
  });
30520
30744
  function textResult(text2) {
30521
30745
  return {
@@ -30654,17 +30878,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
30654
30878
  __name(registerProductResearchTools, "registerProductResearchTools");
30655
30879
 
30656
30880
  // src/tools/dropshipping-projects.ts
30657
- import { z as z128 } from "zod";
30881
+ import { z as z130 } from "zod";
30658
30882
  var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
30659
30883
  var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
30660
30884
  var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
30661
- var ProjectId = z128.string().uuid();
30662
- var DropshippingProjectStatus = z128.enum([
30885
+ var ProjectId = z130.string().uuid();
30886
+ var DropshippingProjectStatus = z130.enum([
30663
30887
  "active",
30664
30888
  "completed",
30665
30889
  "archived"
30666
30890
  ]);
30667
- var DropshippingProjectPhase = z128.enum([
30891
+ var DropshippingProjectPhase = z130.enum([
30668
30892
  "research",
30669
30893
  "costing",
30670
30894
  "media",
@@ -30673,21 +30897,21 @@ var DropshippingProjectPhase = z128.enum([
30673
30897
  "advertising",
30674
30898
  "complete"
30675
30899
  ]);
30676
- var DropshippingRewardMilestone = z128.enum([
30900
+ var DropshippingRewardMilestone = z130.enum([
30677
30901
  "product_selected",
30678
30902
  "costing_saved",
30679
30903
  "product_media_ready",
30680
30904
  "creatives_completed",
30681
30905
  "campaign_created"
30682
30906
  ]);
30683
- var TargetCountry = z128.enum([
30907
+ var TargetCountry = z130.enum([
30684
30908
  "CO",
30685
30909
  "MX",
30686
30910
  "PE",
30687
30911
  "EC",
30688
30912
  "CL"
30689
30913
  ]);
30690
- var ResearchCategory = z128.enum([
30914
+ var ResearchCategory = z130.enum([
30691
30915
  "auto",
30692
30916
  "automotive",
30693
30917
  "kitchen",
@@ -30702,7 +30926,7 @@ var ResearchCategory = z128.enum([
30702
30926
  "garden",
30703
30927
  "cleaning"
30704
30928
  ]);
30705
- var HttpUrl3 = z128.string().url().max(2e3).refine((value) => {
30929
+ var HttpUrl3 = z130.string().url().max(2e3).refine((value) => {
30706
30930
  try {
30707
30931
  return [
30708
30932
  "http:",
@@ -30712,45 +30936,45 @@ var HttpUrl3 = z128.string().url().max(2e3).refine((value) => {
30712
30936
  return false;
30713
30937
  }
30714
30938
  }, "URL must use HTTP(S)");
30715
- var ResearchCandidateOrigin = z128.object({
30716
- type: z128.literal("research_candidate"),
30939
+ var ResearchCandidateOrigin = z130.object({
30940
+ type: z130.literal("research_candidate"),
30717
30941
  runId: ProjectId,
30718
- candidateSourceId: z128.string().min(1).max(160)
30942
+ candidateSourceId: z130.string().min(1).max(160)
30719
30943
  });
30720
- var TaskOrigin = z128.object({
30721
- type: z128.literal("task"),
30944
+ var TaskOrigin = z130.object({
30945
+ type: z130.literal("task"),
30722
30946
  taskId: ProjectId
30723
30947
  });
30724
- var ManualOrigin = z128.object({
30725
- type: z128.literal("manual"),
30948
+ var ManualOrigin = z130.object({
30949
+ type: z130.literal("manual"),
30726
30950
  clientRequestId: ProjectId,
30727
- country: z128.string().min(2).max(3).optional()
30951
+ country: z130.string().min(2).max(3).optional()
30728
30952
  });
30729
- var StartProjectInput = z128.object({
30730
- origin: z128.discriminatedUnion("type", [
30953
+ var StartProjectInput = z130.object({
30954
+ origin: z130.discriminatedUnion("type", [
30731
30955
  ResearchCandidateOrigin,
30732
30956
  TaskOrigin,
30733
30957
  ManualOrigin
30734
30958
  ]),
30735
- productName: z128.string().trim().min(1).max(240).optional(),
30959
+ productName: z130.string().trim().min(1).max(240).optional(),
30736
30960
  productUrl: HttpUrl3.optional(),
30737
- country: z128.string().min(2).max(3).optional(),
30738
- languageCode: z128.string().min(2).max(16).optional()
30961
+ country: z130.string().min(2).max(3).optional(),
30962
+ languageCode: z130.string().min(2).max(16).optional()
30739
30963
  }).strict();
30740
- var CostProjectInput = z128.object({
30964
+ var CostProjectInput = z130.object({
30741
30965
  projectId: ProjectId,
30742
- version: z128.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
30743
- country: z128.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
30966
+ version: z130.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
30967
+ country: z130.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
30744
30968
  message: "Pa\xEDs no soportado por ProductMaker."
30745
30969
  }).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
30746
- supplierCost: z128.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."),
30747
- shippingCost: z128.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
30748
- returnRate: z128.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."),
30749
- cancellationRate: z128.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."),
30750
- adsManagerCpa: z128.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
30751
- desiredMargin: z128.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
30752
- });
30753
- var GuideInput = z128.object({
30970
+ supplierCost: z130.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."),
30971
+ shippingCost: z130.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
30972
+ returnRate: z130.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."),
30973
+ cancellationRate: z130.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."),
30974
+ adsManagerCpa: z130.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
30975
+ desiredMargin: z130.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
30976
+ });
30977
+ var GuideInput = z130.object({
30754
30978
  projectId: ProjectId.optional()
30755
30979
  }).strict();
30756
30980
  var NEXT_ACTION_KINDS = [
@@ -30768,29 +30992,29 @@ var NEXT_ACTION_KINDS = [
30768
30992
  "repair_meta_campaign",
30769
30993
  "review_paused_campaign"
30770
30994
  ];
30771
- var DropshippingProjectNextAction = z128.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z128.object({
30772
- kind: z128.literal(kind),
30773
- href: z128.string().min(1)
30995
+ var DropshippingProjectNextAction = z130.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z130.object({
30996
+ kind: z130.literal(kind),
30997
+ href: z130.string().min(1)
30774
30998
  })));
30775
- var CostingInputSchema = z128.object({
30776
- country: z128.string().min(2).max(3),
30777
- supplierCost: z128.number().finite().positive(),
30778
- shippingCost: z128.number().finite().nonnegative(),
30779
- returnRate: z128.number().finite().min(0).lt(1),
30780
- cancellationRate: z128.number().finite().min(0).lt(1),
30781
- adsManagerCpa: z128.number().finite().nonnegative(),
30782
- desiredMargin: z128.number().finite().min(0).lt(1)
30999
+ var CostingInputSchema = z130.object({
31000
+ country: z130.string().min(2).max(3),
31001
+ supplierCost: z130.number().finite().positive(),
31002
+ shippingCost: z130.number().finite().nonnegative(),
31003
+ returnRate: z130.number().finite().min(0).lt(1),
31004
+ cancellationRate: z130.number().finite().min(0).lt(1),
31005
+ adsManagerCpa: z130.number().finite().nonnegative(),
31006
+ desiredMargin: z130.number().finite().min(0).lt(1)
30783
31007
  }).superRefine(({ returnRate, cancellationRate }, context) => {
30784
31008
  if (returnRate + cancellationRate >= 1) context.addIssue({
30785
- code: z128.ZodIssueCode.custom,
31009
+ code: z130.ZodIssueCode.custom,
30786
31010
  path: [
30787
31011
  "cancellationRate"
30788
31012
  ]
30789
31013
  });
30790
31014
  });
30791
- var FiniteCostingNumber = z128.number().finite();
30792
- var CostingResultSchema = z128.object({
30793
- country: z128.string().min(2).max(3),
31015
+ var FiniteCostingNumber = z130.number().finite();
31016
+ var CostingResultSchema = z130.object({
31017
+ country: z130.string().min(2).max(3),
30794
31018
  deliveryRate: FiniteCostingNumber,
30795
31019
  adjustedShippingCost: FiniteCostingNumber,
30796
31020
  adjustedCpa: FiniteCostingNumber,
@@ -30803,45 +31027,45 @@ var CostingResultSchema = z128.object({
30803
31027
  estimatedProfit: FiniteCostingNumber,
30804
31028
  actualMargin: FiniteCostingNumber,
30805
31029
  breakEvenAdsManagerCpa: FiniteCostingNumber,
30806
- wasPriceAutoAdjusted: z128.boolean(),
30807
- profitabilityStatus: z128.literal("healthy")
30808
- });
30809
- var RewardProgressSchema = z128.object({
30810
- campaignKey: z128.literal("dropshipping-launch-v1"),
30811
- totalCredits: z128.number().int().positive(),
30812
- earnedCredits: z128.number().int().nonnegative(),
30813
- milestones: z128.array(z128.object({
31030
+ wasPriceAutoAdjusted: z130.boolean(),
31031
+ profitabilityStatus: z130.literal("healthy")
31032
+ });
31033
+ var RewardProgressSchema = z130.object({
31034
+ campaignKey: z130.literal("dropshipping-launch-v1"),
31035
+ totalCredits: z130.number().int().positive(),
31036
+ earnedCredits: z130.number().int().nonnegative(),
31037
+ milestones: z130.array(z130.object({
30814
31038
  milestone: DropshippingRewardMilestone,
30815
- credits: z128.number().int().positive(),
30816
- available: z128.boolean().optional(),
30817
- earned: z128.boolean(),
31039
+ credits: z130.number().int().positive(),
31040
+ available: z130.boolean().optional(),
31041
+ earned: z130.boolean(),
30818
31042
  grantId: ProjectId.nullable(),
30819
- grantedAt: z128.string().datetime().nullable()
31043
+ grantedAt: z130.string().datetime().nullable()
30820
31044
  })).length(DropshippingRewardMilestone.options.length)
30821
31045
  });
30822
- var ProjectResponseSchema = z128.object({
31046
+ var ProjectResponseSchema = z130.object({
30823
31047
  id: ProjectId,
30824
31048
  taskId: ProjectId.nullable(),
30825
31049
  status: DropshippingProjectStatus,
30826
- originKey: z128.string().min(1),
31050
+ originKey: z130.string().min(1),
30827
31051
  researchRunId: ProjectId.nullable(),
30828
- candidateSourceId: z128.string().nullable(),
30829
- productName: z128.string().nullable(),
31052
+ candidateSourceId: z130.string().nullable(),
31053
+ productName: z130.string().nullable(),
30830
31054
  productUrl: HttpUrl3.nullable(),
30831
31055
  referenceImageUrl: HttpUrl3.nullable(),
30832
- targetCountry: z128.string().nullable(),
30833
- languageCode: z128.string().nullable(),
30834
- hasReferenceImage: z128.boolean(),
30835
- hasWinnerReferenceImage: z128.boolean(),
31056
+ targetCountry: z130.string().nullable(),
31057
+ languageCode: z130.string().nullable(),
31058
+ hasReferenceImage: z130.boolean(),
31059
+ hasWinnerReferenceImage: z130.boolean(),
30836
31060
  costingInput: CostingInputSchema.nullable(),
30837
31061
  costingResult: CostingResultSchema.nullable(),
30838
- costingVersion: z128.number().int().positive().nullable(),
30839
- version: z128.number().int().positive(),
31062
+ costingVersion: z130.number().int().positive().nullable(),
31063
+ version: z130.number().int().positive(),
30840
31064
  phase: DropshippingProjectPhase,
30841
31065
  nextAction: DropshippingProjectNextAction.nullable(),
30842
31066
  rewards: RewardProgressSchema,
30843
- createdAt: z128.string().datetime(),
30844
- updatedAt: z128.string().datetime()
31067
+ createdAt: z130.string().datetime(),
31068
+ updatedAt: z130.string().datetime()
30845
31069
  }).passthrough();
30846
31070
  var NEXT_ACTION_GUIDANCE = {
30847
31071
  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.",
@@ -30961,58 +31185,58 @@ function registerDropshippingProjectTools(server, api) {
30961
31185
  __name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
30962
31186
 
30963
31187
  // src/tools/daily-control.ts
30964
- import { z as z129 } from "zod";
31188
+ import { z as z131 } from "zod";
30965
31189
  var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
30966
31190
  var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
30967
31191
  var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
30968
- var ProviderCampaignIdentifier = z129.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
30969
- var DateOnly = z129.string().regex(/^\d{4}-\d{2}-\d{2}$/);
30970
- var DailyControlInput = z129.object({
31192
+ var ProviderCampaignIdentifier = z131.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
31193
+ var DateOnly = z131.string().regex(/^\d{4}-\d{2}-\d{2}$/);
31194
+ var DailyControlInput = z131.object({
30971
31195
  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."),
30972
- days: z129.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
30973
- projectId: z129.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
31196
+ days: z131.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
31197
+ projectId: z131.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
30974
31198
  }).strict();
30975
- var LinkCampaignInput = z129.object({
30976
- projectId: z129.string().uuid(),
30977
- provider: z129.enum([
31199
+ var LinkCampaignInput = z131.object({
31200
+ projectId: z131.string().uuid(),
31201
+ provider: z131.enum([
30978
31202
  "meta",
30979
31203
  "tiktok"
30980
31204
  ]),
30981
31205
  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."),
30982
31206
  campaignId: ProviderCampaignIdentifier
30983
31207
  }).strict();
30984
- var ReportReturnsInput = z129.object({
30985
- projectId: z129.string().uuid(),
31208
+ var ReportReturnsInput = z131.object({
31209
+ projectId: z131.string().uuid(),
30986
31210
  date: DateOnly,
30987
- returnedOrders: z129.number().int().min(0).max(1e5),
30988
- note: z129.string().trim().max(280).optional()
31211
+ returnedOrders: z131.number().int().min(0).max(1e5),
31212
+ note: z131.string().trim().max(280).optional()
30989
31213
  }).strict();
30990
- var DailyControlStatusMirror = DailyControlStatusEnum.or(z129.string());
30991
- var DailyControlLightMirror = DailyControlLightEnum.or(z129.string());
30992
- var DailyControlSourceMirror = DailyControlSourceEnum.or(z129.string());
30993
- var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z129.string());
30994
- var DailyControlDayMirror = z129.object({
30995
- date: z129.string(),
30996
- returnedOrders: z129.number(),
31214
+ var DailyControlStatusMirror = DailyControlStatusEnum.or(z131.string());
31215
+ var DailyControlLightMirror = DailyControlLightEnum.or(z131.string());
31216
+ var DailyControlSourceMirror = DailyControlSourceEnum.or(z131.string());
31217
+ var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z131.string());
31218
+ var DailyControlDayMirror = z131.object({
31219
+ date: z131.string(),
31220
+ returnedOrders: z131.number(),
30997
31221
  returnedSource: DailyControlSourceMirror,
30998
31222
  cancelledSource: DailyControlSourceMirror,
30999
- hasEstimates: z129.boolean(),
31223
+ hasEstimates: z131.boolean(),
31000
31224
  light: DailyControlLightMirror
31001
31225
  }).passthrough();
31002
- var DailyControlProductMirror = z129.object({
31003
- projectId: z129.string().uuid(),
31004
- productName: z129.string().nullable(),
31226
+ var DailyControlProductMirror = z131.object({
31227
+ projectId: z131.string().uuid(),
31228
+ productName: z131.string().nullable(),
31005
31229
  status: DailyControlStatusMirror,
31006
- statusMessage: z129.string().nullable(),
31007
- days: z129.array(DailyControlDayMirror),
31230
+ statusMessage: z131.string().nullable(),
31231
+ days: z131.array(DailyControlDayMirror),
31008
31232
  verdict: DailyControlVerdictMirror.nullable(),
31009
- rationale: z129.string().nullable()
31233
+ rationale: z131.string().nullable()
31010
31234
  }).passthrough();
31011
- var DailyControlResponseMirror = z129.object({
31012
- since: z129.string(),
31013
- until: z129.string(),
31014
- products: z129.array(DailyControlProductMirror),
31015
- archivedProjectSpend: z129.array(z129.unknown())
31235
+ var DailyControlResponseMirror = z131.object({
31236
+ since: z131.string(),
31237
+ until: z131.string(),
31238
+ products: z131.array(DailyControlProductMirror),
31239
+ archivedProjectSpend: z131.array(z131.unknown())
31016
31240
  }).passthrough();
31017
31241
  var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
31018
31242
  function withWarnings(response) {
@@ -31087,7 +31311,7 @@ __name(registerDailyControlTools, "registerDailyControlTools");
31087
31311
  // src/tools/product-control.ts
31088
31312
  import { readFile, stat } from "fs/promises";
31089
31313
  import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
31090
- import { z as z130 } from "zod";
31314
+ import { z as z132 } from "zod";
31091
31315
  var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
31092
31316
  var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
31093
31317
  var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
@@ -31100,36 +31324,36 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
31100
31324
  var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
31101
31325
  var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
31102
31326
  var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
31103
- var DateOnly2 = z130.string().regex(/^\d{4}-\d{2}-\d{2}$/);
31327
+ var DateOnly2 = z132.string().regex(/^\d{4}-\d{2}-\d{2}$/);
31104
31328
  var IMPORT_BATCH_MAX2 = 50;
31105
- var ProductControlListInput = z130.object({
31106
- days: z130.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
31329
+ var ProductControlListInput = z132.object({
31330
+ days: z132.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
31107
31331
  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."),
31108
- shopDomain: z130.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
31332
+ shopDomain: z132.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
31109
31333
  }).strict();
31110
- var ImportableProductsInput = z130.object({
31111
- q: z130.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
31112
- after: z130.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
31113
- shopDomain: z130.string().min(1).optional()
31334
+ var ImportableProductsInput = z132.object({
31335
+ q: z132.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
31336
+ after: z132.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
31337
+ shopDomain: z132.string().min(1).optional()
31114
31338
  }).strict();
31115
- var ImportProductControlsInput = z130.object({
31116
- shopifyProductIds: z130.array(z130.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."),
31339
+ var ImportProductControlsInput = z132.object({
31340
+ shopifyProductIds: z132.array(z132.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."),
31117
31341
  // Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
31118
31342
  // sin decir a cuál archivaría el producto bajo la tienda equivocada.
31119
- shopDomain: z130.string().min(1)
31343
+ shopDomain: z132.string().min(1)
31120
31344
  }).strict();
31121
- var SetProductCostingInput = z130.object({
31122
- shopDomain: z130.string().min(1),
31123
- shopifyProductId: z130.string().min(1).max(64),
31124
- targetCountry: z130.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
31125
- supplierCost: z130.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
31126
- shippingCost: z130.number().finite().nonnegative(),
31127
- returnRate: z130.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
31128
- cancellationRate: z130.number().finite().min(0).lt(1)
31345
+ var SetProductCostingInput = z132.object({
31346
+ shopDomain: z132.string().min(1),
31347
+ shopifyProductId: z132.string().min(1).max(64),
31348
+ targetCountry: z132.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
31349
+ supplierCost: z132.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
31350
+ shippingCost: z132.number().finite().nonnegative(),
31351
+ returnRate: z132.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
31352
+ cancellationRate: z132.number().finite().min(0).lt(1)
31129
31353
  }).strict();
31130
- var Count = z130.number().int().min(0).max(1e5).nullable().optional();
31131
- var ReportProductCountsInput = z130.object({
31132
- productControlId: z130.string().uuid().describe("El identificador que devuelve get_product_control."),
31354
+ var Count = z132.number().int().min(0).max(1e5).nullable().optional();
31355
+ var ReportProductCountsInput = z132.object({
31356
+ productControlId: z132.string().uuid().describe("El identificador que devuelve get_product_control."),
31133
31357
  date: DateOnly2,
31134
31358
  orders: Count.describe("Pedidos que entraron ese d\xEDa."),
31135
31359
  cancelledOrders: Count,
@@ -31139,36 +31363,36 @@ var ReportProductCountsInput = z130.object({
31139
31363
  }).strict();
31140
31364
  var MAX_ORDERS_FILE_BYTES = 8 * 1024 * 1024;
31141
31365
  var SyncShopifyOrdersInput = SyncShopifyOrdersSchema;
31142
- var ImportOrdersFileInput = z130.object({
31366
+ var ImportOrdersFileInput = z132.object({
31143
31367
  /** Ruta ABSOLUTA en la máquina de quien usa el MCP. */
31144
- path: z130.string().min(1),
31145
- operationId: z130.string().uuid().optional(),
31368
+ path: z132.string().min(1),
31369
+ operationId: z132.string().uuid().optional(),
31146
31370
  /** Solo mirar: devuelve el resumen y no escribe nada. */
31147
- dryRun: z130.boolean().optional()
31371
+ dryRun: z132.boolean().optional()
31148
31372
  }).strict();
31149
- var CreateOperationInput = z130.object({
31150
- countryCode: z130.string().length(2),
31151
- label: z130.string().trim().min(1).max(60).optional()
31373
+ var CreateOperationInput = z132.object({
31374
+ countryCode: z132.string().length(2),
31375
+ label: z132.string().trim().min(1).max(60).optional()
31152
31376
  }).strict();
31153
- var MergeProductsInput = z130.object({
31154
- sourceId: z130.string().uuid(),
31155
- targetId: z130.string().uuid()
31377
+ var MergeProductsInput = z132.object({
31378
+ sourceId: z132.string().uuid(),
31379
+ targetId: z132.string().uuid()
31156
31380
  }).strict();
31157
- var SetMonthlyExpenseInput = z130.object({
31158
- month: z130.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
31381
+ var SetMonthlyExpenseInput = z132.object({
31382
+ month: z132.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
31159
31383
  label: SaveMonthlyExpenseSchema.shape.label,
31160
- amount: z130.number().finite().min(0),
31161
- operationId: z130.string().uuid().optional()
31384
+ amount: z132.number().finite().min(0),
31385
+ operationId: z132.string().uuid().optional()
31162
31386
  }).strict();
31163
- var SetAdSpendInput = z130.object({
31164
- month: z130.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
31165
- operationId: z130.string().uuid().optional(),
31387
+ var SetAdSpendInput = z132.object({
31388
+ month: z132.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
31389
+ operationId: z132.string().uuid().optional(),
31166
31390
  /** null RETIRA la corrección; cero afirma que no pautó. */
31167
- amount: z130.number().finite().min(0).nullable()
31391
+ amount: z132.number().finite().min(0).nullable()
31168
31392
  }).strict();
31169
- var GetFinancesInput = z130.object({
31170
- month: z130.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."),
31171
- operationId: z130.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
31393
+ var GetFinancesInput = z132.object({
31394
+ month: z132.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."),
31395
+ operationId: z132.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
31172
31396
  }).strict();
31173
31397
  function registerProductControlTools(server, api, { transport = "http" } = {}) {
31174
31398
  server.registerTool("get_product_control", {
@@ -31360,28 +31584,28 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
31360
31584
  __name(registerProductControlTools, "registerProductControlTools");
31361
31585
 
31362
31586
  // src/tools/market-study-estimate.ts
31363
- import { z as z131 } from "zod";
31587
+ import { z as z133 } from "zod";
31364
31588
  var estimateMarketStudyGuidance = getProductMakerCapabilityModelGuidance("estimate_market_study_cost");
31365
- var ProductTaskOutputEnum = z131.enum([
31589
+ var ProductTaskOutputEnum = z133.enum([
31366
31590
  "landing",
31367
31591
  "video",
31368
31592
  "image"
31369
31593
  ]);
31370
- var EstimateMarketStudyInput = z131.object({
31371
- kind: z131.enum([
31594
+ var EstimateMarketStudyInput = z133.object({
31595
+ kind: z133.enum([
31372
31596
  "video",
31373
31597
  "product_task"
31374
31598
  ]).describe('"video" para generate_video_creative; "product_task" para create_product_task.'),
31375
- videoAngleCount: z131.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
31376
- durationSeconds: z131.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
31599
+ videoAngleCount: z133.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
31600
+ durationSeconds: z133.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
31377
31601
  videoStructure: VideoStructureEnum.default("single_take"),
31378
31602
  videoQuality: VideoQualityEnum.default("economy"),
31379
31603
  videoResolution: VideoResolutionEnum.default("480p"),
31380
- productImageCount: z131.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
31604
+ productImageCount: z133.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
31381
31605
  outputs: ProductTaskOutputEnum.array().min(1).max(3).optional().describe('Solo para kind="product_task": los mismos outputs de create_product_task. Default: todos.'),
31382
- generateAiMusic: z131.boolean().optional(),
31606
+ generateAiMusic: z133.boolean().optional(),
31383
31607
  generateAiEdit: AiEditRequestSchema.optional(),
31384
- replicateWinnerWhenFound: z131.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.")
31608
+ replicateWinnerWhenFound: z133.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.")
31385
31609
  }).strict();
31386
31610
  function buildMarketStudyEstimateRequests(input) {
31387
31611
  const quotesVideo = input.kind === "video" || (input.outputs ?? [