CDPM

Executa até 30 instâncias numeradas do Chrome via CDP bruto, compartilhadas por várias sessões e subagentes do Claude Code, com perfis persistentes por slot, filas de comandos por aba e mensagens entre agentes.

Documentação

CDPM

npm npm downloads License: MIT CDPM MCP server

README em coreano

CDPM: numbered Chrome slots for Claude Code agents

O CDPM é um servidor MCP que mantém até 30 instâncias do Chrome ("slots") em portas de depuração fixas e permite que qualquer número de sessões e subagentes do Claude Code as acione por número: "abra o slot 3", "faça login no slot 1 e depois preencha o formulário no slot 2". Cada slot é um Chrome comum com seu próprio perfil, então os logins persistem entre execuções e o navegador é o mesmo que você usaria manualmente.

Ele surgiu da necessidade de executar vários agentes do Claude contra aplicativos web com login ao mesmo tempo, onde as partes difíceis não eram clicar em botões, mas compartilhar navegadores entre sessões, mantê-los ativos e perceber quando o próprio Chrome atrapalhava.

Demonstração

Nove subagentes nos slots 11–19 (headless). Os slots 11–18 leem cada um uma página de repositório do GitHub e enviam os números para o slot 19 com slot_send; o slot 19 aguarda em slot_inbox, escreve uma tabela de comparação e a abre. Gravado via CDP de uma execução real: cerca de 45 segundos de tempo real, um quadro por passagem pelos nove slots.

Nine slots working in parallel

O que é diferente

  • Navegadores compartilhados e numerados. O slot N escuta na porta 14049 + N e mantém seu perfil em sua própria pasta. As sessões não possuem um navegador; elas endereçam um slot. Duas sessões podem trabalhar no mesmo slot em abas diferentes: os comandos são enfileirados por aba, então dois agentes digitando em uma mesma aba não se intercalam. Isso é coberto por um teste de integração e por um teste longo em que três sessões compartilham um slot por 600 rodadas sem crescimento de memória, de abas ou de arquivos de bloqueio.
  • Chrome puro via CDP. Sem Playwright ou Puppeteer. Cliques e teclas são enviados com Input.dispatch*Event, então as páginas recebem eventos confiáveis. O Chrome é iniciado sem --enable-automation, então navigator.webdriver permanece false. O CDPM nunca chama Runtime.enable, e todo script que ele executa para ler a página vive em um mundo isolado que a página não pode ver; os snapshots atravessam shadow roots. Isso remove as impressões digitais usuais de automação. Não o livra de limites de taxa ou reputação de IP: nove slots pesquisando no Google ao mesmo tempo ainda receberão um CAPTCHA.
  • Sobrevive às falhas chatas. Os slots são iniciados de forma destacada, então fechar o VS Code ou o Claude Code (mesmo com kill da árvore de processos) os deixa em execução. Após uma reinicialização, o CDPM se reconecta a qualquer Chrome que responda nas portas dos slots e verifica novamente seu ID de processo antes de tocar nos ícones da barra de tarefas. Se o Chrome se atualizar enquanto um slot está em execução (no Windows, a atualização troca chrome.exe, o navegador antigo não consegue mais iniciar renderizadores e novas abas ficam em branco), o CDPM reinicia esse slot na nova versão e reabre suas abas.
  • Agentes podem se coordenar. slot_send / slot_inbox entregam mensagens endereçadas por slot e nome do agente. Elas são armazenadas em disco, então sobrevivem a uma reinicialização do Chrome, e um agente em espera acorda assim que uma chega.
  • UI do navegador que a página não vê. Diálogos JavaScript são relatados e respondidos com browser_dialog. No Windows, bolhas de permissão ("acessar outros aplicativos e serviços neste dispositivo", notificações, localização) são detectadas via Automação de Interface e respondidas com browser_permission. Seletores de arquivo e diálogos de impressão acionados por uma ação do agente são interceptados em vez de abrir janelas do sistema operacional.

