@productmaker/mcp 6.8.2 → 6.9.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.
- package/dist/http.js +116 -4
- package/dist/stdio.js +116 -4
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -2677,6 +2677,7 @@ function getCurrencyForCountry(country) {
|
|
|
2677
2677
|
}
|
|
2678
2678
|
__name(getCurrencyForCountry, "getCurrencyForCountry");
|
|
2679
2679
|
var MAX_PLAUSIBLE_AMOUNT = 1e10;
|
|
2680
|
+
var KNOWN_CURRENCY_CODES = new Set(Object.values(CURRENCY_BY_COUNTRY).map((c) => c.code));
|
|
2680
2681
|
|
|
2681
2682
|
// ../../packages/types/src/shopify-publish-recovery.ts
|
|
2682
2683
|
var MAX_MONEY_LENGTH = 40;
|
|
@@ -5083,6 +5084,42 @@ var ShopifyPublishErrorResponse = z27.discriminatedUnion("code", [
|
|
|
5083
5084
|
code: z27.literal("SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR"),
|
|
5084
5085
|
action: z27.literal("open_editor"),
|
|
5085
5086
|
message: z27.string().optional()
|
|
5087
|
+
}),
|
|
5088
|
+
z27.object({
|
|
5089
|
+
/**
|
|
5090
|
+
* Code-landing publish refused BEFORE any product mutation: the shared
|
|
5091
|
+
* cl-landing template exists but the merchant has not saved the
|
|
5092
|
+
* code-landing-renderer app block, so the product page would render blank.
|
|
5093
|
+
* `themeEditorDeepLink` is the one-click fix — mandatory because without it
|
|
5094
|
+
* the client has nothing actionable to show.
|
|
5095
|
+
*/
|
|
5096
|
+
code: z27.literal("SHOPIFY_THEME_SETUP_REQUIRED"),
|
|
5097
|
+
message: z27.string().optional(),
|
|
5098
|
+
shopDomain: z27.string().optional(),
|
|
5099
|
+
themeEditorDeepLink: z27.string().url(),
|
|
5100
|
+
/**
|
|
5101
|
+
* Present when the request also carried a commerceCorrection that was
|
|
5102
|
+
* committed before the gate refused — the client must drop the stale
|
|
5103
|
+
* correction before retrying or it dies on CONTEXT_CHANGED.
|
|
5104
|
+
*/
|
|
5105
|
+
commerceCorrectionSaved: z27.literal(true).optional()
|
|
5106
|
+
})
|
|
5107
|
+
]);
|
|
5108
|
+
var CodeLandingThemeSetupResponse = z27.discriminatedUnion("status", [
|
|
5109
|
+
z27.object({
|
|
5110
|
+
/** The app block is saved (ready) or still missing (setup_required). */
|
|
5111
|
+
status: z27.enum([
|
|
5112
|
+
"ready",
|
|
5113
|
+
"setup_required"
|
|
5114
|
+
]),
|
|
5115
|
+
/** One-click theme-editor link that pre-adds the Code Landing block. */
|
|
5116
|
+
themeEditorDeepLink: z27.string().url(),
|
|
5117
|
+
shopDomain: z27.string()
|
|
5118
|
+
}),
|
|
5119
|
+
z27.object({
|
|
5120
|
+
/** Not a code-landing task — the gate does not apply. */
|
|
5121
|
+
status: z27.literal("not_applicable"),
|
|
5122
|
+
shopDomain: z27.string().optional()
|
|
5086
5123
|
})
|
|
5087
5124
|
]);
|
|
5088
5125
|
var ShopifyAuthUrlResponse = z27.object({
|
|
@@ -13047,6 +13084,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13047
13084
|
], [
|
|
13048
13085
|
"product_reference"
|
|
13049
13086
|
], [
|
|
13087
|
+
"task",
|
|
13088
|
+
"product",
|
|
13050
13089
|
"landing"
|
|
13051
13090
|
], SHARED_CHANNEL_EXPOSURE, [
|
|
13052
13091
|
{
|
|
@@ -13144,6 +13183,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13144
13183
|
], [
|
|
13145
13184
|
"product_reference"
|
|
13146
13185
|
], [
|
|
13186
|
+
"task",
|
|
13187
|
+
"creative",
|
|
13147
13188
|
"video"
|
|
13148
13189
|
], SHARED_CHANNEL_EXPOSURE, [
|
|
13149
13190
|
{
|
|
@@ -14198,6 +14239,60 @@ import { z as z65 } from "zod";
|
|
|
14198
14239
|
|
|
14199
14240
|
// ../../packages/types/src/whatsapp-presentation-finalizer.ts
|
|
14200
14241
|
import { z as z64 } from "zod";
|
|
14242
|
+
var WhatsAppQuoteRecoveryChoiceSchema = z64.enum([
|
|
14243
|
+
"without_winner",
|
|
14244
|
+
"retry",
|
|
14245
|
+
"cancel"
|
|
14246
|
+
]);
|
|
14247
|
+
var recoveryBase = {
|
|
14248
|
+
version: z64.literal(1),
|
|
14249
|
+
requestHash: z64.string().min(1).max(256),
|
|
14250
|
+
issuedAt: z64.string().datetime(),
|
|
14251
|
+
expiresAt: z64.string().datetime(),
|
|
14252
|
+
offeredAlternative: z64.literal("without_winner").nullable()
|
|
14253
|
+
};
|
|
14254
|
+
var WhatsAppQuoteRecoveryReceiptSchema = z64.discriminatedUnion("state", [
|
|
14255
|
+
z64.object({
|
|
14256
|
+
...recoveryBase,
|
|
14257
|
+
state: z64.literal("open"),
|
|
14258
|
+
successorCommandId: z64.null(),
|
|
14259
|
+
choice: z64.null()
|
|
14260
|
+
}).strict(),
|
|
14261
|
+
z64.object({
|
|
14262
|
+
...recoveryBase,
|
|
14263
|
+
state: z64.literal("consumed"),
|
|
14264
|
+
successorCommandId: z64.string().uuid(),
|
|
14265
|
+
choice: z64.enum([
|
|
14266
|
+
"without_winner",
|
|
14267
|
+
"retry"
|
|
14268
|
+
])
|
|
14269
|
+
}).strict(),
|
|
14270
|
+
z64.object({
|
|
14271
|
+
...recoveryBase,
|
|
14272
|
+
state: z64.literal("awaiting_media"),
|
|
14273
|
+
successorCommandId: z64.null(),
|
|
14274
|
+
successorCollectionId: z64.string().uuid(),
|
|
14275
|
+
choice: z64.enum([
|
|
14276
|
+
"without_winner",
|
|
14277
|
+
"retry"
|
|
14278
|
+
])
|
|
14279
|
+
}).strict(),
|
|
14280
|
+
z64.object({
|
|
14281
|
+
...recoveryBase,
|
|
14282
|
+
state: z64.literal("cancelled"),
|
|
14283
|
+
successorCommandId: z64.null(),
|
|
14284
|
+
choice: z64.literal("cancel")
|
|
14285
|
+
}).strict()
|
|
14286
|
+
]).refine((receipt) => {
|
|
14287
|
+
const duration = Date.parse(receipt.expiresAt) - Date.parse(receipt.issuedAt);
|
|
14288
|
+
return duration > 0 && duration <= 24 * 60 * 60 * 1e3;
|
|
14289
|
+
}, "Recovery must expire within twenty-four hours");
|
|
14290
|
+
var WhatsAppQuoteBudgetResultSchema = z64.object({
|
|
14291
|
+
estimatedMinCredits: z64.number().finite().nonnegative(),
|
|
14292
|
+
estimatedMaxCredits: z64.number().finite().positive(),
|
|
14293
|
+
balanceCredits: z64.number().finite(),
|
|
14294
|
+
budgetRecovery: WhatsAppQuoteRecoveryReceiptSchema.optional()
|
|
14295
|
+
}).strict().refine((result) => result.estimatedMinCredits <= result.estimatedMaxCredits, "Minimum budget cannot exceed maximum");
|
|
14201
14296
|
var json = z64.lazy(() => z64.union([
|
|
14202
14297
|
z64.null(),
|
|
14203
14298
|
z64.boolean(),
|
|
@@ -14228,6 +14323,12 @@ function sameJson(a, b) {
|
|
|
14228
14323
|
__name(sameJson, "sameJson");
|
|
14229
14324
|
var WhatsAppPresentationFinalizerSchema = z64.object({
|
|
14230
14325
|
command: z64.discriminatedUnion("kind", [
|
|
14326
|
+
z64.object({
|
|
14327
|
+
...proposedSnapshot,
|
|
14328
|
+
kind: z64.literal("reject_quote"),
|
|
14329
|
+
errorCode: z64.literal("insufficient_balance"),
|
|
14330
|
+
result: WhatsAppQuoteBudgetResultSchema
|
|
14331
|
+
}).strict(),
|
|
14231
14332
|
z64.object({
|
|
14232
14333
|
...proposedSnapshot,
|
|
14233
14334
|
kind: z64.literal("reject_command"),
|
|
@@ -14287,7 +14388,7 @@ var WhatsAppPresentationFinalizerSchema = z64.object({
|
|
|
14287
14388
|
expiresAt: z64.string().datetime()
|
|
14288
14389
|
}).strict().optional()
|
|
14289
14390
|
}).strict().superRefine((value, ctx) => {
|
|
14290
|
-
if (value.command?.kind === "reject_command" || value.command?.kind === "complete_cancel") {
|
|
14391
|
+
if (value.command?.kind === "reject_command" || value.command?.kind === "reject_quote" || value.command?.kind === "complete_cancel") {
|
|
14291
14392
|
if (value.plan || value.collection) ctx.addIssue({
|
|
14292
14393
|
code: z64.ZodIssueCode.custom,
|
|
14293
14394
|
message: "Proposed command finalizers cannot bind plans or collections"
|
|
@@ -14296,6 +14397,13 @@ var WhatsAppPresentationFinalizerSchema = z64.object({
|
|
|
14296
14397
|
code: z64.ZodIssueCode.custom,
|
|
14297
14398
|
message: "Rejection must preserve the original result"
|
|
14298
14399
|
});
|
|
14400
|
+
if (value.command.kind === "reject_quote") {
|
|
14401
|
+
const receipt = value.command.result.budgetRecovery;
|
|
14402
|
+
if (receipt && (receipt.requestHash !== value.command.requestHash || receipt.state !== "open")) ctx.addIssue({
|
|
14403
|
+
code: z64.ZodIssueCode.custom,
|
|
14404
|
+
message: "Budget recovery must be new and bound to the rejected request"
|
|
14405
|
+
});
|
|
14406
|
+
}
|
|
14299
14407
|
}
|
|
14300
14408
|
if (!value.command && !value.plan && !value.collection) ctx.addIssue({
|
|
14301
14409
|
code: z64.ZodIssueCode.custom,
|
|
@@ -16081,7 +16189,7 @@ var ApiClient = class {
|
|
|
16081
16189
|
};
|
|
16082
16190
|
|
|
16083
16191
|
// src/index.ts
|
|
16084
|
-
var MCP_VERSION = "6.
|
|
16192
|
+
var MCP_VERSION = "6.9.0";
|
|
16085
16193
|
|
|
16086
16194
|
// src/meta-upload-app.ts
|
|
16087
16195
|
import { readFileSync } from "fs";
|
|
@@ -17199,6 +17307,7 @@ var McpErrorCode = {
|
|
|
17199
17307
|
SHOPIFY_PUBLISH_INPUT_REQUIRED: "SHOPIFY_PUBLISH_INPUT_REQUIRED",
|
|
17200
17308
|
SHOPIFY_PUBLISH_CONTEXT_CHANGED: "SHOPIFY_PUBLISH_CONTEXT_CHANGED",
|
|
17201
17309
|
SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR: "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR",
|
|
17310
|
+
SHOPIFY_THEME_SETUP_REQUIRED: "SHOPIFY_THEME_SETUP_REQUIRED",
|
|
17202
17311
|
// Meta / Facebook Ads
|
|
17203
17312
|
META_NO_FB_PAGE: "META_NO_FB_PAGE",
|
|
17204
17313
|
META_PORTFOLIO_MISMATCH: "META_PORTFOLIO_MISMATCH",
|
|
@@ -17269,6 +17378,7 @@ var CODE_MESSAGES = {
|
|
|
17269
17378
|
SHOPIFY_PUBLISH_INPUT_REQUIRED: "Review every recovery issue with the seller. Ask for missing prices and confirm the exact currency, unit price and pack totals before resending commerceCorrection with confirmed:true. Never invent amounts, convert currency or remove an offer.",
|
|
17270
17379
|
SHOPIFY_PUBLISH_CONTEXT_CHANGED: "The publication context changed. Reopen the task in ProductMaker, review the current store, product and landing revision, and obtain fresh confirmation. Do not reuse this correction.",
|
|
17271
17380
|
SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR: "Open the landing editor in ProductMaker to reconcile the visible offer with checkout prices. The correction was not saved; do not retry it automatically or regenerate the landing without approval.",
|
|
17381
|
+
SHOPIFY_THEME_SETUP_REQUIRED: "The store's Shopify theme is missing the ProductMaker 'Code Landing' app block \u2014 publishing now would create a product whose page renders blank. Send the user the themeEditorDeepLink (in error data) to open the Shopify theme editor, have them confirm the Code Landing block is added and press Save, then retry publishing. This is a one-time step per store; nothing was published.",
|
|
17272
17382
|
SHOPIFY_NO_PUBLISHED_THEME: "The Shopify store has no published theme, so there is nowhere to place the landing. Ask the user to publish a theme (Online Store > Themes > Publish) and retry.",
|
|
17273
17383
|
SHOPIFY_THEME_STRUCTURE_UNSUPPORTED: "The active Shopify theme contains an HTML structure ProductMaker cannot process safely. Ask the user to restore a valid layout/theme.liquid or contact ProductMaker support to correct the theme, then retry.",
|
|
17274
17384
|
// Meta — high-frequency
|
|
@@ -17462,6 +17572,7 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
17462
17572
|
McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED,
|
|
17463
17573
|
McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED,
|
|
17464
17574
|
McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR,
|
|
17575
|
+
McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED,
|
|
17465
17576
|
McpErrorCode.TIKTOK_NOT_CONNECTED,
|
|
17466
17577
|
McpErrorCode.NO_SHOPIFY_SHOPS,
|
|
17467
17578
|
McpErrorCode.NO_META_AD_ACCOUNTS
|
|
@@ -17609,13 +17720,14 @@ function translateError(err) {
|
|
|
17609
17720
|
}
|
|
17610
17721
|
if (err instanceof ApiHttpError) {
|
|
17611
17722
|
const body = isRecord2(err.body) ? err.body : {};
|
|
17612
|
-
if (body.code === McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR || body.code === McpErrorCode.SHOPIFY_PUBLISH_FAILED) {
|
|
17723
|
+
if (body.code === McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR || body.code === McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_FAILED) {
|
|
17613
17724
|
const parsed = ShopifyPublishErrorResponse.safeParse(body);
|
|
17614
17725
|
if (!parsed.success) return mcp(McpErrorCode.INTERNAL, resolveMessage(McpErrorCode.INTERNAL, void 0));
|
|
17615
17726
|
const details = parsed.data;
|
|
17616
17727
|
const extra = {};
|
|
17617
17728
|
if (details.code === "SHOPIFY_PUBLISH_INPUT_REQUIRED") extra.recovery = details.recovery;
|
|
17618
17729
|
if (details.code === "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR") extra.action = details.action;
|
|
17730
|
+
if (details.code === "SHOPIFY_THEME_SETUP_REQUIRED") extra.themeEditorDeepLink = details.themeEditorDeepLink;
|
|
17619
17731
|
const saved = "commerceCorrectionSaved" in details && details.commerceCorrectionSaved === true;
|
|
17620
17732
|
if (saved) extra.commerceCorrectionSaved = true;
|
|
17621
17733
|
const message = resolveMessage(body.code, void 0);
|
|
@@ -20889,7 +21001,7 @@ var TikTokInput = z76.object({
|
|
|
20889
21001
|
});
|
|
20890
21002
|
function registerPublishTools(server, api, opts = {}) {
|
|
20891
21003
|
const transport = opts.transport ?? "http";
|
|
20892
|
-
server.tool("publish_to_shopify", 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. Un contexto obsoleto requiere volver a revisar; open_editor requiere el editor de ProductMaker. 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.", ShopifyInput.shape, OVERWRITES_EXTERNAL, async (input, extra) => {
|
|
21004
|
+
server.tool("publish_to_shopify", 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. Un contexto obsoleto requiere volver a revisar; open_editor requiere el editor de ProductMaker. 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.", ShopifyInput.shape, OVERWRITES_EXTERNAL, async (input, extra) => {
|
|
20893
21005
|
try {
|
|
20894
21006
|
const parsed = parseShopifyInput(input);
|
|
20895
21007
|
if (parsed.publicationMode === "existing" && !parsed.targetProductId) {
|
package/dist/stdio.js
CHANGED
|
@@ -2699,6 +2699,7 @@ function getCurrencyForCountry(country) {
|
|
|
2699
2699
|
}
|
|
2700
2700
|
__name(getCurrencyForCountry, "getCurrencyForCountry");
|
|
2701
2701
|
var MAX_PLAUSIBLE_AMOUNT = 1e10;
|
|
2702
|
+
var KNOWN_CURRENCY_CODES = new Set(Object.values(CURRENCY_BY_COUNTRY).map((c) => c.code));
|
|
2702
2703
|
|
|
2703
2704
|
// ../../packages/types/src/shopify-publish-recovery.ts
|
|
2704
2705
|
var MAX_MONEY_LENGTH = 40;
|
|
@@ -5105,6 +5106,42 @@ var ShopifyPublishErrorResponse = z27.discriminatedUnion("code", [
|
|
|
5105
5106
|
code: z27.literal("SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR"),
|
|
5106
5107
|
action: z27.literal("open_editor"),
|
|
5107
5108
|
message: z27.string().optional()
|
|
5109
|
+
}),
|
|
5110
|
+
z27.object({
|
|
5111
|
+
/**
|
|
5112
|
+
* Code-landing publish refused BEFORE any product mutation: the shared
|
|
5113
|
+
* cl-landing template exists but the merchant has not saved the
|
|
5114
|
+
* code-landing-renderer app block, so the product page would render blank.
|
|
5115
|
+
* `themeEditorDeepLink` is the one-click fix — mandatory because without it
|
|
5116
|
+
* the client has nothing actionable to show.
|
|
5117
|
+
*/
|
|
5118
|
+
code: z27.literal("SHOPIFY_THEME_SETUP_REQUIRED"),
|
|
5119
|
+
message: z27.string().optional(),
|
|
5120
|
+
shopDomain: z27.string().optional(),
|
|
5121
|
+
themeEditorDeepLink: z27.string().url(),
|
|
5122
|
+
/**
|
|
5123
|
+
* Present when the request also carried a commerceCorrection that was
|
|
5124
|
+
* committed before the gate refused — the client must drop the stale
|
|
5125
|
+
* correction before retrying or it dies on CONTEXT_CHANGED.
|
|
5126
|
+
*/
|
|
5127
|
+
commerceCorrectionSaved: z27.literal(true).optional()
|
|
5128
|
+
})
|
|
5129
|
+
]);
|
|
5130
|
+
var CodeLandingThemeSetupResponse = z27.discriminatedUnion("status", [
|
|
5131
|
+
z27.object({
|
|
5132
|
+
/** The app block is saved (ready) or still missing (setup_required). */
|
|
5133
|
+
status: z27.enum([
|
|
5134
|
+
"ready",
|
|
5135
|
+
"setup_required"
|
|
5136
|
+
]),
|
|
5137
|
+
/** One-click theme-editor link that pre-adds the Code Landing block. */
|
|
5138
|
+
themeEditorDeepLink: z27.string().url(),
|
|
5139
|
+
shopDomain: z27.string()
|
|
5140
|
+
}),
|
|
5141
|
+
z27.object({
|
|
5142
|
+
/** Not a code-landing task — the gate does not apply. */
|
|
5143
|
+
status: z27.literal("not_applicable"),
|
|
5144
|
+
shopDomain: z27.string().optional()
|
|
5108
5145
|
})
|
|
5109
5146
|
]);
|
|
5110
5147
|
var ShopifyAuthUrlResponse = z27.object({
|
|
@@ -13069,6 +13106,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13069
13106
|
], [
|
|
13070
13107
|
"product_reference"
|
|
13071
13108
|
], [
|
|
13109
|
+
"task",
|
|
13110
|
+
"product",
|
|
13072
13111
|
"landing"
|
|
13073
13112
|
], SHARED_CHANNEL_EXPOSURE, [
|
|
13074
13113
|
{
|
|
@@ -13166,6 +13205,8 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13166
13205
|
], [
|
|
13167
13206
|
"product_reference"
|
|
13168
13207
|
], [
|
|
13208
|
+
"task",
|
|
13209
|
+
"creative",
|
|
13169
13210
|
"video"
|
|
13170
13211
|
], SHARED_CHANNEL_EXPOSURE, [
|
|
13171
13212
|
{
|
|
@@ -13966,6 +14007,60 @@ import { z as z65 } from "zod";
|
|
|
13966
14007
|
|
|
13967
14008
|
// ../../packages/types/src/whatsapp-presentation-finalizer.ts
|
|
13968
14009
|
import { z as z64 } from "zod";
|
|
14010
|
+
var WhatsAppQuoteRecoveryChoiceSchema = z64.enum([
|
|
14011
|
+
"without_winner",
|
|
14012
|
+
"retry",
|
|
14013
|
+
"cancel"
|
|
14014
|
+
]);
|
|
14015
|
+
var recoveryBase = {
|
|
14016
|
+
version: z64.literal(1),
|
|
14017
|
+
requestHash: z64.string().min(1).max(256),
|
|
14018
|
+
issuedAt: z64.string().datetime(),
|
|
14019
|
+
expiresAt: z64.string().datetime(),
|
|
14020
|
+
offeredAlternative: z64.literal("without_winner").nullable()
|
|
14021
|
+
};
|
|
14022
|
+
var WhatsAppQuoteRecoveryReceiptSchema = z64.discriminatedUnion("state", [
|
|
14023
|
+
z64.object({
|
|
14024
|
+
...recoveryBase,
|
|
14025
|
+
state: z64.literal("open"),
|
|
14026
|
+
successorCommandId: z64.null(),
|
|
14027
|
+
choice: z64.null()
|
|
14028
|
+
}).strict(),
|
|
14029
|
+
z64.object({
|
|
14030
|
+
...recoveryBase,
|
|
14031
|
+
state: z64.literal("consumed"),
|
|
14032
|
+
successorCommandId: z64.string().uuid(),
|
|
14033
|
+
choice: z64.enum([
|
|
14034
|
+
"without_winner",
|
|
14035
|
+
"retry"
|
|
14036
|
+
])
|
|
14037
|
+
}).strict(),
|
|
14038
|
+
z64.object({
|
|
14039
|
+
...recoveryBase,
|
|
14040
|
+
state: z64.literal("awaiting_media"),
|
|
14041
|
+
successorCommandId: z64.null(),
|
|
14042
|
+
successorCollectionId: z64.string().uuid(),
|
|
14043
|
+
choice: z64.enum([
|
|
14044
|
+
"without_winner",
|
|
14045
|
+
"retry"
|
|
14046
|
+
])
|
|
14047
|
+
}).strict(),
|
|
14048
|
+
z64.object({
|
|
14049
|
+
...recoveryBase,
|
|
14050
|
+
state: z64.literal("cancelled"),
|
|
14051
|
+
successorCommandId: z64.null(),
|
|
14052
|
+
choice: z64.literal("cancel")
|
|
14053
|
+
}).strict()
|
|
14054
|
+
]).refine((receipt) => {
|
|
14055
|
+
const duration = Date.parse(receipt.expiresAt) - Date.parse(receipt.issuedAt);
|
|
14056
|
+
return duration > 0 && duration <= 24 * 60 * 60 * 1e3;
|
|
14057
|
+
}, "Recovery must expire within twenty-four hours");
|
|
14058
|
+
var WhatsAppQuoteBudgetResultSchema = z64.object({
|
|
14059
|
+
estimatedMinCredits: z64.number().finite().nonnegative(),
|
|
14060
|
+
estimatedMaxCredits: z64.number().finite().positive(),
|
|
14061
|
+
balanceCredits: z64.number().finite(),
|
|
14062
|
+
budgetRecovery: WhatsAppQuoteRecoveryReceiptSchema.optional()
|
|
14063
|
+
}).strict().refine((result) => result.estimatedMinCredits <= result.estimatedMaxCredits, "Minimum budget cannot exceed maximum");
|
|
13969
14064
|
var json = z64.lazy(() => z64.union([
|
|
13970
14065
|
z64.null(),
|
|
13971
14066
|
z64.boolean(),
|
|
@@ -13996,6 +14091,12 @@ function sameJson(a, b) {
|
|
|
13996
14091
|
__name(sameJson, "sameJson");
|
|
13997
14092
|
var WhatsAppPresentationFinalizerSchema = z64.object({
|
|
13998
14093
|
command: z64.discriminatedUnion("kind", [
|
|
14094
|
+
z64.object({
|
|
14095
|
+
...proposedSnapshot,
|
|
14096
|
+
kind: z64.literal("reject_quote"),
|
|
14097
|
+
errorCode: z64.literal("insufficient_balance"),
|
|
14098
|
+
result: WhatsAppQuoteBudgetResultSchema
|
|
14099
|
+
}).strict(),
|
|
13999
14100
|
z64.object({
|
|
14000
14101
|
...proposedSnapshot,
|
|
14001
14102
|
kind: z64.literal("reject_command"),
|
|
@@ -14055,7 +14156,7 @@ var WhatsAppPresentationFinalizerSchema = z64.object({
|
|
|
14055
14156
|
expiresAt: z64.string().datetime()
|
|
14056
14157
|
}).strict().optional()
|
|
14057
14158
|
}).strict().superRefine((value, ctx) => {
|
|
14058
|
-
if (value.command?.kind === "reject_command" || value.command?.kind === "complete_cancel") {
|
|
14159
|
+
if (value.command?.kind === "reject_command" || value.command?.kind === "reject_quote" || value.command?.kind === "complete_cancel") {
|
|
14059
14160
|
if (value.plan || value.collection) ctx.addIssue({
|
|
14060
14161
|
code: z64.ZodIssueCode.custom,
|
|
14061
14162
|
message: "Proposed command finalizers cannot bind plans or collections"
|
|
@@ -14064,6 +14165,13 @@ var WhatsAppPresentationFinalizerSchema = z64.object({
|
|
|
14064
14165
|
code: z64.ZodIssueCode.custom,
|
|
14065
14166
|
message: "Rejection must preserve the original result"
|
|
14066
14167
|
});
|
|
14168
|
+
if (value.command.kind === "reject_quote") {
|
|
14169
|
+
const receipt = value.command.result.budgetRecovery;
|
|
14170
|
+
if (receipt && (receipt.requestHash !== value.command.requestHash || receipt.state !== "open")) ctx.addIssue({
|
|
14171
|
+
code: z64.ZodIssueCode.custom,
|
|
14172
|
+
message: "Budget recovery must be new and bound to the rejected request"
|
|
14173
|
+
});
|
|
14174
|
+
}
|
|
14067
14175
|
}
|
|
14068
14176
|
if (!value.command && !value.plan && !value.collection) ctx.addIssue({
|
|
14069
14177
|
code: z64.ZodIssueCode.custom,
|
|
@@ -14460,7 +14568,7 @@ var ApiClient = class {
|
|
|
14460
14568
|
};
|
|
14461
14569
|
|
|
14462
14570
|
// src/index.ts
|
|
14463
|
-
var MCP_VERSION = "6.
|
|
14571
|
+
var MCP_VERSION = "6.9.0";
|
|
14464
14572
|
|
|
14465
14573
|
// src/meta-upload-app.ts
|
|
14466
14574
|
import { readFileSync } from "fs";
|
|
@@ -15578,6 +15686,7 @@ var McpErrorCode = {
|
|
|
15578
15686
|
SHOPIFY_PUBLISH_INPUT_REQUIRED: "SHOPIFY_PUBLISH_INPUT_REQUIRED",
|
|
15579
15687
|
SHOPIFY_PUBLISH_CONTEXT_CHANGED: "SHOPIFY_PUBLISH_CONTEXT_CHANGED",
|
|
15580
15688
|
SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR: "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR",
|
|
15689
|
+
SHOPIFY_THEME_SETUP_REQUIRED: "SHOPIFY_THEME_SETUP_REQUIRED",
|
|
15581
15690
|
// Meta / Facebook Ads
|
|
15582
15691
|
META_NO_FB_PAGE: "META_NO_FB_PAGE",
|
|
15583
15692
|
META_PORTFOLIO_MISMATCH: "META_PORTFOLIO_MISMATCH",
|
|
@@ -15648,6 +15757,7 @@ var CODE_MESSAGES = {
|
|
|
15648
15757
|
SHOPIFY_PUBLISH_INPUT_REQUIRED: "Review every recovery issue with the seller. Ask for missing prices and confirm the exact currency, unit price and pack totals before resending commerceCorrection with confirmed:true. Never invent amounts, convert currency or remove an offer.",
|
|
15649
15758
|
SHOPIFY_PUBLISH_CONTEXT_CHANGED: "The publication context changed. Reopen the task in ProductMaker, review the current store, product and landing revision, and obtain fresh confirmation. Do not reuse this correction.",
|
|
15650
15759
|
SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR: "Open the landing editor in ProductMaker to reconcile the visible offer with checkout prices. The correction was not saved; do not retry it automatically or regenerate the landing without approval.",
|
|
15760
|
+
SHOPIFY_THEME_SETUP_REQUIRED: "The store's Shopify theme is missing the ProductMaker 'Code Landing' app block \u2014 publishing now would create a product whose page renders blank. Send the user the themeEditorDeepLink (in error data) to open the Shopify theme editor, have them confirm the Code Landing block is added and press Save, then retry publishing. This is a one-time step per store; nothing was published.",
|
|
15651
15761
|
SHOPIFY_NO_PUBLISHED_THEME: "The Shopify store has no published theme, so there is nowhere to place the landing. Ask the user to publish a theme (Online Store > Themes > Publish) and retry.",
|
|
15652
15762
|
SHOPIFY_THEME_STRUCTURE_UNSUPPORTED: "The active Shopify theme contains an HTML structure ProductMaker cannot process safely. Ask the user to restore a valid layout/theme.liquid or contact ProductMaker support to correct the theme, then retry.",
|
|
15653
15763
|
// Meta — high-frequency
|
|
@@ -15841,6 +15951,7 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
15841
15951
|
McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED,
|
|
15842
15952
|
McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED,
|
|
15843
15953
|
McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR,
|
|
15954
|
+
McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED,
|
|
15844
15955
|
McpErrorCode.TIKTOK_NOT_CONNECTED,
|
|
15845
15956
|
McpErrorCode.NO_SHOPIFY_SHOPS,
|
|
15846
15957
|
McpErrorCode.NO_META_AD_ACCOUNTS
|
|
@@ -15988,13 +16099,14 @@ function translateError(err) {
|
|
|
15988
16099
|
}
|
|
15989
16100
|
if (err instanceof ApiHttpError) {
|
|
15990
16101
|
const body = isRecord2(err.body) ? err.body : {};
|
|
15991
|
-
if (body.code === McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR || body.code === McpErrorCode.SHOPIFY_PUBLISH_FAILED) {
|
|
16102
|
+
if (body.code === McpErrorCode.SHOPIFY_PUBLISH_INPUT_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CONTEXT_CHANGED || body.code === McpErrorCode.SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR || body.code === McpErrorCode.SHOPIFY_THEME_SETUP_REQUIRED || body.code === McpErrorCode.SHOPIFY_PUBLISH_FAILED) {
|
|
15992
16103
|
const parsed = ShopifyPublishErrorResponse.safeParse(body);
|
|
15993
16104
|
if (!parsed.success) return mcp(McpErrorCode.INTERNAL, resolveMessage(McpErrorCode.INTERNAL, void 0));
|
|
15994
16105
|
const details = parsed.data;
|
|
15995
16106
|
const extra = {};
|
|
15996
16107
|
if (details.code === "SHOPIFY_PUBLISH_INPUT_REQUIRED") extra.recovery = details.recovery;
|
|
15997
16108
|
if (details.code === "SHOPIFY_PUBLISH_CORRECTION_REQUIRES_EDITOR") extra.action = details.action;
|
|
16109
|
+
if (details.code === "SHOPIFY_THEME_SETUP_REQUIRED") extra.themeEditorDeepLink = details.themeEditorDeepLink;
|
|
15998
16110
|
const saved = "commerceCorrectionSaved" in details && details.commerceCorrectionSaved === true;
|
|
15999
16111
|
if (saved) extra.commerceCorrectionSaved = true;
|
|
16000
16112
|
const message = resolveMessage(body.code, void 0);
|
|
@@ -19321,7 +19433,7 @@ var TikTokInput = z75.object({
|
|
|
19321
19433
|
});
|
|
19322
19434
|
function registerPublishTools(server, api, opts = {}) {
|
|
19323
19435
|
const transport = opts.transport ?? "http";
|
|
19324
|
-
server.tool("publish_to_shopify", 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. Un contexto obsoleto requiere volver a revisar; open_editor requiere el editor de ProductMaker. 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.", ShopifyInput.shape, OVERWRITES_EXTERNAL, async (input, extra) => {
|
|
19436
|
+
server.tool("publish_to_shopify", 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. Un contexto obsoleto requiere volver a revisar; open_editor requiere el editor de ProductMaker. 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.", ShopifyInput.shape, OVERWRITES_EXTERNAL, async (input, extra) => {
|
|
19325
19437
|
try {
|
|
19326
19438
|
const parsed = parseShopifyInput(input);
|
|
19327
19439
|
if (parsed.publicationMode === "existing" && !parsed.targetProductId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Product Maker MCP server — cost products, generate dropshipping landing pages, UGC videos, and ad creatives, and publish to Shopify and Meta Ads from Claude, ChatGPT, or Gemini.",
|