Introducción

La mayoría de las herramientas de productividad para navegadores fallan en un punto clave: no impiden activamente las distracciones. Los temporizadores Pomodoro clásicos dependen de tu fuerza de voluntad para respetar el tiempo, pero basta un clic en una notificación o un «solo un minuto más» para romper el flujo. Este artículo detalla cómo construir una extensión de Chrome que no solo mide el tiempo, sino que controla el comportamiento del navegador durante las sesiones, con niveles de enfoque configurables y bloqueo reactivo de tabs.

El enfoque es técnico y práctico: usaremos vibe coding con IA para prototipar una extensión funcional en minutos, iterando hasta lograr un MVP estable. Incluiremos manejo de estados, detección de cambios de tabs, y reglas de bloqueo escalables. Al final, tendrás una base lista para personalizar o integrar con otras herramientas de infraestructura.

Qué es y para qué sirve

Esta extensión implementa un Pomodoro inteligente con tres niveles de enfoque:

  1. Relajado: Permite cambiar de tabs, pero notifica si te excedes del tiempo configurado.
  2. Moderado: Bloquea la apertura de nuevas tabs y advierte al intentar salir del tab actual.
  3. Estricto: Fuerza el retorno al tab de trabajo y evita cualquier cambio de contexto.

La arquitectura se basa en:

  • Un popup con interfaz minimalista (generada por IA) que muestra el timer y los controles.
  • Un servicio en background que gestiona el estado del timer y las reglas de enfoque.
  • Escuchadores de eventos para detectar cambios de tabs y activar/desactivar bloqueos.
  • Almacenamiento local para persistir configuraciones y estadísticas básicas.
Casos de uso reales:
  • Evitar el «scroll infinito» en redes sociales durante sesiones de trabajo.
  • Bloquear tabs distractoras (ej: YouTube, Reddit) en modo estricto.
  • Integrar con herramientas de DevOps para registrar productividad en dashboards.

Prerequisitos

Antes de empezar, asegúrate de tener instalado y configurado:

RequisitoVersión mínimaNotas
**Chrome**120+Usar Chromium (Edge, Brave) también funciona.
**Node.js**18+Para ejecutar el entorno de desarrollo local.
**npm**9+Incluido con Node.js.
**Claude Code**0.10+Opcional, pero recomendado para vibe coding.
**Git**2.40+Para clonar repositorios de ejemplo.
**Permisos**Chrome en modo desarrollador (BLOCK9 > «Modo desarrollador»).
Accesos necesarios:
  • Cuenta de Google para instalar extensiones en modo desarrollador.
  • Editor de código (VS Code, Neovim, etc.) con soporte para JavaScript/TypeScript.

Guía paso a paso

Paso 1: Crear la estructura base de la extensión

  1. Generar los archivos mínimos con IA (recomendado) o manualmente:
   mkdir chrome-pomodoro-focus && cd chrome-pomodoro-focus
   touch manifest.json popup.html popup.js background.js styles.css
   
  1. Configurar el manifest.json (versión 3):
   {
     "manifest_version": 3,
     "name": "Pomodoro Focus Control",
     "version": "1.0",
     "description": "Pomodoro con niveles de enfoque y bloqueo de tabs",
     "action": {
       "default_popup": "popup.html",
       "default_icon": "icon.png"
     },
     "background": {
       "service_worker": "background.js"
     },
     "permissions": ["activeTab", "tabs", "alarms"],
     "icons": {
       "16": "icon.png",
       "48": "icon.png",
       "128": "icon.png"
     }
   }
   
Nota: Si no tienes un icon.png, usa uno de Flaticon (8×8 px, formato PNG).
  1. Crear el popup.html con un botón básico:
   <!DOCTYPE html>
   <html>
   <head>
     <link rel="stylesheet" href="styles.css">
   </head>
   <body>
     <div class="container">
       <h1>Pomodoro Focus</h1>
       <button id="startBtn">Iniciar</button>
       <div id="timer">00:00</div>
     </div>
     <script src="popup.js"></script>
   </body>
   </html>
   
  1. Cargar la extensión en Chrome:
– Abre chrome://extensions y activa «Modo desarrollador».

– Haz clic en «Cargar extensión sin comprimir» y selecciona la carpeta /chrome-pomodoro-focus.

– Verifica que aparezca el icono en la barra de herramientas.

