@productmaker/mcp 12.2.5 → 12.2.6

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/stdio.js CHANGED
@@ -2667,7 +2667,8 @@ var sha256 = z3.string().regex(/^[a-f0-9]{64}$/i);
2667
2667
  var MAX_LLM_ROUTE_POLICY_STEPS = 512;
2668
2668
  var MAX_LLM_ROUTE_POLICY_PROFILES = 64;
2669
2669
  var MAX_LLM_ROUTE_POLICY_SUBMISSIONS = 2048;
2670
- var MAX_LLM_NATIVE_RETRY_POLICY_SUBMISSIONS = MAX_LLM_ROUTE_POLICY_STEPS * 60;
2670
+ var MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS = 120;
2671
+ var MAX_LLM_NATIVE_RETRY_POLICY_SUBMISSIONS = MAX_LLM_ROUTE_POLICY_STEPS * MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS;
2671
2672
  var NATIVE_OWNED_LLM_MAX_SUBMISSIONS = 9;
2672
2673
  var NativeMessagesBudgetSchema = z3.object({
2673
2674
  version: z3.literal("native_messages_bytes_v1"),
@@ -3003,7 +3004,7 @@ var LlmAttemptRetryCauseSchema = z3.enum([
3003
3004
  ]);
3004
3005
  var LlmAttemptBudgetSchema = z3.object({
3005
3006
  maxCostUsd: z3.number().finite().nonnegative(),
3006
- maxSubmissions: z3.number().int().min(1).max(60),
3007
+ maxSubmissions: z3.number().int().min(1).max(MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS),
3007
3008
  maxSameTargetRetries: z3.number().int().min(0).max(29),
3008
3009
  finalizationReserveMs: z3.number().int().nonnegative(),
3009
3010
  retryPolicy: LlmAttemptRetryPolicySchema.optional()
@@ -3486,7 +3487,7 @@ var LlmAttemptAdmissionInputSchema = z3.object({
3486
3487
  }).strict();
3487
3488
  var LlmAttemptAdmissionGrantSchema = z3.object({
3488
3489
  attemptId: identifier,
3489
- ordinal: z3.number().int().min(1).max(60),
3490
+ ordinal: z3.number().int().min(1).max(MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS),
3490
3491
  attemptToken: identifier,
3491
3492
  targetId: identifier,
3492
3493
  reservedMaxCostUsd: z3.number().finite().nonnegative()
@@ -3691,7 +3692,7 @@ var ModelRoutePolicyBaseSchema = z4.object({
3691
3692
  maxEntries: z4.number().int().min(1).max(MODEL_ROUTE_MAX_ENTRIES),
3692
3693
  models: z4.array(model).min(1).max(8),
3693
3694
  routes: z4.array(provider).min(1).max(3),
3694
- /** New CE edits alone opt in; immutable legacy service policies stay two-leg. */
3695
+ /** Every new routed claim for a protocol-10 reader; stored two-leg policies stay two-leg. */
3695
3696
  nativeRouting: z4.object({
3696
3697
  version: z4.literal(1),
3697
3698
  byModel: z4.record(model, LlmRouteSnapshotSchema)
@@ -14283,8 +14284,9 @@ var CostEstimationResponse = z50.object({
14283
14284
  /** True when userBalanceCents >= max estimated cost (worst case). */
14284
14285
  hasSufficientBalance: z50.boolean()
14285
14286
  });
14287
+ var COST_ESTIMATION_BATCH_LIMIT = 32;
14286
14288
  var CostEstimationBatchRequest = z50.object({
14287
- requests: z50.array(CostEstimationRequest).min(1).max(32)
14289
+ requests: z50.array(CostEstimationRequest).min(1).max(COST_ESTIMATION_BATCH_LIMIT)
14288
14290
  });
14289
14291
  var CostEstimationUnavailableCode = z50.enum([
14290
14292
  "CREATIVE_ENGINE_VIDEO_QUALITY_NOT_ADMITTED",
@@ -14304,7 +14306,7 @@ var CostEstimationBatchEstimate = z50.union([
14304
14306
  }).strict()
14305
14307
  ]);
14306
14308
  var CostEstimationBatchResponse = z50.object({
14307
- estimates: z50.array(CostEstimationBatchEstimate).max(32)
14309
+ estimates: z50.array(CostEstimationBatchEstimate).max(COST_ESTIMATION_BATCH_LIMIT)
14308
14310
  });
14309
14311
  var UnitCreditRange = z50.object({
14310
14312
  /** Best-case credits (most units → HIGH end of the count band). */
@@ -14361,6 +14363,10 @@ var CODE_LANDING_LLM_V2_TARGETS = {
14361
14363
  transport: "openrouter",
14362
14364
  model: "deepseek/deepseek-v4.1-flash"
14363
14365
  },
14366
+ "deepseek-v4.1-1017-openrouter": {
14367
+ transport: "openrouter",
14368
+ model: "deepseek/deepseek-v4.1-flash-1017"
14369
+ },
14364
14370
  "qwen-omni-openrouter": {
14365
14371
  transport: "openrouter",
14366
14372
  model: "qwen/qwen3.8-omni-flash"
@@ -14429,18 +14435,32 @@ var CodeLandingLlmChildCallBudgetSchema = z51.object({
14429
14435
  provider: z51.literal("google").optional(),
14430
14436
  targetId: z51.literal("gemini-flash-google").optional(),
14431
14437
  /** The second physical ordinal is the explicitly funded DeepSeek leg. */
14432
- fallbackTarget: z51.object({
14433
- transport: z51.literal("openrouter"),
14434
- provider: z51.literal("openrouter"),
14435
- targetId: z51.literal("deepseek-v4.1-openrouter"),
14436
- model: z51.literal("deepseek/deepseek-v4.1-flash"),
14437
- companyColdPricing: z51.object({
14438
- source: z51.literal("verified_catalog"),
14439
- snapshotDate: z51.literal("2026-10-07"),
14440
- inputUsdPerMillionTokens: z51.literal(0.14),
14441
- outputUsdPerMillionTokens: z51.literal(0.42)
14438
+ fallbackTarget: z51.union([
14439
+ z51.object({
14440
+ transport: z51.literal("openrouter"),
14441
+ provider: z51.literal("openrouter"),
14442
+ targetId: z51.literal("deepseek-v4.1-openrouter"),
14443
+ model: z51.literal("deepseek/deepseek-v4.1-flash"),
14444
+ companyColdPricing: z51.object({
14445
+ source: z51.literal("verified_catalog"),
14446
+ snapshotDate: z51.literal("2026-10-07"),
14447
+ inputUsdPerMillionTokens: z51.literal(0.14),
14448
+ outputUsdPerMillionTokens: z51.literal(0.42)
14449
+ }).strict()
14450
+ }).strict(),
14451
+ z51.object({
14452
+ transport: z51.literal("openrouter"),
14453
+ provider: z51.literal("openrouter"),
14454
+ targetId: z51.literal("deepseek-v4.1-1017-openrouter"),
14455
+ model: z51.literal("deepseek/deepseek-v4.1-flash-1017"),
14456
+ companyColdPricing: z51.object({
14457
+ source: z51.literal("verified_catalog"),
14458
+ snapshotDate: z51.literal("2026-10-24"),
14459
+ inputUsdPerMillionTokens: z51.literal(0.454),
14460
+ outputUsdPerMillionTokens: z51.literal(1.2)
14461
+ }).strict()
14442
14462
  }).strict()
14443
- }).strict().optional(),
14463
+ ]).optional(),
14444
14464
  model: z51.string().min(1),
14445
14465
  maxGroups: z51.number().int().positive().max(14),
14446
14466
  maxCallsPerGroup: z51.number().int().positive().max(5),
@@ -14652,7 +14672,12 @@ var CodeLandingEnvelopeNodeSchema = z51.object({
14652
14672
  companyOutput: 12e3,
14653
14673
  // Fresh direction uses Sonnet. Historical DeepSeek/Grok quotes
14654
14674
  // retain their exact model, tariff and one-call budget.
14655
- ...budget.model === "anthropic/claude-sonnet-5.5" ? CODE_LANDING_SONNET_NATIVE_PRICING : budget.model === "deepseek/deepseek-v4.1-flash" ? {
14675
+ ...budget.model === "anthropic/claude-sonnet-5.5" ? CODE_LANDING_SONNET_NATIVE_PRICING : budget.model === "deepseek/deepseek-v4.1-flash-1017" ? {
14676
+ model: "deepseek/deepseek-v4.1-flash-1017",
14677
+ snapshotDate: "2026-10-24",
14678
+ inputRate: 0.454,
14679
+ outputRate: 1.2
14680
+ } : budget.model === "deepseek/deepseek-v4.1-flash" ? {
14656
14681
  model: "deepseek/deepseek-v4.1-flash",
14657
14682
  snapshotDate: "2026-10-07",
14658
14683
  inputRate: 0.14,
@@ -21351,6 +21376,150 @@ var CAPABILITY_MODEL_GUIDANCE = {
21351
21376
  "requiere confirmaci\xF3n; cero afirma que no pauto, null vuelve a campanas"
21352
21377
  ]
21353
21378
  },
21379
+ get_dropi_status: {
21380
+ summary: "Dice si su cuenta Dropi est\xE1 conectada y hasta d\xF3nde lleg\xF3 la lectura de pedidos.",
21381
+ useWhen: [
21382
+ "est\xE1 conectado mi Dropi",
21383
+ "por qu\xE9 no llegan mis pedidos de Dropi"
21384
+ ],
21385
+ avoidWhen: [
21386
+ "quiere el mes armado: get_finances"
21387
+ ],
21388
+ defaults: [
21389
+ "pa\xEDs de la operaci\xF3n; con varias cuentas del mismo pa\xEDs pregunta cu\xE1l"
21390
+ ],
21391
+ disclosures: [
21392
+ "solo lectura; no conecta ni desconecta cuentas"
21393
+ ]
21394
+ },
21395
+ sync_dropi_orders: {
21396
+ summary: "Trae los pedidos reales de su cuenta Dropi al libro de cuentas.",
21397
+ useWhen: [
21398
+ "sincroniza mis pedidos de Dropi",
21399
+ "actualiza lo que vend\xED por Dropi"
21400
+ ],
21401
+ avoidWhen: [
21402
+ "la cuenta no est\xE1 conectada: la conexi\xF3n se hace en Integraciones, no por chat"
21403
+ ],
21404
+ defaults: [
21405
+ "mes en curso cuando no dan fechas"
21406
+ ],
21407
+ disclosures: [
21408
+ "requiere confirmaci\xF3n; una lectura larga puede quedar pendiente y responde lo que alcanz\xF3 a leer"
21409
+ ]
21410
+ },
21411
+ create_manual_product: {
21412
+ summary: "Crea un producto a mano en su control financiero: sin tienda ni tarea.",
21413
+ useWhen: [
21414
+ "vendo algo que no est\xE1 en mi tienda",
21415
+ "agr\xE9game este producto que vendo por fuera"
21416
+ ],
21417
+ avoidWhen: [
21418
+ "el producto ya est\xE1 en su tienda: import_product_controls"
21419
+ ],
21420
+ defaults: [
21421
+ "el pa\xEDs fija la moneda: nunca la inventes ni la preguntes aparte"
21422
+ ],
21423
+ disclosures: [
21424
+ "requiere confirmaci\xF3n; aqu\xED el precio S\xCD se escribe a mano porque no hay tienda que lo mande"
21425
+ ]
21426
+ },
21427
+ list_unmatched_products: {
21428
+ summary: "Lista los productos que una importaci\xF3n trajo y todav\xEDa no tienen due\xF1o en su libro.",
21429
+ useWhen: [
21430
+ "qu\xE9 productos no reconociste",
21431
+ "hay pedidos sin producto"
21432
+ ],
21433
+ avoidWhen: [
21434
+ "quiere el cat\xE1logo ya controlado: get_product_control"
21435
+ ],
21436
+ defaults: [
21437
+ "la operaci\xF3n se deduce del pa\xEDs cuando solo hay una"
21438
+ ],
21439
+ disclosures: [
21440
+ "solo lectura; los pedidos ya est\xE1n guardados \u2014 esto muestra a qui\xE9n falta asignarlos"
21441
+ ]
21442
+ },
21443
+ resolve_unmatched_product: {
21444
+ summary: "Le da due\xF1o a un producto que la importaci\xF3n no reconoci\xF3: crea la ficha nueva o la cuelga de una que ya tiene.",
21445
+ useWhen: [
21446
+ "ese producto es el termo que ya vendo",
21447
+ "reconoce este producto del proveedor"
21448
+ ],
21449
+ avoidWhen: [
21450
+ "quiere unir dos fichas ya creadas: merge_products"
21451
+ ],
21452
+ defaults: [
21453
+ "con el id de un producto existente cuelga el alias ah\xED; sin \xE9l crea la ficha con el nombre que vino"
21454
+ ],
21455
+ disclosures: [
21456
+ "requiere confirmaci\xF3n; sus pedidos ya est\xE1n guardados \u2014 esto solo les pone due\xF1o y nada se descarta"
21457
+ ]
21458
+ },
21459
+ list_linkable_campaigns: {
21460
+ summary: "Muestra las campa\xF1as de Meta y TikTok que puede atar a un producto, sin teclear identificadores.",
21461
+ useWhen: [
21462
+ "qu\xE9 campa\xF1as puedo vincular",
21463
+ "a qu\xE9 anuncio le pego este producto"
21464
+ ],
21465
+ avoidWhen: [
21466
+ "ya sabe cu\xE1l va: link_product_campaign directo"
21467
+ ],
21468
+ defaults: [
21469
+ "salen de las cuentas de publicidad ya conectadas"
21470
+ ],
21471
+ disclosures: [
21472
+ "solo lectura"
21473
+ ]
21474
+ },
21475
+ link_product_campaign: {
21476
+ summary: "Ata una campa\xF1a de publicidad a un producto de su control financiero.",
21477
+ useWhen: [
21478
+ "vincula esta campa\xF1a a mi termo",
21479
+ "ese producto se anuncia por esta campa\xF1a"
21480
+ ],
21481
+ avoidWhen: [
21482
+ "la campa\xF1a no sale: list_linkable_campaigns primero"
21483
+ ],
21484
+ defaults: [
21485
+ "el producto va por su id del control o por tienda + id de Shopify"
21486
+ ],
21487
+ disclosures: [
21488
+ "requiere confirmaci\xF3n; desde ese momento el sem\xE1foro lee el gasto de esa campa\xF1a"
21489
+ ]
21490
+ },
21491
+ delete_monthly_expense: {
21492
+ summary: "Borra un gasto fijo del mes.",
21493
+ useWhen: [
21494
+ "quita el gasto de arriendo",
21495
+ "borra el sueldo de este mes"
21496
+ ],
21497
+ avoidWhen: [
21498
+ "solo quiere corregir el monto: set_monthly_expense con el valor nuevo"
21499
+ ],
21500
+ defaults: [
21501
+ "mes en curso si no se dice otro"
21502
+ ],
21503
+ disclosures: [
21504
+ "requiere confirmaci\xF3n; el borrado mueve la utilidad neta al instante"
21505
+ ]
21506
+ },
21507
+ remove_product_control: {
21508
+ summary: "Saca un producto de su control financiero, junto con sus costos y su anuncio vinculado.",
21509
+ useWhen: [
21510
+ "ya no vendo ese producto",
21511
+ "elimina el termo del control"
21512
+ ],
21513
+ avoidWhen: [
21514
+ "quiere unirlo con otro producto: merge_products"
21515
+ ],
21516
+ defaults: [
21517
+ "pide el producto del listado; nunca lo inventes"
21518
+ ],
21519
+ disclosures: [
21520
+ "requiere confirmaci\xF3n; sus costos y su anuncio se van con \xE9l"
21521
+ ]
21522
+ },
21354
21523
  report_daily_returns: {
21355
21524
  summary: "Registra el n\xFAmero real de pedidos devueltos de un producto en un d\xEDa concreto.",
21356
21525
  useWhen: [
@@ -21674,6 +21843,78 @@ var DROPI_COUNTRY_CODES = [
21674
21843
  "AR",
21675
21844
  "CR"
21676
21845
  ];
21846
+ var DROPI_COUNTRIES = {
21847
+ CO: {
21848
+ name: "Colombia",
21849
+ currency: "COP",
21850
+ timeZone: "America/Bogota",
21851
+ productionBaseUrl: "https://api.dropi.co/integrations"
21852
+ },
21853
+ EC: {
21854
+ name: "Ecuador",
21855
+ currency: "USD",
21856
+ timeZone: "America/Guayaquil",
21857
+ productionBaseUrl: "https://api.dropi.ec/integrations"
21858
+ },
21859
+ VE: {
21860
+ name: "Venezuela",
21861
+ currency: "USD",
21862
+ timeZone: "America/Caracas",
21863
+ productionBaseUrl: "https://api.dropi.com.ve/integrations"
21864
+ },
21865
+ MX: {
21866
+ name: "M\xE9xico",
21867
+ currency: "MXN",
21868
+ timeZone: "America/Mexico_City",
21869
+ productionBaseUrl: "https://api.dropi.mx/integrations"
21870
+ },
21871
+ PE: {
21872
+ name: "Per\xFA",
21873
+ currency: "PEN",
21874
+ timeZone: "America/Lima",
21875
+ productionBaseUrl: "https://api.dropi.pe/integrations"
21876
+ },
21877
+ PA: {
21878
+ name: "Panam\xE1",
21879
+ currency: "USD",
21880
+ timeZone: "America/Panama",
21881
+ productionBaseUrl: "https://api.dropi.pa/integrations"
21882
+ },
21883
+ PY: {
21884
+ name: "Paraguay",
21885
+ currency: "PYG",
21886
+ timeZone: "America/Asuncion",
21887
+ productionBaseUrl: "https://api.dropi.com.py/integrations"
21888
+ },
21889
+ GT: {
21890
+ name: "Guatemala",
21891
+ currency: "GTQ",
21892
+ timeZone: "America/Guatemala",
21893
+ productionBaseUrl: "https://api.dropi.gt/integrations"
21894
+ },
21895
+ CL: {
21896
+ name: "Chile",
21897
+ currency: "CLP",
21898
+ timeZone: "America/Santiago",
21899
+ productionBaseUrl: "https://api.dropi.cl/integrations"
21900
+ },
21901
+ AR: {
21902
+ name: "Argentina",
21903
+ currency: "ARS",
21904
+ timeZone: "America/Argentina/Buenos_Aires",
21905
+ productionBaseUrl: "https://api.dropi.ar/integrations"
21906
+ },
21907
+ CR: {
21908
+ name: "Costa Rica",
21909
+ currency: "CRC",
21910
+ timeZone: "America/Costa_Rica",
21911
+ productionBaseUrl: "https://api.dropi.cr/integrations"
21912
+ }
21913
+ };
21914
+ function isDropiCountryCode(value) {
21915
+ return typeof value === "string" && DROPI_COUNTRY_CODES.some((code) => code === value);
21916
+ }
21917
+ __name(isDropiCountryCode, "isDropiCountryCode");
21677
21918
 
21678
21919
  // ../../packages/types/src/finance-country-timezones.ts
21679
21920
  var FINANCE_COUNTRY_TIME_ZONES = Object.freeze({
@@ -21724,6 +21965,19 @@ var FINANCE_COUNTRY_TIME_ZONES = Object.freeze({
21724
21965
  LV: "Europe/Riga",
21725
21966
  LT: "Europe/Vilnius"
21726
21967
  });
21968
+ function financeCountryTimeZone(countryCode) {
21969
+ const normalized = countryCode?.toUpperCase();
21970
+ if (!normalized) return DROPI_COUNTRIES.CO.timeZone;
21971
+ if (isDropiCountryCode(normalized)) {
21972
+ return DROPI_COUNTRIES[normalized].timeZone;
21973
+ }
21974
+ const timeZone = FINANCE_COUNTRY_TIME_ZONES[normalized];
21975
+ if (!timeZone) {
21976
+ throw new RangeError(`Unsupported finance calendar country: ${normalized}`);
21977
+ }
21978
+ return timeZone;
21979
+ }
21980
+ __name(financeCountryTimeZone, "financeCountryTimeZone");
21727
21981
 
21728
21982
  // ../../packages/types/src/finance-operation.ts
21729
21983
  var CreateFinanceOperationSchema = z97.object({
@@ -21839,6 +22093,8 @@ var ProductOrderLineSchema = z99.object({
21839
22093
  provider: z99.string().min(1).max(32).optional(),
21840
22094
  externalOrderId: z99.string().trim().min(1).max(64),
21841
22095
  externalProductId: z99.string().trim().min(1).max(64),
22096
+ /** Product display name only; never a buyer name. Unknown names stay null or absent. */
22097
+ externalProductLabel: z99.string().trim().min(1).max(300).nullable().optional(),
21842
22098
  /** YYYY-MM-DD, fecha DEL PEDIDO, nunca la de descarga del reporte. */
21843
22099
  orderedAt: z99.string().regex(/^\d{4}-\d{2}-\d{2}$/),
21844
22100
  status: z99.enum(PRODUCT_ORDER_LINE_STATUSES),
@@ -22307,6 +22563,41 @@ var ImportFulfillmentCountsResponseSchema = z100.object({
22307
22563
  skippedManual: z100.number().int().min(0),
22308
22564
  skippedUnknownProduct: z100.number().int().min(0)
22309
22565
  });
22566
+ var CreateManualProductControlSchema = z100.object({
22567
+ /** UUID que el diálogo fija por apertura; es además el id del producto. */
22568
+ requestId: z100.string().uuid(),
22569
+ title: z100.string().trim().min(1).max(200),
22570
+ /** País donde vende este producto; la moneda sale de él en el servidor. */
22571
+ targetCountry: z100.string().regex(/^[A-Z]{2}$/).refine((code) => {
22572
+ try {
22573
+ financeCountryTimeZone(code);
22574
+ return true;
22575
+ } catch {
22576
+ return false;
22577
+ }
22578
+ }, "unsupported_finance_country"),
22579
+ /** Solo cuando coincide con el país elegido; si no, se omite. */
22580
+ operationId: z100.string().uuid().optional(),
22581
+ manualSellingPrice: z100.number().finite().positive().max(Number.MAX_SAFE_INTEGER),
22582
+ supplierCost: z100.number().finite().positive().max(Number.MAX_SAFE_INTEGER),
22583
+ shippingCost: z100.number().finite().nonnegative().max(Number.MAX_SAFE_INTEGER),
22584
+ returnRate: z100.number().finite().min(0).lt(1),
22585
+ cancellationRate: z100.number().finite().min(0).lt(1)
22586
+ }).strict().superRefine(({ returnRate, cancellationRate }, ctx) => {
22587
+ if (returnRate + cancellationRate >= 1) {
22588
+ ctx.addIssue({
22589
+ code: z100.ZodIssueCode.custom,
22590
+ message: "delivery_rate_positive",
22591
+ path: [
22592
+ "cancellationRate"
22593
+ ]
22594
+ });
22595
+ }
22596
+ });
22597
+ var CreateManualProductControlResponseSchema = z100.object({
22598
+ productControlId: z100.string().uuid(),
22599
+ created: z100.boolean()
22600
+ });
22310
22601
 
22311
22602
  // ../../packages/types/src/productmaker-capability-registry.ts
22312
22603
  var SHARED_CHANNEL_EXPOSURE = {
@@ -24026,13 +24317,22 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24026
24317
  ], [
24027
24318
  "product_control"
24028
24319
  ]),
24029
- defineCapability("set_product_costing", "d3048558a7e380cdcc17d6b959e9d2ac782a933554a2dde1e914e89e13b24f0c", "state_change", "business", [
24320
+ defineCapability("set_product_costing", "cce7a31e434c7a1f0af2e3ecaf591eb63c6e3570c466c29e2cab00432ab26bc9", "state_change", "business", [
24030
24321
  "state_change"
24031
24322
  ], [
24032
- slot("product", true, [
24323
+ /* La identidad sin tienda solo existe en el contrato MCP: el
24324
+ esquema de WhatsApp sigue pidiendo la pareja de tienda, así que
24325
+ estos campos no se declaran allí (whatsapp: []). */
24326
+ slot("product_control", false, [
24327
+ "productControlId"
24328
+ ], []),
24329
+ slot("selling_price", false, [
24330
+ "manualSellingPrice"
24331
+ ], []),
24332
+ slot("product", false, [
24033
24333
  "shopifyProductId"
24034
24334
  ]),
24035
- slot("shop", true, [
24335
+ slot("shop", false, [
24036
24336
  "shopDomain"
24037
24337
  ]),
24038
24338
  slot("market", true, [
@@ -24223,6 +24523,271 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24223
24523
  ], [
24224
24524
  "monthly_pl"
24225
24525
  ]),
24526
+ defineCapability(
24527
+ "get_dropi_status",
24528
+ // Filled by the MCP schema fingerprint test (sha256 of the canonicalized
24529
+ // inputSchema) — run apps/mcp server.test.ts to compute.
24530
+ "3465e644ebdcaa404d8bcc1af629012c858bb4aed5bb1b56cfaa2af0d53cfc6e",
24531
+ "none",
24532
+ "read_only",
24533
+ [
24534
+ "read"
24535
+ ],
24536
+ [
24537
+ slot("country", false, [
24538
+ "countryCode"
24539
+ ]),
24540
+ slot("dropi_connection", false, [
24541
+ "connectionId"
24542
+ ])
24543
+ ],
24544
+ [
24545
+ "dropi_connection"
24546
+ ],
24547
+ [
24548
+ "dropi_status"
24549
+ ],
24550
+ MCP_ONLY_CHANNEL_EXPOSURE
24551
+ ),
24552
+ defineCapability(
24553
+ "sync_dropi_orders",
24554
+ // Filled by the MCP schema fingerprint test.
24555
+ "46f1172e7afe42991957a2dc262cce235dbf31ededdf37ccf866a583bb19123b",
24556
+ "state_change",
24557
+ "business",
24558
+ [
24559
+ "state_change"
24560
+ ],
24561
+ [
24562
+ slot("country", false, [
24563
+ "countryCode"
24564
+ ]),
24565
+ slot("operation", false, [
24566
+ "operationId"
24567
+ ]),
24568
+ slot("dropi_connection", false, [
24569
+ "connectionId"
24570
+ ]),
24571
+ slot("window_start", false, [
24572
+ "since"
24573
+ ]),
24574
+ slot("window_end", false, [
24575
+ "until"
24576
+ ])
24577
+ ],
24578
+ [
24579
+ "dropi_connection"
24580
+ ],
24581
+ [
24582
+ "product_order_line"
24583
+ ],
24584
+ MCP_ONLY_CHANNEL_EXPOSURE
24585
+ ),
24586
+ defineCapability(
24587
+ "create_manual_product",
24588
+ // Filled by the MCP schema fingerprint test.
24589
+ "4da701236ab1fd460e66f6def729f61a392bad62e8fecdaf8b3b3098fdec53cb",
24590
+ "state_change",
24591
+ "business",
24592
+ [
24593
+ "state_change"
24594
+ ],
24595
+ [
24596
+ slot("product", true, [
24597
+ "title"
24598
+ ]),
24599
+ slot("market", true, [
24600
+ "targetCountry"
24601
+ ]),
24602
+ slot("operation", false, [
24603
+ "operationId"
24604
+ ]),
24605
+ slot("selling_price", true, [
24606
+ "manualSellingPrice"
24607
+ ]),
24608
+ slot("supplier_cost", true, [
24609
+ "supplierCost"
24610
+ ]),
24611
+ slot("shipping_cost", true, [
24612
+ "shippingCost"
24613
+ ]),
24614
+ slot("return_rate", true, [
24615
+ "returnRate"
24616
+ ]),
24617
+ slot("cancellation_rate", true, [
24618
+ "cancellationRate"
24619
+ ])
24620
+ ],
24621
+ [
24622
+ "finance_operation"
24623
+ ],
24624
+ [
24625
+ "product_control"
24626
+ ],
24627
+ MCP_ONLY_CHANNEL_EXPOSURE
24628
+ ),
24629
+ defineCapability(
24630
+ "list_unmatched_products",
24631
+ // Filled by the MCP schema fingerprint test.
24632
+ "2c89690b4282a881f29f3bae11268786abf385c2bec0e3d7a1643098f4986e1b",
24633
+ "none",
24634
+ "read_only",
24635
+ [
24636
+ "read"
24637
+ ],
24638
+ [
24639
+ slot("operation", false, [
24640
+ "operationId"
24641
+ ])
24642
+ ],
24643
+ [
24644
+ "finance_operation"
24645
+ ],
24646
+ [
24647
+ "product_order_line"
24648
+ ],
24649
+ MCP_ONLY_CHANNEL_EXPOSURE
24650
+ ),
24651
+ defineCapability(
24652
+ "resolve_unmatched_product",
24653
+ // Filled by the MCP schema fingerprint test.
24654
+ "39ccb99a5d138f7f99e25c00b68eec8972e34dbcbd966d2081cdaa7c76ac63ba",
24655
+ "state_change",
24656
+ "business",
24657
+ [
24658
+ "state_change"
24659
+ ],
24660
+ [
24661
+ slot("order_provider", true, [
24662
+ "provider"
24663
+ ]),
24664
+ slot("external_id", true, [
24665
+ "externalId"
24666
+ ]),
24667
+ slot("product_label", true, [
24668
+ "label"
24669
+ ]),
24670
+ slot("operation", true, [
24671
+ "operationId"
24672
+ ]),
24673
+ slot("product_control", false, [
24674
+ "productControlId"
24675
+ ])
24676
+ ],
24677
+ [
24678
+ "product_order_line"
24679
+ ],
24680
+ [
24681
+ "product_control"
24682
+ ],
24683
+ MCP_ONLY_CHANNEL_EXPOSURE
24684
+ ),
24685
+ defineCapability(
24686
+ "list_linkable_campaigns",
24687
+ // Filled by the MCP schema fingerprint test.
24688
+ "7a014b717a77aac971ea0ab5c0ff47bb13e6cae7ef9442d9dedb15ce36381b15",
24689
+ "none",
24690
+ "read_only",
24691
+ [
24692
+ "read"
24693
+ ],
24694
+ [],
24695
+ [
24696
+ "ad_account"
24697
+ ],
24698
+ [
24699
+ "campaign_link"
24700
+ ],
24701
+ MCP_ONLY_CHANNEL_EXPOSURE
24702
+ ),
24703
+ defineCapability(
24704
+ "link_product_campaign",
24705
+ // Filled by the MCP schema fingerprint test.
24706
+ "a9976318693f137dd37f4608d382fe1deb13b44c2f5257580c8b52b015899dde",
24707
+ "state_change",
24708
+ "business",
24709
+ [
24710
+ "state_change"
24711
+ ],
24712
+ [
24713
+ slot("ad_provider", true, [
24714
+ "provider"
24715
+ ]),
24716
+ slot("ad_account", true, [
24717
+ "accountId"
24718
+ ]),
24719
+ slot("campaign", true, [
24720
+ "campaignId"
24721
+ ]),
24722
+ slot("product_control", false, [
24723
+ "productControlId"
24724
+ ]),
24725
+ slot("shop", false, [
24726
+ "shopDomain"
24727
+ ]),
24728
+ slot("shopify_product", false, [
24729
+ "shopifyProductId"
24730
+ ])
24731
+ ],
24732
+ [
24733
+ "product_control",
24734
+ "campaign_link"
24735
+ ],
24736
+ [
24737
+ "campaign_link"
24738
+ ],
24739
+ MCP_ONLY_CHANNEL_EXPOSURE
24740
+ ),
24741
+ defineCapability(
24742
+ "delete_monthly_expense",
24743
+ // Filled by the MCP schema fingerprint test.
24744
+ "fe9c5d5896165b9c65fbfed779db7918dabf87c69e1601430a1509ad2d452de9",
24745
+ "state_change",
24746
+ "business",
24747
+ [
24748
+ "state_change"
24749
+ ],
24750
+ [
24751
+ slot("expense_label", true, [
24752
+ "label"
24753
+ ]),
24754
+ slot("month", true, [
24755
+ "month"
24756
+ ]),
24757
+ slot("operation", false, [
24758
+ "operationId"
24759
+ ])
24760
+ ],
24761
+ [
24762
+ "monthly_expense"
24763
+ ],
24764
+ [
24765
+ "finance_operation"
24766
+ ],
24767
+ MCP_ONLY_CHANNEL_EXPOSURE
24768
+ ),
24769
+ defineCapability(
24770
+ "remove_product_control",
24771
+ // Filled by the MCP schema fingerprint test.
24772
+ "ff0b7411497a0b28eda7294c35b09c45f8beff842bbc6a9a4cc993ba3d766cae",
24773
+ "state_change",
24774
+ "business",
24775
+ [
24776
+ "state_change"
24777
+ ],
24778
+ [
24779
+ slot("product_control", true, [
24780
+ "productControlId"
24781
+ ])
24782
+ ],
24783
+ [
24784
+ "product_control"
24785
+ ],
24786
+ [
24787
+ "product_control"
24788
+ ],
24789
+ MCP_ONLY_CHANNEL_EXPOSURE
24790
+ ),
24226
24791
  defineCapability("report_daily_returns", "7130d216656cc29a47fc972b4edad5003a6653fca48d95052fbf2b561636e91a", "state_change", "business", [
24227
24792
  "state_change"
24228
24793
  ], [
@@ -27343,27 +27908,39 @@ var PublishedClassicLandingSchema = z122.object({
27343
27908
  import { z as z123 } from "zod";
27344
27909
  var DropiCountrySchema = z123.enum(DROPI_COUNTRY_CODES);
27345
27910
  var DropiCountryQuerySchema = z123.object({
27346
- countryCode: DropiCountrySchema.default("CO")
27911
+ countryCode: DropiCountrySchema.default("CO"),
27912
+ connectionId: z123.string().uuid().optional()
27347
27913
  }).strict();
27348
27914
  var ConnectDropiFinancialSchema = z123.object({
27349
27915
  countryCode: DropiCountrySchema.default("CO"),
27916
+ connectionId: z123.string().uuid().optional(),
27917
+ label: z123.string().trim().min(1).max(80).optional(),
27350
27918
  integrationKey: z123.string().trim().min(1).max(4096).regex(/^[\x21-\x7e]+$/)
27351
27919
  }).strict();
27352
27920
  var SyncDropiFinancialSchema = z123.object({
27353
27921
  countryCode: DropiCountrySchema.optional(),
27354
27922
  operationId: z123.string().uuid().optional(),
27923
+ connectionId: z123.string().uuid().optional(),
27355
27924
  since: z123.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
27356
27925
  until: z123.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
27357
27926
  }).strict();
27358
27927
  var connectionCountries = z123.array(DropiCountrySchema).max(DROPI_COUNTRY_CODES.length).refine((countries) => new Set(countries).size === countries.length);
27359
27928
  var DropiFinancialConnectionsSchema = z123.object({
27360
27929
  connectedCountries: connectionCountries,
27930
+ connections: z123.array(z123.object({
27931
+ connectionId: z123.string().uuid(),
27932
+ countryCode: DropiCountrySchema,
27933
+ label: z123.string().min(1).max(80)
27934
+ }).strict()).max(21).optional(),
27361
27935
  /** Effective connect availability after flags, proxy and scoped-identity readiness. */
27362
27936
  enabledCountries: connectionCountries
27363
27937
  }).strict();
27364
27938
  var DropiFinancialStatusSchema = z123.object({
27365
27939
  enabled: z123.boolean(),
27366
27940
  connected: z123.boolean(),
27941
+ connectionId: z123.string().uuid().optional(),
27942
+ connectionCount: z123.number().int().nonnegative().optional(),
27943
+ label: z123.string().min(1).max(80).optional(),
27367
27944
  countryCode: DropiCountrySchema,
27368
27945
  /** Configured environment allowlist; selected-country availability is `enabled`. */
27369
27946
  enabledCountries: z123.array(DropiCountrySchema).optional(),
@@ -27372,6 +27949,8 @@ var DropiFinancialStatusSchema = z123.object({
27372
27949
  "production"
27373
27950
  ]),
27374
27951
  lastSyncAt: z123.string().nullable(),
27952
+ /** Latest successful unit across accounts; triggers refresh but never certifies coverage. */
27953
+ lastActivityAt: z123.string().nullable().optional(),
27375
27954
  lastError: z123.string().nullable(),
27376
27955
  historyNext: z123.string().nullable(),
27377
27956
  historyUntil: z123.string().nullable(),
@@ -28609,7 +29188,7 @@ var ApiClient = class {
28609
29188
  };
28610
29189
 
28611
29190
  // src/index.ts
28612
- var MCP_VERSION = "12.2.5";
29191
+ var MCP_VERSION = "12.2.6";
28613
29192
 
28614
29193
  // src/meta-upload-app.ts
28615
29194
  import { readFileSync } from "fs";
@@ -38406,6 +38985,7 @@ function registerDailyControlTools(server, api) {
38406
38985
  __name(registerDailyControlTools, "registerDailyControlTools");
38407
38986
 
38408
38987
  // src/tools/product-control.ts
38988
+ import { createHash as createHash4 } from "crypto";
38409
38989
  import { readFile, stat } from "fs/promises";
38410
38990
  import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
38411
38991
  import { z as z154 } from "zod";
@@ -38421,6 +39001,15 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
38421
39001
  var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
38422
39002
  var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
38423
39003
  var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
39004
+ var getDropiStatusGuidance = getProductMakerCapabilityModelGuidance("get_dropi_status");
39005
+ var syncDropiOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_dropi_orders");
39006
+ var createManualProductGuidance = getProductMakerCapabilityModelGuidance("create_manual_product");
39007
+ var listUnmatchedGuidance = getProductMakerCapabilityModelGuidance("list_unmatched_products");
39008
+ var resolveUnmatchedGuidance = getProductMakerCapabilityModelGuidance("resolve_unmatched_product");
39009
+ var listLinkableCampaignsGuidance = getProductMakerCapabilityModelGuidance("list_linkable_campaigns");
39010
+ var linkProductCampaignGuidance = getProductMakerCapabilityModelGuidance("link_product_campaign");
39011
+ var deleteMonthlyExpenseGuidance = getProductMakerCapabilityModelGuidance("delete_monthly_expense");
39012
+ var removeProductControlGuidance = getProductMakerCapabilityModelGuidance("remove_product_control");
38424
39013
  var DateOnly2 = z154.string().regex(/^\d{4}-\d{2}-\d{2}$/);
38425
39014
  var IMPORT_BATCH_MAX2 = 50;
38426
39015
  var ProductControlListInput = z154.object({
@@ -38440,8 +39029,14 @@ var ImportProductControlsInput = z154.object({
38440
39029
  shopDomain: z154.string().min(1)
38441
39030
  }).strict();
38442
39031
  var SetProductCostingInput = z154.object({
38443
- shopDomain: z154.string().min(1),
38444
- shopifyProductId: z154.string().min(1).max(64),
39032
+ /* La identidad, de UNA forma: la del producto nuestro, o la pareja
39033
+ tienda + id de Shopify. El esquema canónico también las admite juntas,
39034
+ pero pedirlas por separado evita que el modelo emita una mezcla que
39035
+ diga dos productos a la vez. */
39036
+ productControlId: z154.string().uuid().optional().describe("El id nuestro (lo devuelven get_product_control y create_manual_product). Obligatorio para productos manuales o importados sin tienda."),
39037
+ manualSellingPrice: z154.number().positive().nullable().optional().describe("Precio de venta \u2014 SOLO con productControlId: para el producto sin tienda no hay otra verdad. En un producto de Shopify NO se manda: el precio lo manda la tienda."),
39038
+ shopDomain: z154.string().min(1).optional(),
39039
+ shopifyProductId: z154.string().min(1).max(64).optional(),
38445
39040
  targetCountry: z154.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
38446
39041
  supplierCost: z154.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
38447
39042
  shippingCost: z154.number().finite().nonnegative(),
@@ -38491,6 +39086,48 @@ var GetFinancesInput = z154.object({
38491
39086
  month: z154.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional().describe("Mes en YYYY-MM. Si se omite, el mes en curso. Solo mes calendario."),
38492
39087
  operationId: z154.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
38493
39088
  }).strict();
39089
+ var GetDropiStatusInput = DropiCountryQuerySchema.extend({
39090
+ countryCode: DropiCountrySchema.optional().describe("Pa\xEDs de la cuenta (ISO-2). Si se omite, el servidor responde por Colombia (CO)."),
39091
+ connectionId: z154.string().uuid().optional().describe("Una cuenta concreta cuando el pa\xEDs tiene varias. Sale de la lista de conexiones; nunca se inventa.")
39092
+ });
39093
+ var SyncDropiOrdersInput = SyncDropiFinancialSchema;
39094
+ var CreateManualProductInput = CreateManualProductControlSchema.innerType().omit({
39095
+ requestId: true
39096
+ });
39097
+ var ListUnmatchedProductsInput = z154.object({
39098
+ operationId: z154.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
39099
+ }).strict();
39100
+ var ResolveUnmatchedProductInput = ResolveUnmatchedProductSchema;
39101
+ var ListLinkableCampaignsInput = z154.object({}).strict();
39102
+ var LinkProductCampaignInput = z154.object({
39103
+ provider: z154.enum([
39104
+ "meta",
39105
+ "tiktok"
39106
+ ]).describe("La red publicitaria de la campa\xF1a."),
39107
+ accountId: z154.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/).describe("La cuenta publicitaria. Sale de list_linkable_campaigns; nunca se inventa."),
39108
+ campaignId: z154.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/).describe("La campa\xF1a. Sale de list_linkable_campaigns; nunca se inventa."),
39109
+ productControlId: z154.string().uuid().optional().describe("El id del producto en su control financiero."),
39110
+ shopDomain: z154.string().min(1).optional().describe("La tienda del producto; con shopifyProductId es la otra forma de decir cu\xE1l es."),
39111
+ shopifyProductId: z154.string().min(1).optional().describe("El id del producto en su tienda. Va junto a shopDomain.")
39112
+ }).strict();
39113
+ var DeleteMonthlyExpenseInput = DeleteMonthlyExpenseSchema;
39114
+ var RemoveProductControlInput = z154.object({
39115
+ productControlId: z154.string().uuid().describe("El id del producto en su control. Sale del listado; nunca se inventa.")
39116
+ }).strict();
39117
+ function manualProductRequestId(input) {
39118
+ const digest3 = createHash4("sha256").update(JSON.stringify(input, [
39119
+ "cancellationRate",
39120
+ "manualSellingPrice",
39121
+ "operationId",
39122
+ "returnRate",
39123
+ "shippingCost",
39124
+ "supplierCost",
39125
+ "targetCountry",
39126
+ "title"
39127
+ ])).digest("hex");
39128
+ return `${digest3.slice(0, 8)}-${digest3.slice(8, 12)}-4${digest3.slice(13, 16)}-${"89ab"[parseInt(digest3[16] ?? "8", 16) % 4]}${digest3.slice(17, 20)}-` + digest3.slice(20, 32);
39129
+ }
39130
+ __name(manualProductRequestId, "manualProductRequestId");
38494
39131
  function registerProductControlTools(server, api, { transport = "http" } = {}) {
38495
39132
  server.registerTool("get_product_control", {
38496
39133
  description: getProductControlGuidance.summary + ' Responde la pregunta que de verdad importa \u2014cu\xE1les dejo correr y cu\xE1les apago\u2014 con `verdict` por producto: `scale` (escalar), `hold` (mantener), `kill` (matar) e `insufficient_sample` (muestra insuficiente). `insufficient_sample` NO es `kill`: significa que todav\xEDa no hay pedidos suficientes para decidir, y tratarlo como \xABap\xE1galo\xBB mata productos que nunca se midieron. `light` (`green`/`amber`/`red`/`none`) es el mismo juicio en color; `none` es \xABno hay juicio\xBB, no \xABneutro\xBB. Un d\xEDa con `cancelledSource: "shopify_settling"` est\xE1 medido pero NO cerrado \u2014las cancelaciones de contra-entrega llegan d\xEDas despu\xE9s\u2014, as\xED que ese veredicto solo puede empeorar: dilo antes de que alguien escale con \xE9l. Es READ-ONLY: nunca pausa ni modifica una campa\xF1a. Cada fila trae `productControlId`, que es lo que piden las dem\xE1s herramientas del control \u2014 \xFAsalo tal cual, nunca lo construyas. Un producto con `status` distinto de `ok` NO tiene m\xE9tricas: explica el `statusMessage` y no inventes n\xFAmeros para reemplazarlo. `status: "no_costing"` significa que falta decir cu\xE1nto cuesta (set_product_costing); `sales_unavailable` significa que no podemos leer los pedidos de la tienda \u2014 ah\xED la salida es report_product_counts, no reconectar. Y cuando un d\xEDa trae `effectiveSalesSource` distinto de `"user"`, esa cifra de ventas entregadas NO fue medida: sale de una resta que da por entregado lo que a\xFAn va en camino, as\xED que dilo y no la presentes como un hecho.',
@@ -38553,12 +39190,12 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
38553
39190
  throw new Error("El archivo pesa m\xE1s de 8 MB.");
38554
39191
  }
38555
39192
  const name = basename2(absolute).toLowerCase();
38556
- if (!/\.(xlsx|xls|csv)$/.test(name)) {
38557
- throw new Error("Solo puedo leer archivos .xlsx, .xls o .csv de pedidos.");
39193
+ if (!name.endsWith(".xlsx")) {
39194
+ throw new Error("Solo puedo leer archivos .xlsx de pedidos.");
38558
39195
  }
38559
39196
  const bytes = await readFile(absolute);
38560
39197
  const isZip = bytes[0] === 80 && bytes[1] === 75;
38561
- if (name.endsWith(".xlsx") && !isZip) {
39198
+ if (!isZip) {
38562
39199
  throw new Error("Ese archivo no es un .xlsx de verdad.");
38563
39200
  }
38564
39201
  return asText(await api.postJson("/v1/product-control/order-lines/file", {
@@ -38655,11 +39292,18 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
38655
39292
  }
38656
39293
  });
38657
39294
  server.registerTool("set_product_costing", {
38658
- description: setProductCostingGuidance.summary + " El precio de venta NO se pide aqu\xED: lo manda la tienda, y aceptarlo crear\xEDa una segunda verdad que se desincroniza en silencio. Las dos tasas son proporciones entre 0 y 1 y son la ESTIMACI\xD3N de la persona, no una medici\xF3n \u2014 si ella ya tiene los n\xFAmeros reales del d\xEDa, eso es report_product_counts. Nunca inventes un costo ni lo deduzcas del precio: sin costo real no hay sem\xE1foro, y un cero volver\xEDa infinitamente rentable cualquier producto.",
39295
+ description: setProductCostingGuidance.summary + " El producto se identifica de UNA forma: `productControlId` para el manual o importado sin tienda, o `shopDomain` + `shopifyProductId` para el de la tienda \u2014 nunca las dos mezcladas. El precio de venta SOLO viaja con `productControlId` (`manualSellingPrice`): para el producto sin tienda no hay otra verdad; para el de Shopify lo manda la tienda y aceptarlo crear\xEDa una segunda que se desincroniza en silencio. Las dos tasas son proporciones entre 0 y 1 y son la ESTIMACI\xD3N de la persona, no una medici\xF3n \u2014 si ella ya tiene los n\xFAmeros reales del d\xEDa, eso es report_product_counts. Nunca inventes un costo ni lo deduzcas del precio: sin costo real no hay sem\xE1foro, y un cero volver\xEDa infinitamente rentable cualquier producto.",
38659
39296
  inputSchema: SetProductCostingInput.shape,
38660
39297
  annotations: OVERWRITES_INTERNAL
38661
39298
  }, async (input) => {
38662
39299
  try {
39300
+ const { productControlId, shopDomain, shopifyProductId } = input;
39301
+ if (productControlId !== void 0 && (shopDomain !== void 0 || shopifyProductId !== void 0)) {
39302
+ throw new Error("El producto se dice de una sola forma: quita productControlId o quita shopDomain + shopifyProductId.");
39303
+ }
39304
+ if (productControlId === void 0 && (shopDomain === void 0 || shopifyProductId === void 0)) {
39305
+ throw new Error("Falta el producto: manda productControlId o shopDomain + shopifyProductId.");
39306
+ }
38663
39307
  return asText(await api.putJson("/v1/product-control/costing", input));
38664
39308
  } catch (error) {
38665
39309
  throw translateError(error);
@@ -38677,6 +39321,134 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
38677
39321
  throw translateError(error);
38678
39322
  }
38679
39323
  });
39324
+ server.registerTool("get_dropi_status", {
39325
+ description: getDropiStatusGuidance.summary + " Devuelve si la cuenta est\xE1 conectada, cu\xE1ntas hay en el pa\xEDs, la \xFAltima lectura y si qued\xF3 algo pendiente. La conexi\xF3n NO se hace por aqu\xED: la llave de Dropi se pega en Integraciones y dec\xEDrselo a la persona es parte de la respuesta cuando salga `connected: false`.",
39326
+ inputSchema: GetDropiStatusInput.shape,
39327
+ annotations: READS_INTERNAL
39328
+ }, async (input) => {
39329
+ try {
39330
+ const params = new URLSearchParams();
39331
+ if (input.countryCode) params.set("countryCode", input.countryCode);
39332
+ if (input.connectionId) params.set("connectionId", input.connectionId);
39333
+ return asText(await api.getJson(`/v1/product-control/dropi/status?${params.toString()}`));
39334
+ } catch (error) {
39335
+ throw translateError(error);
39336
+ }
39337
+ });
39338
+ server.registerTool("sync_dropi_orders", {
39339
+ description: syncDropiOrdersGuidance.summary + " Es idempotente: leer el mismo rango dos veces actualiza las l\xEDneas en vez de duplicarlas, as\xED que no hay miedo en repetirlo. Si la respuesta queda `pending`, la lectura sigui\xF3 por detr\xE1s: dilo y ofrece mirar de nuevo con get_dropi_status, no afirmes un total que a\xFAn no termina.",
39340
+ inputSchema: SyncDropiOrdersInput.shape,
39341
+ // Lee Dropi sin mutarlo, pero puede sobrescribir sus líneas en nuestro libro.
39342
+ annotations: OVERWRITES_INTERNAL
39343
+ }, async (input) => {
39344
+ try {
39345
+ return asText(await api.postJson("/v1/product-control/dropi/sync", input));
39346
+ } catch (error) {
39347
+ throw translateError(error);
39348
+ }
39349
+ });
39350
+ server.registerTool("create_manual_product", {
39351
+ description: createManualProductGuidance.summary + " Pide TODOS los datos antes de llamarla: el costo del proveedor y el flete sin inventar \u2014 un cero volver\xEDa infinitamente rentable el producto. Las dos tasas son proporciones 0\u20131 y SU estimaci\xF3n, no una medici\xF3n. Reintentar con los mismos datos devuelve el mismo producto; no duplica.",
39352
+ inputSchema: CreateManualProductInput.shape,
39353
+ annotations: CREATES_INTERNAL
39354
+ }, async (input) => {
39355
+ try {
39356
+ return asText(await api.postJson("/v1/product-control/manual", {
39357
+ ...input,
39358
+ requestId: manualProductRequestId(input)
39359
+ }));
39360
+ } catch (error) {
39361
+ throw translateError(error);
39362
+ }
39363
+ });
39364
+ server.registerTool("list_unmatched_products", {
39365
+ description: listUnmatchedGuidance.summary + " Un producto aqu\xED ya tiene pedidos guardados: lo \xFAnico que falta es decir qui\xE9n es. Con la lista a la mano, resolve_unmatched_product le pone due\xF1o.",
39366
+ inputSchema: ListUnmatchedProductsInput.shape,
39367
+ annotations: READS_INTERNAL
39368
+ }, async (input) => {
39369
+ try {
39370
+ const params = new URLSearchParams();
39371
+ if (input.operationId) params.set("operationId", input.operationId);
39372
+ const query = params.toString();
39373
+ return asText(await api.getJson(`/v1/product-control/unmatched${query ? `?${query}` : ""}`));
39374
+ } catch (error) {
39375
+ throw translateError(error);
39376
+ }
39377
+ });
39378
+ server.registerTool("resolve_unmatched_product", {
39379
+ description: resolveUnmatchedGuidance.summary + " Con `productControlId` el alias se cuelga de esa ficha y sus pedidos se mudan ah\xED; sin \xE9l se crea la ficha nueva con `label`. Ninguno de los dos caminos descarta pedidos \u2014 no existe un \xABesto no es m\xEDo\xBB porque la informaci\xF3n ya entr\xF3.",
39380
+ inputSchema: ResolveUnmatchedProductInput.shape,
39381
+ annotations: CREATES_INTERNAL
39382
+ }, async (input) => {
39383
+ try {
39384
+ return asText(await api.postJson("/v1/product-control/resolve-unmatched", input));
39385
+ } catch (error) {
39386
+ throw translateError(error);
39387
+ }
39388
+ });
39389
+ server.registerTool("list_linkable_campaigns", {
39390
+ description: listLinkableCampaignsGuidance.summary + " Si sale vac\xEDa, la cuenta de publicidad no est\xE1 conectada o no tiene campa\xF1as: la conexi\xF3n se hace en Integraciones, no por aqu\xED.",
39391
+ inputSchema: ListLinkableCampaignsInput.shape,
39392
+ annotations: READS_EXTERNAL
39393
+ }, async () => {
39394
+ try {
39395
+ return asText(await api.getJson("/v1/product-control/linkable-campaigns"));
39396
+ } catch (error) {
39397
+ throw translateError(error);
39398
+ }
39399
+ });
39400
+ server.registerTool("link_product_campaign", {
39401
+ description: linkProductCampaignGuidance.summary + " Los identificadores salen de list_linkable_campaigns \u2014 nunca los inventes. El producto se dice de UNA forma: `productControlId`, o `shopDomain` + `shopifyProductId`. Desde el enlace, su costo por venta empieza a leerse de esa campa\xF1a.",
39402
+ inputSchema: LinkProductCampaignInput.shape,
39403
+ annotations: CREATES_INTERNAL
39404
+ }, async (input) => {
39405
+ try {
39406
+ const { provider: provider2, accountId, campaignId, productControlId, shopDomain, shopifyProductId } = input;
39407
+ if (productControlId !== void 0 && (shopDomain !== void 0 || shopifyProductId !== void 0)) {
39408
+ throw new Error("El producto se dice de una sola forma: quita productControlId o quita shopDomain + shopifyProductId.");
39409
+ }
39410
+ if (productControlId === void 0 && (shopDomain === void 0 || shopifyProductId === void 0)) {
39411
+ throw new Error("Falta el producto: manda productControlId o shopDomain + shopifyProductId.");
39412
+ }
39413
+ const body = productControlId !== void 0 ? {
39414
+ provider: provider2,
39415
+ accountId,
39416
+ campaignId,
39417
+ productControlId
39418
+ } : {
39419
+ provider: provider2,
39420
+ accountId,
39421
+ campaignId,
39422
+ shopDomain,
39423
+ shopifyProductId
39424
+ };
39425
+ return asText(await api.postJson("/v1/product-control/campaigns", body));
39426
+ } catch (error) {
39427
+ throw translateError(error);
39428
+ }
39429
+ });
39430
+ server.registerTool("delete_monthly_expense", {
39431
+ description: deleteMonthlyExpenseGuidance.summary + " Borra por mes + etiqueta, los dos datos que la persona ve en su lista. Para cambiar el monto NO se borra: set_monthly_expense con el valor nuevo es la correcci\xF3n.",
39432
+ inputSchema: DeleteMonthlyExpenseInput.shape,
39433
+ annotations: OVERWRITES_INTERNAL
39434
+ }, async (input) => {
39435
+ try {
39436
+ return asText(await api.postJson("/v1/product-control/expenses/delete", input));
39437
+ } catch (error) {
39438
+ throw translateError(error);
39439
+ }
39440
+ });
39441
+ server.registerTool("remove_product_control", {
39442
+ description: removeProductControlGuidance.summary + " Se va con sus costos y su anuncio vinculado; sus l\xEDneas del libro quedan sin producto hasta que alguien las reconozca de nuevo. Confirma con la persona el nombre del producto antes de llamarla.",
39443
+ inputSchema: RemoveProductControlInput.shape,
39444
+ annotations: OVERWRITES_INTERNAL
39445
+ }, async (input) => {
39446
+ try {
39447
+ return asText(await api.deleteJson(`/v1/product-control/${encodeURIComponent(input.productControlId)}`));
39448
+ } catch (error) {
39449
+ throw translateError(error);
39450
+ }
39451
+ });
38680
39452
  }
38681
39453
  __name(registerProductControlTools, "registerProductControlTools");
38682
39454