@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/http.js CHANGED
@@ -2892,7 +2892,8 @@ var sha256 = z3.string().regex(/^[a-f0-9]{64}$/i);
2892
2892
  var MAX_LLM_ROUTE_POLICY_STEPS = 512;
2893
2893
  var MAX_LLM_ROUTE_POLICY_PROFILES = 64;
2894
2894
  var MAX_LLM_ROUTE_POLICY_SUBMISSIONS = 2048;
2895
- var MAX_LLM_NATIVE_RETRY_POLICY_SUBMISSIONS = MAX_LLM_ROUTE_POLICY_STEPS * 60;
2895
+ var MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS = 120;
2896
+ var MAX_LLM_NATIVE_RETRY_POLICY_SUBMISSIONS = MAX_LLM_ROUTE_POLICY_STEPS * MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS;
2896
2897
  var NATIVE_OWNED_LLM_MAX_SUBMISSIONS = 9;
2897
2898
  var NativeMessagesBudgetSchema = z3.object({
2898
2899
  version: z3.literal("native_messages_bytes_v1"),
@@ -3228,7 +3229,7 @@ var LlmAttemptRetryCauseSchema = z3.enum([
3228
3229
  ]);
3229
3230
  var LlmAttemptBudgetSchema = z3.object({
3230
3231
  maxCostUsd: z3.number().finite().nonnegative(),
3231
- maxSubmissions: z3.number().int().min(1).max(60),
3232
+ maxSubmissions: z3.number().int().min(1).max(MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS),
3232
3233
  maxSameTargetRetries: z3.number().int().min(0).max(29),
3233
3234
  finalizationReserveMs: z3.number().int().nonnegative(),
3234
3235
  retryPolicy: LlmAttemptRetryPolicySchema.optional()
@@ -3711,7 +3712,7 @@ var LlmAttemptAdmissionInputSchema = z3.object({
3711
3712
  }).strict();
3712
3713
  var LlmAttemptAdmissionGrantSchema = z3.object({
3713
3714
  attemptId: identifier,
3714
- ordinal: z3.number().int().min(1).max(60),
3715
+ ordinal: z3.number().int().min(1).max(MAX_LLM_NATIVE_ATTEMPT_SUBMISSIONS),
3715
3716
  attemptToken: identifier,
3716
3717
  targetId: identifier,
3717
3718
  reservedMaxCostUsd: z3.number().finite().nonnegative()
@@ -3916,7 +3917,7 @@ var ModelRoutePolicyBaseSchema = z4.object({
3916
3917
  maxEntries: z4.number().int().min(1).max(MODEL_ROUTE_MAX_ENTRIES),
3917
3918
  models: z4.array(model).min(1).max(8),
3918
3919
  routes: z4.array(provider).min(1).max(3),
3919
- /** New CE edits alone opt in; immutable legacy service policies stay two-leg. */
3920
+ /** Every new routed claim for a protocol-10 reader; stored two-leg policies stay two-leg. */
3920
3921
  nativeRouting: z4.object({
3921
3922
  version: z4.literal(1),
3922
3923
  byModel: z4.record(model, LlmRouteSnapshotSchema)
@@ -14508,8 +14509,9 @@ var CostEstimationResponse = z50.object({
14508
14509
  /** True when userBalanceCents >= max estimated cost (worst case). */
14509
14510
  hasSufficientBalance: z50.boolean()
14510
14511
  });
14512
+ var COST_ESTIMATION_BATCH_LIMIT = 32;
14511
14513
  var CostEstimationBatchRequest = z50.object({
14512
- requests: z50.array(CostEstimationRequest).min(1).max(32)
14514
+ requests: z50.array(CostEstimationRequest).min(1).max(COST_ESTIMATION_BATCH_LIMIT)
14513
14515
  });
14514
14516
  var CostEstimationUnavailableCode = z50.enum([
14515
14517
  "CREATIVE_ENGINE_VIDEO_QUALITY_NOT_ADMITTED",
@@ -14529,7 +14531,7 @@ var CostEstimationBatchEstimate = z50.union([
14529
14531
  }).strict()
14530
14532
  ]);
14531
14533
  var CostEstimationBatchResponse = z50.object({
14532
- estimates: z50.array(CostEstimationBatchEstimate).max(32)
14534
+ estimates: z50.array(CostEstimationBatchEstimate).max(COST_ESTIMATION_BATCH_LIMIT)
14533
14535
  });
14534
14536
  var UnitCreditRange = z50.object({
14535
14537
  /** Best-case credits (most units → HIGH end of the count band). */
@@ -14586,6 +14588,10 @@ var CODE_LANDING_LLM_V2_TARGETS = {
14586
14588
  transport: "openrouter",
14587
14589
  model: "deepseek/deepseek-v4.1-flash"
14588
14590
  },
14591
+ "deepseek-v4.1-1017-openrouter": {
14592
+ transport: "openrouter",
14593
+ model: "deepseek/deepseek-v4.1-flash-1017"
14594
+ },
14589
14595
  "qwen-omni-openrouter": {
14590
14596
  transport: "openrouter",
14591
14597
  model: "qwen/qwen3.8-omni-flash"
@@ -14654,18 +14660,32 @@ var CodeLandingLlmChildCallBudgetSchema = z51.object({
14654
14660
  provider: z51.literal("google").optional(),
14655
14661
  targetId: z51.literal("gemini-flash-google").optional(),
14656
14662
  /** The second physical ordinal is the explicitly funded DeepSeek leg. */
14657
- fallbackTarget: z51.object({
14658
- transport: z51.literal("openrouter"),
14659
- provider: z51.literal("openrouter"),
14660
- targetId: z51.literal("deepseek-v4.1-openrouter"),
14661
- model: z51.literal("deepseek/deepseek-v4.1-flash"),
14662
- companyColdPricing: z51.object({
14663
- source: z51.literal("verified_catalog"),
14664
- snapshotDate: z51.literal("2026-10-07"),
14665
- inputUsdPerMillionTokens: z51.literal(0.14),
14666
- outputUsdPerMillionTokens: z51.literal(0.42)
14663
+ fallbackTarget: z51.union([
14664
+ z51.object({
14665
+ transport: z51.literal("openrouter"),
14666
+ provider: z51.literal("openrouter"),
14667
+ targetId: z51.literal("deepseek-v4.1-openrouter"),
14668
+ model: z51.literal("deepseek/deepseek-v4.1-flash"),
14669
+ companyColdPricing: z51.object({
14670
+ source: z51.literal("verified_catalog"),
14671
+ snapshotDate: z51.literal("2026-10-07"),
14672
+ inputUsdPerMillionTokens: z51.literal(0.14),
14673
+ outputUsdPerMillionTokens: z51.literal(0.42)
14674
+ }).strict()
14675
+ }).strict(),
14676
+ z51.object({
14677
+ transport: z51.literal("openrouter"),
14678
+ provider: z51.literal("openrouter"),
14679
+ targetId: z51.literal("deepseek-v4.1-1017-openrouter"),
14680
+ model: z51.literal("deepseek/deepseek-v4.1-flash-1017"),
14681
+ companyColdPricing: z51.object({
14682
+ source: z51.literal("verified_catalog"),
14683
+ snapshotDate: z51.literal("2026-10-24"),
14684
+ inputUsdPerMillionTokens: z51.literal(0.454),
14685
+ outputUsdPerMillionTokens: z51.literal(1.2)
14686
+ }).strict()
14667
14687
  }).strict()
14668
- }).strict().optional(),
14688
+ ]).optional(),
14669
14689
  model: z51.string().min(1),
14670
14690
  maxGroups: z51.number().int().positive().max(14),
14671
14691
  maxCallsPerGroup: z51.number().int().positive().max(5),
@@ -14877,7 +14897,12 @@ var CodeLandingEnvelopeNodeSchema = z51.object({
14877
14897
  companyOutput: 12e3,
14878
14898
  // Fresh direction uses Sonnet. Historical DeepSeek/Grok quotes
14879
14899
  // retain their exact model, tariff and one-call budget.
14880
- ...budget.model === "anthropic/claude-sonnet-5.5" ? CODE_LANDING_SONNET_NATIVE_PRICING : budget.model === "deepseek/deepseek-v4.1-flash" ? {
14900
+ ...budget.model === "anthropic/claude-sonnet-5.5" ? CODE_LANDING_SONNET_NATIVE_PRICING : budget.model === "deepseek/deepseek-v4.1-flash-1017" ? {
14901
+ model: "deepseek/deepseek-v4.1-flash-1017",
14902
+ snapshotDate: "2026-10-24",
14903
+ inputRate: 0.454,
14904
+ outputRate: 1.2
14905
+ } : budget.model === "deepseek/deepseek-v4.1-flash" ? {
14881
14906
  model: "deepseek/deepseek-v4.1-flash",
14882
14907
  snapshotDate: "2026-10-07",
14883
14908
  inputRate: 0.14,
@@ -21576,6 +21601,150 @@ var CAPABILITY_MODEL_GUIDANCE = {
21576
21601
  "requiere confirmaci\xF3n; cero afirma que no pauto, null vuelve a campanas"
21577
21602
  ]
21578
21603
  },
21604
+ get_dropi_status: {
21605
+ summary: "Dice si su cuenta Dropi est\xE1 conectada y hasta d\xF3nde lleg\xF3 la lectura de pedidos.",
21606
+ useWhen: [
21607
+ "est\xE1 conectado mi Dropi",
21608
+ "por qu\xE9 no llegan mis pedidos de Dropi"
21609
+ ],
21610
+ avoidWhen: [
21611
+ "quiere el mes armado: get_finances"
21612
+ ],
21613
+ defaults: [
21614
+ "pa\xEDs de la operaci\xF3n; con varias cuentas del mismo pa\xEDs pregunta cu\xE1l"
21615
+ ],
21616
+ disclosures: [
21617
+ "solo lectura; no conecta ni desconecta cuentas"
21618
+ ]
21619
+ },
21620
+ sync_dropi_orders: {
21621
+ summary: "Trae los pedidos reales de su cuenta Dropi al libro de cuentas.",
21622
+ useWhen: [
21623
+ "sincroniza mis pedidos de Dropi",
21624
+ "actualiza lo que vend\xED por Dropi"
21625
+ ],
21626
+ avoidWhen: [
21627
+ "la cuenta no est\xE1 conectada: la conexi\xF3n se hace en Integraciones, no por chat"
21628
+ ],
21629
+ defaults: [
21630
+ "mes en curso cuando no dan fechas"
21631
+ ],
21632
+ disclosures: [
21633
+ "requiere confirmaci\xF3n; una lectura larga puede quedar pendiente y responde lo que alcanz\xF3 a leer"
21634
+ ]
21635
+ },
21636
+ create_manual_product: {
21637
+ summary: "Crea un producto a mano en su control financiero: sin tienda ni tarea.",
21638
+ useWhen: [
21639
+ "vendo algo que no est\xE1 en mi tienda",
21640
+ "agr\xE9game este producto que vendo por fuera"
21641
+ ],
21642
+ avoidWhen: [
21643
+ "el producto ya est\xE1 en su tienda: import_product_controls"
21644
+ ],
21645
+ defaults: [
21646
+ "el pa\xEDs fija la moneda: nunca la inventes ni la preguntes aparte"
21647
+ ],
21648
+ disclosures: [
21649
+ "requiere confirmaci\xF3n; aqu\xED el precio S\xCD se escribe a mano porque no hay tienda que lo mande"
21650
+ ]
21651
+ },
21652
+ list_unmatched_products: {
21653
+ summary: "Lista los productos que una importaci\xF3n trajo y todav\xEDa no tienen due\xF1o en su libro.",
21654
+ useWhen: [
21655
+ "qu\xE9 productos no reconociste",
21656
+ "hay pedidos sin producto"
21657
+ ],
21658
+ avoidWhen: [
21659
+ "quiere el cat\xE1logo ya controlado: get_product_control"
21660
+ ],
21661
+ defaults: [
21662
+ "la operaci\xF3n se deduce del pa\xEDs cuando solo hay una"
21663
+ ],
21664
+ disclosures: [
21665
+ "solo lectura; los pedidos ya est\xE1n guardados \u2014 esto muestra a qui\xE9n falta asignarlos"
21666
+ ]
21667
+ },
21668
+ resolve_unmatched_product: {
21669
+ 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.",
21670
+ useWhen: [
21671
+ "ese producto es el termo que ya vendo",
21672
+ "reconoce este producto del proveedor"
21673
+ ],
21674
+ avoidWhen: [
21675
+ "quiere unir dos fichas ya creadas: merge_products"
21676
+ ],
21677
+ defaults: [
21678
+ "con el id de un producto existente cuelga el alias ah\xED; sin \xE9l crea la ficha con el nombre que vino"
21679
+ ],
21680
+ disclosures: [
21681
+ "requiere confirmaci\xF3n; sus pedidos ya est\xE1n guardados \u2014 esto solo les pone due\xF1o y nada se descarta"
21682
+ ]
21683
+ },
21684
+ list_linkable_campaigns: {
21685
+ summary: "Muestra las campa\xF1as de Meta y TikTok que puede atar a un producto, sin teclear identificadores.",
21686
+ useWhen: [
21687
+ "qu\xE9 campa\xF1as puedo vincular",
21688
+ "a qu\xE9 anuncio le pego este producto"
21689
+ ],
21690
+ avoidWhen: [
21691
+ "ya sabe cu\xE1l va: link_product_campaign directo"
21692
+ ],
21693
+ defaults: [
21694
+ "salen de las cuentas de publicidad ya conectadas"
21695
+ ],
21696
+ disclosures: [
21697
+ "solo lectura"
21698
+ ]
21699
+ },
21700
+ link_product_campaign: {
21701
+ summary: "Ata una campa\xF1a de publicidad a un producto de su control financiero.",
21702
+ useWhen: [
21703
+ "vincula esta campa\xF1a a mi termo",
21704
+ "ese producto se anuncia por esta campa\xF1a"
21705
+ ],
21706
+ avoidWhen: [
21707
+ "la campa\xF1a no sale: list_linkable_campaigns primero"
21708
+ ],
21709
+ defaults: [
21710
+ "el producto va por su id del control o por tienda + id de Shopify"
21711
+ ],
21712
+ disclosures: [
21713
+ "requiere confirmaci\xF3n; desde ese momento el sem\xE1foro lee el gasto de esa campa\xF1a"
21714
+ ]
21715
+ },
21716
+ delete_monthly_expense: {
21717
+ summary: "Borra un gasto fijo del mes.",
21718
+ useWhen: [
21719
+ "quita el gasto de arriendo",
21720
+ "borra el sueldo de este mes"
21721
+ ],
21722
+ avoidWhen: [
21723
+ "solo quiere corregir el monto: set_monthly_expense con el valor nuevo"
21724
+ ],
21725
+ defaults: [
21726
+ "mes en curso si no se dice otro"
21727
+ ],
21728
+ disclosures: [
21729
+ "requiere confirmaci\xF3n; el borrado mueve la utilidad neta al instante"
21730
+ ]
21731
+ },
21732
+ remove_product_control: {
21733
+ summary: "Saca un producto de su control financiero, junto con sus costos y su anuncio vinculado.",
21734
+ useWhen: [
21735
+ "ya no vendo ese producto",
21736
+ "elimina el termo del control"
21737
+ ],
21738
+ avoidWhen: [
21739
+ "quiere unirlo con otro producto: merge_products"
21740
+ ],
21741
+ defaults: [
21742
+ "pide el producto del listado; nunca lo inventes"
21743
+ ],
21744
+ disclosures: [
21745
+ "requiere confirmaci\xF3n; sus costos y su anuncio se van con \xE9l"
21746
+ ]
21747
+ },
21579
21748
  report_daily_returns: {
21580
21749
  summary: "Registra el n\xFAmero real de pedidos devueltos de un producto en un d\xEDa concreto.",
21581
21750
  useWhen: [
@@ -21899,6 +22068,78 @@ var DROPI_COUNTRY_CODES = [
21899
22068
  "AR",
21900
22069
  "CR"
21901
22070
  ];
22071
+ var DROPI_COUNTRIES = {
22072
+ CO: {
22073
+ name: "Colombia",
22074
+ currency: "COP",
22075
+ timeZone: "America/Bogota",
22076
+ productionBaseUrl: "https://api.dropi.co/integrations"
22077
+ },
22078
+ EC: {
22079
+ name: "Ecuador",
22080
+ currency: "USD",
22081
+ timeZone: "America/Guayaquil",
22082
+ productionBaseUrl: "https://api.dropi.ec/integrations"
22083
+ },
22084
+ VE: {
22085
+ name: "Venezuela",
22086
+ currency: "USD",
22087
+ timeZone: "America/Caracas",
22088
+ productionBaseUrl: "https://api.dropi.com.ve/integrations"
22089
+ },
22090
+ MX: {
22091
+ name: "M\xE9xico",
22092
+ currency: "MXN",
22093
+ timeZone: "America/Mexico_City",
22094
+ productionBaseUrl: "https://api.dropi.mx/integrations"
22095
+ },
22096
+ PE: {
22097
+ name: "Per\xFA",
22098
+ currency: "PEN",
22099
+ timeZone: "America/Lima",
22100
+ productionBaseUrl: "https://api.dropi.pe/integrations"
22101
+ },
22102
+ PA: {
22103
+ name: "Panam\xE1",
22104
+ currency: "USD",
22105
+ timeZone: "America/Panama",
22106
+ productionBaseUrl: "https://api.dropi.pa/integrations"
22107
+ },
22108
+ PY: {
22109
+ name: "Paraguay",
22110
+ currency: "PYG",
22111
+ timeZone: "America/Asuncion",
22112
+ productionBaseUrl: "https://api.dropi.com.py/integrations"
22113
+ },
22114
+ GT: {
22115
+ name: "Guatemala",
22116
+ currency: "GTQ",
22117
+ timeZone: "America/Guatemala",
22118
+ productionBaseUrl: "https://api.dropi.gt/integrations"
22119
+ },
22120
+ CL: {
22121
+ name: "Chile",
22122
+ currency: "CLP",
22123
+ timeZone: "America/Santiago",
22124
+ productionBaseUrl: "https://api.dropi.cl/integrations"
22125
+ },
22126
+ AR: {
22127
+ name: "Argentina",
22128
+ currency: "ARS",
22129
+ timeZone: "America/Argentina/Buenos_Aires",
22130
+ productionBaseUrl: "https://api.dropi.ar/integrations"
22131
+ },
22132
+ CR: {
22133
+ name: "Costa Rica",
22134
+ currency: "CRC",
22135
+ timeZone: "America/Costa_Rica",
22136
+ productionBaseUrl: "https://api.dropi.cr/integrations"
22137
+ }
22138
+ };
22139
+ function isDropiCountryCode(value) {
22140
+ return typeof value === "string" && DROPI_COUNTRY_CODES.some((code) => code === value);
22141
+ }
22142
+ __name(isDropiCountryCode, "isDropiCountryCode");
21902
22143
 
21903
22144
  // ../../packages/types/src/finance-country-timezones.ts
21904
22145
  var FINANCE_COUNTRY_TIME_ZONES = Object.freeze({
@@ -21949,6 +22190,19 @@ var FINANCE_COUNTRY_TIME_ZONES = Object.freeze({
21949
22190
  LV: "Europe/Riga",
21950
22191
  LT: "Europe/Vilnius"
21951
22192
  });
22193
+ function financeCountryTimeZone(countryCode) {
22194
+ const normalized = countryCode?.toUpperCase();
22195
+ if (!normalized) return DROPI_COUNTRIES.CO.timeZone;
22196
+ if (isDropiCountryCode(normalized)) {
22197
+ return DROPI_COUNTRIES[normalized].timeZone;
22198
+ }
22199
+ const timeZone = FINANCE_COUNTRY_TIME_ZONES[normalized];
22200
+ if (!timeZone) {
22201
+ throw new RangeError(`Unsupported finance calendar country: ${normalized}`);
22202
+ }
22203
+ return timeZone;
22204
+ }
22205
+ __name(financeCountryTimeZone, "financeCountryTimeZone");
21952
22206
 
21953
22207
  // ../../packages/types/src/finance-operation.ts
21954
22208
  var CreateFinanceOperationSchema = z97.object({
@@ -22064,6 +22318,8 @@ var ProductOrderLineSchema = z99.object({
22064
22318
  provider: z99.string().min(1).max(32).optional(),
22065
22319
  externalOrderId: z99.string().trim().min(1).max(64),
22066
22320
  externalProductId: z99.string().trim().min(1).max(64),
22321
+ /** Product display name only; never a buyer name. Unknown names stay null or absent. */
22322
+ externalProductLabel: z99.string().trim().min(1).max(300).nullable().optional(),
22067
22323
  /** YYYY-MM-DD, fecha DEL PEDIDO, nunca la de descarga del reporte. */
22068
22324
  orderedAt: z99.string().regex(/^\d{4}-\d{2}-\d{2}$/),
22069
22325
  status: z99.enum(PRODUCT_ORDER_LINE_STATUSES),
@@ -22532,6 +22788,41 @@ var ImportFulfillmentCountsResponseSchema = z100.object({
22532
22788
  skippedManual: z100.number().int().min(0),
22533
22789
  skippedUnknownProduct: z100.number().int().min(0)
22534
22790
  });
22791
+ var CreateManualProductControlSchema = z100.object({
22792
+ /** UUID que el diálogo fija por apertura; es además el id del producto. */
22793
+ requestId: z100.string().uuid(),
22794
+ title: z100.string().trim().min(1).max(200),
22795
+ /** País donde vende este producto; la moneda sale de él en el servidor. */
22796
+ targetCountry: z100.string().regex(/^[A-Z]{2}$/).refine((code) => {
22797
+ try {
22798
+ financeCountryTimeZone(code);
22799
+ return true;
22800
+ } catch {
22801
+ return false;
22802
+ }
22803
+ }, "unsupported_finance_country"),
22804
+ /** Solo cuando coincide con el país elegido; si no, se omite. */
22805
+ operationId: z100.string().uuid().optional(),
22806
+ manualSellingPrice: z100.number().finite().positive().max(Number.MAX_SAFE_INTEGER),
22807
+ supplierCost: z100.number().finite().positive().max(Number.MAX_SAFE_INTEGER),
22808
+ shippingCost: z100.number().finite().nonnegative().max(Number.MAX_SAFE_INTEGER),
22809
+ returnRate: z100.number().finite().min(0).lt(1),
22810
+ cancellationRate: z100.number().finite().min(0).lt(1)
22811
+ }).strict().superRefine(({ returnRate, cancellationRate }, ctx) => {
22812
+ if (returnRate + cancellationRate >= 1) {
22813
+ ctx.addIssue({
22814
+ code: z100.ZodIssueCode.custom,
22815
+ message: "delivery_rate_positive",
22816
+ path: [
22817
+ "cancellationRate"
22818
+ ]
22819
+ });
22820
+ }
22821
+ });
22822
+ var CreateManualProductControlResponseSchema = z100.object({
22823
+ productControlId: z100.string().uuid(),
22824
+ created: z100.boolean()
22825
+ });
22535
22826
 
22536
22827
  // ../../packages/types/src/productmaker-capability-registry.ts
22537
22828
  var SHARED_CHANNEL_EXPOSURE = {
@@ -24251,13 +24542,22 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24251
24542
  ], [
24252
24543
  "product_control"
24253
24544
  ]),
24254
- defineCapability("set_product_costing", "d3048558a7e380cdcc17d6b959e9d2ac782a933554a2dde1e914e89e13b24f0c", "state_change", "business", [
24545
+ defineCapability("set_product_costing", "cce7a31e434c7a1f0af2e3ecaf591eb63c6e3570c466c29e2cab00432ab26bc9", "state_change", "business", [
24255
24546
  "state_change"
24256
24547
  ], [
24257
- slot("product", true, [
24548
+ /* La identidad sin tienda solo existe en el contrato MCP: el
24549
+ esquema de WhatsApp sigue pidiendo la pareja de tienda, así que
24550
+ estos campos no se declaran allí (whatsapp: []). */
24551
+ slot("product_control", false, [
24552
+ "productControlId"
24553
+ ], []),
24554
+ slot("selling_price", false, [
24555
+ "manualSellingPrice"
24556
+ ], []),
24557
+ slot("product", false, [
24258
24558
  "shopifyProductId"
24259
24559
  ]),
24260
- slot("shop", true, [
24560
+ slot("shop", false, [
24261
24561
  "shopDomain"
24262
24562
  ]),
24263
24563
  slot("market", true, [
@@ -24448,6 +24748,271 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
24448
24748
  ], [
24449
24749
  "monthly_pl"
24450
24750
  ]),
24751
+ defineCapability(
24752
+ "get_dropi_status",
24753
+ // Filled by the MCP schema fingerprint test (sha256 of the canonicalized
24754
+ // inputSchema) — run apps/mcp server.test.ts to compute.
24755
+ "3465e644ebdcaa404d8bcc1af629012c858bb4aed5bb1b56cfaa2af0d53cfc6e",
24756
+ "none",
24757
+ "read_only",
24758
+ [
24759
+ "read"
24760
+ ],
24761
+ [
24762
+ slot("country", false, [
24763
+ "countryCode"
24764
+ ]),
24765
+ slot("dropi_connection", false, [
24766
+ "connectionId"
24767
+ ])
24768
+ ],
24769
+ [
24770
+ "dropi_connection"
24771
+ ],
24772
+ [
24773
+ "dropi_status"
24774
+ ],
24775
+ MCP_ONLY_CHANNEL_EXPOSURE
24776
+ ),
24777
+ defineCapability(
24778
+ "sync_dropi_orders",
24779
+ // Filled by the MCP schema fingerprint test.
24780
+ "46f1172e7afe42991957a2dc262cce235dbf31ededdf37ccf866a583bb19123b",
24781
+ "state_change",
24782
+ "business",
24783
+ [
24784
+ "state_change"
24785
+ ],
24786
+ [
24787
+ slot("country", false, [
24788
+ "countryCode"
24789
+ ]),
24790
+ slot("operation", false, [
24791
+ "operationId"
24792
+ ]),
24793
+ slot("dropi_connection", false, [
24794
+ "connectionId"
24795
+ ]),
24796
+ slot("window_start", false, [
24797
+ "since"
24798
+ ]),
24799
+ slot("window_end", false, [
24800
+ "until"
24801
+ ])
24802
+ ],
24803
+ [
24804
+ "dropi_connection"
24805
+ ],
24806
+ [
24807
+ "product_order_line"
24808
+ ],
24809
+ MCP_ONLY_CHANNEL_EXPOSURE
24810
+ ),
24811
+ defineCapability(
24812
+ "create_manual_product",
24813
+ // Filled by the MCP schema fingerprint test.
24814
+ "4da701236ab1fd460e66f6def729f61a392bad62e8fecdaf8b3b3098fdec53cb",
24815
+ "state_change",
24816
+ "business",
24817
+ [
24818
+ "state_change"
24819
+ ],
24820
+ [
24821
+ slot("product", true, [
24822
+ "title"
24823
+ ]),
24824
+ slot("market", true, [
24825
+ "targetCountry"
24826
+ ]),
24827
+ slot("operation", false, [
24828
+ "operationId"
24829
+ ]),
24830
+ slot("selling_price", true, [
24831
+ "manualSellingPrice"
24832
+ ]),
24833
+ slot("supplier_cost", true, [
24834
+ "supplierCost"
24835
+ ]),
24836
+ slot("shipping_cost", true, [
24837
+ "shippingCost"
24838
+ ]),
24839
+ slot("return_rate", true, [
24840
+ "returnRate"
24841
+ ]),
24842
+ slot("cancellation_rate", true, [
24843
+ "cancellationRate"
24844
+ ])
24845
+ ],
24846
+ [
24847
+ "finance_operation"
24848
+ ],
24849
+ [
24850
+ "product_control"
24851
+ ],
24852
+ MCP_ONLY_CHANNEL_EXPOSURE
24853
+ ),
24854
+ defineCapability(
24855
+ "list_unmatched_products",
24856
+ // Filled by the MCP schema fingerprint test.
24857
+ "2c89690b4282a881f29f3bae11268786abf385c2bec0e3d7a1643098f4986e1b",
24858
+ "none",
24859
+ "read_only",
24860
+ [
24861
+ "read"
24862
+ ],
24863
+ [
24864
+ slot("operation", false, [
24865
+ "operationId"
24866
+ ])
24867
+ ],
24868
+ [
24869
+ "finance_operation"
24870
+ ],
24871
+ [
24872
+ "product_order_line"
24873
+ ],
24874
+ MCP_ONLY_CHANNEL_EXPOSURE
24875
+ ),
24876
+ defineCapability(
24877
+ "resolve_unmatched_product",
24878
+ // Filled by the MCP schema fingerprint test.
24879
+ "39ccb99a5d138f7f99e25c00b68eec8972e34dbcbd966d2081cdaa7c76ac63ba",
24880
+ "state_change",
24881
+ "business",
24882
+ [
24883
+ "state_change"
24884
+ ],
24885
+ [
24886
+ slot("order_provider", true, [
24887
+ "provider"
24888
+ ]),
24889
+ slot("external_id", true, [
24890
+ "externalId"
24891
+ ]),
24892
+ slot("product_label", true, [
24893
+ "label"
24894
+ ]),
24895
+ slot("operation", true, [
24896
+ "operationId"
24897
+ ]),
24898
+ slot("product_control", false, [
24899
+ "productControlId"
24900
+ ])
24901
+ ],
24902
+ [
24903
+ "product_order_line"
24904
+ ],
24905
+ [
24906
+ "product_control"
24907
+ ],
24908
+ MCP_ONLY_CHANNEL_EXPOSURE
24909
+ ),
24910
+ defineCapability(
24911
+ "list_linkable_campaigns",
24912
+ // Filled by the MCP schema fingerprint test.
24913
+ "7a014b717a77aac971ea0ab5c0ff47bb13e6cae7ef9442d9dedb15ce36381b15",
24914
+ "none",
24915
+ "read_only",
24916
+ [
24917
+ "read"
24918
+ ],
24919
+ [],
24920
+ [
24921
+ "ad_account"
24922
+ ],
24923
+ [
24924
+ "campaign_link"
24925
+ ],
24926
+ MCP_ONLY_CHANNEL_EXPOSURE
24927
+ ),
24928
+ defineCapability(
24929
+ "link_product_campaign",
24930
+ // Filled by the MCP schema fingerprint test.
24931
+ "a9976318693f137dd37f4608d382fe1deb13b44c2f5257580c8b52b015899dde",
24932
+ "state_change",
24933
+ "business",
24934
+ [
24935
+ "state_change"
24936
+ ],
24937
+ [
24938
+ slot("ad_provider", true, [
24939
+ "provider"
24940
+ ]),
24941
+ slot("ad_account", true, [
24942
+ "accountId"
24943
+ ]),
24944
+ slot("campaign", true, [
24945
+ "campaignId"
24946
+ ]),
24947
+ slot("product_control", false, [
24948
+ "productControlId"
24949
+ ]),
24950
+ slot("shop", false, [
24951
+ "shopDomain"
24952
+ ]),
24953
+ slot("shopify_product", false, [
24954
+ "shopifyProductId"
24955
+ ])
24956
+ ],
24957
+ [
24958
+ "product_control",
24959
+ "campaign_link"
24960
+ ],
24961
+ [
24962
+ "campaign_link"
24963
+ ],
24964
+ MCP_ONLY_CHANNEL_EXPOSURE
24965
+ ),
24966
+ defineCapability(
24967
+ "delete_monthly_expense",
24968
+ // Filled by the MCP schema fingerprint test.
24969
+ "fe9c5d5896165b9c65fbfed779db7918dabf87c69e1601430a1509ad2d452de9",
24970
+ "state_change",
24971
+ "business",
24972
+ [
24973
+ "state_change"
24974
+ ],
24975
+ [
24976
+ slot("expense_label", true, [
24977
+ "label"
24978
+ ]),
24979
+ slot("month", true, [
24980
+ "month"
24981
+ ]),
24982
+ slot("operation", false, [
24983
+ "operationId"
24984
+ ])
24985
+ ],
24986
+ [
24987
+ "monthly_expense"
24988
+ ],
24989
+ [
24990
+ "finance_operation"
24991
+ ],
24992
+ MCP_ONLY_CHANNEL_EXPOSURE
24993
+ ),
24994
+ defineCapability(
24995
+ "remove_product_control",
24996
+ // Filled by the MCP schema fingerprint test.
24997
+ "ff0b7411497a0b28eda7294c35b09c45f8beff842bbc6a9a4cc993ba3d766cae",
24998
+ "state_change",
24999
+ "business",
25000
+ [
25001
+ "state_change"
25002
+ ],
25003
+ [
25004
+ slot("product_control", true, [
25005
+ "productControlId"
25006
+ ])
25007
+ ],
25008
+ [
25009
+ "product_control"
25010
+ ],
25011
+ [
25012
+ "product_control"
25013
+ ],
25014
+ MCP_ONLY_CHANNEL_EXPOSURE
25015
+ ),
24451
25016
  defineCapability("report_daily_returns", "7130d216656cc29a47fc972b4edad5003a6653fca48d95052fbf2b561636e91a", "state_change", "business", [
24452
25017
  "state_change"
24453
25018
  ], [
@@ -27575,27 +28140,39 @@ var PublishedClassicLandingSchema = z122.object({
27575
28140
  import { z as z123 } from "zod";
27576
28141
  var DropiCountrySchema = z123.enum(DROPI_COUNTRY_CODES);
27577
28142
  var DropiCountryQuerySchema = z123.object({
27578
- countryCode: DropiCountrySchema.default("CO")
28143
+ countryCode: DropiCountrySchema.default("CO"),
28144
+ connectionId: z123.string().uuid().optional()
27579
28145
  }).strict();
27580
28146
  var ConnectDropiFinancialSchema = z123.object({
27581
28147
  countryCode: DropiCountrySchema.default("CO"),
28148
+ connectionId: z123.string().uuid().optional(),
28149
+ label: z123.string().trim().min(1).max(80).optional(),
27582
28150
  integrationKey: z123.string().trim().min(1).max(4096).regex(/^[\x21-\x7e]+$/)
27583
28151
  }).strict();
27584
28152
  var SyncDropiFinancialSchema = z123.object({
27585
28153
  countryCode: DropiCountrySchema.optional(),
27586
28154
  operationId: z123.string().uuid().optional(),
28155
+ connectionId: z123.string().uuid().optional(),
27587
28156
  since: z123.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
27588
28157
  until: z123.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
27589
28158
  }).strict();
27590
28159
  var connectionCountries = z123.array(DropiCountrySchema).max(DROPI_COUNTRY_CODES.length).refine((countries) => new Set(countries).size === countries.length);
27591
28160
  var DropiFinancialConnectionsSchema = z123.object({
27592
28161
  connectedCountries: connectionCountries,
28162
+ connections: z123.array(z123.object({
28163
+ connectionId: z123.string().uuid(),
28164
+ countryCode: DropiCountrySchema,
28165
+ label: z123.string().min(1).max(80)
28166
+ }).strict()).max(21).optional(),
27593
28167
  /** Effective connect availability after flags, proxy and scoped-identity readiness. */
27594
28168
  enabledCountries: connectionCountries
27595
28169
  }).strict();
27596
28170
  var DropiFinancialStatusSchema = z123.object({
27597
28171
  enabled: z123.boolean(),
27598
28172
  connected: z123.boolean(),
28173
+ connectionId: z123.string().uuid().optional(),
28174
+ connectionCount: z123.number().int().nonnegative().optional(),
28175
+ label: z123.string().min(1).max(80).optional(),
27599
28176
  countryCode: DropiCountrySchema,
27600
28177
  /** Configured environment allowlist; selected-country availability is `enabled`. */
27601
28178
  enabledCountries: z123.array(DropiCountrySchema).optional(),
@@ -27604,6 +28181,8 @@ var DropiFinancialStatusSchema = z123.object({
27604
28181
  "production"
27605
28182
  ]),
27606
28183
  lastSyncAt: z123.string().nullable(),
28184
+ /** Latest successful unit across accounts; triggers refresh but never certifies coverage. */
28185
+ lastActivityAt: z123.string().nullable().optional(),
27607
28186
  lastError: z123.string().nullable(),
27608
28187
  historyNext: z123.string().nullable(),
27609
28188
  historyUntil: z123.string().nullable(),
@@ -30282,7 +30861,7 @@ var ApiClient = class {
30282
30861
  };
30283
30862
 
30284
30863
  // src/index.ts
30285
- var MCP_VERSION = "12.2.5";
30864
+ var MCP_VERSION = "12.2.6";
30286
30865
 
30287
30866
  // src/meta-upload-app.ts
30288
30867
  import { readFileSync } from "fs";
@@ -39925,6 +40504,7 @@ function registerDailyControlTools(server, api) {
39925
40504
  __name(registerDailyControlTools, "registerDailyControlTools");
39926
40505
 
39927
40506
  // src/tools/product-control.ts
40507
+ import { createHash as createHash5 } from "crypto";
39928
40508
  import { readFile, stat } from "fs/promises";
39929
40509
  import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
39930
40510
  import { z as z155 } from "zod";
@@ -39940,6 +40520,15 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
39940
40520
  var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
39941
40521
  var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
39942
40522
  var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
40523
+ var getDropiStatusGuidance = getProductMakerCapabilityModelGuidance("get_dropi_status");
40524
+ var syncDropiOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_dropi_orders");
40525
+ var createManualProductGuidance = getProductMakerCapabilityModelGuidance("create_manual_product");
40526
+ var listUnmatchedGuidance = getProductMakerCapabilityModelGuidance("list_unmatched_products");
40527
+ var resolveUnmatchedGuidance = getProductMakerCapabilityModelGuidance("resolve_unmatched_product");
40528
+ var listLinkableCampaignsGuidance = getProductMakerCapabilityModelGuidance("list_linkable_campaigns");
40529
+ var linkProductCampaignGuidance = getProductMakerCapabilityModelGuidance("link_product_campaign");
40530
+ var deleteMonthlyExpenseGuidance = getProductMakerCapabilityModelGuidance("delete_monthly_expense");
40531
+ var removeProductControlGuidance = getProductMakerCapabilityModelGuidance("remove_product_control");
39943
40532
  var DateOnly2 = z155.string().regex(/^\d{4}-\d{2}-\d{2}$/);
39944
40533
  var IMPORT_BATCH_MAX2 = 50;
39945
40534
  var ProductControlListInput = z155.object({
@@ -39959,8 +40548,14 @@ var ImportProductControlsInput = z155.object({
39959
40548
  shopDomain: z155.string().min(1)
39960
40549
  }).strict();
39961
40550
  var SetProductCostingInput = z155.object({
39962
- shopDomain: z155.string().min(1),
39963
- shopifyProductId: z155.string().min(1).max(64),
40551
+ /* La identidad, de UNA forma: la del producto nuestro, o la pareja
40552
+ tienda + id de Shopify. El esquema canónico también las admite juntas,
40553
+ pero pedirlas por separado evita que el modelo emita una mezcla que
40554
+ diga dos productos a la vez. */
40555
+ productControlId: z155.string().uuid().optional().describe("El id nuestro (lo devuelven get_product_control y create_manual_product). Obligatorio para productos manuales o importados sin tienda."),
40556
+ manualSellingPrice: z155.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."),
40557
+ shopDomain: z155.string().min(1).optional(),
40558
+ shopifyProductId: z155.string().min(1).max(64).optional(),
39964
40559
  targetCountry: z155.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
39965
40560
  supplierCost: z155.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
39966
40561
  shippingCost: z155.number().finite().nonnegative(),
@@ -40010,6 +40605,48 @@ var GetFinancesInput = z155.object({
40010
40605
  month: z155.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."),
40011
40606
  operationId: z155.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
40012
40607
  }).strict();
40608
+ var GetDropiStatusInput = DropiCountryQuerySchema.extend({
40609
+ countryCode: DropiCountrySchema.optional().describe("Pa\xEDs de la cuenta (ISO-2). Si se omite, el servidor responde por Colombia (CO)."),
40610
+ connectionId: z155.string().uuid().optional().describe("Una cuenta concreta cuando el pa\xEDs tiene varias. Sale de la lista de conexiones; nunca se inventa.")
40611
+ });
40612
+ var SyncDropiOrdersInput = SyncDropiFinancialSchema;
40613
+ var CreateManualProductInput = CreateManualProductControlSchema.innerType().omit({
40614
+ requestId: true
40615
+ });
40616
+ var ListUnmatchedProductsInput = z155.object({
40617
+ operationId: z155.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
40618
+ }).strict();
40619
+ var ResolveUnmatchedProductInput = ResolveUnmatchedProductSchema;
40620
+ var ListLinkableCampaignsInput = z155.object({}).strict();
40621
+ var LinkProductCampaignInput = z155.object({
40622
+ provider: z155.enum([
40623
+ "meta",
40624
+ "tiktok"
40625
+ ]).describe("La red publicitaria de la campa\xF1a."),
40626
+ accountId: z155.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/).describe("La cuenta publicitaria. Sale de list_linkable_campaigns; nunca se inventa."),
40627
+ campaignId: z155.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/).describe("La campa\xF1a. Sale de list_linkable_campaigns; nunca se inventa."),
40628
+ productControlId: z155.string().uuid().optional().describe("El id del producto en su control financiero."),
40629
+ shopDomain: z155.string().min(1).optional().describe("La tienda del producto; con shopifyProductId es la otra forma de decir cu\xE1l es."),
40630
+ shopifyProductId: z155.string().min(1).optional().describe("El id del producto en su tienda. Va junto a shopDomain.")
40631
+ }).strict();
40632
+ var DeleteMonthlyExpenseInput = DeleteMonthlyExpenseSchema;
40633
+ var RemoveProductControlInput = z155.object({
40634
+ productControlId: z155.string().uuid().describe("El id del producto en su control. Sale del listado; nunca se inventa.")
40635
+ }).strict();
40636
+ function manualProductRequestId(input) {
40637
+ const digest3 = createHash5("sha256").update(JSON.stringify(input, [
40638
+ "cancellationRate",
40639
+ "manualSellingPrice",
40640
+ "operationId",
40641
+ "returnRate",
40642
+ "shippingCost",
40643
+ "supplierCost",
40644
+ "targetCountry",
40645
+ "title"
40646
+ ])).digest("hex");
40647
+ 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);
40648
+ }
40649
+ __name(manualProductRequestId, "manualProductRequestId");
40013
40650
  function registerProductControlTools(server, api, { transport = "http" } = {}) {
40014
40651
  server.registerTool("get_product_control", {
40015
40652
  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.',
@@ -40072,12 +40709,12 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
40072
40709
  throw new Error("El archivo pesa m\xE1s de 8 MB.");
40073
40710
  }
40074
40711
  const name = basename2(absolute).toLowerCase();
40075
- if (!/\.(xlsx|xls|csv)$/.test(name)) {
40076
- throw new Error("Solo puedo leer archivos .xlsx, .xls o .csv de pedidos.");
40712
+ if (!name.endsWith(".xlsx")) {
40713
+ throw new Error("Solo puedo leer archivos .xlsx de pedidos.");
40077
40714
  }
40078
40715
  const bytes = await readFile(absolute);
40079
40716
  const isZip = bytes[0] === 80 && bytes[1] === 75;
40080
- if (name.endsWith(".xlsx") && !isZip) {
40717
+ if (!isZip) {
40081
40718
  throw new Error("Ese archivo no es un .xlsx de verdad.");
40082
40719
  }
40083
40720
  return asText(await api.postJson("/v1/product-control/order-lines/file", {
@@ -40174,11 +40811,18 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
40174
40811
  }
40175
40812
  });
40176
40813
  server.registerTool("set_product_costing", {
40177
- 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.",
40814
+ 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.",
40178
40815
  inputSchema: SetProductCostingInput.shape,
40179
40816
  annotations: OVERWRITES_INTERNAL
40180
40817
  }, async (input) => {
40181
40818
  try {
40819
+ const { productControlId, shopDomain, shopifyProductId } = input;
40820
+ if (productControlId !== void 0 && (shopDomain !== void 0 || shopifyProductId !== void 0)) {
40821
+ throw new Error("El producto se dice de una sola forma: quita productControlId o quita shopDomain + shopifyProductId.");
40822
+ }
40823
+ if (productControlId === void 0 && (shopDomain === void 0 || shopifyProductId === void 0)) {
40824
+ throw new Error("Falta el producto: manda productControlId o shopDomain + shopifyProductId.");
40825
+ }
40182
40826
  return asText(await api.putJson("/v1/product-control/costing", input));
40183
40827
  } catch (error) {
40184
40828
  throw translateError(error);
@@ -40196,6 +40840,134 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
40196
40840
  throw translateError(error);
40197
40841
  }
40198
40842
  });
40843
+ server.registerTool("get_dropi_status", {
40844
+ 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`.",
40845
+ inputSchema: GetDropiStatusInput.shape,
40846
+ annotations: READS_INTERNAL
40847
+ }, async (input) => {
40848
+ try {
40849
+ const params = new URLSearchParams();
40850
+ if (input.countryCode) params.set("countryCode", input.countryCode);
40851
+ if (input.connectionId) params.set("connectionId", input.connectionId);
40852
+ return asText(await api.getJson(`/v1/product-control/dropi/status?${params.toString()}`));
40853
+ } catch (error) {
40854
+ throw translateError(error);
40855
+ }
40856
+ });
40857
+ server.registerTool("sync_dropi_orders", {
40858
+ 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.",
40859
+ inputSchema: SyncDropiOrdersInput.shape,
40860
+ // Lee Dropi sin mutarlo, pero puede sobrescribir sus líneas en nuestro libro.
40861
+ annotations: OVERWRITES_INTERNAL
40862
+ }, async (input) => {
40863
+ try {
40864
+ return asText(await api.postJson("/v1/product-control/dropi/sync", input));
40865
+ } catch (error) {
40866
+ throw translateError(error);
40867
+ }
40868
+ });
40869
+ server.registerTool("create_manual_product", {
40870
+ 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.",
40871
+ inputSchema: CreateManualProductInput.shape,
40872
+ annotations: CREATES_INTERNAL
40873
+ }, async (input) => {
40874
+ try {
40875
+ return asText(await api.postJson("/v1/product-control/manual", {
40876
+ ...input,
40877
+ requestId: manualProductRequestId(input)
40878
+ }));
40879
+ } catch (error) {
40880
+ throw translateError(error);
40881
+ }
40882
+ });
40883
+ server.registerTool("list_unmatched_products", {
40884
+ 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.",
40885
+ inputSchema: ListUnmatchedProductsInput.shape,
40886
+ annotations: READS_INTERNAL
40887
+ }, async (input) => {
40888
+ try {
40889
+ const params = new URLSearchParams();
40890
+ if (input.operationId) params.set("operationId", input.operationId);
40891
+ const query = params.toString();
40892
+ return asText(await api.getJson(`/v1/product-control/unmatched${query ? `?${query}` : ""}`));
40893
+ } catch (error) {
40894
+ throw translateError(error);
40895
+ }
40896
+ });
40897
+ server.registerTool("resolve_unmatched_product", {
40898
+ 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.",
40899
+ inputSchema: ResolveUnmatchedProductInput.shape,
40900
+ annotations: CREATES_INTERNAL
40901
+ }, async (input) => {
40902
+ try {
40903
+ return asText(await api.postJson("/v1/product-control/resolve-unmatched", input));
40904
+ } catch (error) {
40905
+ throw translateError(error);
40906
+ }
40907
+ });
40908
+ server.registerTool("list_linkable_campaigns", {
40909
+ 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.",
40910
+ inputSchema: ListLinkableCampaignsInput.shape,
40911
+ annotations: READS_EXTERNAL
40912
+ }, async () => {
40913
+ try {
40914
+ return asText(await api.getJson("/v1/product-control/linkable-campaigns"));
40915
+ } catch (error) {
40916
+ throw translateError(error);
40917
+ }
40918
+ });
40919
+ server.registerTool("link_product_campaign", {
40920
+ 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.",
40921
+ inputSchema: LinkProductCampaignInput.shape,
40922
+ annotations: CREATES_INTERNAL
40923
+ }, async (input) => {
40924
+ try {
40925
+ const { provider: provider2, accountId, campaignId, productControlId, shopDomain, shopifyProductId } = input;
40926
+ if (productControlId !== void 0 && (shopDomain !== void 0 || shopifyProductId !== void 0)) {
40927
+ throw new Error("El producto se dice de una sola forma: quita productControlId o quita shopDomain + shopifyProductId.");
40928
+ }
40929
+ if (productControlId === void 0 && (shopDomain === void 0 || shopifyProductId === void 0)) {
40930
+ throw new Error("Falta el producto: manda productControlId o shopDomain + shopifyProductId.");
40931
+ }
40932
+ const body = productControlId !== void 0 ? {
40933
+ provider: provider2,
40934
+ accountId,
40935
+ campaignId,
40936
+ productControlId
40937
+ } : {
40938
+ provider: provider2,
40939
+ accountId,
40940
+ campaignId,
40941
+ shopDomain,
40942
+ shopifyProductId
40943
+ };
40944
+ return asText(await api.postJson("/v1/product-control/campaigns", body));
40945
+ } catch (error) {
40946
+ throw translateError(error);
40947
+ }
40948
+ });
40949
+ server.registerTool("delete_monthly_expense", {
40950
+ 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.",
40951
+ inputSchema: DeleteMonthlyExpenseInput.shape,
40952
+ annotations: OVERWRITES_INTERNAL
40953
+ }, async (input) => {
40954
+ try {
40955
+ return asText(await api.postJson("/v1/product-control/expenses/delete", input));
40956
+ } catch (error) {
40957
+ throw translateError(error);
40958
+ }
40959
+ });
40960
+ server.registerTool("remove_product_control", {
40961
+ 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.",
40962
+ inputSchema: RemoveProductControlInput.shape,
40963
+ annotations: OVERWRITES_INTERNAL
40964
+ }, async (input) => {
40965
+ try {
40966
+ return asText(await api.deleteJson(`/v1/product-control/${encodeURIComponent(input.productControlId)}`));
40967
+ } catch (error) {
40968
+ throw translateError(error);
40969
+ }
40970
+ });
40199
40971
  }
40200
40972
  __name(registerProductControlTools, "registerProductControlTools");
40201
40973