Início rápido

npm install -g cdpm-mcp
cdpm install

Reinicie o Claude Code e peça um slot, por exemplo: "Abra o slot 1 com uma janela e vá para github.com."

Comparação com outros servidores MCP de navegador

CDPMPlaywright MCPChrome DevTools MCP
Navegadoresaté 30 slots numerados compartilhados por todas as sessõesum por processo do servidorum por processo do servidor
Várias sessões em um navegadorsim: filas por aba, avisos de propriedadenão é um objetivo de designnão é um objetivo de design
Logins mantidos entre execuçõessim, um perfil por slotsim, um perfil persistente (--isolated para um novo)sim, um perfil persistente (--isolated para um novo)
Controlado porCDP puroPlaywrightPuppeteer
Mensagens entre agentesintegradonãonão
Ícones por slot na barra de tarefasbarra de tarefas do Windows, Dock do macOSnãonão
Outros navegadoresapenas ChromeChromium, Firefox, WebKitapenas Chrome

Os outros dois são boas ferramentas e a melhor escolha se você precisar de Firefox ou WebKit (Playwright) ou de traces de desempenho e painéis do DevTools (Chrome DevTools MCP). As colunas deles refletem a documentação de outubro de 2026.

Segurança

As portas dos slots escutam apenas em 127.0.0.1, mas qualquer processo nesta máquina pode se conectar a elas e agir com as sessões logadas daquele slot. Trate um slot em execução como um navegador destravado: não deixe contas sensíveis logadas em slots enquanto executa software em que você não confia. Slots fechados mantêm seus perfis em disco (cdpm purge N exclui um).

Detalhes

  • CDP puro. Sem Playwright, sem Puppeteer, sem patches furtivos. Um Chrome normal com porta de depuração, controlado com eventos de entrada reais.
  • Slots numerados. O slot N usa a porta CDP 14049 + N (slot 1 = 14050 … slot 30 = 14079) e sua própria pasta de perfil. O intervalo evita a porta padrão comum 9222; defina CDPM_PORT_BASE para movê-lo se algo mais usar essas portas. Portas fora desse intervalo não são gerenciadas.
  • Inicia somente quando solicitado. Nenhuma ferramenta inicia um slot fechado, exceto browser_launch. Sem um número, o slot livre mais baixo é usado.
  • Slots sobrevivem ao chamador. Fechar o CDPM, o Claude Code ou o VS Code (mesmo quando ele mata toda a árvore de processos) não fecha o Chrome do slot. Os slots terminam apenas com browser_close / cdpm close ou quando você fecha esse Chrome você mesmo.
  • Um botão na barra de tarefas por slot, com um ícone de janela do navegador na cor do slot e o número do slot, pré-corrigido para que a barra de tarefas o exiba com nitidez de pixel (desenhado com a fonte do sistema via GDI+, então nenhum arquivo de fonte é enviado no repositório). O título da janela mostra "3번" via recurso de nome de janela do próprio Chrome (as páginas não podem vê-lo).
  • Feito para muitos agentes. Toda ferramenta recebe slot explicitamente, registra quem abriu cada aba e quem a tocou por último, avisa (sem bloquear) quando você age em uma aba que outra pessoa acabou de usar e serializa comandos concorrentes na mesma aba.
  • Agentes podem conversar com slot_send / slot_inbox; mensagens não lidas também são entregues no topo de todo resultado.
  • Linha de status. cdpm statusline imprime slots ativos como números na cor do slot; cada slot mostra o título da aba na qual se agiu por último (sem nomes de agentes; apenas abas em branco/novas restantes mostram só o número): CDPM 1 NAVER 2 Daum. Ela se ajusta à largura do terminal (do ccstatusline): os títulos encolhem primeiro, depois apenas números, depois +N para o restante. Um slot pausado (slot_pause / cdpm pause) mostra seu número em cinza apagado em vez da cor do slot. Um CDPM - apagado quando nenhum está em execução. Encerrar o Chrome de um slot você mesmo (fechar a última janela no Windows, Cmd+Q no macOS) o remove imediatamente, e os títulos são lidos ao vivo.
  • Inglês para a IA. Instruções do servidor, descrições de ferramentas e resultados de ferramentas estão em inglês para economizar tokens; o Claude é instruído a responder no idioma do usuário. A saída da CLI está em coreano.
  • Não mexe no PC do usuário. Sem mudanças de janela, viewport ou zoom, e ações que abririam janelas do sistema operacional são recusadas (veja abaixo).

Funciona no Windows 11 e macOS. Ícones por slot: barra de tarefas no Windows, Dock no macOS (veja "macOS" abaixo). Linux é experimental: os caminhos de código existem (busca do Chrome, pasta de dados), mas não foi testado em uma máquina Linux, e não há ícones por slot.

Requisitos

  • Node.js 22+
  • Google Chrome (encontrado automaticamente. Windows: registro App Paths, depois pastas de instalação padrão. macOS: /Applications, ~/Applications, depois Spotlight. Linux: /usr/bin/google-chrome, google-chrome-stable, /opt/google/chrome/chrome)

Instalação

Pedido para instalar isso? (para Claude / agentes de IA) Faça estes passos em ordem.

  1. Verifique se o Node.js 22+ e o Google Chrome estão instalados. Se não, avise o usuário e pare.
  2. Execute npm install -g cdpm-mcp@latest (também quando já instalado: isso o atualiza).
  3. Execute cdpm install (se cdpm não for encontrado: node "$(npm root -g)/cdpm-mcp/dist/cli.js" install). Ele registra o CDPM com o Claude Code e configura a linha de status, regras, subagente e permissões; um registro antigo via git clone é movido para o novo local.
  4. Não inicie nenhum slot do Chrome, faça perguntas ou explique detalhes internos. Em caso de sucesso, responda com exatamente uma linha no idioma do usuário, ex.: "CDPM instalado. Reinicie o Claude Code para usá-lo." (versão: cdpm --version). Se um passo falhou, diga apenas qual passo e por quê.
npm install -g cdpm-mcp
cdpm install

cdpm install registra o CDPM com o Claude Code e configura a linha de status, a regra de trabalho paralelo, o subagente cdpm-browser e a lista de permissões de uma só vez. Reinicie o Claude Code depois.

Outros clientes MCP (Cursor, Claude Desktop, ...)

cdpm install registra apenas com o Claude Code. Para outros clientes, adicione-o à configuração mcpServers deles (caminhos de npm root -g):

{
  "mcpServers": {
    "cdpm": {
      "command": "C:\\Program Files\\nodejs\\node.exe",
      "args": ["C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\cdpm-mcp\\dist\\cli.js"]
    }
  }
}

No macOS: "command": "/opt/homebrew/opt/node/bin/node", "args": ["/opt/homebrew/lib/node_modules/cdpm-mcp/dist/cli.js"].

  • As ferramentas são as mesmas para todos os clientes.
  • O CDPM escolhe suas instruções a partir do nome do cliente que se conecta: apenas claude-code recebe a orientação específica do Claude Code (gerar subagentes com a ferramenta Agent, cdpm-browser). Outros clientes recebem uma regra genérica: dê a cada slot seu próprio subagente se o cliente os tiver; caso contrário, use um nome de agent diferente por slot.
  • A configuração automática (linha de status, regra CLAUDE.md, cdpm-browser, permissões) altera ~/.claude, então ela só roda quando o Claude Code se conecta. Iniciar o CDPM de outro cliente nunca toca nas configurações do Claude Code.

A partir de um clone (desenvolvimento)

git clone https://github.com/IGELHARINE/CDPM.git
cd CDPM
npm install
node dist/cli.js install