Paso 2: Implementar el timer Pomodoro básico

  1. Actualizar popup.js para manejar el timer:
   let timer;
   let seconds = 0;
   let isRunning = false;
   const workDuration = 25 * 60; // 25 minutos en segundos

   document.getElementById('startBtn').addEventListener('click', () => {
     if (isRunning) {
       clearInterval(timer);
       isRunning = false;
       document.getElementById('startBtn').textContent = 'Iniciar';
     } else {
       startTimer(workDuration);
       document.getElementById('startBtn').textContent = 'Pausar';
     }
   });

   function startTimer(duration) {
     seconds = duration;
     isRunning = true;
     updateTimerDisplay();
     timer = setInterval(() => {
       seconds--;
       updateTimerDisplay();
       if (seconds <= 0) {
         clearInterval(timer);
         isRunning = false;
         alert('¡Tiempo terminado!');
       }
     }, 1000);
   }

   function updateTimerDisplay() {
     const minutes = Math.floor(seconds / 60);
     const secs = seconds % 60;
     document.getElementById('timer').textContent =
       `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
   }
   
  1. Probar el timer:
– Haz clic en «Iniciar». El contador debe decrementar cada segundo.

– Si cierras y reabres el popup, el timer debe reiniciarse (este comportamiento se corregirá en pasos posteriores).

  1. Error común:
– Si el timer no se muestra, verifica que popup.js esté vinculado correctamente en popup.html y que no haya errores en la consola (Ctrl+Shift+J).

Paso 3: Agregar niveles de enfoque y gestión de estado

  1. Modificar manifest.json para incluir permisos adicionales:
   "permissions": ["activeTab", "tabs", "alarms", "storage"]
   
  1. Crear background.js para manejar el estado global:
   let focusLevel = 'moderado'; // 'relajado', 'moderado', 'estricto'
   let currentTabId = null;

   // Escuchar cambios de tabs
   chrome.tabs.onActivated.addListener((activeInfo) => {
     currentTabId = activeInfo.tabId;
     enforceFocusLevel(focusLevel);
   });

   // Escuchar clicks en la barra de herramientas
   chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
     if (request.action === 'setFocusLevel') {
       focusLevel = request.level;
       enforceFocusLevel(focusLevel);
     }
   });

   function enforceFocusLevel(level) {
     if (level === 'estricto') {
       chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
         if (tabs[0].id !== currentTabId) {
           chrome.tabs.update(currentTabId, {active: true});
         }
       });
     }
   }
   
  1. Actualizar popup.js para enviar mensajes al background:
   // Agregar opciones de enfoque
   const focusOptions = document.createElement('div');
   focusOptions.innerHTML = `
     <select id="focusLevel">
       <option value="relajado">Relajado</option>
       <option value="moderado">Moderado</option>
       <option value="estricto">Estricto</option>
     </select>
   `;
   document.querySelector('.container').appendChild(focusOptions);

   document.getElementById('focusLevel').addEventListener('change', (e) => {
     chrome.runtime.sendMessage({
       action: 'setFocusLevel',
       level: e.target.value
     });
   });
   
  1. Verificar el comportamiento:
– Cambia el nivel a «Estricto» y prueba a cambiar de tab. El navegador debe forzarte a volver al tab inicial.

– Cambia a «Moderado» y verifica que aparezcan advertencias al intentar salir.

Paso 4: Persistir configuraciones y corregir bugs

  1. Usar chrome.storage en background.js para guardar el nivel de enfoque:
   // Cargar configuración al iniciar
   chrome.storage.sync.get(['focusLevel'], (result) => {
     if (result.focusLevel) {
       focusLevel = result.focusLevel;
       document.getElementById('focusLevel').value = focusLevel;
     }
   });

   // Guardar al cambiar
   chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
     if (request.action === 'setFocusLevel') {
       focusLevel = request.level;
       chrome.storage.sync.set({ focusLevel });
       enforceFocusLevel(focusLevel);
     }
   });
   
  1. Corregir el bug del timer:
– Modificar popup.js para usar chrome.alarms y evitar reinicios:
   // Reemplazar startTimer con:
   function startTimer(duration) {
     chrome.alarms.create('pomodoroTimer', { delayInMinutes: duration / 60 });
     seconds = duration;
     isRunning = true;
     updateTimerDisplay();
     chrome.alarms.onAlarm.addListener((alarm) => {
       if (alarm.name === 'pomodoroTimer') {
         clearInterval(timer);
         isRunning = false;
         alert('¡Tiempo terminado!');
       }
     });
   }
   
  1. Probar la persistencia:
– Cierra y reabre Chrome. El nivel de enfoque debe mantenerse.

Consideraciones y buenas prácticas

Limitaciones conocidas

  • Chrome API: Las reglas de bloqueo en «Estricto» pueden interferir con extensiones como bloqueadores de anuncios. Usa chrome.tabs.query para filtrar tabs del sistema.
  • Rendimiento: Escuchar eventos de tabs en background puede consumir recursos en ventanas con +50 tabs abiertos. Optimiza con debounce en los escuchadores.
  • Cross-browser: Firefox requiere ajustes en manifest.json (usar manifest_version: 2 para compatibilidad con algunas APIs).

Alternativas de implementación

  • Para equipos de SRE: Integrar el timer con Prometheus usando la API de Chrome (chrome.debugger) para registrar métricas de productividad en tiempo real.
  • Para DevOps: Extender el background con un WebSocket que envíe eventos a un dashboard interno (ej: Grafana).

Errores comunes y soluciones

ProblemaCausaSolución
El timer no persiste al cerrar el popupFalta usar BLOCK31Reemplazar BLOCK32 con BLOCK33.
El bloqueo no funciona en «Estricto»Permisos faltantes en BLOCK34Agregar BLOCK35 a BLOCK36.
La interfaz no se actualiza al cambiar el nivelMensajes no sincronizadosUsar BLOCK37 con callbacks.
## Conclusión

Construir una extensión de Chrome para controlar distracciones usando Pomodoro y IA es viable en menos de una hora, iterando con herramientas como Claude Code. La clave está en:

  1. Enfocarse en el MVP: timer básico + niveles de enfoque + bloqueo reactivo.
  2. Usar las APIs de Chrome correctamente: chrome.tabs, chrome.storage, y chrome.alarms.
  3. Validar con pruebas locales: Cambiar de tabs y cerrar/reabrir el popup para detectar fallas de estado.

Esta extensión puede escalarse para equipos de DevOps añadiendo:

  • Integración con APIs de monitoreo (Prometheus, Datadog).
  • Sincronización entre dispositivos con chrome.storage.sync.
  • Reglas de bloqueo personalizadas basadas en URLs o dominios.
Próximos pasos:
  • Subir el código a GitHub y configurar GitHub Actions para CI/CD.
  • Publicar en Chrome Web Store (requiere pago de $5 USD único).
  • Añadir pruebas automatizadas con Jest y Puppeteer.

Fuentes

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *