@productmaker/mcp 12.7.0 → 12.8.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 (3) hide show
  1. package/dist/http.js +60 -13
  2. package/dist/stdio.js +60 -13
  3. package/package.json +3 -3
package/dist/http.js CHANGED
@@ -8352,6 +8352,7 @@ var LandingAssetRequestSchema = z23.discriminatedUnion("kind", [
8352
8352
  var CodeLandingTypographySchema = z23.object({
8353
8353
  googleFamilies: z23.array(z23.string().regex(/^[A-Za-z0-9 ]+(:wght@[0-9;]+)?$/)).max(4)
8354
8354
  }).strict();
8355
+ var MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS = 96;
8355
8356
  var CodeLandingAuthorEnvelopeSchema = z23.object({
8356
8357
  mode: LandingDocumentModeSchema,
8357
8358
  document: CodeLandingDocumentSchema,
@@ -8359,7 +8360,7 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
8359
8360
  anchors: z23.array(CodeLandingAnchorSchema).min(1).max(64),
8360
8361
  components: z23.array(ComponentManifestEntrySchema).max(64),
8361
8362
  interactions: z23.array(InteractionProgramSchema).max(64),
8362
- assetRequests: z23.array(LandingAssetRequestSchema).max(96),
8363
+ assetRequests: z23.array(LandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS),
8363
8364
  /** Optional: only the block library authoring path (compose.ts) sets this. */
8364
8365
  typography: CodeLandingTypographySchema.optional(),
8365
8366
  /**
@@ -8380,6 +8381,12 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
8380
8381
  */
8381
8382
  variantFacts: z23.array(LandingVariantFactSchema).max(16).optional()
8382
8383
  });
8384
+ var PreparedLandingAssetRequestSchema = z23.union(LandingAssetRequestSchema.options.map((schema) => schema.shape.kind.value === "generate" || schema.shape.kind.value === "adapt_reference" ? schema.extend({
8385
+ prompt: z23.string().min(1)
8386
+ }) : schema));
8387
+ var CodeLandingPreparedAuthorEnvelopeSchema = CodeLandingAuthorEnvelopeSchema.extend({
8388
+ assetRequests: z23.array(PreparedLandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS)
8389
+ });
8383
8390
  var CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND = "code_landing_deferred_author_provider_v1";
8384
8391
  var CodeLandingDeferredAuthorProviderResultSchema = z23.object({
8385
8392
  kind: z23.literal(CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND),
@@ -14140,6 +14147,10 @@ var StatusResponse = z49.object({
14140
14147
  /** Backend-owned guidance. Render verbatim instead of inspecting provider errors. */
14141
14148
  userMessage: z49.string().min(1).max(500).optional()
14142
14149
  }).optional(),
14150
+ /** Credits-cents handed back on this task: automatic error/expiry and
14151
+ * partial-delivery refunds from the ledger plus approved quality-report
14152
+ * refunds. Absent when nothing was refunded. Drives «+X créditos devueltos». */
14153
+ refundedCents: BillingNonNegativeAmount.optional(),
14143
14154
  /** Persisted target country (ISO 3166-1 alpha-2 or country name) used to pre-fill
14144
14155
  * campaign target geo when creating Meta ads from this task. */
14145
14156
  targetCountry: z49.string().optional(),
@@ -14381,6 +14392,9 @@ var TaskSummary = z49.object({
14381
14392
  * normal users. Multiply by CREDITS_PER_USD_CENT on the client to render
14382
14393
  * credits. */
14383
14394
  spentCents: BillingNonNegativeAmount.optional(),
14395
+ /** Credits-cents handed back on this task (same source as
14396
+ * `StatusResponse.refundedCents`), for every viewer. Absent when 0. */
14397
+ refundedCents: BillingNonNegativeAmount.optional(),
14384
14398
  product: z49.object({
14385
14399
  /** Absent for tasks with no scraped Product (free-mode video): those
14386
14400
  * carry only a thumbnail. Clients fall back to a "pending" label. */
@@ -24873,7 +24887,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24873
24887
  ], [
24874
24888
  "meta_publication"
24875
24889
  ]),
24876
- defineCapability("publish_to_shopify", "00c4c7af09bb45a72896118ca154a2dc9518f05d74bb9386c825be541fa10fdb", "external_mutation", "publishing", [
24890
+ defineCapability("publish_to_shopify", "655a4e7e2d57493c38972ae31f7fcd0bba154abc7e42f30a74151253cedf59d3", "external_mutation", "publishing", [
24877
24891
  "external_mutation",
24878
24892
  "state_change"
24879
24893
  ], [
@@ -24883,7 +24897,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24883
24897
  slot("shop", true, [
24884
24898
  "shopDomain"
24885
24899
  ]),
24900
+ // WhatsApp's publish schema has no GIF opt-out; only MCP exposes it.
24886
24901
  slot("landing_selection", false, [
24902
+ "numLandingImages",
24903
+ "includeLandingGif"
24904
+ ], [
24887
24905
  "numLandingImages"
24888
24906
  ]),
24889
24907
  slot("variant_selection", false, [
@@ -31738,7 +31756,7 @@ var ApiClient = class {
31738
31756
  };
31739
31757
 
31740
31758
  // src/index.ts
31741
- var MCP_VERSION = "12.7.0";
31759
+ var MCP_VERSION = "12.8.0";
31742
31760
 
31743
31761
  // src/meta-upload-app.ts
31744
31762
  import { readFileSync } from "fs";
@@ -39235,6 +39253,9 @@ var ShopifyInput = z149.object({
39235
39253
  /** Add an announcement bar text above add-to-cart (optional). */
39236
39254
  announcementBarEnabled: z149.boolean().optional(),
39237
39255
  announcementBarText: z149.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
39256
+ /** Default true: publish the task's QA-passed landing GIF, as the web
39257
+ * editor does when the seller keeps it selected. false omits it. */
39258
+ includeLandingGif: z149.boolean().optional(),
39238
39259
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
39239
39260
  confirmed: z149.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
39240
39261
  });
@@ -39541,7 +39562,7 @@ var TikTokInput = z149.object({
39541
39562
  function registerPublishTools(server, api, opts = {}) {
39542
39563
  const transport = opts.transport ?? "http";
39543
39564
  server.registerTool("publish_to_shopify", {
39544
- description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
39565
+ description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. Tambi\xE9n publica el GIF de la landing si la tarea tiene uno aprobado por QA; pasa `includeLandingGif: false` s\xF3lo si el usuario no lo quiere. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
39545
39566
  inputSchema: ShopifyInput.shape,
39546
39567
  // Publication reaches the public storefront, beyond private account data.
39547
39568
  annotations: {
@@ -39563,7 +39584,21 @@ function registerPublishTools(server, api, opts = {}) {
39563
39584
  };
39564
39585
  }
39565
39586
  const variantIndex = parsed.variantIndex ?? 0;
39566
- const availableImages = await fetchLandingImageCount(api, parsed.taskId);
39587
+ const defaults = await fetchLandingPublishDefaults(api, parsed.taskId);
39588
+ const includeLandingGif = parsed.includeLandingGif !== false;
39589
+ if (!defaults && includeLandingGif) {
39590
+ return {
39591
+ isError: true,
39592
+ content: [
39593
+ {
39594
+ type: "text",
39595
+ text: "No pude leer los resultados de la tarea para incluir su GIF; nada se public\xF3. Reintenta, o pasa includeLandingGif: false para publicar sin GIF."
39596
+ }
39597
+ ]
39598
+ };
39599
+ }
39600
+ const availableImages = defaults?.imageCount ?? 0;
39601
+ const selectedLandingGif = includeLandingGif ? defaults?.gif ?? null : null;
39567
39602
  const effectiveAvailable = availableImages > 0 ? availableImages : 3;
39568
39603
  const numImages = Math.min(parsed.numLandingImages ?? effectiveAvailable, effectiveAvailable, SHOPIFY_MAX_LANDING_IMAGES);
39569
39604
  const selectedLandingImages = Array.from({
@@ -39580,6 +39615,9 @@ function registerPublishTools(server, api, opts = {}) {
39580
39615
  }),
39581
39616
  shopDomain: parsed.shopDomain,
39582
39617
  selectedLandingImages,
39618
+ ...selectedLandingGif ? {
39619
+ selectedLandingGif
39620
+ } : {},
39583
39621
  showVariantPicker: parsed.showVariantPicker,
39584
39622
  publicationMode: parsed.publicationMode,
39585
39623
  targetProductId: parsed.targetProductId,
@@ -39867,19 +39905,28 @@ function renderBundleMappingMarkdown(mapping) {
39867
39905
  }
39868
39906
  }
39869
39907
  __name(renderBundleMappingMarkdown, "renderBundleMappingMarkdown");
39870
- async function fetchLandingImageCount(api, taskId) {
39908
+ async function fetchLandingPublishDefaults(api, taskId) {
39871
39909
  try {
39872
39910
  const r = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}`);
39873
- if (!isRecord3(r)) return 0;
39874
- const landing = r.landing;
39875
- if (!isRecord3(landing)) return 0;
39876
- const images = landing.images;
39877
- return Array.isArray(images) ? images.length : 0;
39911
+ if (!isRecord3(r) || !isRecord3(r.landing)) return {
39912
+ imageCount: 0,
39913
+ gif: null
39914
+ };
39915
+ const images = r.landing.images;
39916
+ const demo = LandingGifReadableSchema.safeParse(r.landing.demoGif);
39917
+ const gif = demo.success && demo.data.ownerTaskId === taskId && demo.data.quality.verdict === "passed" ? {
39918
+ ownerTaskId: taskId,
39919
+ gifRevision: demo.data.gifRevision
39920
+ } : null;
39921
+ return {
39922
+ imageCount: Array.isArray(images) ? images.length : 0,
39923
+ gif
39924
+ };
39878
39925
  } catch {
39879
- return 0;
39926
+ return null;
39880
39927
  }
39881
39928
  }
39882
- __name(fetchLandingImageCount, "fetchLandingImageCount");
39929
+ __name(fetchLandingPublishDefaults, "fetchLandingPublishDefaults");
39883
39930
  function toMetaCampaignOverrides(cfg) {
39884
39931
  const out = {};
39885
39932
  if (cfg.dailyBudgetUsd !== void 0) out.dailyBudgetUsd = cfg.dailyBudgetUsd;
package/dist/stdio.js CHANGED
@@ -8127,6 +8127,7 @@ var LandingAssetRequestSchema = z23.discriminatedUnion("kind", [
8127
8127
  var CodeLandingTypographySchema = z23.object({
8128
8128
  googleFamilies: z23.array(z23.string().regex(/^[A-Za-z0-9 ]+(:wght@[0-9;]+)?$/)).max(4)
8129
8129
  }).strict();
8130
+ var MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS = 96;
8130
8131
  var CodeLandingAuthorEnvelopeSchema = z23.object({
8131
8132
  mode: LandingDocumentModeSchema,
8132
8133
  document: CodeLandingDocumentSchema,
@@ -8134,7 +8135,7 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
8134
8135
  anchors: z23.array(CodeLandingAnchorSchema).min(1).max(64),
8135
8136
  components: z23.array(ComponentManifestEntrySchema).max(64),
8136
8137
  interactions: z23.array(InteractionProgramSchema).max(64),
8137
- assetRequests: z23.array(LandingAssetRequestSchema).max(96),
8138
+ assetRequests: z23.array(LandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS),
8138
8139
  /** Optional: only the block library authoring path (compose.ts) sets this. */
8139
8140
  typography: CodeLandingTypographySchema.optional(),
8140
8141
  /**
@@ -8155,6 +8156,12 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
8155
8156
  */
8156
8157
  variantFacts: z23.array(LandingVariantFactSchema).max(16).optional()
8157
8158
  });
8159
+ var PreparedLandingAssetRequestSchema = z23.union(LandingAssetRequestSchema.options.map((schema) => schema.shape.kind.value === "generate" || schema.shape.kind.value === "adapt_reference" ? schema.extend({
8160
+ prompt: z23.string().min(1)
8161
+ }) : schema));
8162
+ var CodeLandingPreparedAuthorEnvelopeSchema = CodeLandingAuthorEnvelopeSchema.extend({
8163
+ assetRequests: z23.array(PreparedLandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS)
8164
+ });
8158
8165
  var CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND = "code_landing_deferred_author_provider_v1";
8159
8166
  var CodeLandingDeferredAuthorProviderResultSchema = z23.object({
8160
8167
  kind: z23.literal(CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND),
@@ -13915,6 +13922,10 @@ var StatusResponse = z49.object({
13915
13922
  /** Backend-owned guidance. Render verbatim instead of inspecting provider errors. */
13916
13923
  userMessage: z49.string().min(1).max(500).optional()
13917
13924
  }).optional(),
13925
+ /** Credits-cents handed back on this task: automatic error/expiry and
13926
+ * partial-delivery refunds from the ledger plus approved quality-report
13927
+ * refunds. Absent when nothing was refunded. Drives «+X créditos devueltos». */
13928
+ refundedCents: BillingNonNegativeAmount.optional(),
13918
13929
  /** Persisted target country (ISO 3166-1 alpha-2 or country name) used to pre-fill
13919
13930
  * campaign target geo when creating Meta ads from this task. */
13920
13931
  targetCountry: z49.string().optional(),
@@ -14156,6 +14167,9 @@ var TaskSummary = z49.object({
14156
14167
  * normal users. Multiply by CREDITS_PER_USD_CENT on the client to render
14157
14168
  * credits. */
14158
14169
  spentCents: BillingNonNegativeAmount.optional(),
14170
+ /** Credits-cents handed back on this task (same source as
14171
+ * `StatusResponse.refundedCents`), for every viewer. Absent when 0. */
14172
+ refundedCents: BillingNonNegativeAmount.optional(),
14159
14173
  product: z49.object({
14160
14174
  /** Absent for tasks with no scraped Product (free-mode video): those
14161
14175
  * carry only a thumbnail. Clients fall back to a "pending" label. */
@@ -24648,7 +24662,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24648
24662
  ], [
24649
24663
  "meta_publication"
24650
24664
  ]),
24651
- defineCapability("publish_to_shopify", "00c4c7af09bb45a72896118ca154a2dc9518f05d74bb9386c825be541fa10fdb", "external_mutation", "publishing", [
24665
+ defineCapability("publish_to_shopify", "655a4e7e2d57493c38972ae31f7fcd0bba154abc7e42f30a74151253cedf59d3", "external_mutation", "publishing", [
24652
24666
  "external_mutation",
24653
24667
  "state_change"
24654
24668
  ], [
@@ -24658,7 +24672,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24658
24672
  slot("shop", true, [
24659
24673
  "shopDomain"
24660
24674
  ]),
24675
+ // WhatsApp's publish schema has no GIF opt-out; only MCP exposes it.
24661
24676
  slot("landing_selection", false, [
24677
+ "numLandingImages",
24678
+ "includeLandingGif"
24679
+ ], [
24662
24680
  "numLandingImages"
24663
24681
  ]),
24664
24682
  slot("variant_selection", false, [
@@ -30065,7 +30083,7 @@ var ApiClient = class {
30065
30083
  };
30066
30084
 
30067
30085
  // src/index.ts
30068
- var MCP_VERSION = "12.7.0";
30086
+ var MCP_VERSION = "12.8.0";
30069
30087
 
30070
30088
  // src/meta-upload-app.ts
30071
30089
  import { readFileSync } from "fs";
@@ -37720,6 +37738,9 @@ var ShopifyInput = z148.object({
37720
37738
  /** Add an announcement bar text above add-to-cart (optional). */
37721
37739
  announcementBarEnabled: z148.boolean().optional(),
37722
37740
  announcementBarText: z148.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
37741
+ /** Default true: publish the task's QA-passed landing GIF, as the web
37742
+ * editor does when the seller keeps it selected. false omits it. */
37743
+ includeLandingGif: z148.boolean().optional(),
37723
37744
  commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
37724
37745
  confirmed: z148.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
37725
37746
  });
@@ -38026,7 +38047,7 @@ var TikTokInput = z148.object({
38026
38047
  function registerPublishTools(server, api, opts = {}) {
38027
38048
  const transport = opts.transport ?? "http";
38028
38049
  server.registerTool("publish_to_shopify", {
38029
- description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
38050
+ description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. Tambi\xE9n publica el GIF de la landing si la tarea tiene uno aprobado por QA; pasa `includeLandingGif: false` s\xF3lo si el usuario no lo quiere. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
38030
38051
  inputSchema: ShopifyInput.shape,
38031
38052
  // Publication reaches the public storefront, beyond private account data.
38032
38053
  annotations: {
@@ -38048,7 +38069,21 @@ function registerPublishTools(server, api, opts = {}) {
38048
38069
  };
38049
38070
  }
38050
38071
  const variantIndex = parsed.variantIndex ?? 0;
38051
- const availableImages = await fetchLandingImageCount(api, parsed.taskId);
38072
+ const defaults = await fetchLandingPublishDefaults(api, parsed.taskId);
38073
+ const includeLandingGif = parsed.includeLandingGif !== false;
38074
+ if (!defaults && includeLandingGif) {
38075
+ return {
38076
+ isError: true,
38077
+ content: [
38078
+ {
38079
+ type: "text",
38080
+ text: "No pude leer los resultados de la tarea para incluir su GIF; nada se public\xF3. Reintenta, o pasa includeLandingGif: false para publicar sin GIF."
38081
+ }
38082
+ ]
38083
+ };
38084
+ }
38085
+ const availableImages = defaults?.imageCount ?? 0;
38086
+ const selectedLandingGif = includeLandingGif ? defaults?.gif ?? null : null;
38052
38087
  const effectiveAvailable = availableImages > 0 ? availableImages : 3;
38053
38088
  const numImages = Math.min(parsed.numLandingImages ?? effectiveAvailable, effectiveAvailable, SHOPIFY_MAX_LANDING_IMAGES);
38054
38089
  const selectedLandingImages = Array.from({
@@ -38065,6 +38100,9 @@ function registerPublishTools(server, api, opts = {}) {
38065
38100
  }),
38066
38101
  shopDomain: parsed.shopDomain,
38067
38102
  selectedLandingImages,
38103
+ ...selectedLandingGif ? {
38104
+ selectedLandingGif
38105
+ } : {},
38068
38106
  showVariantPicker: parsed.showVariantPicker,
38069
38107
  publicationMode: parsed.publicationMode,
38070
38108
  targetProductId: parsed.targetProductId,
@@ -38352,19 +38390,28 @@ function renderBundleMappingMarkdown(mapping) {
38352
38390
  }
38353
38391
  }
38354
38392
  __name(renderBundleMappingMarkdown, "renderBundleMappingMarkdown");
38355
- async function fetchLandingImageCount(api, taskId) {
38393
+ async function fetchLandingPublishDefaults(api, taskId) {
38356
38394
  try {
38357
38395
  const r = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}`);
38358
- if (!isRecord3(r)) return 0;
38359
- const landing = r.landing;
38360
- if (!isRecord3(landing)) return 0;
38361
- const images = landing.images;
38362
- return Array.isArray(images) ? images.length : 0;
38396
+ if (!isRecord3(r) || !isRecord3(r.landing)) return {
38397
+ imageCount: 0,
38398
+ gif: null
38399
+ };
38400
+ const images = r.landing.images;
38401
+ const demo = LandingGifReadableSchema.safeParse(r.landing.demoGif);
38402
+ const gif = demo.success && demo.data.ownerTaskId === taskId && demo.data.quality.verdict === "passed" ? {
38403
+ ownerTaskId: taskId,
38404
+ gifRevision: demo.data.gifRevision
38405
+ } : null;
38406
+ return {
38407
+ imageCount: Array.isArray(images) ? images.length : 0,
38408
+ gif
38409
+ };
38363
38410
  } catch {
38364
- return 0;
38411
+ return null;
38365
38412
  }
38366
38413
  }
38367
- __name(fetchLandingImageCount, "fetchLandingImageCount");
38414
+ __name(fetchLandingPublishDefaults, "fetchLandingPublishDefaults");
38368
38415
  function toMetaCampaignOverrides(cfg) {
38369
38416
  const out = {};
38370
38417
  if (cfg.dailyBudgetUsd !== void 0) out.dailyBudgetUsd = cfg.dailyBudgetUsd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "12.7.0",
3
+ "version": "12.8.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "ProductMaker MCP server — cost products, generate landing pages, UGC videos, and ad creatives, and publish to Shopify, Meta Ads, and TikTok Ads.",
@@ -67,8 +67,8 @@
67
67
  "typescript": "^7.0.2",
68
68
  "vitest": "5.0.3",
69
69
  "@packages/product-economics": "0.1.0",
70
- "@packages/utils": "0.1.0",
71
- "@packages/types": "0.1.0"
70
+ "@packages/types": "0.1.0",
71
+ "@packages/utils": "0.1.0"
72
72
  },
73
73
  "publishConfig": {
74
74
  "access": "public"