Atualização

npm install -g cdpm-mcp@latest

Depois reinicie o Claude Code. A partir de um clone: git fetch origin && git reset --hard origin/main e npm install. O registro MCP e a configuração da linha de status permanecem como estão. Verifique a versão com node dist/cli.js --version; as mudanças estão listadas em CHANGELOG.md.

Ou apenas peça ao Claude: "atualize o CDPM".

O que acontece automaticamente

Na primeira vez que o servidor MCP inicia, o CDPM configura o seguinte uma vez, sem passos extras (arquivos originais com backup como .before-cdpm):

  • a exibição dos slots na linha de status do Claude Code (redesenhada a cada 3 s)
  • uma regra no CLAUDE.md do usuário: quando vários slots recebem tarefas diferentes, use um subagente por slot em paralelo e deixe cada um escrever sua própria parte da saída (o Claude segue instruções do usuário de forma mais confiável do que orientação MCP)
  • um subagente exclusivo do CDPM, cdpm-browser, em ~/.claude/agents/: apenas ferramentas do CDPM mais escrita de arquivos, sem CLAUDE.md, então ele inicia mais rápido (medido em uma tarefa paralela de 3 slots: mediana de 28,7 s -> 20,6 s, cerca de 37% menos uso); mesmo modelo e esforço do agente principal. Ele usa o nome sob o qual o CDPM está registrado.
  • ferramentas do CDPM (mcp__cdpm) na lista de permissões do Claude Code (permissions.allow em settings.json), para que o classificador do modo automático não bloqueie digitação e preenchimento no meio da tarefa. O Claude então executa entrada e cliques do CDPM (enviar e-mail, publicar) sem perguntar a cada vez.
  • subagentes rodam no máximo 20 por vez, então além de 20 slots o Claude é instruído a lançá-los em lotes (aumente com CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS).

Desfaça com cdpm unsetup; pule completamente com CDPM_NO_AUTO_SETUP=1. Quando uma atualização muda a configuração automática, ela roda mais uma vez, item por item: itens ainda presentes são atualizados, itens que você removeu (inclusive com cdpm unsetup) não são trazidos de volta. cdpm setup re-adiciona tudo.

Apenas linha de status

cdpm install (e o primeiro início do servidor) já a ativa. Para refazer apenas a linha de status: cdpm statusline-setup. Sem linha de status, ele adiciona uma às configurações do Claude; com ccstatusline, adiciona um widget; com qualquer outra linha de status, não muda nada e imprime o comando para anexar. O arquivo original é salvo como backup como .before-cdpm.

Como se comporta

Cada resultado começa com um cabeçalho: as abas do slot (> = agiu agora, ·앞 = a aba à frente em sua janela), avisos e novas mensagens (marcadas como lidas ali).

Regras de abas: uma aba → essa aba; a aba usada por último pelo agente (ou recém-aberta) → essa aba; primeiro uso → ferramentas de visualização usam a aba da frente, ferramentas de ação exigem tab. Os números das abas seguem a ordem de primeira visualização; IDs como t7 nunca mudam enquanto a aba existir.

Compartilhando um slot: vários agentes (mesmo em sessões diferentes do Claude) podem trabalhar em um slot ao mesmo tempo, cada um em sua própria aba. Comandos são enfileirados por aba, então o agente A pode digitar na aba 1 enquanto o agente B clica na aba 2; apenas comandos na mesma aba esperam uns pelos outros, inclusive entre sessões do Claude (um arquivo de bloqueio por aba), então duas sessões digitando na mesma aba nunca se intercalam; um bloqueio mantido por um processo morto é liberado imediatamente, e um mantido por mais de 2 minutos é relatado em vez de aguardado. Iniciar e fechar um slot também usa um bloqueio por slot, então duas sessões iniciando o mesmo slot ao mesmo tempo lançam o Chrome apenas uma vez (a outra se anexa). Um slot é um perfil do Chrome, então um site logado em uma aba também está logado em uma nova aba (exceto sites que autenticam por aba). browser_tab_new abre em segundo plano, então nem a visualização do usuário nem a aba de outro agente mudam, e quem abriu continua usando sua própria aba. Cada sessão recebe seu próprio nome (claude-a3f1, subagentes usam os seus); cabeçalhos mostram quem abriu e usou por último cada aba, e agir em uma aba que outro acabou de usar é relatado, não bloqueado. Um agente dirige um slot: agir em um segundo slot dentro de um minuto é recusado com conselho de iniciar um subagente para ele (multiSlot: true para comparações); ler outros slots é sempre permitido. Refira-se aos slots por número ("slot 3"); um nome como "browser B" faz o Claude adivinhar.

