diff --git a/src/chrome/src/agent/adapters.js b/src/chrome/src/agent/adapters.js index 86edbfe1f..c271c50c4 100644 --- a/src/chrome/src/agent/adapters.js +++ b/src/chrome/src/agent/adapters.js @@ -16279,6 +16279,21 @@ const ADAPTERS = [ - Pre-orders / "Made to order" listings have a longer ship date — surface that to the user before buying.`, }, + // ─── Regional — Mercado Libre / Mercado Livre (LATAM) ──────────────── + // Start with the AR, MX, and BR storefronts requested in CONTRIBUTING.md. + // Other country sites need separate localization research before inclusion. + { + name: 'mercado-libre', + category: 'general', + matches: (url) => /^https?:\/\/(?:[a-z0-9-]+\.)*(?:mercadolibre\.com\.(?:ar|mx)|mercadolivre\.com\.br)\//.test(url), + notes: ` +- Multi-seller MARKETPLACE. As of 2026-07 the buy controls are AR/MX "Comprar ahora" / "Agregar al carrito" / "Otras opciones de compra"; BR "Comprar agora" / "Adicionar ao carrinho" / "Outras opções de compra". Use one locale's labels, never a blend of the two. +- Catalog pages (path contains /p/MLA…, /p/MLM…, /p/MLB…) group MANY sellers under one product: the buy box is ONE offer, and "Otras opciones de compra"/"Outras opções de compra" lists the rest at different prices and arrival dates — open it before quoting a price. Single-seller listings (articulo.mercadolibre.com.*, produto.mercadolivre.com.br, paths ending -_JM) have no such list. +- Shipping cost and arrival date are computed from the destination "código postal" (AR/MX) / "CEP" (BR) and differ per seller. Set it before stating either, and re-check in the cart. +- Buy-now hands off to a Mercado Pago host where this guidance stops applying — confirm the final total there. +- Search hosts (listado.mercadolibre.com.ar, listado.mercadolibre.com.mx, lista.mercadolivre.com.br) can redirect automation to /gz/account-verification. If that wall appears, STOP and ask the user to complete it manually — do not retry, bypass, or claim results were read.`, + }, + // ─── Regional — Türkiye (TR) ────────────────────────────────────────── // Regional adapters are the project's #1 wanted contribution (CONTRIBUTING.md); // Türkiye is top of the priority list. Add more TR sites (trendyol, diff --git a/src/firefox/src/agent/adapters.js b/src/firefox/src/agent/adapters.js index eede90d57..2f58e93a0 100644 --- a/src/firefox/src/agent/adapters.js +++ b/src/firefox/src/agent/adapters.js @@ -16277,6 +16277,21 @@ const ADAPTERS = [ - Pre-orders / "Made to order" listings have a longer ship date — surface that to the user before buying.`, }, + // ─── Regional — Mercado Libre / Mercado Livre (LATAM) ──────────────── + // Start with the AR, MX, and BR storefronts requested in CONTRIBUTING.md. + // Other country sites need separate localization research before inclusion. + { + name: 'mercado-libre', + category: 'general', + matches: (url) => /^https?:\/\/(?:[a-z0-9-]+\.)*(?:mercadolibre\.com\.(?:ar|mx)|mercadolivre\.com\.br)\//.test(url), + notes: ` +- Multi-seller MARKETPLACE. As of 2026-07 the buy controls are AR/MX "Comprar ahora" / "Agregar al carrito" / "Otras opciones de compra"; BR "Comprar agora" / "Adicionar ao carrinho" / "Outras opções de compra". Use one locale's labels, never a blend of the two. +- Catalog pages (path contains /p/MLA…, /p/MLM…, /p/MLB…) group MANY sellers under one product: the buy box is ONE offer, and "Otras opciones de compra"/"Outras opções de compra" lists the rest at different prices and arrival dates — open it before quoting a price. Single-seller listings (articulo.mercadolibre.com.*, produto.mercadolivre.com.br, paths ending -_JM) have no such list. +- Shipping cost and arrival date are computed from the destination "código postal" (AR/MX) / "CEP" (BR) and differ per seller. Set it before stating either, and re-check in the cart. +- Buy-now hands off to a Mercado Pago host where this guidance stops applying — confirm the final total there. +- Search hosts (listado.mercadolibre.com.ar, listado.mercadolibre.com.mx, lista.mercadolivre.com.br) can redirect automation to /gz/account-verification. If that wall appears, STOP and ask the user to complete it manually — do not retry, bypass, or claim results were read.`, + }, + // ─── Regional — Türkiye (TR) ────────────────────────────────────────── // Regional adapters are the project's #1 wanted contribution (CONTRIBUTING.md); // Türkiye is top of the priority list. Add more TR sites (trendyol, diff --git a/test/run.js b/test/run.js index c99a712d8..c617a5486 100644 --- a/test/run.js +++ b/test/run.js @@ -2387,6 +2387,50 @@ test('matches apple store pages', () => { assert.equal(getActiveAdapter('https://secure.store.apple.com/shop/checkout')?.name, 'apple'); }); +test('matches Mercado Libre LATAM storefronts and includes marketplace guidance', () => { + const trustedUrls = [ + 'https://mercadolibre.com.ar/', + 'https://www.mercadolibre.com.ar/notebook/p/MLA123', + 'https://listado.mercadolibre.com.ar/notebook', + 'https://articulo.mercadolibre.com.ar/MLA-123-notebook-_JM', + 'https://www.mercadolibre.com.mx/notebook/p/MLM123', + 'https://listado.mercadolibre.com.mx/notebook', + 'https://mercadolivre.com.br/', + 'https://www.mercadolivre.com.br/notebook/p/MLB123', + 'https://lista.mercadolivre.com.br/notebook', + 'https://produto.mercadolivre.com.br/MLB-123-notebook-_JM', + ]; + for (const url of trustedUrls) { + assert.equal(getActiveAdapter(url)?.name, 'mercado-libre'); + assert.equal(getActiveAdapterFx(url)?.name, 'mercado-libre'); + } + + const rejectedUrls = [ + 'https://mercadolibre.com.ar.phishing.example/notebook', + 'https://mercadolivre.com.br.evil.example/notebook', + 'https://example.com/mercadolibre.com.mx/notebook', + // Other country storefronts need their own localized research before inclusion. + 'https://www.mercadolibre.cl/notebook', + ]; + for (const url of rejectedUrls) { + assert.notEqual(getActiveAdapter(url)?.name, 'mercado-libre'); + assert.notEqual(getActiveAdapterFx(url)?.name, 'mercado-libre'); + } + + const adapter = getActiveAdapter('https://www.mercadolibre.com.mx/notebook/p/MLM123'); + const firefoxAdapter = getActiveAdapterFx('https://www.mercadolivre.com.br/notebook/p/MLB123'); + assert.match(adapter?.notes || '', /MARKETPLACE/); + assert.match(adapter?.notes || '', /Otras opciones de compra/); + assert.match(adapter?.notes || '', /Outras opções de compra/); + assert.match(adapter?.notes || '', /CEP/); + assert.match(adapter?.notes || '', /account-verification/); + // Checkout leaves the matched hosts, so the notes must hand the total off. + assert.match(adapter?.notes || '', /Mercado Pago/); + // Blended ES/PT labels match no real control on either storefront. + assert.doesNotMatch(adapter?.notes || '', /Agregar\/Adicionar|ahora\/agora|carrito\/carrinho/); + assert.equal(firefoxAdapter?.notes, adapter?.notes); +}); + test('matches sahibinden.com and includes anti-bot guidance', () => { assert.equal(getActiveAdapter('https://www.sahibinden.com/')?.name, 'sahibinden'); assert.equal(getActiveAdapter('https://sahibinden.com/kategori/vasita')?.name, 'sahibinden');