618e3b0295
- CAPABILITIES_TODO.md - demo_e2e/RESUMEN.md - demo_e2e/results/prueba_1_quotes.json - demo_e2e/results/prueba_2_perceive.json - demo_e2e/results/prueba_3_search.json - demo_e2e/results/prueba_4_login_session.json - demo_e2e/results/prueba_5_books.json - demo_e2e/results/prueba_6_session_storage.json - demo_e2e/results/prueba_7_find_honesto.json - demo_e2e/results/prueba_8_verificacion.json - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
582 lines
42 KiB
Markdown
582 lines
42 KiB
Markdown
---
|
||
title: Capacidades de navegador (CDP) + construcción del MCP full-CDP
|
||
artefacto: project · projects/web_scraping
|
||
created: 06/06/2026 00:00
|
||
updated: 06/06/2026 09:00
|
||
status: in_progress
|
||
related_issues: []
|
||
related_flows: []
|
||
---
|
||
|
||
## Objetivo
|
||
|
||
Dos objetivos encadenados:
|
||
|
||
1. **Inventario** — mapear todas las capacidades de control de navegador del proyecto `web_scraping`
|
||
contra el dominio `browser` del registry (funciones Go, Bash y pipelines Python) y la app
|
||
`script_navegador`. Marcar qué está cubierto, qué está a medias y qué falta.
|
||
2. **MCP full-CDP** — construir un servidor MCP (`browser_mcp`) que exponga TODAS estas capacidades como
|
||
tools, para que cualquier agente Claude controle el navegador de punta a punta. Los gaps que faltan
|
||
se construyen en paralelo con varios `fn-constructor`, y el MCP los envuelve a medida que aparecen.
|
||
|
||
Este documento es la lista de trabajo viva del proyecto: cada gap es una tarea candidata a delegar a
|
||
`fn-constructor`, y cada función del registry es una tool candidata del `browser_mcp`.
|
||
|
||
Convención de estado por capacidad:
|
||
|
||
- `[x]` Cubierto — hay función(es) del registry dedicadas y probadas.
|
||
- `[~]` Parcial — se puede hacer pero indirecto (vía `cdp_evaluate`) o incompleto (falta parte del CRUD).
|
||
- `[ ]` Falta — no existe ninguna función para esto.
|
||
|
||
---
|
||
|
||
## Resumen ejecutivo
|
||
|
||
| # | Capacidad pedida | Estado | Notas |
|
||
|---|---|---|---|
|
||
| 1 | CRUD de perfiles | `[x]` | Create + Read + Delete + Update(apariencia/clonar/reset). Completo. |
|
||
| 2 | CRUD de ventanas | `[ ]` | No hay nada. Falta crear/listar/mover/redimensionar/cerrar ventanas (Browser.*WindowBounds). |
|
||
| 3 | CRUD de pestañas | `[x]` | Create/List/Navigate + **close/activate** (cdp_close_tab/activate_tab) + **back/forward**. Completo. |
|
||
| 4 | Lanzador personalizado | `[x]` | Perfil, flags, extensiones, proxy, headless. Completo. |
|
||
| 5 | Configuración de detalles | `[~]` | Apariencia + flag CDP global + policy de extensiones. Falta config genérica de prefs. |
|
||
| 6 | Datos del navegador (cookies, historial, marcadores) | `[~]` | Cookies: **CRUD completo** (get/set/delete/clear). Historial perfil: nada. Marcadores: backup/restore. |
|
||
| 7 | Lectura de página (HTML, AX tree, texto) | `[~]` | HTML sí, AX tree sí. Texto plano solo vía `cdp_evaluate` (no dedicado). |
|
||
| 8 | Selección de elementos del DOM | `[x]` | find_by_text, wait_element, picker interactivo, querySelector vía evaluate. |
|
||
| 9 | CRUD de iframes | `[x]` | **list_frames + eval_in_frame + get_frame_html**. Manejo de frames completo. |
|
||
| 10 | Lanzamiento de JS en la página | `[x]` | `cdp_evaluate` + steps `js` de `cdp_extract_recipe`. Completo. |
|
||
|
||
Extras que ya tenemos y no estaban en la lista (capital acumulado): captura de tráfico (HAR +
|
||
mitmproxy), interacción humanizada (curva Bézier + jitter anti-bot), esperas inteligentes
|
||
(idle/load/element), screenshot.
|
||
|
||
---
|
||
|
||
## Catálogo completo — todas nuestras habilidades de un vistazo
|
||
|
||
39 funciones del dominio `browser` (23 Go + 12 Bash + 4 pipelines Python) + 1 pipeline Bash de reset.
|
||
Cada una es una tool candidata del futuro `browser_mcp`. Columna "MCP tool" = nombre propuesto de la tool.
|
||
|
||
### CDP core — Go (`functions/browser/`, importables directo por el MCP)
|
||
|
||
| Función (registry id) | Qué hace | MCP tool propuesta |
|
||
|---|---|---|
|
||
| `chrome_launch_go_browser` | Lanza Chrome/Chromium con remote debugging, mata árbol de proceso | `browser_launch` |
|
||
| `cdp_connect_go_browser` | Handshake WebSocket CDP sobre localhost:port → conexión lista | (interno, lo usa el MCP) |
|
||
| `cdp_close_go_browser` | Cierra conexión WS y/o mata proceso Chrome por PID | `browser_close` |
|
||
| `cdp_navigate_go_browser` | Navega la pestaña a una URL (`Page.navigate`) | `tab_navigate` |
|
||
| `cdp_new_tab_go_browser` | Abre pestaña nueva (`/json/new`) → CdpTab | `tab_new` |
|
||
| `cdp_list_tabs_go_browser` | Lista pestañas/targets (`GET /json`), sólo HTTP | `tab_list` |
|
||
| `cdp_get_html_go_browser` | HTML del DOM vivo post-JS (`outerHTML`) | `page_get_html` |
|
||
| `cdp_screenshot_go_browser` | Screenshot PNG/JPEG, viewport o página completa | `page_screenshot` |
|
||
| `cdp_evaluate_go_browser` | Ejecuta JS arbitrario (`Runtime.evaluate`, soporta await) | `page_eval_js` |
|
||
| `cdp_click_go_browser` | Click por selector CSS (scroll + mousedown/up) | `dom_click` |
|
||
| `cdp_click_human_go_browser` | Click humanizado (Bézier + jitter + micro-pausa) anti-bot | `dom_click_human` |
|
||
| `cdp_click_text_go_browser` | Click sobre el elemento cuyo innerText matchea | `dom_click_text` |
|
||
| `cdp_type_text_go_browser` | Escribe texto char a char en el elemento activo | `dom_type` |
|
||
| `cdp_move_mouse_human_go_browser` | Mueve ratón con curva Bézier humanizada | `mouse_move_human` |
|
||
| `cdp_find_by_text_go_browser` | Texto visible → selector CSS único | `dom_find_by_text` |
|
||
| `cdp_wait_element_go_browser` | Espera a que un selector exista en el DOM | `dom_wait_element` |
|
||
| `cdp_pick_element_js_go_browser` | Picker interactivo: hover overlay + click captura selector/XPath/bbox | `dom_pick_element` |
|
||
| `cdp_wait_load_go_browser` | Espera `document.readyState === complete` | `page_wait_load` |
|
||
| `cdp_wait_idle_go_browser` | Espera red en idle (inflight ≤ N durante quietMs) | `page_wait_idle` |
|
||
| `cdp_set_cookie_go_browser` | Set cookie (incl. HttpOnly) vía `Network.setCookie` | `cookie_set` |
|
||
| `cdp_har_record_go_browser` | Captura HAR 1.2 de todo el tráfico de una acción | `traffic_record_har` |
|
||
| `list_chrome_profiles_go_browser` | Lista perfiles de un user-data-dir | `profile_list` |
|
||
| `list_chrome_profile_extensions_go_browser` | Lista extensiones instaladas de un perfil | `profile_list_extensions` |
|
||
|
||
### Perfiles + sistema — Bash (`bash/functions/browser/`, el MCP las invoca vía `fn run`/shell)
|
||
|
||
| Función (registry id) | Qué hace | MCP tool propuesta |
|
||
|---|---|---|
|
||
| `create_chrome_profile_bash_browser` | Crea perfil nuevo (con/sin lanzar headless para policy) | `profile_create` |
|
||
| `delete_chrome_profile_bash_browser` | Borra perfil(es) + limpia Local State (backup automático) | `profile_delete` |
|
||
| `prepare_chrome_profile_bash_browser` | Clona user-data-dir limpio (whitelist de extensiones) | `profile_prepare` |
|
||
| `set_chrome_profile_appearance_bash_browser` | Avatar + color de tema de un perfil | `profile_set_appearance` |
|
||
| `backup_chrome_bookmarks_bash_browser` | Backup byte a byte de Bookmarks (preserva checksum) | `bookmark_backup` |
|
||
| `restore_chrome_bookmarks_bash_browser` | Restaura Bookmarks desde backup | `bookmark_restore` |
|
||
| `chrome_load_extensions_bash_browser` | Lanza Chrome con extensiones unpacked (`--load-extension`) | `ext_load_unpacked` |
|
||
| `clean_chrome_profile_extensions_bash_browser` | Purga extensiones fuera de la whitelist de un perfil | `ext_clean` |
|
||
| `apply_chromium_extension_policy_bash_browser` | Policy managed: forcelist + blocklist de extensiones | `ext_apply_policy` |
|
||
| `install_chromium_proxy_extension_bash_browser` | Instala extensión unpacked en todos los perfiles (persistente) | `ext_install_persistent` |
|
||
| `apply_chromium_cdp_flag_bash_browser` | Activa CDP global del sistema (`/etc/chromium.d/cdp`) | `system_cdp_flag` |
|
||
| `launch_chromium_proxy_bash_browser` | Lanza Chromium con perfil aislado apuntando a proxy mitm | `browser_launch_proxy` |
|
||
|
||
### Pipelines — Python + Bash (`*/functions/pipelines/`, el MCP los invoca vía `fn run`)
|
||
|
||
| Pipeline (registry id) | Qué hace | MCP tool propuesta |
|
||
|---|---|---|
|
||
| `cdp_get_ax_tree_py_pipelines` | Accessibility tree completo de un tab | `page_get_ax_tree` |
|
||
| `cdp_open_url_and_wait_py_pipelines` | Crea tab + navega + espera loadEventFired → tab_id | `tab_open_and_wait` |
|
||
| `cdp_extract_recipe_py_pipelines` | Ejecuta recipe YAML (wait_selector/js) contra Chrome | `run_recipe` |
|
||
| `extract_hls_from_cdp_tab_py_pipelines` | Extrae manifests HLS de tabs + iframes | `extract_hls` |
|
||
| `reset_chrome_profiles_bash_pipelines` | Reset destructivo de perfiles (preserva bookmarks) | `profile_reset` |
|
||
|
||
> El MCP tendrá ~28 tools al ensamblar lo existente, y crecerá hasta ~40 al cerrar los gaps de abajo.
|
||
|
||
---
|
||
|
||
## Benchmark vs estado del arte (Playwright MCP + Chrome DevTools MCP)
|
||
|
||
Comparación contra los dos servidores MCP de referencia de la comunidad para fijar qué nos falta
|
||
para tener paridad con un "lanzador típico":
|
||
|
||
- **Microsoft Playwright MCP** — ~60+ tools (incluye testing/assertions/video). Modo por defecto =
|
||
accessibility snapshot, no HTML crudo. Fuente: github.com/microsoft/playwright-mcp.
|
||
- **Google Chrome DevTools MCP** — 26 tools en 6 categorías (input, navegación, emulación,
|
||
performance, network, debugging), CDP crudo igual que nosotros. Fuente: github.com/ChromeDevTools/chrome-devtools-mcp.
|
||
|
||
### Tabla de paridad por categoría
|
||
|
||
| Categoría | Ellos tienen | Nosotros | Veredicto |
|
||
|---|---|---|---|
|
||
| Navegación URL | navigate, back/forward | navigate ✅, back/forward ❌ | falta back/forward |
|
||
| Pestañas | list/new/close/select | list/new ✅, close/activate ❌ (planeado) | en gaps tanda 1 |
|
||
| Lectura DOM | snapshot (AX) + HTML | AX tree ✅, HTML ✅ | paridad |
|
||
| Selección | locators, find by text/role | find_by_text ✅, picker ✅, wait_element ✅ | paridad |
|
||
| Click / type | click, type, **press_key**, **hover** | click(+human) ✅, type ✅, press_key ❌, hover ❌ | falta press_key, hover |
|
||
| Formularios | **fill_form**, **select_option** | ❌ (manual con click+type) | falta |
|
||
| Mouse | xy click/move/**wheel(scroll)**/drag | move_human ✅, click ✅, wheel(scroll) ❌, drag ❌ | falta scroll + drag |
|
||
| Diálogos | **handle_dialog** (alert/confirm) | ❌ | falta (bloquea flujos) |
|
||
| Subida archivos | **file_upload** | ❌ | falta |
|
||
| JS | evaluate | evaluate ✅ | paridad |
|
||
| Consola | **console_messages** | ❌ | falta (debug + detección) |
|
||
| Cookies | get/list/set/delete/clear | set ✅, resto ❌ (planeado) | en gaps tanda 1 |
|
||
| Storage local | **localStorage/sessionStorage** CRUD | ❌ | falta |
|
||
| Estado de sesión | **storage_state** save/restore | ❌ | falta (login persistente) |
|
||
| Network captura | requests list + inspect, **HAR** | HAR ✅, list/inspect en vivo ❌ | HAR cubre; falta inspección puntual |
|
||
| Network mock | **route/abort/fulfill** (intercept) | ❌ (sí mitmproxy externo) | falta intercept inline CDP |
|
||
| Network emulación | online/offline, throttle | ❌ | falta |
|
||
| Emulación device | **emulate** (device/CPU), **resize** viewport | ❌ | falta |
|
||
| Screenshot | screenshot, **PDF** | screenshot ✅, PDF ❌ | falta PDF |
|
||
| Performance | **trace + lighthouse** | ❌ | falta (nicho) |
|
||
| Anti-bot humanizado | — (ellos NO tienen) | click_human, move_human, jitter ✅ | **ventaja nuestra** |
|
||
| Captura tráfico proxy | — (vía HAR) | web_proxy mitmproxy ✅ | **ventaja nuestra** |
|
||
| Perfiles (CRUD disco) | — (ellos NO gestionan perfiles) | create/delete/prepare/appearance/reset ✅ | **ventaja nuestra** |
|
||
|
||
**Conclusión**: en lectura/selección/JS/click hay paridad. Nuestras ventajas: humanización anti-bot,
|
||
captura mitmproxy y gestión de perfiles en disco (Playwright/CDP-MCP no hacen nada de esto). Nos
|
||
faltan, además de los gaps de la lista 1 (tabs/iframes/cookies/ventanas/historial), las capacidades
|
||
de abajo (tanda 2) para alcanzar paridad de automatización.
|
||
|
||
---
|
||
|
||
## Pendiente (gaps a construir)
|
||
|
||
> ✅ **CERRADOS en la tanda mínima viable (06/06/2026)**: #2 (tabs close/activate), #3 (cookies get/delete/clear),
|
||
> #6 (iframes) + tanda 2 #10 (press_key), #11 (handle_dialog), #13 (storage_state), #14 (scroll), #15 (nav back/forward).
|
||
> Ver sección **Hecho**. Lo de abajo es lo que QUEDA.
|
||
|
||
- [ ] 1. **CRUD de ventanas** — funciones nuevas dominio `browser`:
|
||
- `cdp_list_windows` — `Browser.getWindowForTarget` por cada target → id de ventana + bounds.
|
||
- `cdp_set_window_bounds` — mover/redimensionar/maximizar/minimizar (`Browser.setWindowBounds`).
|
||
- `cdp_new_window` — abrir ventana nueva (Target con `newWindow:true`) vs pestaña.
|
||
- `cdp_close_window` — cerrar una ventana concreta sin matar todo el proceso.
|
||
- [ ] 2. **Cerrar/activar pestaña individual** — hoy `cdp_close` mata el proceso entero o cierra la conexión:
|
||
- `cdp_close_tab` — `Target.closeTarget(targetId)` (cierra UNA pestaña).
|
||
- `cdp_activate_tab` — `Target.activateTarget` / `/json/activate/<id>` (traer al frente).
|
||
- [ ] 3. **Cookies completas** — hoy solo `cdp_set_cookie`:
|
||
- `cdp_get_cookies` — `Network.getCookies` / `getAllCookies` (leer, filtrar por dominio).
|
||
- `cdp_delete_cookies` — `Network.deleteCookies`.
|
||
- `cdp_clear_cookies` — `Network.clearBrowserCookies` (wipe completo).
|
||
- [ ] 4. **Historial del navegador** — no existe nada:
|
||
- `cdp_get_history` — leer historial (vía `History` DB del perfil o `Page.getNavigationHistory` para la sesión actual).
|
||
- `cdp_clear_history` — limpiar historial del perfil (decidir: SQLite del perfil con Chromium cerrado, como bookmarks).
|
||
- [ ] 5. **Marcadores CRUD individual** — hoy solo backup/restore byte a byte:
|
||
- `cdp_add_bookmark` / `cdp_remove_bookmark` / `cdp_list_bookmarks` — editar el archivo `Bookmarks` (JSON)
|
||
preservando el checksum, o vía CDP si hay endpoint. Complementa, no sustituye, backup/restore.
|
||
- [ ] 6. **CRUD de iframes** — solo hay lectura indirecta en `extract_hls_from_cdp_tab`:
|
||
- `cdp_list_frames` — árbol de frames (`Page.getFrameTree`): id, url, parent.
|
||
- `cdp_eval_in_frame` — ejecutar JS en el **contexto de ejecución** de un iframe concreto
|
||
(`Runtime.evaluate` con el `executionContextId`/`uniqueContextId` del frame).
|
||
- `cdp_get_frame_html` — HTML de un iframe específico.
|
||
- (opcional) `cdp_navigate_frame` — navegar un iframe a otra URL.
|
||
- [ ] 7. **Texto plano de página dedicado** — hoy se saca con `cdp_evaluate("document.body.innerText")`:
|
||
- `cdp_get_text` — función dedicada que devuelve el texto visible limpio (útil para LLM/scraping rápido).
|
||
Decidir si vale la pena o si el patrón vía evaluate es suficiente (no inflar por inflar).
|
||
- [ ] 8. **Configuración de detalles genérica** — hoy solo apariencia + flag CDP + policy extensiones:
|
||
- Evaluar si hace falta `set_chrome_profile_pref` (editar `Preferences` del perfil: idioma, descargas,
|
||
permisos por defecto, etc.) o si se cubre caso por caso. NO construir hasta tener caso real.
|
||
- [ ] 9. **Playground del proyecto** — `web_scraping` **no tiene** `playground/` (sí lo tienen `analysis/nats`
|
||
y `message_bus/unibus`). Candidato: un `playground/` con UI mínima (server single-file) que liste las
|
||
capacidades CDP y deje lanzarlas contra una pestaña viva para probarlas visualmente. Opcional, solo si
|
||
aporta para validar las funciones nuevas.
|
||
|
||
### Tanda 2 — gaps detectados en el benchmark (paridad con Playwright/CDP-MCP)
|
||
|
||
Prioridad ALTA (bloquean automatización real, los construiría antes que ventanas/historial):
|
||
|
||
- [x] 10. **`cdp_press_key`** ✅ HECHO — `Input.dispatchKeyEvent` con tabla de teclas especiales.
|
||
- [x] 11. **`cdp_handle_dialog`** ✅ HECHO — auto-handler `Page.javascriptDialogOpening` (con `go sendCDP` anti-deadlock).
|
||
- [ ] 12. **`cdp_get_console`** — capturar mensajes de consola y excepciones JS
|
||
(`Runtime.consoleAPICalled` + `Runtime.exceptionThrown`). Debug + detección de errores de la página.
|
||
**PENDIENTE** — único ALTA de tanda 2 sin construir. Sube a P1 (ver análisis LLM-readiness).
|
||
- [x] 13. **`cdp_save_storage_state` / `cdp_load_storage_state`** ✅ HECHO — cookies + localStorage a archivo.
|
||
⚠️ Falta `sessionStorage` y forzar navigate-first (ver deuda P2 del análisis).
|
||
- [x] 14. **`cdp_scroll`** ✅ HECHO — `Input.dispatchMouseEvent mouseWheel`. ⚠️ punto (100,100) hardcodeado (deuda P1).
|
||
- [x] 15. **`cdp_nav_back` / `cdp_nav_forward`** ✅ HECHO — `Page.getNavigationHistory` + `navigateToHistoryEntry`.
|
||
|
||
Prioridad MEDIA (formularios, storage fino, subida, intercept):
|
||
|
||
- [ ] 16. **`cdp_select_option`** — seleccionar valor en `<select>` (vía `cdp_evaluate` envuelto o CDP).
|
||
- [ ] 17. **`cdp_hover`** — hover sobre elemento (`Input.dispatchMouseEvent mouseMoved`) para menús
|
||
desplegables que aparecen al pasar el ratón.
|
||
- [ ] 18. **`cdp_file_upload`** — adjuntar archivos a un `<input type=file>` (`DOM.setFileInputFiles`).
|
||
- [ ] 19. **`cdp_storage_get` / `set` / `clear`** — CRUD de localStorage y sessionStorage (vía evaluate
|
||
o `DOMStorage` domain). Útil si no se quiere todo el storage_state.
|
||
- [ ] 20. **`cdp_intercept_requests`** — interceptar/abortar/modificar/mockear peticiones inline vía
|
||
`Fetch.enable` (bloquear ads/trackers, mockear respuestas, inyectar headers). Complementa, no
|
||
sustituye, al `web_proxy` mitmproxy (este es inline sin proxy externo).
|
||
- [ ] 21. **`cdp_emulate_network`** — online/offline + throttle (`Network.emulateNetworkConditions`).
|
||
- [ ] 22. **`cdp_save_pdf`** — guardar la página como PDF (`Page.printToPDF`).
|
||
|
||
Prioridad BAJA (formularios compuestos, emulación device, performance, drag):
|
||
|
||
- [ ] 23. **`cdp_fill_form`** — rellenar varios campos de una (composición de find+click+type, candidato
|
||
a **pipeline** no a función — encaja con la doctrina de promover composiciones).
|
||
- [ ] 24. **`cdp_emulate_device`** — viewport/userAgent/touch móvil (`Emulation.setDeviceMetricsOverride`).
|
||
- [ ] 25. **`cdp_drag_drop`** — drag and drop entre elementos.
|
||
- [ ] 26. **Performance/Lighthouse** — `cdp_perf_trace` (Tracing domain) + audit Lighthouse. Nicho, solo
|
||
si aparece caso de análisis de rendimiento web.
|
||
|
||
## En curso
|
||
|
||
- [~] (ninguna ahora mismo — documento recién creado)
|
||
|
||
## Hecho (lo que YA tenemos)
|
||
|
||
- [x] **Gap #1 — bucle percibir→actuar por `#ref` + auto-observe** (06/06/2026, 9/9 e2e)
|
||
- `#ref` = `backendDOMNodeId` (estable, no el efímero del AX) → ref→acción + refs estables resueltos
|
||
juntos y **stateless** (sin mapa en el MCP). Validado con dump de AXNode real antes de codear.
|
||
- Funciones nuevas: `cdp_click_xy_human` (primitivo de click humanizado por coords, compartido por
|
||
selector/#ref/visión), `cdp_click_ref`, `cdp_type_ref`, `cdp_hover_ref`. `cdp_click_human`
|
||
refactorizado para usar el primitivo (un solo camino de click).
|
||
- MCP: tools `dom_click_ref`/`dom_type_ref`/`dom_hover_ref` con **auto-observe** (devuelven el outline
|
||
tras la acción). browser_mcp v0.3.0, **39 tools**.
|
||
- `render_ax_outline` mejorado (defectos F1): guard de ciclo + profundidad, sin `ljust`, renderiza `value`.
|
||
- Validado prueba e2e 9: login en the-internet **solo por `#ref`**, sin un selector CSS.
|
||
- Pendiente de la familia: política de humanización por sesión (`human`/`fast`/`instant`).
|
||
- enlace: functions/browser/cdp_{click_xy_human,click_ref,type_ref,hover_ref}.go + render_ax_outline.py
|
||
- [x] **Tanda de deuda A+D+E+B — 4 fixes + 8/8 e2e** (06/06/2026)
|
||
- **A** aislamiento robusto: `chrome_launch` usa el binario real (salta el wrapper que pisaba flags).
|
||
- **D** `sessionStorage` añadido a `storage_state` (save+load). Validado por prueba e2e 6.
|
||
- **E** `cdp_find_by_text` devuelve error en no-encontrado (antes vacío silencioso). Validado por prueba 7.
|
||
- **B** fin del fire-and-forget: `cdp_click` verifica visibilidad, `cdp_type_text` verifica foco. Validado por prueba 8.
|
||
- La batería e2e pasó de 5 a 8 pruebas, todas verdes. Pendiente: C (Enter en widgets JS), `cdp_scroll`
|
||
con target (P1.5), puente percepción→acción por nodeId (P1.3).
|
||
- enlace: functions/browser/{chrome_launch,cdp_save_storage_state,cdp_load_storage_state,cdp_find_by_text,cdp_click,cdp_type_text}.go
|
||
- [x] **Fase C — validación e2e real: 5/5 PASS** (06/06/2026, headless + ventana visible)
|
||
- resultado: batería `projects/web_scraping/demo_e2e/` contra sitios sandbox (quotes/books.toscrape.com,
|
||
the-internet.herokuapp.com). 5 tareas simples→complejas: extracción estructurada, percepción AX,
|
||
teclado/form, **login persistente (storage_state)**, scraping paginado+dedup. Cliente MCP stdio
|
||
secuencial. Chrome aislado en 9333.
|
||
- **3 bugs reales encontrados y arreglados ejecutando** (lo que "compila" no detecta):
|
||
`page_perceive` (args posicionales a fn run), `cdp_save_storage_state` (filtrar cookies por dominio),
|
||
`cdp_load_storage_state` (añadir `url` por cookie para httpOnly). Login persistente ahora funciona.
|
||
- enlace: projects/web_scraping/demo_e2e/RESUMEN.md + results/
|
||
- [x] **`browser_mcp` v1 — servidor MCP de control de navegador** (Go, 06/06/2026)
|
||
- resultado: app en `projects/web_scraping/apps/browser_mcp/` (sub-repo Gitea, `git init` hecho).
|
||
**36 tools** (v0.2.0), pool de conexiones por puerto, stdio + `--http` + `--read-only`. **Build verde**
|
||
(smoke `tools/list`=36). Registrado en `projects/web_scraping/.mcp.json` como server `browser`.
|
||
- ✅ Fase B.5 (P0 LLM-readiness) cerrada: Chrome aislado 9333, `tab_select` determinista, `page_get_text`,
|
||
`page_perceive`. Pendiente Fase C (e2e real contra Chrome) + P1 (verificación post-acción).
|
||
- enlace: projects/web_scraping/apps/browser_mcp/ — patrón `apps/registry_mcp`.
|
||
- [x] **Fix bug `%v` en `cdp_evaluate` + `cdp_eval_in_frame`** (06/06/2026)
|
||
- resultado: objetos/arrays JS ahora se serializan con `json.Marshal` (antes repr de Go inservible).
|
||
Build+vet+test del paquete `browser` verdes. Reindexado.
|
||
- enlace: functions/browser/cdp_evaluate.go, cdp_eval_in_frame.go
|
||
- [x] **Tanda mínima viable del MCP — 15 funciones CDP nuevas** (Go, dominio `browser`, 06/06/2026)
|
||
- resultado: 5 `fn-constructor` en paralelo. Compila (`go build`/`vet`/`test` verdes), indexado (`fn index`),
|
||
15 entradas confirmadas. Tag de grupo `navegator` en todas.
|
||
- **Tabs/navegación**: `cdp_close_tab_go_browser`, `cdp_activate_tab_go_browser` (registradas — el código ya
|
||
vivía en `cdp_list_tabs.go`), `cdp_nav_back_go_browser`, `cdp_nav_forward_go_browser`.
|
||
- **Iframes**: `cdp_list_frames_go_browser`, `cdp_eval_in_frame_go_browser`, `cdp_get_frame_html_go_browser`.
|
||
- **Cookies**: `cdp_get_cookies_go_browser`, `cdp_delete_cookies_go_browser`, `cdp_clear_cookies_go_browser`.
|
||
- **Input/diálogos**: `cdp_press_key_go_browser`, `cdp_scroll_go_browser`, `cdp_handle_dialog_go_browser`.
|
||
- **Sesión**: `cdp_save_storage_state_go_browser`, `cdp_load_storage_state_go_browser` (login persistente).
|
||
- enlace: functions/browser/cdp_*.go — cierra gaps #2, #3, #6(cookies), #9 + tanda2 #10/#11/#13/#14/#15.
|
||
- [x] **Perfiles — CRUD completo** (Bash, dominio `browser`)
|
||
- resultado: Create `create_chrome_profile`, Read `list_chrome_profiles` (+ `list_chrome_profile_extensions`),
|
||
Delete `delete_chrome_profile`, Update `set_chrome_profile_appearance` (avatar + color de tema) /
|
||
`prepare_chrome_profile` (clonar limpio) / `reset_chrome_profiles` (pipeline reset destructivo con
|
||
preservación de bookmarks).
|
||
- enlace: bash/functions/browser/, bash/functions/pipelines/reset_chrome_profiles.md
|
||
- [x] **Lanzador personalizado** (Go + Bash)
|
||
- resultado: `chrome_launch` (remote debugging, multi-OS, mata árbol de proceso),
|
||
`launch_chromium_proxy` (perfil aislado apuntando a proxy mitm/Burp),
|
||
`chrome_load_extensions` (unpacked), `apply_chromium_cdp_flag` (CDP global del sistema),
|
||
`apply_chromium_extension_policy` + `install_chromium_proxy_extension` (distribuir extensiones),
|
||
y subcomando `launch` de `script_navegador`.
|
||
- enlace: functions/browser/chrome_launch.go, bash/functions/browser/
|
||
- [x] **Pestañas — crear / listar / navegar**
|
||
- resultado: `cdp_new_tab`, `cdp_open_url_and_wait` (crear+navegar+esperar load), `cdp_list_tabs`,
|
||
`cdp_navigate`. (Falta cerrar/activar una pestaña concreta → Pendiente #2.)
|
||
- enlace: functions/browser/cdp_new_tab.md, cdp_list_tabs.go, cdp_navigate.go
|
||
- [x] **Lectura de página — HTML + Accessibility tree**
|
||
- resultado: `cdp_get_html` (DOM vivo post-JS), `cdp_get_ax_tree` (pipeline Python, AX tree completo).
|
||
Texto plano hoy vía `cdp_evaluate` (ver Pendiente #7).
|
||
- enlace: functions/browser/cdp_get_html.go, python/functions/pipelines/cdp_get_ax_tree.md
|
||
- [x] **Selección de elementos del DOM**
|
||
- resultado: `cdp_find_by_text` (texto→selector CSS único), `cdp_wait_element` (polling existencia),
|
||
`cdp_pick_element_js` (picker interactivo: hover overlay + click captura selector/XPath/bbox),
|
||
querySelector arbitrario vía `cdp_evaluate`.
|
||
- enlace: functions/browser/cdp_find_by_text.go, cdp_pick_element_js.js, cdp_wait_element.go
|
||
- [x] **Lanzamiento de JS en la página**
|
||
- resultado: `cdp_evaluate` (expresión JS arbitraria, soporta await, reporta excepciones),
|
||
steps `js` de `cdp_extract_recipe` (recipe YAML).
|
||
- enlace: functions/browser/cdp_evaluate.go, python/functions/pipelines/cdp_extract_recipe.md
|
||
- [x] **Marcadores — backup / restore**
|
||
- resultado: `backup_chrome_bookmarks` + `restore_chrome_bookmarks` (copia byte a byte preservando
|
||
checksum, sin reserializar JSON). CRUD individual de bookmarks pendiente (#5).
|
||
- enlace: bash/functions/browser/backup_chrome_bookmarks.sh, restore_chrome_bookmarks.sh
|
||
- [x] **Cookies — set**
|
||
- resultado: `cdp_set_cookie` (incl. HttpOnly, para auth e2e). get/delete/clear pendientes (#3).
|
||
- enlace: functions/browser/cdp_set_cookie.go
|
||
- [x] **Extras (capital acumulado, fuera de la lista pedida)**
|
||
- resultado: captura de tráfico `cdp_har_record` (HAR 1.2) + app `web_proxy` (mitmproxy siempre activo);
|
||
interacción humanizada `cdp_click_human` / `cdp_move_mouse_human` / `cdp_type_text` (anti-detección);
|
||
esperas inteligentes `cdp_wait_idle` / `cdp_wait_load` / `cdp_wait_element`; `cdp_screenshot`;
|
||
pipeline `extract_hls_from_cdp_tab` (manifests HLS de tabs+iframes).
|
||
- enlace: functions/browser/, projects/web_scraping/apps/web_proxy
|
||
|
||
## MCP full-CDP (`browser_mcp`) — estado e iteración
|
||
|
||
**Meta**: un servidor MCP que da a cualquier agente Claude control total del navegador vía CDP.
|
||
Nombre **resuelto: `browser_mcp`** (genérico, para todo control de navegador, no solo CDP).
|
||
|
||
### Estado actual — v1 construido (06/06/2026)
|
||
|
||
- **App**: `projects/web_scraping/apps/browser_mcp/` (Go, sub-repo Gitea propio, `git init` hecho).
|
||
Patrón `registry_mcp`: `github.com/mark3labs/mcp-go` v0.52.0, archivos `tools_<grupo>.go`, registro en
|
||
`main.go`, stdio por defecto + `--http` opcional + flag `--read-only`. **Build verde, 33 tools.**
|
||
- **Pool de conexiones** (resuelto: pool por puerto, NO connect-per-tool). Ver explicación abajo.
|
||
- **Registro**: `projects/web_scraping/.mcp.json` con el server `browser`.
|
||
- **Omitido v1**: `cdp_har_record` (requiere callback), `cdp_get_ax_tree` (pipeline Python), perfiles Bash
|
||
(requieren Chrome cerrado → incompatible con un Chrome vivo).
|
||
|
||
### Pool de conexiones — por qué es requisito, no opción
|
||
|
||
`browser.CdpConnect(port)` hace un handshake WebSocket a una tab "page" de Chrome (~50-200 ms) y esa
|
||
conexión ES una sesión viva (Page.*/Runtime.*/Input.* + un `readLoop` en goroutine + event handlers).
|
||
Si reconectáramos en cada tool: (1) pagaríamos el handshake cada vez, (2) **perderíamos estado entre
|
||
tools** — los handlers de eventos (p.ej. el auto-handler de `handle_dialog`) mueren al cerrar la conexión.
|
||
Por eso `browser_mcp` mantiene `map[port]→*CDPConn`: la primera tool que toca el puerto abre la conexión,
|
||
las siguientes la reusan; se cierra al apagar el MCP o con `browser_disconnect`. **Sin pool, encadenar
|
||
navigate→wait→click→eval es imposible** (cada `fn run` suelto pierde la conexión al terminar el proceso).
|
||
|
||
### ⚠️ Deuda crítica (análisis LLM-readiness) — ver sección dedicada abajo
|
||
|
||
El v1 **envuelve las funciones tal cual**. Un LLM percibe-decide-actúa-verifica; las funciones están
|
||
hechas para un script que ya sabe qué hacer. Antes de declarar el MCP "usable por un agente" hay que
|
||
cerrar los P0 de la sección siguiente (percepción compacta + verificación + target determinista). El
|
||
valor del MCP está en lo que AÑADE encima, no en el wrapping.
|
||
|
||
### Fases
|
||
|
||
- **Fase 0** — inventario + catálogo + plan. ✅
|
||
- **Fase A** — 15 funciones gap de la tanda mínima viable. ✅ (5 fn-constructor paralelos)
|
||
- **Fase B** — ensamblar `browser_mcp` v1 (33 tools, pool, build verde). ✅
|
||
- **Fase B.5 — NUEVO, BLOQUEANTE** — cerrar los P0 del análisis (abajo) y elevar el MCP de "wrapper" a
|
||
"capa de agente": percepción compacta, verificación post-acción, target determinista.
|
||
- **Fase C** — registrar en Claude + e2e (un agente abre Chrome aislado, navega, lee, click, extrae) +
|
||
documentar en `LLM_BROWSER_GUIDE.md`.
|
||
|
||
### Capability group
|
||
|
||
Crear/actualizar `docs/capabilities/browser.md` con el cluster completo (39 funciones + 15 nuevas) +
|
||
ejemplo canónico end-to-end + las tools del MCP, para cargar el grupo en un solo read.
|
||
|
||
---
|
||
|
||
## Análisis LLM-readiness — deuda P0/P1/P2
|
||
|
||
Crítica recibida (06/06/2026): el núcleo CDP es sólido y la cobertura de verbos casi completa, pero el
|
||
sistema está hecho para un programa que ya sabe qué hacer, no para un LLM que percibe-decide-actúa-verifica.
|
||
Faltan las dos piezas que un agente necesita: **percibir sin colapsar el contexto** y **saber si la acción
|
||
funcionó**. Evaluado contra el bucle PERCIBIR → DECIDIR → ACTUAR → VERIFICAR (+ ESTADO transversal).
|
||
|
||
### Ya corregido este turno
|
||
|
||
- [x] **BUG GRAVE `cdp_evaluate` / `cdp_eval_in_frame`** — usaban `fmt.Sprintf("%v", value)`; objetos/arrays
|
||
JS llegaban como repr de Go (`map[a:1]`) en vez de JSON. Arreglado: `json.Marshal` para no-strings.
|
||
(Sin esto el scraping de datos estructurados era inservible.)
|
||
- [x] **Comentario mentiroso de `cdp_navigate`** — decía "espera Page.loadEventFired"; el código solo lanza
|
||
`Page.navigate`. Comentario corregido: NO espera carga, hay que encadenar `CdpWaitLoad`/`CdpWaitIdle`.
|
||
|
||
### P0 — CERRADOS (06/06/2026, Fase B.5) ✅
|
||
|
||
- [x] **P0.1 `render_ax_outline`** ✅ — `render_ax_outline_py_core` (puro: nodos AX → outline indentado con
|
||
`#ref`) + pipeline `cdp_perceive_outline_py_pipelines` (compone `cdp_get_ax_tree` + `trim_ax_tree` +
|
||
`render_ax_outline`). Expuesto como tool `page_perceive` del MCP (vía `fn run`). La pieza de PERCEPCIÓN.
|
||
- [x] **P0.2 Lecturas con límite** ✅ — `cdp_get_text_go_browser` (texto visible, selector opcional, `maxBytes`
|
||
con corte rune-safe). Tool `page_get_text` del MCP (default 20000 bytes). `get_html` se deja intacto
|
||
(sin romper firma); el truncado de HTML vive en la tool del MCP (200k). Decisión KISS documentada.
|
||
- [x] **P0.3 Target determinista + Chrome aislado** ✅ — `cdp_connect_target_go_browser` (elige target por id o
|
||
substring de URL) + refactor `cdp_connect.go` (helper `cdpConnectWS`). En el MCP: **default puerto 9333 =
|
||
Chrome aislado del MCP** (no el 9222 diario), `browser_launch` con `user_data_dir` dedicado, y tool
|
||
`tab_select` para fijar la pestaña determinísticamente. **Cierra el riesgo de operar sobre banca/correo.**
|
||
- [x] **Aislamiento robusto del binario** ✅ (06/06) — `chrome_launch` usa el binario real
|
||
`/usr/lib/chromium/chromium` (salta el wrapper `/etc/chromium.d/cdp` que inyectaba flags globales).
|
||
Antes el aislamiento dependía del orden de los flags.
|
||
|
||
### P1 — fiabilidad de acción
|
||
|
||
- [x] **P1.1 Verificación post-acción** ✅ (06/06) — `cdp_click` verifica visibilidad (oculto → error, no clic
|
||
en (0,0)); `cdp_type_text` verifica foco editable (sin foco → error). Validado por prueba e2e 8. PENDIENTE:
|
||
`cdp_scroll`/`press_key` con confirmación de efecto (menor).
|
||
- [x] **P1.2 `cdp_find_by_text` honesto** ✅ (06/06) — ahora devuelve error explícito en no-encontrado (antes
|
||
`("", nil)` silencioso). Validado por prueba e2e 7. (Aviso de múltiples matches: pendiente, menor.)
|
||
- [ ] **P1.3 Puente percepción→acción** — el LLM percibe en AX tree (role/name/nodeId) pero actúa por selector
|
||
CSS. Falta `click(nodeId)`/`act(#ref)` para actuar por ref del snapshot (como Playwright), sin adivinar CSS.
|
||
- [x] **P1.4 `cdp_type_text` verifica focus** ✅ (06/06) — error claro si no hay campo editable enfocado
|
||
(antes el texto iba a `document.body` en silencio). Validado por prueba e2e 8.
|
||
- [ ] **P1.5 `cdp_scroll` con target** — punto (100,100) hardcodeado; si ahí hay un navbar fixed no scrollea el
|
||
contenido. Permitir x,y o selector/elemento objetivo.
|
||
- [ ] **P1.6 `cdp_get_console`** (era tanda2 #12) — capturar consola + excepciones; el LLM detecta errores de página.
|
||
|
||
### P2 — paridad
|
||
|
||
- [ ] **P2.1** `cdp_select_option`, `cdp_file_upload`, `cdp_hover` (ver tanda 2 #16-18).
|
||
- [x] **P2.2 `storage_state`** ✅ (06/06) — cookies (filtradas por dominio) + localStorage + **sessionStorage**
|
||
+ login persistente, todo validado e2e (pruebas 4 y 6). `load` sigue exigiendo navigate-first al dominio (documentado).
|
||
|
||
> Implicación: el MCP NO es "envolver 39 funciones". Es la capa que arregla los 4 ejes (pool=estado,
|
||
> representaciones compactas=percepción, JSON real=ya hecho, verificación=acción fiable). Un MCP que solo
|
||
> expone las funciones hereda todos los defectos.
|
||
|
||
---
|
||
|
||
## Roadmap MCP de clase — benchmark Playwright + Visión (apuntado 06/06/2026)
|
||
|
||
Objetivo: pasar de "wrapper con ~36 tools" a un MCP de clase. La métrica NO es el número de tools
|
||
(Playwright MCP ~60, Chrome DevTools MCP 26) — gran parte de los 60 de Playwright son inflado (storage
|
||
desglosado, video/tracing). Lo que sube el nivel real es **cerrar los 4 gaps de clase + dar al agente
|
||
tres sentidos de percepción→acción**.
|
||
|
||
### Los tres sentidos del agente (percepción → acción)
|
||
|
||
El agente tendrá tres vías para "ver" una página y actuar sobre ella. Cada una necesita su puente a la acción:
|
||
|
||
1. **DOM / AX tree** (hoy parcial) — `page_perceive` → outline con `#ref`. **Falta el puente `#ref` → acción.**
|
||
2. **Texto** (hoy) — `cdp_get_text` (compacto, selector opcional).
|
||
3. **Visión** (futuro, el usuario aportará los modelos) — screenshot → **OCR** (texto + bbox) + **YOLO**
|
||
(objetos + bbox) → el agente ve la página como imagen. **Puente a la acción = coordinate mouse**
|
||
(`click_xy` sobre el bounding box detectado). Por esto coordinate mouse NO es inflado: es el sentido
|
||
de la mano para el ojo visual.
|
||
|
||
### Transversal — humanización SIEMPRE en las acciones (anti-detección)
|
||
|
||
REGLA DE DISEÑO: todas las acciones de ratón/teclado del agente usan por defecto la variante humanizada
|
||
(curva de Bézier + jitter + micro-pausas variables), no el evento sintético directo. Ya existen
|
||
`cdp_click_human` y `cdp_move_mouse_human`; el `cdp_type_text` ya escribe char a char con pausa. Aplicar:
|
||
|
||
- El puente `#ref` → acción (A1) y `click_xy` (C1) deben ir **por defecto** por el camino humanizado
|
||
(mover el ratón con Bézier hasta el destino + click con micro-pausa press/release), no por
|
||
`Input.dispatchMouseEvent` seco. Exponer un flag `instant=true` solo para tests/velocidad.
|
||
- Donde falte versión humanizada (scroll, drag_xy), crear la variante con jitter/easing.
|
||
- Objetivo: que el tráfico de input sea indistinguible de un humano — es ventaja nuestra frente a
|
||
Playwright/CDP-MCP, que no humanizan. No perderla al añadir tools nuevas.
|
||
|
||
### A. Gaps de clase (los 4 que de verdad suben el nivel)
|
||
|
||
- [x] **A1 — Puente `#ref` → acción** ✅ (06/06). `cdp_click_ref`/`cdp_type_ref`/`cdp_hover_ref` + primitivo
|
||
`cdp_click_xy_human`. Tools MCP `dom_click_ref`/`type_ref`/`hover_ref`. Validado prueba e2e 9.
|
||
Hoy el outline da `#ref=44` pero el LLM no puede usarlo: tiene que volver a selector CSS. Cierra el loop
|
||
percibir↔actuar. **Gap #1 ahora.**
|
||
- [x] **A2 — Refs estables** ✅ (06/06). Resuelto stateless: el `#ref` ES el `backendDOMNodeId` (estable
|
||
mientras el nodo viva), no el `nodeId` efímero del AX. Sin mapa de estado en el MCP. `render_ax_outline` actualizado.
|
||
- [x] **A3 — Auto-observe tras acción** ✅ (06/06). Las tools `_ref` del MCP devuelven el outline AX
|
||
actualizado tras la acción (settle 400ms + perceiveOutline). Verificación implícita. Validado prueba 9.
|
||
- [ ] **A4 — Política de target segura en el MCP** (P0 seguridad). `cdp_connect_target` da la herramienta;
|
||
falta la regla: el MCP lanza Chrome propio (perfil + puerto dedicados, ya en 9333) o exige target
|
||
explícito; nunca engancha a la tab del 9222 por `match=""`.
|
||
- [ ] **A5 — Intercept / mock de red** (`Fetch.enable`) (P0 programático). Mockear APIs, bloquear recursos,
|
||
inyectar headers. La tool más valiosa de Playwright (`route`). Hoy 0.
|
||
|
||
### B. Tools valiosas del benchmark Playwright (delta real, ~12)
|
||
|
||
- [ ] **B1 verbos de formulario**: `hover`, `select_option` (`<select>`), `file_upload` (`DOM.setFileInputFiles`),
|
||
`drag`/`drop`.
|
||
- [ ] **B2 network observability**: `network_requests` (lista en vivo) + `network_request` (inspeccionar uno).
|
||
Complementa el HAR post-mortem.
|
||
- [ ] **B3 `console_messages`**: capturar consola + excepciones JS (`Runtime.consoleAPICalled`). Debug + detección.
|
||
- [ ] **B4 assertions (modo programático)**: `verify_element_visible` / `verify_text_visible` / `verify_value`.
|
||
Es el EJE VERIFICAR aplicado a recetas YAML (assert por paso).
|
||
|
||
### C. Coordinate mouse — IMPORTANTE (base del modo visión)
|
||
|
||
Reclasificado de "inflado" a importante por el usuario: es el puente entre visión (bbox de OCR/YOLO) y acción.
|
||
|
||
- [ ] **C1** `cdp_click_xy(x, y)` — click por coordenadas (sobre lo que la visión detecta).
|
||
- [ ] **C2** `cdp_move_xy` / `cdp_mouse_down` / `cdp_mouse_up` — control fino del ratón por píxeles.
|
||
- [ ] **C3** `cdp_drag_xy(x1,y1,x2,y2)` — drag por coordenadas.
|
||
- [ ] **C4** `cdp_scroll` ya existe; añadir target por coordenadas/elemento (P1.5).
|
||
|
||
### D. Misc — IMPORTANTE
|
||
|
||
- [ ] **D1** `cdp_save_pdf` (`Page.printToPDF`) — exportar página a PDF.
|
||
- [ ] **D2** `cdp_get_console` (= B3) — consola + excepciones.
|
||
- [ ] **D3** `cdp_resize` / `cdp_emulate_device` (`Emulation.setDeviceMetricsOverride`) — viewport conocido
|
||
(clave para visión: coordenadas estables) + mobile/touch.
|
||
- [ ] **D4** `cdp_nav_back`/`forward` ya existen; `wait_for` cubierto por wait_load/idle/element.
|
||
- [ ] Screenshot como **MCP image content** (hoy `page_screenshot` va a archivo → el LLM no lo ve). Prerequisito
|
||
del modo visión.
|
||
|
||
### E. VISIÓN (OCR + YOLO) — tarea futura, el usuario aporta los modelos
|
||
|
||
- [ ] **E1** Pipeline de percepción visual: `page_screenshot` (a buffer) → **OCR** (texto + bbox) + **YOLO**
|
||
(objetos UI + bbox) → estructura `{label, text, bbox}` que el agente consume como "outline visual".
|
||
- [ ] **E2** Función `ocr_page` y `detect_ui_elements` (los modelos los aportará el usuario). Dominio nuevo
|
||
(¿`vision`?) o `browser`. Probable Python (modelos ML).
|
||
- [ ] **E3** Puente visión → acción vía coordinate mouse (sección C): el agente clica el centro del bbox.
|
||
- [ ] **E4** Screenshot como image content en el MCP (D) para que el LLM también vea el píxel directamente.
|
||
- Nota: la visión es el tercer sentido — complementa, no sustituye, al AX outline (que es más barato en
|
||
tokens). Útil cuando el DOM miente (canvas, iframes cross-origin, apps que pintan en `<canvas>`).
|
||
|
||
### F. Defectos de calidad a corregir en lo ya construido (del coach)
|
||
|
||
- [x] **F1** ✅ (06/06) `render_ax_outline`: guard de ciclo (`visited`) + límite de profundidad (`_MAX_DEPTH=60`);
|
||
`ljust(60)` eliminado; renderiza el `value` de inputs (`= 'texto'`). Hecho en la misma edición del `#ref`.
|
||
- [ ] **F2** `cdp_get_html` sin límite: **documentar** que es "crudo a propósito" (la vía compacta es
|
||
get_text + outline).
|
||
- [ ] **F3** `cdp_connect_target` con `match=""`: documentar que es inseguro fuera del MCP; la política
|
||
segura vive en A4.
|
||
- [ ] **F4** Limpieza de recursos: isolated worlds que crea `cdp_eval_in_frame`, conexiones del pool del MCP.
|
||
|
||
### G. Inflado de Playwright — NO construir salvo necesidad concreta
|
||
|
||
Storage granular desglosado (cookie/localStorage/sessionStorage × get/set/delete/list/clear = 17 tools;
|
||
nosotros lo hacemos con 6), video/tracing/highlight (9 tools de debug visual de testing), `generate_locator`,
|
||
`run_code_unsafe` (= nuestro `page_eval_js`). Replicar esto sube el contador a ~45 sin añadir poder.
|
||
|
||
### Telemetría
|
||
|
||
`call_monitor` ya existe — cada tool del MCP encaja sin trabajo extra.
|
||
|
||
---
|
||
|
||
## Enlaces
|
||
|
||
- App orquestadora — projects/web_scraping/apps/script_navegador (CLI rápido: open/click/type/eval/html/shot/wait/tabs/launch/close/profiles + runner YAML)
|
||
- App captura — projects/web_scraping/apps/web_proxy (mitmproxy, service systemd-user puerto 8080)
|
||
- Guía LLM — projects/web_scraping/LLM_BROWSER_GUIDE.md
|
||
- Setup CDP global — projects/web_scraping/CHROMIUM_SYSTEM.md
|
||
- Dominio browser en registry — `mcp__registry__fn_search query="" domain="browser"`
|
||
|
||
## Issues / flows relacionados
|
||
|
||
- (ninguno aún — al priorizar los gaps, abrir issue por bloque o delegar a fn-constructor)
|
||
|
||
## Notas
|
||
|
||
- **Decisión de arquitectura**: el control de navegador es CDP crudo sobre Chrome/Chromium en Linux nativo,
|
||
no Playwright/Selenium. Toda capacidad reutilizable vive en `functions/browser/`; las apps solo orquestan.
|
||
- **Prioridad sugerida de gaps** (mayor impacto scraping/automatización primero):
|
||
1) Cerrar/activar pestaña individual (#2) y CRUD de iframes (#6) — bloquean automatización de SPAs reales.
|
||
2) Cookies completas (#3) — leer/borrar cookies es básico para sesiones y limpieza.
|
||
3) CRUD de ventanas (#1) — útil para multi-ventana y posicionamiento, menos urgente para scraping headless.
|
||
4) Historial (#4) y bookmarks CRUD (#5) — nicho, construir cuando haya caso concreto.
|
||
- **No inflar por inflar**: `cdp_get_text` (#7) y config genérica de prefs (#8) solo si aparece un caso real
|
||
repetido; el patrón vía `cdp_evaluate` puede ser suficiente (regla function_growth_and_self_docs).
|
||
- Cada función nueva del dominio `browser` debe declararse en `uses_functions` del `app.md` que la consuma
|
||
(el indexer no deduce deps en Go automáticamente para apps).
|