Abas em segundo plano podem ser lidas, dirigidas e capturadas sem trocar de aba: ao agir em uma aba oculta, o CDPM habilita brevemente Emulation.setFocusEmulationEnabled para o Chrome pintá-la e depois desliga. A visualização do usuário não muda, mas durante esse momento a página vê a aba como focada (document.hasFocus() etc.), então um site pode notar.

Páginas longas: browser_snapshot retorna a página 1 (~12 mil caracteres) com "1/8 · próximo: page=2". Páginas posteriores carregam o contexto ancestral; refs permanecem os mesmos entre páginas. find corresponde a linhas ignorando espaços em branco e mostra ancestrais mais as duas próximas linhas; ref mostra uma subárvore. browser_text é mais curto para ler conteúdo. O mesmo elemento mantém o mesmo ref até a navegação, e novos refs são únicos por agente entre abas, então um ref de outra aba ou página antiga é sempre rejeitado.

Ferramentas

Todas as ferramentas aceitam slot (1–30) e agent (nome de exibição). Ferramentas de ação também aceitam tab, summary e read: read: "text" | "snapshot" | "changes" anexa a página após a ação ao mesmo resultado (sem chamada de leitura separada). changes mostra apenas linhas adicionadas ou removidas desde o snapshot anterior do agente daquela página — o caminho mais curto para ver o que um clique fez.

