@productmaker/mcp 8.13.1 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/http.js +226 -139
- package/dist/stdio.js +226 -139
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ separate release step.
|
|
|
137
137
|
| `get_task_status` | Check task progress (optional `waitSeconds` for near-sync polling) |
|
|
138
138
|
| `list_tasks` | List recent tasks |
|
|
139
139
|
| `edit_task_draft` | Edit angle / pain point / persona before generation |
|
|
140
|
-
| `create_service_video` |
|
|
140
|
+
| `create_service_video` | **Hidden from the MCP since 9.0.0** (owner decision 2026-10-08, still on WhatsApp): use `create_animated_video` for a service video. |
|
|
141
141
|
| `create_animated_video` | Animated _service_ video ("Video animado", motion graphics: text, shapes and the site's visual identity, music, no presenter) from its landing page URL. Choose `format` (vertical/square/horizontal), `durationSec` (10/15/30/45/60), `language` (es/en/pt) and optional `notes`. **Paid action** — flat price by duration (listed in the tool description, refunded on failure); takes minutes in a queue. Follow it with `get_task_status` (stage, queue position, render %, activity, preview, final MP4). In closed testing: other accounts get `FEATURE_NOT_AVAILABLE` |
|
|
142
142
|
| `generate_video_creative` | Standalone UGC video creative |
|
|
143
143
|
| `generate_free_video` | One free-form video from an exact prompt/script, optionally with a reference image (async: returns a `taskId`) |
|
|
@@ -390,7 +390,7 @@ Release metadata synchronized with per-store Meta controls. MCP tool inputs, res
|
|
|
390
390
|
|
|
391
391
|
### 8.3.0 — Idempotencia de tools pagadas + refresh OAuth
|
|
392
392
|
|
|
393
|
-
- Tools pagadas (`create_product_task`, `
|
|
393
|
+
- Tools pagadas (`create_product_task`, `create_animated_video` (sin `notes` en la llave), `generate_video_creative`, `generate_free_video`, `generate_image_creatives`, `generate_landing`, `create_creative_variant`): envían un `Idempotency-Key` derivado de los argumentos semánticos (ventana de 15 min). Un reintento con los mismos argumentos devuelve la misma tarea (`replayed: true`) sin segundo cargo; una tarea en `error` sí se reintenta.
|
|
394
394
|
- OAuth alojado: se anuncia `offline_access` + grant `refresh_token`; un token a punto de expirar responde `401` + `WWW-Authenticate` para que el host refresque en silencio (`MCP_SUBJECT_TOKEN_REAUTH_WINDOW_MS`, por defecto 180000; `0` lo desactiva).
|
|
395
395
|
|
|
396
396
|
### 8.2.0 — Fase 3 (modelos)
|
package/dist/http.js
CHANGED
|
@@ -13912,7 +13912,7 @@ var CAPABILITY_MODEL_GUIDANCE = {
|
|
|
13912
13912
|
"mes en curso"
|
|
13913
13913
|
],
|
|
13914
13914
|
disclosures: [
|
|
13915
|
-
"
|
|
13915
|
+
"ventas, costos o publicidad desconocidos: utilidad INCOMPLETA"
|
|
13916
13916
|
]
|
|
13917
13917
|
},
|
|
13918
13918
|
sync_shopify_orders: {
|
|
@@ -13988,7 +13988,7 @@ var CAPABILITY_MODEL_GUIDANCE = {
|
|
|
13988
13988
|
"es gasto de anuncios: usa set_ad_spend"
|
|
13989
13989
|
],
|
|
13990
13990
|
defaults: [
|
|
13991
|
-
"mes
|
|
13991
|
+
"mes de la operaci\xF3n; misma etiqueta REEMPLAZA el total compartido y conserva el reparto"
|
|
13992
13992
|
],
|
|
13993
13993
|
disclosures: [
|
|
13994
13994
|
"requiere confirmaci\xF3n; sin gastos escritos la utilidad sale mas alta"
|
|
@@ -14318,6 +14318,73 @@ var LinkableCampaignsResponseSchema = z66.object({
|
|
|
14318
14318
|
|
|
14319
14319
|
// ../../packages/types/src/finance-operation.ts
|
|
14320
14320
|
import { z as z67 } from "zod";
|
|
14321
|
+
|
|
14322
|
+
// ../../packages/types/src/dropi-countries.ts
|
|
14323
|
+
var DROPI_COUNTRY_CODES = [
|
|
14324
|
+
"CO",
|
|
14325
|
+
"EC",
|
|
14326
|
+
"VE",
|
|
14327
|
+
"MX",
|
|
14328
|
+
"PE",
|
|
14329
|
+
"PA",
|
|
14330
|
+
"PY",
|
|
14331
|
+
"GT",
|
|
14332
|
+
"CL",
|
|
14333
|
+
"AR",
|
|
14334
|
+
"CR"
|
|
14335
|
+
];
|
|
14336
|
+
|
|
14337
|
+
// ../../packages/types/src/finance-country-timezones.ts
|
|
14338
|
+
var FINANCE_COUNTRY_TIME_ZONES = Object.freeze({
|
|
14339
|
+
US: "America/New_York",
|
|
14340
|
+
CA: "America/Toronto",
|
|
14341
|
+
BZ: "America/Belize",
|
|
14342
|
+
SV: "America/El_Salvador",
|
|
14343
|
+
HN: "America/Tegucigalpa",
|
|
14344
|
+
NI: "America/Managua",
|
|
14345
|
+
CU: "America/Havana",
|
|
14346
|
+
DO: "America/Santo_Domingo",
|
|
14347
|
+
HT: "America/Port-au-Prince",
|
|
14348
|
+
JM: "America/Jamaica",
|
|
14349
|
+
PR: "America/Puerto_Rico",
|
|
14350
|
+
TT: "America/Port_of_Spain",
|
|
14351
|
+
BO: "America/La_Paz",
|
|
14352
|
+
BR: "America/Sao_Paulo",
|
|
14353
|
+
UY: "America/Montevideo",
|
|
14354
|
+
ES: "Europe/Madrid",
|
|
14355
|
+
FR: "Europe/Paris",
|
|
14356
|
+
DE: "Europe/Berlin",
|
|
14357
|
+
IT: "Europe/Rome",
|
|
14358
|
+
PT: "Europe/Lisbon",
|
|
14359
|
+
NL: "Europe/Amsterdam",
|
|
14360
|
+
BE: "Europe/Brussels",
|
|
14361
|
+
AT: "Europe/Vienna",
|
|
14362
|
+
IE: "Europe/Dublin",
|
|
14363
|
+
LU: "Europe/Luxembourg",
|
|
14364
|
+
GB: "Europe/London",
|
|
14365
|
+
CH: "Europe/Zurich",
|
|
14366
|
+
SE: "Europe/Stockholm",
|
|
14367
|
+
NO: "Europe/Oslo",
|
|
14368
|
+
DK: "Europe/Copenhagen",
|
|
14369
|
+
FI: "Europe/Helsinki",
|
|
14370
|
+
IS: "Atlantic/Reykjavik",
|
|
14371
|
+
PL: "Europe/Warsaw",
|
|
14372
|
+
CZ: "Europe/Prague",
|
|
14373
|
+
HU: "Europe/Budapest",
|
|
14374
|
+
RO: "Europe/Bucharest",
|
|
14375
|
+
BG: "Europe/Sofia",
|
|
14376
|
+
HR: "Europe/Zagreb",
|
|
14377
|
+
SI: "Europe/Ljubljana",
|
|
14378
|
+
SK: "Europe/Bratislava",
|
|
14379
|
+
GR: "Europe/Athens",
|
|
14380
|
+
MT: "Europe/Malta",
|
|
14381
|
+
CY: "Asia/Nicosia",
|
|
14382
|
+
EE: "Europe/Tallinn",
|
|
14383
|
+
LV: "Europe/Riga",
|
|
14384
|
+
LT: "Europe/Vilnius"
|
|
14385
|
+
});
|
|
14386
|
+
|
|
14387
|
+
// ../../packages/types/src/finance-operation.ts
|
|
14321
14388
|
var CreateFinanceOperationSchema = z67.object({
|
|
14322
14389
|
countryCode: z67.string().length(2).toUpperCase(),
|
|
14323
14390
|
/** Cómo la llama ella. Vacío ⇒ se usa el nombre del país. */
|
|
@@ -14342,6 +14409,7 @@ var MonthlyPLQuerySchema = z67.object({
|
|
|
14342
14409
|
var RESERVED_EXPENSE_LABEL_PREFIX = "__ad_spend__";
|
|
14343
14410
|
var isReservedExpenseLabel = /* @__PURE__ */ __name((label) => label.trim().startsWith(RESERVED_EXPENSE_LABEL_PREFIX), "isReservedExpenseLabel");
|
|
14344
14411
|
var SaveMonthlyExpenseSchema = z67.object({
|
|
14412
|
+
operationId: z67.string().uuid().optional(),
|
|
14345
14413
|
month: z67.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
|
|
14346
14414
|
label: z67.string().trim().min(1).max(80).refine((label) => !isReservedExpenseLabel(label), {
|
|
14347
14415
|
message: "reserved_expense_label"
|
|
@@ -14351,13 +14419,14 @@ var SaveMonthlyExpenseSchema = z67.object({
|
|
|
14351
14419
|
allocations: z67.array(z67.object({
|
|
14352
14420
|
operationId: z67.string().uuid(),
|
|
14353
14421
|
sharePct: z67.number().int().min(1).max(100)
|
|
14354
|
-
})).min(1).refine((allocations) => allocations.reduce((sum, one) => sum + one.sharePct, 0)
|
|
14422
|
+
})).min(1).refine((allocations) => allocations.reduce((sum, one) => sum + one.sharePct, 0) <= 100, {
|
|
14355
14423
|
message: "allocations_must_sum_to_100"
|
|
14356
14424
|
}).refine((allocations) => new Set(allocations.map((one) => one.operationId)).size === allocations.length, {
|
|
14357
14425
|
message: "duplicate_operation_in_allocations"
|
|
14358
14426
|
}).optional()
|
|
14359
14427
|
}).strict();
|
|
14360
14428
|
var DeleteMonthlyExpenseSchema = z67.object({
|
|
14429
|
+
operationId: z67.string().uuid().optional(),
|
|
14361
14430
|
month: z67.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
|
|
14362
14431
|
label: z67.string().trim().min(1).max(80).refine((label) => !isReservedExpenseLabel(label), {
|
|
14363
14432
|
message: "reserved_expense_label"
|
|
@@ -14369,6 +14438,7 @@ var SetAdSpendSchema = z67.object({
|
|
|
14369
14438
|
amount: z67.number().finite().min(0).nullable()
|
|
14370
14439
|
}).strict();
|
|
14371
14440
|
var MonthlyExpensesQuerySchema = z67.object({
|
|
14441
|
+
operationId: z67.string().uuid().optional(),
|
|
14372
14442
|
month: z67.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional()
|
|
14373
14443
|
}).strict();
|
|
14374
14444
|
|
|
@@ -15274,44 +15344,58 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
15274
15344
|
"product"
|
|
15275
15345
|
]
|
|
15276
15346
|
),
|
|
15277
|
-
defineCapability(
|
|
15347
|
+
defineCapability(
|
|
15348
|
+
"create_service_video",
|
|
15349
|
+
"c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21",
|
|
15278
15350
|
"credit_consuming",
|
|
15279
|
-
"
|
|
15280
|
-
|
|
15281
|
-
|
|
15282
|
-
"
|
|
15283
|
-
]
|
|
15284
|
-
|
|
15285
|
-
"
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
"
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
"
|
|
15292
|
-
|
|
15293
|
-
|
|
15294
|
-
"
|
|
15295
|
-
|
|
15296
|
-
|
|
15297
|
-
"
|
|
15298
|
-
|
|
15299
|
-
|
|
15300
|
-
"
|
|
15301
|
-
|
|
15302
|
-
|
|
15303
|
-
|
|
15304
|
-
|
|
15305
|
-
|
|
15306
|
-
|
|
15307
|
-
"
|
|
15308
|
-
|
|
15309
|
-
|
|
15310
|
-
|
|
15311
|
-
|
|
15312
|
-
|
|
15313
|
-
|
|
15314
|
-
|
|
15351
|
+
"creative",
|
|
15352
|
+
[
|
|
15353
|
+
"credit_consuming",
|
|
15354
|
+
"state_change"
|
|
15355
|
+
],
|
|
15356
|
+
[
|
|
15357
|
+
slot("service_landing", true, [
|
|
15358
|
+
"landingUrl"
|
|
15359
|
+
]),
|
|
15360
|
+
slot("locale", true, [
|
|
15361
|
+
"language"
|
|
15362
|
+
]),
|
|
15363
|
+
slot("service_context", false, [
|
|
15364
|
+
"additionalContext"
|
|
15365
|
+
]),
|
|
15366
|
+
slot("voice", false, [
|
|
15367
|
+
"voiceId"
|
|
15368
|
+
]),
|
|
15369
|
+
slot("brand", false, [
|
|
15370
|
+
"brandId"
|
|
15371
|
+
]),
|
|
15372
|
+
slot("review_mode", false, [
|
|
15373
|
+
"reviewMode"
|
|
15374
|
+
]),
|
|
15375
|
+
slot("video_preset", false, [
|
|
15376
|
+
"videoPreset"
|
|
15377
|
+
]),
|
|
15378
|
+
// MCP-only for now: WhatsApp's service flow keeps the economy default.
|
|
15379
|
+
slot("video_quality", false, [
|
|
15380
|
+
"videoQuality"
|
|
15381
|
+
], []),
|
|
15382
|
+
slot("video_resolution", false, [
|
|
15383
|
+
"videoResolution"
|
|
15384
|
+
], [])
|
|
15385
|
+
],
|
|
15386
|
+
[
|
|
15387
|
+
"service_context"
|
|
15388
|
+
],
|
|
15389
|
+
[
|
|
15390
|
+
"task",
|
|
15391
|
+
"video"
|
|
15392
|
+
],
|
|
15393
|
+
// Owner decision 2026-10-08: the presenter service video is hidden from the
|
|
15394
|
+
// MCP for now — dropshipping sellers ordered it for products and cancelled.
|
|
15395
|
+
// MCP clients get `create_animated_video` instead. Flip back to
|
|
15396
|
+
// SHARED_CHANNEL_EXPOSURE to restore it.
|
|
15397
|
+
WHATSAPP_ONLY_CHANNEL_EXPOSURE
|
|
15398
|
+
),
|
|
15315
15399
|
defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
|
|
15316
15400
|
"credit_consuming",
|
|
15317
15401
|
"state_change"
|
|
@@ -18066,10 +18150,16 @@ var RegenerateVideoScriptCapabilityRequest = z80.object({
|
|
|
18066
18150
|
|
|
18067
18151
|
// ../../packages/types/src/dropi-financial.ts
|
|
18068
18152
|
import { z as z81 } from "zod";
|
|
18153
|
+
var DropiCountrySchema = z81.enum(DROPI_COUNTRY_CODES);
|
|
18154
|
+
var DropiCountryQuerySchema = z81.object({
|
|
18155
|
+
countryCode: DropiCountrySchema.default("CO")
|
|
18156
|
+
}).strict();
|
|
18069
18157
|
var ConnectDropiFinancialSchema = z81.object({
|
|
18158
|
+
countryCode: DropiCountrySchema.default("CO"),
|
|
18070
18159
|
integrationKey: z81.string().trim().min(1).max(4096).regex(/^[\x21-\x7e]+$/)
|
|
18071
18160
|
}).strict();
|
|
18072
18161
|
var SyncDropiFinancialSchema = z81.object({
|
|
18162
|
+
countryCode: DropiCountrySchema.optional(),
|
|
18073
18163
|
operationId: z81.string().uuid().optional(),
|
|
18074
18164
|
since: z81.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
18075
18165
|
until: z81.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
@@ -18077,7 +18167,8 @@ var SyncDropiFinancialSchema = z81.object({
|
|
|
18077
18167
|
var DropiFinancialStatusSchema = z81.object({
|
|
18078
18168
|
enabled: z81.boolean(),
|
|
18079
18169
|
connected: z81.boolean(),
|
|
18080
|
-
countryCode:
|
|
18170
|
+
countryCode: DropiCountrySchema,
|
|
18171
|
+
enabledCountries: z81.array(DropiCountrySchema).optional(),
|
|
18081
18172
|
environment: z81.enum([
|
|
18082
18173
|
"sandbox",
|
|
18083
18174
|
"production"
|
|
@@ -19789,7 +19880,7 @@ var ApiClient = class {
|
|
|
19789
19880
|
};
|
|
19790
19881
|
|
|
19791
19882
|
// src/index.ts
|
|
19792
|
-
var MCP_VERSION = "
|
|
19883
|
+
var MCP_VERSION = "9.0.1";
|
|
19793
19884
|
|
|
19794
19885
|
// src/meta-upload-app.ts
|
|
19795
19886
|
import { readFileSync } from "fs";
|
|
@@ -22338,7 +22429,7 @@ function renderAnimatedVideoStatus(result) {
|
|
|
22338
22429
|
__name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
|
|
22339
22430
|
function registerAnimatedVideoTools(server, api) {
|
|
22340
22431
|
server.registerTool("create_animated_video", {
|
|
22341
|
-
description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo.
|
|
22432
|
+
description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
|
|
22342
22433
|
inputSchema: CreateAnimatedVideoInput.shape,
|
|
22343
22434
|
annotations: CREATES_PAID_OPEN_WORLD
|
|
22344
22435
|
}, async (input) => {
|
|
@@ -22443,7 +22534,7 @@ function renderCreateProductTaskAvoidWhenForMcp(fragment) {
|
|
|
22443
22534
|
__name(renderCreateProductTaskAvoidWhenForMcp, "renderCreateProductTaskAvoidWhenForMcp");
|
|
22444
22535
|
var createProductTaskDefaultDescription = renderCreateProductTaskDefaultForMcp(createProductTaskGuidance.defaults[0]);
|
|
22445
22536
|
var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenForMcp(createProductTaskGuidance.avoidWhen[0]);
|
|
22446
|
-
var
|
|
22537
|
+
var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
|
|
22447
22538
|
var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
|
|
22448
22539
|
var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
|
|
22449
22540
|
var CreateProductTaskInput = z87.object({
|
|
@@ -22878,7 +22969,7 @@ async function fetchAnimatedVideoResult(api, taskId, signal, serviceMode = void
|
|
|
22878
22969
|
}
|
|
22879
22970
|
}
|
|
22880
22971
|
__name(fetchAnimatedVideoResult, "fetchAnimatedVideoResult");
|
|
22881
|
-
function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
|
|
22972
|
+
function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http", serviceVideo = CREATE_SERVICE_VIDEO_ON_MCP } = {}) {
|
|
22882
22973
|
server.registerTool("create_product_task", {
|
|
22883
22974
|
description: createProductTaskGuidance.summary + ` ${createProductTaskDefaultDescription} \xDAsala cuando el usuario pide todo o varios outputs, no creando tareas individuales. Usa images para solicitudes directas. Usa projectId \xFAnicamente si el usuario pidi\xF3 expl\xEDcitamente continuar el proyecto guiado que acaba de costear; nunca busques, infieras ni menciones proyectos previos.
|
|
22884
22975
|
|
|
@@ -23001,97 +23092,100 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
23001
23092
|
throw translateError(e);
|
|
23002
23093
|
}
|
|
23003
23094
|
});
|
|
23004
|
-
|
|
23005
|
-
|
|
23006
|
-
|
|
23007
|
-
|
|
23008
|
-
|
|
23009
|
-
|
|
23010
|
-
|
|
23011
|
-
|
|
23012
|
-
|
|
23013
|
-
|
|
23014
|
-
|
|
23015
|
-
|
|
23016
|
-
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23020
|
-
|
|
23021
|
-
|
|
23022
|
-
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
|
|
23033
|
-
|
|
23034
|
-
|
|
23035
|
-
|
|
23036
|
-
|
|
23037
|
-
|
|
23038
|
-
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
|
|
23042
|
-
|
|
23043
|
-
|
|
23044
|
-
|
|
23045
|
-
|
|
23046
|
-
|
|
23047
|
-
|
|
23048
|
-
|
|
23049
|
-
|
|
23050
|
-
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
if (
|
|
23054
|
-
|
|
23055
|
-
|
|
23056
|
-
|
|
23057
|
-
|
|
23095
|
+
if (serviceVideo) {
|
|
23096
|
+
const createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
|
|
23097
|
+
server.registerTool("create_service_video", {
|
|
23098
|
+
description: createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.",
|
|
23099
|
+
inputSchema: CreateServiceVideoInput.shape,
|
|
23100
|
+
annotations: CREATES_PAID_OPEN_WORLD
|
|
23101
|
+
}, async (input) => {
|
|
23102
|
+
try {
|
|
23103
|
+
if (input.videoQuality === "medium" && input.videoResolution === "720p") {
|
|
23104
|
+
throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
|
|
23105
|
+
}
|
|
23106
|
+
await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
|
|
23107
|
+
const created = await api.postJson("/v2/ingest", {
|
|
23108
|
+
taskType: "service",
|
|
23109
|
+
serviceLandingUrl: input.landingUrl,
|
|
23110
|
+
...input.additionalContext ? {
|
|
23111
|
+
additionalContext: input.additionalContext
|
|
23112
|
+
} : {},
|
|
23113
|
+
lang: input.language,
|
|
23114
|
+
...input.voiceId ? {
|
|
23115
|
+
voiceId: input.voiceId
|
|
23116
|
+
} : {},
|
|
23117
|
+
videoPreset: input.videoPreset,
|
|
23118
|
+
videoQuality: input.videoQuality,
|
|
23119
|
+
videoResolution: input.videoResolution,
|
|
23120
|
+
reviewMode: input.reviewMode,
|
|
23121
|
+
...input.brandId ? {
|
|
23122
|
+
brandId: input.brandId
|
|
23123
|
+
} : {},
|
|
23124
|
+
media: {
|
|
23125
|
+
assets: []
|
|
23126
|
+
},
|
|
23127
|
+
appDemoVideos: []
|
|
23128
|
+
}, {
|
|
23129
|
+
// The 2026-09-25 incident: four retries of this exact tool created
|
|
23130
|
+
// four charged service tasks because the host rephrased
|
|
23131
|
+
// `additionalContext` and flipped the landing between `/` and
|
|
23132
|
+
// `/es`. The derived key is stable across both rewrites (see
|
|
23133
|
+
// request-key.ts).
|
|
23134
|
+
idempotencyKey: derivePaidRequestKey({
|
|
23135
|
+
fingerprint: api.fingerprint(),
|
|
23136
|
+
tool: "create_service_video",
|
|
23137
|
+
input,
|
|
23138
|
+
nowMs: Date.now()
|
|
23139
|
+
})
|
|
23140
|
+
});
|
|
23141
|
+
const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
|
|
23142
|
+
const first = angles[0];
|
|
23143
|
+
const replayed = created.replayed === true;
|
|
23144
|
+
if (input.reviewMode === "automatic") {
|
|
23145
|
+
if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
|
|
23146
|
+
if (!(replayed && created.status !== "queued")) {
|
|
23147
|
+
await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
|
|
23148
|
+
angleIds: [
|
|
23149
|
+
first.id
|
|
23150
|
+
]
|
|
23151
|
+
});
|
|
23152
|
+
}
|
|
23153
|
+
return asText({
|
|
23154
|
+
taskId: created.taskId,
|
|
23155
|
+
status: replayed ? created.status ?? "processing" : "processing",
|
|
23156
|
+
...replayed ? {
|
|
23157
|
+
replayed: true
|
|
23158
|
+
} : {},
|
|
23159
|
+
reviewMode: input.reviewMode,
|
|
23160
|
+
selectedConcept: first
|
|
23161
|
+
});
|
|
23162
|
+
}
|
|
23163
|
+
if (replayed && created.status !== "queued") {
|
|
23164
|
+
return asText({
|
|
23165
|
+
taskId: created.taskId,
|
|
23166
|
+
status: created.status,
|
|
23167
|
+
replayed: true,
|
|
23168
|
+
reviewMode: input.reviewMode,
|
|
23169
|
+
angles
|
|
23058
23170
|
});
|
|
23059
23171
|
}
|
|
23060
23172
|
return asText({
|
|
23061
23173
|
taskId: created.taskId,
|
|
23062
|
-
status:
|
|
23174
|
+
status: "waiting_for_user",
|
|
23063
23175
|
...replayed ? {
|
|
23064
23176
|
replayed: true
|
|
23065
23177
|
} : {},
|
|
23066
23178
|
reviewMode: input.reviewMode,
|
|
23067
|
-
|
|
23068
|
-
|
|
23069
|
-
|
|
23070
|
-
|
|
23071
|
-
return asText({
|
|
23072
|
-
taskId: created.taskId,
|
|
23073
|
-
status: created.status,
|
|
23074
|
-
replayed: true,
|
|
23075
|
-
reviewMode: input.reviewMode,
|
|
23076
|
-
angles
|
|
23179
|
+
pendingUserAction: {
|
|
23180
|
+
kind: "service_angle_approval",
|
|
23181
|
+
angles
|
|
23182
|
+
}
|
|
23077
23183
|
});
|
|
23184
|
+
} catch (e) {
|
|
23185
|
+
throw translateError(e);
|
|
23078
23186
|
}
|
|
23079
|
-
|
|
23080
|
-
|
|
23081
|
-
status: "waiting_for_user",
|
|
23082
|
-
...replayed ? {
|
|
23083
|
-
replayed: true
|
|
23084
|
-
} : {},
|
|
23085
|
-
reviewMode: input.reviewMode,
|
|
23086
|
-
pendingUserAction: {
|
|
23087
|
-
kind: "service_angle_approval",
|
|
23088
|
-
angles
|
|
23089
|
-
}
|
|
23090
|
-
});
|
|
23091
|
-
} catch (e) {
|
|
23092
|
-
throw translateError(e);
|
|
23093
|
-
}
|
|
23094
|
-
});
|
|
23187
|
+
});
|
|
23188
|
+
}
|
|
23095
23189
|
server.registerTool("verify_landing_commerce", {
|
|
23096
23190
|
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.",
|
|
23097
23191
|
inputSchema: {
|
|
@@ -27441,7 +27535,7 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
27441
27535
|
}
|
|
27442
27536
|
});
|
|
27443
27537
|
server.registerTool("get_finances", {
|
|
27444
|
-
description: getFinancesGuidance.summary + ' Contesta la pregunta que de verdad importa --- \xABeste negocio gana plata?\xBB --- con el mes armado: ventas totales y entregadas, fletes, costo de los productos, utilidad bruta, publicidad, gastos fijos y utilidad NETA. Esa utilidad es ANTES de impuestos y hay que decirlo asi: el contador es un gasto mas, no un calculo nuestro. Trae tambien los porcentajes contra sus metas. Si `costsKnown` viene en `false`, esos pedidos llegaron de una fuente que NO sabe cuanto costaron \u2014la tienda, o la API del proveedor\u2014 y la utilidad BRUTA esta incompleta: no es que el producto salga gratis. Si `adSpendKnown` viene en `false`, la publicidad NO se pudo leer y la utilidad esta INCOMPLETA: dilo antes de que alguien celebre un mes que perdio plata. `adSpendSource: "user"` significa que ella corrigio la cifra a mano, y eso se revisa distinto de una leida. Si `unconfirmedExpenses` es mayor que cero, ese monto viene heredado del mes pasado y ella no lo ha revisado. Es READ-ONLY: nunca pausa ni modifica una campana.',
|
|
27538
|
+
description: getFinancesGuidance.summary + ' Contesta la pregunta que de verdad importa --- \xABeste negocio gana plata?\xBB --- con el mes armado: ventas totales y entregadas, fletes, costo de los productos, utilidad bruta, publicidad, gastos fijos y utilidad NETA. Esa utilidad es ANTES de impuestos y hay que decirlo asi: el contador es un gasto mas, no un calculo nuestro. Trae tambien los porcentajes contra sus metas. Si `deliveredSalesKnown` no es true, faltan importes de ventas entregadas: la utilidad y los m\xE1rgenes no est\xE1n completos. `grossSalesKnown` distinto de true indica ventas totales parciales. Si `costsKnown` viene en `false`, esos pedidos llegaron de una fuente que NO sabe cuanto costaron \u2014la tienda, o la API del proveedor\u2014 y la utilidad BRUTA esta incompleta: no es que el producto salga gratis. Si `adSpendKnown` viene en `false`, la publicidad NO se pudo leer y la utilidad esta INCOMPLETA: dilo antes de que alguien celebre un mes que perdio plata. `adSpendSource: "user"` significa que ella corrigio la cifra a mano, y eso se revisa distinto de una leida. Si `unconfirmedExpenses` es mayor que cero, ese monto viene heredado del mes pasado y ella no lo ha revisado. Es READ-ONLY: nunca pausa ni modifica una campana.',
|
|
27445
27539
|
inputSchema: GetFinancesInput.shape,
|
|
27446
27540
|
annotations: READS_INTERNAL
|
|
27447
27541
|
}, async (input) => {
|
|
@@ -27528,23 +27622,16 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
27528
27622
|
}
|
|
27529
27623
|
});
|
|
27530
27624
|
server.registerTool("set_monthly_expense", {
|
|
27531
|
-
description: setMonthlyExpenseGuidance.summary + " Es un gasto FIJO: arriendo, sueldos, contador, plataformas \u2014 lo que se paga venda o no. Escribir la misma etiqueta otra vez REEMPLAZA el monto, no suma otro gasto. Sin gastos fijos escritos, la utilidad del mes sale siempre M\xC1S ALTA de lo que es, y ese es el error que nadie reclama. No lo uses para el gasto en anuncios: eso es set_ad_spend.",
|
|
27625
|
+
description: setMonthlyExpenseGuidance.summary + " El importe indicado es el TOTAL del gasto compartido existente; la parte de la operaci\xF3n se calcula conservando el reparto. Es un gasto FIJO: arriendo, sueldos, contador, plataformas \u2014 lo que se paga venda o no. Escribir la misma etiqueta otra vez REEMPLAZA el monto, no suma otro gasto. Sin gastos fijos escritos, la utilidad del mes sale siempre M\xC1S ALTA de lo que es, y ese es el error que nadie reclama. No lo uses para el gasto en anuncios: eso es set_ad_spend.",
|
|
27532
27626
|
inputSchema: SetMonthlyExpenseInput.shape,
|
|
27533
27627
|
annotations: OVERWRITES_INTERNAL
|
|
27534
27628
|
}, async (input) => {
|
|
27535
27629
|
try {
|
|
27536
|
-
const month = input.month ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 7);
|
|
27537
|
-
const operationId = input.operationId ?? (await api.getJson("/v1/product-control/operations"))[0]?.id;
|
|
27538
27630
|
return asText(await api.putJson("/v1/product-control/expenses", {
|
|
27539
|
-
month,
|
|
27631
|
+
month: input.month,
|
|
27632
|
+
operationId: input.operationId,
|
|
27540
27633
|
label: input.label,
|
|
27541
|
-
amount: input.amount
|
|
27542
|
-
allocations: operationId ? [
|
|
27543
|
-
{
|
|
27544
|
-
operationId,
|
|
27545
|
-
sharePct: 100
|
|
27546
|
-
}
|
|
27547
|
-
] : void 0
|
|
27634
|
+
amount: input.amount
|
|
27548
27635
|
}));
|
|
27549
27636
|
} catch (error) {
|
|
27550
27637
|
throw translateError(error);
|
|
@@ -27557,7 +27644,7 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
27557
27644
|
}, async (input) => {
|
|
27558
27645
|
try {
|
|
27559
27646
|
return asText(await api.putJson("/v1/product-control/ad-spend", {
|
|
27560
|
-
month: input.month
|
|
27647
|
+
month: input.month,
|
|
27561
27648
|
operationId: input.operationId,
|
|
27562
27649
|
amount: input.amount
|
|
27563
27650
|
}));
|
package/dist/stdio.js
CHANGED
|
@@ -13934,7 +13934,7 @@ var CAPABILITY_MODEL_GUIDANCE = {
|
|
|
13934
13934
|
"mes en curso"
|
|
13935
13935
|
],
|
|
13936
13936
|
disclosures: [
|
|
13937
|
-
"
|
|
13937
|
+
"ventas, costos o publicidad desconocidos: utilidad INCOMPLETA"
|
|
13938
13938
|
]
|
|
13939
13939
|
},
|
|
13940
13940
|
sync_shopify_orders: {
|
|
@@ -14010,7 +14010,7 @@ var CAPABILITY_MODEL_GUIDANCE = {
|
|
|
14010
14010
|
"es gasto de anuncios: usa set_ad_spend"
|
|
14011
14011
|
],
|
|
14012
14012
|
defaults: [
|
|
14013
|
-
"mes
|
|
14013
|
+
"mes de la operaci\xF3n; misma etiqueta REEMPLAZA el total compartido y conserva el reparto"
|
|
14014
14014
|
],
|
|
14015
14015
|
disclosures: [
|
|
14016
14016
|
"requiere confirmaci\xF3n; sin gastos escritos la utilidad sale mas alta"
|
|
@@ -14340,6 +14340,73 @@ var LinkableCampaignsResponseSchema = z66.object({
|
|
|
14340
14340
|
|
|
14341
14341
|
// ../../packages/types/src/finance-operation.ts
|
|
14342
14342
|
import { z as z67 } from "zod";
|
|
14343
|
+
|
|
14344
|
+
// ../../packages/types/src/dropi-countries.ts
|
|
14345
|
+
var DROPI_COUNTRY_CODES = [
|
|
14346
|
+
"CO",
|
|
14347
|
+
"EC",
|
|
14348
|
+
"VE",
|
|
14349
|
+
"MX",
|
|
14350
|
+
"PE",
|
|
14351
|
+
"PA",
|
|
14352
|
+
"PY",
|
|
14353
|
+
"GT",
|
|
14354
|
+
"CL",
|
|
14355
|
+
"AR",
|
|
14356
|
+
"CR"
|
|
14357
|
+
];
|
|
14358
|
+
|
|
14359
|
+
// ../../packages/types/src/finance-country-timezones.ts
|
|
14360
|
+
var FINANCE_COUNTRY_TIME_ZONES = Object.freeze({
|
|
14361
|
+
US: "America/New_York",
|
|
14362
|
+
CA: "America/Toronto",
|
|
14363
|
+
BZ: "America/Belize",
|
|
14364
|
+
SV: "America/El_Salvador",
|
|
14365
|
+
HN: "America/Tegucigalpa",
|
|
14366
|
+
NI: "America/Managua",
|
|
14367
|
+
CU: "America/Havana",
|
|
14368
|
+
DO: "America/Santo_Domingo",
|
|
14369
|
+
HT: "America/Port-au-Prince",
|
|
14370
|
+
JM: "America/Jamaica",
|
|
14371
|
+
PR: "America/Puerto_Rico",
|
|
14372
|
+
TT: "America/Port_of_Spain",
|
|
14373
|
+
BO: "America/La_Paz",
|
|
14374
|
+
BR: "America/Sao_Paulo",
|
|
14375
|
+
UY: "America/Montevideo",
|
|
14376
|
+
ES: "Europe/Madrid",
|
|
14377
|
+
FR: "Europe/Paris",
|
|
14378
|
+
DE: "Europe/Berlin",
|
|
14379
|
+
IT: "Europe/Rome",
|
|
14380
|
+
PT: "Europe/Lisbon",
|
|
14381
|
+
NL: "Europe/Amsterdam",
|
|
14382
|
+
BE: "Europe/Brussels",
|
|
14383
|
+
AT: "Europe/Vienna",
|
|
14384
|
+
IE: "Europe/Dublin",
|
|
14385
|
+
LU: "Europe/Luxembourg",
|
|
14386
|
+
GB: "Europe/London",
|
|
14387
|
+
CH: "Europe/Zurich",
|
|
14388
|
+
SE: "Europe/Stockholm",
|
|
14389
|
+
NO: "Europe/Oslo",
|
|
14390
|
+
DK: "Europe/Copenhagen",
|
|
14391
|
+
FI: "Europe/Helsinki",
|
|
14392
|
+
IS: "Atlantic/Reykjavik",
|
|
14393
|
+
PL: "Europe/Warsaw",
|
|
14394
|
+
CZ: "Europe/Prague",
|
|
14395
|
+
HU: "Europe/Budapest",
|
|
14396
|
+
RO: "Europe/Bucharest",
|
|
14397
|
+
BG: "Europe/Sofia",
|
|
14398
|
+
HR: "Europe/Zagreb",
|
|
14399
|
+
SI: "Europe/Ljubljana",
|
|
14400
|
+
SK: "Europe/Bratislava",
|
|
14401
|
+
GR: "Europe/Athens",
|
|
14402
|
+
MT: "Europe/Malta",
|
|
14403
|
+
CY: "Asia/Nicosia",
|
|
14404
|
+
EE: "Europe/Tallinn",
|
|
14405
|
+
LV: "Europe/Riga",
|
|
14406
|
+
LT: "Europe/Vilnius"
|
|
14407
|
+
});
|
|
14408
|
+
|
|
14409
|
+
// ../../packages/types/src/finance-operation.ts
|
|
14343
14410
|
var CreateFinanceOperationSchema = z67.object({
|
|
14344
14411
|
countryCode: z67.string().length(2).toUpperCase(),
|
|
14345
14412
|
/** Cómo la llama ella. Vacío ⇒ se usa el nombre del país. */
|
|
@@ -14364,6 +14431,7 @@ var MonthlyPLQuerySchema = z67.object({
|
|
|
14364
14431
|
var RESERVED_EXPENSE_LABEL_PREFIX = "__ad_spend__";
|
|
14365
14432
|
var isReservedExpenseLabel = /* @__PURE__ */ __name((label) => label.trim().startsWith(RESERVED_EXPENSE_LABEL_PREFIX), "isReservedExpenseLabel");
|
|
14366
14433
|
var SaveMonthlyExpenseSchema = z67.object({
|
|
14434
|
+
operationId: z67.string().uuid().optional(),
|
|
14367
14435
|
month: z67.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
|
|
14368
14436
|
label: z67.string().trim().min(1).max(80).refine((label) => !isReservedExpenseLabel(label), {
|
|
14369
14437
|
message: "reserved_expense_label"
|
|
@@ -14373,13 +14441,14 @@ var SaveMonthlyExpenseSchema = z67.object({
|
|
|
14373
14441
|
allocations: z67.array(z67.object({
|
|
14374
14442
|
operationId: z67.string().uuid(),
|
|
14375
14443
|
sharePct: z67.number().int().min(1).max(100)
|
|
14376
|
-
})).min(1).refine((allocations) => allocations.reduce((sum, one) => sum + one.sharePct, 0)
|
|
14444
|
+
})).min(1).refine((allocations) => allocations.reduce((sum, one) => sum + one.sharePct, 0) <= 100, {
|
|
14377
14445
|
message: "allocations_must_sum_to_100"
|
|
14378
14446
|
}).refine((allocations) => new Set(allocations.map((one) => one.operationId)).size === allocations.length, {
|
|
14379
14447
|
message: "duplicate_operation_in_allocations"
|
|
14380
14448
|
}).optional()
|
|
14381
14449
|
}).strict();
|
|
14382
14450
|
var DeleteMonthlyExpenseSchema = z67.object({
|
|
14451
|
+
operationId: z67.string().uuid().optional(),
|
|
14383
14452
|
month: z67.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
|
|
14384
14453
|
label: z67.string().trim().min(1).max(80).refine((label) => !isReservedExpenseLabel(label), {
|
|
14385
14454
|
message: "reserved_expense_label"
|
|
@@ -14391,6 +14460,7 @@ var SetAdSpendSchema = z67.object({
|
|
|
14391
14460
|
amount: z67.number().finite().min(0).nullable()
|
|
14392
14461
|
}).strict();
|
|
14393
14462
|
var MonthlyExpensesQuerySchema = z67.object({
|
|
14463
|
+
operationId: z67.string().uuid().optional(),
|
|
14394
14464
|
month: z67.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional()
|
|
14395
14465
|
}).strict();
|
|
14396
14466
|
|
|
@@ -15296,44 +15366,58 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
15296
15366
|
"product"
|
|
15297
15367
|
]
|
|
15298
15368
|
),
|
|
15299
|
-
defineCapability(
|
|
15369
|
+
defineCapability(
|
|
15370
|
+
"create_service_video",
|
|
15371
|
+
"c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21",
|
|
15300
15372
|
"credit_consuming",
|
|
15301
|
-
"
|
|
15302
|
-
|
|
15303
|
-
|
|
15304
|
-
"
|
|
15305
|
-
]
|
|
15306
|
-
|
|
15307
|
-
"
|
|
15308
|
-
|
|
15309
|
-
|
|
15310
|
-
"
|
|
15311
|
-
|
|
15312
|
-
|
|
15313
|
-
"
|
|
15314
|
-
|
|
15315
|
-
|
|
15316
|
-
"
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
"
|
|
15320
|
-
|
|
15321
|
-
|
|
15322
|
-
"
|
|
15323
|
-
|
|
15324
|
-
|
|
15325
|
-
|
|
15326
|
-
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
"
|
|
15330
|
-
|
|
15331
|
-
|
|
15332
|
-
|
|
15333
|
-
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15373
|
+
"creative",
|
|
15374
|
+
[
|
|
15375
|
+
"credit_consuming",
|
|
15376
|
+
"state_change"
|
|
15377
|
+
],
|
|
15378
|
+
[
|
|
15379
|
+
slot("service_landing", true, [
|
|
15380
|
+
"landingUrl"
|
|
15381
|
+
]),
|
|
15382
|
+
slot("locale", true, [
|
|
15383
|
+
"language"
|
|
15384
|
+
]),
|
|
15385
|
+
slot("service_context", false, [
|
|
15386
|
+
"additionalContext"
|
|
15387
|
+
]),
|
|
15388
|
+
slot("voice", false, [
|
|
15389
|
+
"voiceId"
|
|
15390
|
+
]),
|
|
15391
|
+
slot("brand", false, [
|
|
15392
|
+
"brandId"
|
|
15393
|
+
]),
|
|
15394
|
+
slot("review_mode", false, [
|
|
15395
|
+
"reviewMode"
|
|
15396
|
+
]),
|
|
15397
|
+
slot("video_preset", false, [
|
|
15398
|
+
"videoPreset"
|
|
15399
|
+
]),
|
|
15400
|
+
// MCP-only for now: WhatsApp's service flow keeps the economy default.
|
|
15401
|
+
slot("video_quality", false, [
|
|
15402
|
+
"videoQuality"
|
|
15403
|
+
], []),
|
|
15404
|
+
slot("video_resolution", false, [
|
|
15405
|
+
"videoResolution"
|
|
15406
|
+
], [])
|
|
15407
|
+
],
|
|
15408
|
+
[
|
|
15409
|
+
"service_context"
|
|
15410
|
+
],
|
|
15411
|
+
[
|
|
15412
|
+
"task",
|
|
15413
|
+
"video"
|
|
15414
|
+
],
|
|
15415
|
+
// Owner decision 2026-10-08: the presenter service video is hidden from the
|
|
15416
|
+
// MCP for now — dropshipping sellers ordered it for products and cancelled.
|
|
15417
|
+
// MCP clients get `create_animated_video` instead. Flip back to
|
|
15418
|
+
// SHARED_CHANNEL_EXPOSURE to restore it.
|
|
15419
|
+
WHATSAPP_ONLY_CHANNEL_EXPOSURE
|
|
15420
|
+
),
|
|
15337
15421
|
defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
|
|
15338
15422
|
"credit_consuming",
|
|
15339
15423
|
"state_change"
|
|
@@ -17834,10 +17918,16 @@ var RegenerateVideoScriptCapabilityRequest = z80.object({
|
|
|
17834
17918
|
|
|
17835
17919
|
// ../../packages/types/src/dropi-financial.ts
|
|
17836
17920
|
import { z as z81 } from "zod";
|
|
17921
|
+
var DropiCountrySchema = z81.enum(DROPI_COUNTRY_CODES);
|
|
17922
|
+
var DropiCountryQuerySchema = z81.object({
|
|
17923
|
+
countryCode: DropiCountrySchema.default("CO")
|
|
17924
|
+
}).strict();
|
|
17837
17925
|
var ConnectDropiFinancialSchema = z81.object({
|
|
17926
|
+
countryCode: DropiCountrySchema.default("CO"),
|
|
17838
17927
|
integrationKey: z81.string().trim().min(1).max(4096).regex(/^[\x21-\x7e]+$/)
|
|
17839
17928
|
}).strict();
|
|
17840
17929
|
var SyncDropiFinancialSchema = z81.object({
|
|
17930
|
+
countryCode: DropiCountrySchema.optional(),
|
|
17841
17931
|
operationId: z81.string().uuid().optional(),
|
|
17842
17932
|
since: z81.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
17843
17933
|
until: z81.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
@@ -17845,7 +17935,8 @@ var SyncDropiFinancialSchema = z81.object({
|
|
|
17845
17935
|
var DropiFinancialStatusSchema = z81.object({
|
|
17846
17936
|
enabled: z81.boolean(),
|
|
17847
17937
|
connected: z81.boolean(),
|
|
17848
|
-
countryCode:
|
|
17938
|
+
countryCode: DropiCountrySchema,
|
|
17939
|
+
enabledCountries: z81.array(DropiCountrySchema).optional(),
|
|
17849
17940
|
environment: z81.enum([
|
|
17850
17941
|
"sandbox",
|
|
17851
17942
|
"production"
|
|
@@ -18121,7 +18212,7 @@ var ApiClient = class {
|
|
|
18121
18212
|
};
|
|
18122
18213
|
|
|
18123
18214
|
// src/index.ts
|
|
18124
|
-
var MCP_VERSION = "
|
|
18215
|
+
var MCP_VERSION = "9.0.1";
|
|
18125
18216
|
|
|
18126
18217
|
// src/meta-upload-app.ts
|
|
18127
18218
|
import { readFileSync } from "fs";
|
|
@@ -20723,7 +20814,7 @@ function renderAnimatedVideoStatus(result) {
|
|
|
20723
20814
|
__name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
|
|
20724
20815
|
function registerAnimatedVideoTools(server, api) {
|
|
20725
20816
|
server.registerTool("create_animated_video", {
|
|
20726
|
-
description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo.
|
|
20817
|
+
description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
|
|
20727
20818
|
inputSchema: CreateAnimatedVideoInput.shape,
|
|
20728
20819
|
annotations: CREATES_PAID_OPEN_WORLD
|
|
20729
20820
|
}, async (input) => {
|
|
@@ -20828,7 +20919,7 @@ function renderCreateProductTaskAvoidWhenForMcp(fragment) {
|
|
|
20828
20919
|
__name(renderCreateProductTaskAvoidWhenForMcp, "renderCreateProductTaskAvoidWhenForMcp");
|
|
20829
20920
|
var createProductTaskDefaultDescription = renderCreateProductTaskDefaultForMcp(createProductTaskGuidance.defaults[0]);
|
|
20830
20921
|
var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenForMcp(createProductTaskGuidance.avoidWhen[0]);
|
|
20831
|
-
var
|
|
20922
|
+
var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
|
|
20832
20923
|
var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
|
|
20833
20924
|
var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
|
|
20834
20925
|
var CreateProductTaskInput = z86.object({
|
|
@@ -21263,7 +21354,7 @@ async function fetchAnimatedVideoResult(api, taskId, signal, serviceMode = void
|
|
|
21263
21354
|
}
|
|
21264
21355
|
}
|
|
21265
21356
|
__name(fetchAnimatedVideoResult, "fetchAnimatedVideoResult");
|
|
21266
|
-
function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
|
|
21357
|
+
function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http", serviceVideo = CREATE_SERVICE_VIDEO_ON_MCP } = {}) {
|
|
21267
21358
|
server.registerTool("create_product_task", {
|
|
21268
21359
|
description: createProductTaskGuidance.summary + ` ${createProductTaskDefaultDescription} \xDAsala cuando el usuario pide todo o varios outputs, no creando tareas individuales. Usa images para solicitudes directas. Usa projectId \xFAnicamente si el usuario pidi\xF3 expl\xEDcitamente continuar el proyecto guiado que acaba de costear; nunca busques, infieras ni menciones proyectos previos.
|
|
21269
21360
|
|
|
@@ -21386,97 +21477,100 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
21386
21477
|
throw translateError(e);
|
|
21387
21478
|
}
|
|
21388
21479
|
});
|
|
21389
|
-
|
|
21390
|
-
|
|
21391
|
-
|
|
21392
|
-
|
|
21393
|
-
|
|
21394
|
-
|
|
21395
|
-
|
|
21396
|
-
|
|
21397
|
-
|
|
21398
|
-
|
|
21399
|
-
|
|
21400
|
-
|
|
21401
|
-
|
|
21402
|
-
|
|
21403
|
-
|
|
21404
|
-
|
|
21405
|
-
|
|
21406
|
-
|
|
21407
|
-
|
|
21408
|
-
|
|
21409
|
-
|
|
21410
|
-
|
|
21411
|
-
|
|
21412
|
-
|
|
21413
|
-
|
|
21414
|
-
|
|
21415
|
-
|
|
21416
|
-
|
|
21417
|
-
|
|
21418
|
-
|
|
21419
|
-
|
|
21420
|
-
|
|
21421
|
-
|
|
21422
|
-
|
|
21423
|
-
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
21428
|
-
|
|
21429
|
-
|
|
21430
|
-
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
if (
|
|
21439
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21480
|
+
if (serviceVideo) {
|
|
21481
|
+
const createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
|
|
21482
|
+
server.registerTool("create_service_video", {
|
|
21483
|
+
description: createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.",
|
|
21484
|
+
inputSchema: CreateServiceVideoInput.shape,
|
|
21485
|
+
annotations: CREATES_PAID_OPEN_WORLD
|
|
21486
|
+
}, async (input) => {
|
|
21487
|
+
try {
|
|
21488
|
+
if (input.videoQuality === "medium" && input.videoResolution === "720p") {
|
|
21489
|
+
throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
|
|
21490
|
+
}
|
|
21491
|
+
await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
|
|
21492
|
+
const created = await api.postJson("/v2/ingest", {
|
|
21493
|
+
taskType: "service",
|
|
21494
|
+
serviceLandingUrl: input.landingUrl,
|
|
21495
|
+
...input.additionalContext ? {
|
|
21496
|
+
additionalContext: input.additionalContext
|
|
21497
|
+
} : {},
|
|
21498
|
+
lang: input.language,
|
|
21499
|
+
...input.voiceId ? {
|
|
21500
|
+
voiceId: input.voiceId
|
|
21501
|
+
} : {},
|
|
21502
|
+
videoPreset: input.videoPreset,
|
|
21503
|
+
videoQuality: input.videoQuality,
|
|
21504
|
+
videoResolution: input.videoResolution,
|
|
21505
|
+
reviewMode: input.reviewMode,
|
|
21506
|
+
...input.brandId ? {
|
|
21507
|
+
brandId: input.brandId
|
|
21508
|
+
} : {},
|
|
21509
|
+
media: {
|
|
21510
|
+
assets: []
|
|
21511
|
+
},
|
|
21512
|
+
appDemoVideos: []
|
|
21513
|
+
}, {
|
|
21514
|
+
// The 2026-09-25 incident: four retries of this exact tool created
|
|
21515
|
+
// four charged service tasks because the host rephrased
|
|
21516
|
+
// `additionalContext` and flipped the landing between `/` and
|
|
21517
|
+
// `/es`. The derived key is stable across both rewrites (see
|
|
21518
|
+
// request-key.ts).
|
|
21519
|
+
idempotencyKey: derivePaidRequestKey({
|
|
21520
|
+
fingerprint: api.fingerprint(),
|
|
21521
|
+
tool: "create_service_video",
|
|
21522
|
+
input,
|
|
21523
|
+
nowMs: Date.now()
|
|
21524
|
+
})
|
|
21525
|
+
});
|
|
21526
|
+
const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
|
|
21527
|
+
const first = angles[0];
|
|
21528
|
+
const replayed = created.replayed === true;
|
|
21529
|
+
if (input.reviewMode === "automatic") {
|
|
21530
|
+
if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
|
|
21531
|
+
if (!(replayed && created.status !== "queued")) {
|
|
21532
|
+
await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
|
|
21533
|
+
angleIds: [
|
|
21534
|
+
first.id
|
|
21535
|
+
]
|
|
21536
|
+
});
|
|
21537
|
+
}
|
|
21538
|
+
return asText({
|
|
21539
|
+
taskId: created.taskId,
|
|
21540
|
+
status: replayed ? created.status ?? "processing" : "processing",
|
|
21541
|
+
...replayed ? {
|
|
21542
|
+
replayed: true
|
|
21543
|
+
} : {},
|
|
21544
|
+
reviewMode: input.reviewMode,
|
|
21545
|
+
selectedConcept: first
|
|
21546
|
+
});
|
|
21547
|
+
}
|
|
21548
|
+
if (replayed && created.status !== "queued") {
|
|
21549
|
+
return asText({
|
|
21550
|
+
taskId: created.taskId,
|
|
21551
|
+
status: created.status,
|
|
21552
|
+
replayed: true,
|
|
21553
|
+
reviewMode: input.reviewMode,
|
|
21554
|
+
angles
|
|
21443
21555
|
});
|
|
21444
21556
|
}
|
|
21445
21557
|
return asText({
|
|
21446
21558
|
taskId: created.taskId,
|
|
21447
|
-
status:
|
|
21559
|
+
status: "waiting_for_user",
|
|
21448
21560
|
...replayed ? {
|
|
21449
21561
|
replayed: true
|
|
21450
21562
|
} : {},
|
|
21451
21563
|
reviewMode: input.reviewMode,
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
|
|
21455
|
-
|
|
21456
|
-
return asText({
|
|
21457
|
-
taskId: created.taskId,
|
|
21458
|
-
status: created.status,
|
|
21459
|
-
replayed: true,
|
|
21460
|
-
reviewMode: input.reviewMode,
|
|
21461
|
-
angles
|
|
21564
|
+
pendingUserAction: {
|
|
21565
|
+
kind: "service_angle_approval",
|
|
21566
|
+
angles
|
|
21567
|
+
}
|
|
21462
21568
|
});
|
|
21569
|
+
} catch (e) {
|
|
21570
|
+
throw translateError(e);
|
|
21463
21571
|
}
|
|
21464
|
-
|
|
21465
|
-
|
|
21466
|
-
status: "waiting_for_user",
|
|
21467
|
-
...replayed ? {
|
|
21468
|
-
replayed: true
|
|
21469
|
-
} : {},
|
|
21470
|
-
reviewMode: input.reviewMode,
|
|
21471
|
-
pendingUserAction: {
|
|
21472
|
-
kind: "service_angle_approval",
|
|
21473
|
-
angles
|
|
21474
|
-
}
|
|
21475
|
-
});
|
|
21476
|
-
} catch (e) {
|
|
21477
|
-
throw translateError(e);
|
|
21478
|
-
}
|
|
21479
|
-
});
|
|
21572
|
+
});
|
|
21573
|
+
}
|
|
21480
21574
|
server.registerTool("verify_landing_commerce", {
|
|
21481
21575
|
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.",
|
|
21482
21576
|
inputSchema: {
|
|
@@ -25826,7 +25920,7 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
25826
25920
|
}
|
|
25827
25921
|
});
|
|
25828
25922
|
server.registerTool("get_finances", {
|
|
25829
|
-
description: getFinancesGuidance.summary + ' Contesta la pregunta que de verdad importa --- \xABeste negocio gana plata?\xBB --- con el mes armado: ventas totales y entregadas, fletes, costo de los productos, utilidad bruta, publicidad, gastos fijos y utilidad NETA. Esa utilidad es ANTES de impuestos y hay que decirlo asi: el contador es un gasto mas, no un calculo nuestro. Trae tambien los porcentajes contra sus metas. Si `costsKnown` viene en `false`, esos pedidos llegaron de una fuente que NO sabe cuanto costaron \u2014la tienda, o la API del proveedor\u2014 y la utilidad BRUTA esta incompleta: no es que el producto salga gratis. Si `adSpendKnown` viene en `false`, la publicidad NO se pudo leer y la utilidad esta INCOMPLETA: dilo antes de que alguien celebre un mes que perdio plata. `adSpendSource: "user"` significa que ella corrigio la cifra a mano, y eso se revisa distinto de una leida. Si `unconfirmedExpenses` es mayor que cero, ese monto viene heredado del mes pasado y ella no lo ha revisado. Es READ-ONLY: nunca pausa ni modifica una campana.',
|
|
25923
|
+
description: getFinancesGuidance.summary + ' Contesta la pregunta que de verdad importa --- \xABeste negocio gana plata?\xBB --- con el mes armado: ventas totales y entregadas, fletes, costo de los productos, utilidad bruta, publicidad, gastos fijos y utilidad NETA. Esa utilidad es ANTES de impuestos y hay que decirlo asi: el contador es un gasto mas, no un calculo nuestro. Trae tambien los porcentajes contra sus metas. Si `deliveredSalesKnown` no es true, faltan importes de ventas entregadas: la utilidad y los m\xE1rgenes no est\xE1n completos. `grossSalesKnown` distinto de true indica ventas totales parciales. Si `costsKnown` viene en `false`, esos pedidos llegaron de una fuente que NO sabe cuanto costaron \u2014la tienda, o la API del proveedor\u2014 y la utilidad BRUTA esta incompleta: no es que el producto salga gratis. Si `adSpendKnown` viene en `false`, la publicidad NO se pudo leer y la utilidad esta INCOMPLETA: dilo antes de que alguien celebre un mes que perdio plata. `adSpendSource: "user"` significa que ella corrigio la cifra a mano, y eso se revisa distinto de una leida. Si `unconfirmedExpenses` es mayor que cero, ese monto viene heredado del mes pasado y ella no lo ha revisado. Es READ-ONLY: nunca pausa ni modifica una campana.',
|
|
25830
25924
|
inputSchema: GetFinancesInput.shape,
|
|
25831
25925
|
annotations: READS_INTERNAL
|
|
25832
25926
|
}, async (input) => {
|
|
@@ -25913,23 +26007,16 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
25913
26007
|
}
|
|
25914
26008
|
});
|
|
25915
26009
|
server.registerTool("set_monthly_expense", {
|
|
25916
|
-
description: setMonthlyExpenseGuidance.summary + " Es un gasto FIJO: arriendo, sueldos, contador, plataformas \u2014 lo que se paga venda o no. Escribir la misma etiqueta otra vez REEMPLAZA el monto, no suma otro gasto. Sin gastos fijos escritos, la utilidad del mes sale siempre M\xC1S ALTA de lo que es, y ese es el error que nadie reclama. No lo uses para el gasto en anuncios: eso es set_ad_spend.",
|
|
26010
|
+
description: setMonthlyExpenseGuidance.summary + " El importe indicado es el TOTAL del gasto compartido existente; la parte de la operaci\xF3n se calcula conservando el reparto. Es un gasto FIJO: arriendo, sueldos, contador, plataformas \u2014 lo que se paga venda o no. Escribir la misma etiqueta otra vez REEMPLAZA el monto, no suma otro gasto. Sin gastos fijos escritos, la utilidad del mes sale siempre M\xC1S ALTA de lo que es, y ese es el error que nadie reclama. No lo uses para el gasto en anuncios: eso es set_ad_spend.",
|
|
25917
26011
|
inputSchema: SetMonthlyExpenseInput.shape,
|
|
25918
26012
|
annotations: OVERWRITES_INTERNAL
|
|
25919
26013
|
}, async (input) => {
|
|
25920
26014
|
try {
|
|
25921
|
-
const month = input.month ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 7);
|
|
25922
|
-
const operationId = input.operationId ?? (await api.getJson("/v1/product-control/operations"))[0]?.id;
|
|
25923
26015
|
return asText(await api.putJson("/v1/product-control/expenses", {
|
|
25924
|
-
month,
|
|
26016
|
+
month: input.month,
|
|
26017
|
+
operationId: input.operationId,
|
|
25925
26018
|
label: input.label,
|
|
25926
|
-
amount: input.amount
|
|
25927
|
-
allocations: operationId ? [
|
|
25928
|
-
{
|
|
25929
|
-
operationId,
|
|
25930
|
-
sharePct: 100
|
|
25931
|
-
}
|
|
25932
|
-
] : void 0
|
|
26019
|
+
amount: input.amount
|
|
25933
26020
|
}));
|
|
25934
26021
|
} catch (error) {
|
|
25935
26022
|
throw translateError(error);
|
|
@@ -25942,7 +26029,7 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
25942
26029
|
}, async (input) => {
|
|
25943
26030
|
try {
|
|
25944
26031
|
return asText(await api.putJson("/v1/product-control/ad-spend", {
|
|
25945
|
-
month: input.month
|
|
26032
|
+
month: input.month,
|
|
25946
26033
|
operationId: input.operationId,
|
|
25947
26034
|
amount: input.amount
|
|
25948
26035
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.1",
|
|
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.",
|