FerramentaO que faz
browser_statusSlots ativos, abas, quem abriu, últimas ações, resumos, diálogos
browser_launchIniciar um slot — apenas quando o usuário pede; sem slot = menor livre; slots (lista) ou count iniciam vários de uma vez, do menor primeiro; url / urls abrem uma página inicial imediatamente. Janela ou headless é escolha do usuário: se ele não disse, o Claude pergunta primeiro (sem headless, um slot fechado não é iniciado). headless: true adiciona apenas --headless. proxy / proxies (apenas quando o usuário pede um proxy): host:port, http://user:pass@host:port, socks5://..., host:port:user:pass. Sem isso, nenhuma flag de proxy é adicionada. Proxies com nome de usuário e senha passam por um pequeno relay local por slot que adiciona as credenciais e sai com esse Chrome
browser_closeFechar graciosamente (perfil mantido)
browser_tabs / browser_tab_new / browser_tab_close / browser_tab_selectListar / abrir em segundo plano (retorna ID) / fechar / trazer para a frente (apenas quando o usuário quer)
browser_snapshotTexto de acessibilidade com refs; page, find, ref
browser_textTexto legível (main/article primeiro, ou um ref), paginado
browser_screenshotÁrea visível como PNG, abas em segundo plano incluídas; sem captura de página inteira
browser_navigate / browser_backAguarda o carregamento; servidores lentos são relatados como "ainda carregando", não como erros
browser_clickClique real de mouse; relata elementos sobrepostos, novas abas, falhas de validação de formulário
browser_typeEventos reais de teclado por caractere (clear, submit, fast); verifica o valor e não pressiona Enter para submit se o valor diferir (o site rejeitou ou reformatou a entrada); entradas de data/hora são definidas após validação de formato
browser_fillPreencher vários campos em uma página em ordem, então opcionalmente submit ("Enter" ou um ref de botão); para na primeira falha, mudança de página, diálogo ou campo cujo valor difere do digitado (nada é enviado então)
browser_dialogAceitar ou dispensar um alerta/confirm/prompt/beforeunload aberto (text para prompt). O Claude decide pela mensagem
browser_permissionListar ou responder bolhas de permissão do Chrome ("o site quer acessar outros apps e serviços neste dispositivo", notificações, localização…) pelo nome exato do botão. Janelas, slots com janela
browser_forward / browser_reloadAvançar / recarregar (recarga própria do Chrome, ignore_cache)
browser_hoverMouse real sobre um elemento (menus somente em hover)
browser_dragArrasto real de mouse: arrastar e soltar, controles deslizantes, reordenação. Soltar em to (ref), to_text (texto) ou dx/dy. Arrastos HTML5 são tratados sem arrasto do SO; elementos draggable recebem refs
browser_download_waitAguardar um download terminar e retornar o caminho do arquivo salvo (a configuração da pasta de downloads do Chrome é mantida)
browser_pdfSalvar a página como PDF (padrão: pasta Downloads, nomeado pelo título)
browser_uploadEnviar arquivos: em um input de arquivo por ref, ou após clicar em um botão "anexar" (o CDPM intercepta o diálogo de arquivo do SO para que nunca apareça) sem ref
browser_select<select>: foco + teclas (setas no Windows, prefixo option no macOS; eventos confiáveis, sem popup)
browser_press_keyEnter, Tab, Control+A (Meta+A no macOS), … (teclas de área de transferência recusadas)
browser_scrollPara um ref, ou exatamente dy pixels (relata posição A → B)
browser_waitTexto no body ou título / gone (texto desaparece) / url mudança / enabled (um botão ou input deixa de estar desabilitado) / response (uma resposta de rede cuja URL corresponde termina; retorna seu corpo, ex. o JSON por trás de uma lista SPA — respostas que chegaram enquanto você clicava também são capturadas; nada extra é enviado) / network_idle / N segundos
browser_evalJavaScript em um mundo isolado (DOM visível, globais da página não)
browser_network / browser_network_detailRequisições (últimas 500, 30 min) / cabeçalhos, dados POST, corpo
browser_blockBloquear/desbloquear padrões de URL em uma aba, incluindo iframes de outros sites (já abertos ou criados depois, bloqueados antes da primeira requisição); enquanto a sessão viver; visível para outros agentes
slot_send / slot_inboxMensagem para um agente (use o número do slot do destinatário, funciona entre slots) / receber (wait retorna em ~0,1 s de uma mensagem, até 600 s). Uma mensagem também interrompe browser_wait imediatamente
slot_pause / slot_resumePausar um slot quando o usuário disser ("pare o slot 3"): toda ação é recusada na hora, uma ação em andamento para antes do próximo evento de tecla ou mouse, e esperas retornam. Ler a tela ainda funciona. Retomar acorda os agentes com uma mensagem para que releiam a página e continuem. Aplica-se a toda sessão do Claude

Subagentes compartilham o processo MCP do pai — dê a cada um seu próprio nome agent. Quando vários slots recebem tarefas diferentes ("abra 3: Naver, Daum, Google News"), o Claude os executa em paralelo por padrão, um subagente por slot, não um após o outro.

Linha de status

cdpm statusline sai em ~0,1 s (registro local mais uma verificação rápida de aba em cada porta de slot ativo); a configuração faz o Claude Code redesenhá-la a cada 3 s. Ativada por cdpm install; refaça com cdpm statusline-setup. Para conectar manualmente: para ccstatusline, adicione um widget Custom Command com "C:\Program Files\nodejs\node.exe" "C:\path\to\CDPM\dist\cli.js" statusline (preserve cores). Caso contrário, aponte statusLine.command para o mesmo comando.

CLI

cdpm                               run the MCP server (stdio)
cdpm install                       register with Claude Code and run the automatic setup (once after installing)
cdpm setup                         add the status line, CLAUDE.md rule, cdpm-browser subagent and permission allow list, including ones you removed (also done automatically on first server start)
cdpm unsetup                       remove what CDPM added
cdpm --version                     print the version
cdpm launch [slot...]              start slots (ascending order; no number = lowest free)
cdpm launch --headless [slot...]   start without a window
cdpm close <slot...> | --all       close gracefully
cdpm pause <slot...> | --all       pause: stop all agent actions on the slot immediately
cdpm resume <slot...> | --all      resume: wake the waiting agents
cdpm purge <slot>                  delete a closed slot's profile
cdpm status | statusline
cdpm statusline-setup              turn on the slot display in Claude Code's status line (backs up settings)

Os dados vivem em %LOCALAPPDATA%\cdpm\ no Windows, ~/Library/Application Support/cdpm/ no macOS e ~/.cdpm/ no Linux (CDPM_HOME substitui): registry.json, messages\<slot>.jsonl (últimas 500 linhas uma vez acima de 1000) e messages\<slot>.cursors.json (posição de leitura por agente, últimas 200), locks\ (arquivos de bloqueio por aba e por slot para que sessões do Claude nunca dirijam uma aba, ou iniciem/fechem um slot, ao mesmo tempo; removidos quando a ação termina, restos de processos mortos limpos a cada minuto), profiles\<slot>\, icons\, auto-setup.json (qual versão de configuração rodou e quais itens o CDPM adicionou, para que itens removidos não sejam trazidos de volta), opcional config.json (chromePath, extraArgs).

macOS

  • Iniciar, dirigir, ferramentas de rede, mensagens de agente e a linha de status funcionam igual ao Windows.
  • O ícone do Dock de cada slot é definido para o mesmo ícone numerado colorido do slot como no Windows, através do próprio comando CDP do Chrome Browser.setDockTile (sem copiar app ou re-assinar). Ele volta ao ícone normal do Chrome se o Chrome reiniciar fora do CDPM, e é definido novamente na próxima vez que o CDPM iniciar ou anexar. Este código roda apenas no macOS.
  • Seguindo a convenção do Mac, fechar a janela de um slot (botão vermelho, Cmd+W) mantém o slot; a linha de status continua mostrando o título da última aba usada. Sair do Chrome com Cmd+Q encerra o slot e o remove. (No Windows, fechar a última janela encerra o slot.)
  • O Chrome no macOS não executa atalhos de edição apenas com eventos de tecla, então Meta+A (selecionar tudo), Meta+Z (desfazer), Meta+←/→, Option+←/→ e similares também enviam o comando de edição correspondente do Chrome com o mesmo evento de tecla — a mesma coisa que uma pessoa pressionando a tecla obtém.
  • Setas em um <select> abrem o menu popup do macOS, então browser_select digita o início do texto da opção. Se uma opção anterior compartilhar esse prefixo, ele define o valor diretamente e avisa.

O que o CDPM não faz / recusa

  • Sem alterações de user-agent ou fingerprint, emulação de dispositivo ou modificação do Chrome, e nenhuma alteração nos scripts da página, exceto pela proteção de impressão abaixo.
  • As coisas que você clica abrem normalmente. Apenas enquanto uma ação de agente está em execução, o CDPM impede que janelas do sistema operacional apareçam:
    • Seletores de arquivo são interceptados independentemente de como a ação os abre (clique, Enter em um campo de arquivo, envio de formulário), com uma dica para usar browser_upload.
    • window.print() abriria a pré-visualização de impressão e congelaria a aba (não pode ser fechada via CDP), então o print da página é desativado apenas durante a ação, relatado e restaurado logo em seguida. Use browser_pdf para um PDF.
    • Campos de data, hora e cor não são clicados (eles abrem um seletor); browser_type define seus valores (#ff0000 para cores).
    • Atalhos do navegador como Ctrl+S/Ctrl+O/Ctrl+P enviados via CDP não acionam as janelas de salvar/abrir/imprimir do Chrome.
  • Limitações conhecidas: um botão cujo JavaScript navega para um esquema de programa externo (mailto: etc.) não é capturado antecipadamente (links são); prompts de autenticação HTTP não podem ser preenchidos por um agente.
  • As flags de inicialização são apenas --remote-debugging-port, --user-data-dir, --no-first-run, --no-default-browser-check, --window-name (mais --headless sob solicitação, e --proxy-server + --force-webrtc-ip-handling-policy=disable_non_proxied_udp apenas quando o usuário pede um proxy; o Chrome headless ainda relata HeadlessChrome).
  • Nunca altera o tamanho/posição/estado da janela, viewport ou zoom; se um clique colocar a página em tela cheia, ela é fechada imediatamente.
  • Sem Runtime.enable; scripts auxiliares são executados em um mundo isolado.
  • Se o Chrome se atualizar enquanto um slot está em execução (o Windows troca chrome.exe), o navegador antigo não consegue mais iniciar renderizadores, então novas abas ficam em branco. O CDPM compara a versão em execução com a instalada (ao anexar, e sempre que o arquivo chrome.exe mudar, verificado a cada 10s apenas pelas informações do arquivo) e reinicia esse slot na nova versão, reabrindo suas abas em ordem (logins são mantidos; slots de proxy são apenas relatados).
  • Bolhas de permissão do Chrome são UI do navegador, então nunca aparecem em snapshots ou capturas de tela e as ferramentas de página não podem clicar nelas, enquanto a página fica aguardando. No Windows, o CDPM as detecta (uma pequena janela pertencente ao Chrome do slot cujo título contém o host de uma aba, então bolhas de tradução ou senha são ignoradas e o idioma do Chrome não importa), avisa no cabeçalho do resultado, interrompe browser_wait assim que uma aparece, e permite que Claude pressione um botão com browser_permission (Automação de UI; funciona enquanto a janela está minimizada ou coberta). Claude pergunta antes de permitir câmera, microfone ou localização que o usuário não solicitou.
  • Diálogos (alert/confirm/prompt/beforeunload) são relatados, nunca tratados automaticamente. Claude lê a mensagem e a trata ele mesmo com browser_dialog (aceitar ou dispensar); ele pergunta ao usuário apenas quando o diálogo confirmaria algo irreversível que o usuário não pediu (um pagamento, uma exclusão).
  • Recusas: links de esquema mailto:/tel:/app e endereços em cliques, navegação, páginas iniciais de lançamento e novas abas (iniciariam outros programas), clicar em <select> (popup), Ctrl+C/X/V/Shift+Insert (área de transferência do usuário). Downloads acionados por navegação são relatados com o nome do arquivo.

Verificação

58 testes unitários e 40 testes de integração (npm test, npm run test:integration, Chrome real nas portas de teste 29222+). Verificações de longa duração (npm run test:long, ~20 min): 4.000 rodadas em um SPA que substitui seu DOM, com um novo nome de agente a cada rodada, mantiveram o heap do servidor CDPM dentro de uma faixa fixa (26–39 MB, sem tendência de aumento) e a página em 1.421 nós DOM / 0,8 MB de heap JS; 3 sessões compartilhando um slot por 600 rodadas cada (1.800 abas abertas e fechadas, o slot reiniciado 3 vezes) permaneceram em ~20 MB de heap por sessão, sem arquivos de bloqueio ou abas deixadas para trás. Uma execução concorrente com 15 subagentes e 30 slots confirmou que a posição/tamanho/estado de todas as 30 janelas e o viewport (innerWidth×innerHeight) e zoom de todas as 52 abas permaneceram inalterados.

Licença

MIT