@diegosouzacdv/jev-browser-mcp 0.5.0 → 0.6.1

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/README.md CHANGED
@@ -17,10 +17,10 @@ versão em produção, use o número explícito no argumento do pacote:
17
17
  "mcpServers": {
18
18
  "jev-browser": {
19
19
  "command": "npx",
20
- "args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.5.0"],
20
+ "args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.6.1"],
21
21
  "env": {
22
22
  "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}",
23
- "JEV_BROWSER_MODE": "computer"
23
+ "JEV_BROWSER_MODE": "computer"
24
24
  }
25
25
  }
26
26
  }
@@ -31,30 +31,30 @@ O formato de interpolação de variáveis varia por harness. Injete a chave por
31
31
  um secret manager ou pelo ambiente do processo; não grave a chave no arquivo
32
32
  de configuração. Para instalar no projeto Node do próprio harness:
33
33
 
34
- ```sh
35
- npm install @diegosouzacdv/jev-browser-mcp
36
- ```
37
-
38
- Se o harness executa o MCP repetidamente nesta máquina, instale uma versão
39
- fixa globalmente para evitar a resolução e o download feitos pelo `npx` em cada
40
- inicialização:
41
-
42
- ```sh
43
- npm install --global @diegosouzacdv/jev-browser-mcp@0.5.0
44
- ```
45
-
46
- Depois configure o servidor MCP com `command: "jev-browser-mcp"` e `args: []`.
47
- Para atualizar, rode `npm install --global
48
- @diegosouzacdv/jev-browser-mcp@<versão>` e reinicie o processo do harness.
49
-
50
- O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
51
- configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
52
- pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp --install-browser`.
53
-
54
- O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
55
- persistente exclusivo em `browser.computer_user_data_dir`. No modo `harness`, a
56
- instalação baixa uma vez o Chrome/Edge que o Playwright controlará. Personalize
57
- as escolhas com `JEV_BROWSER_MODE`, `JEV_BROWSER_CHANNEL` e
34
+ ```sh
35
+ npm install @diegosouzacdv/jev-browser-mcp@0.6.1
36
+ ```
37
+
38
+ Se o harness executa o MCP repetidamente nesta máquina, instale uma versão
39
+ fixa globalmente para evitar a resolução e o download feitos pelo `npx` em cada
40
+ inicialização:
41
+
42
+ ```sh
43
+ npm install --global @diegosouzacdv/jev-browser-mcp@0.6.1
44
+ ```
45
+
46
+ Depois configure o servidor MCP com `command: "jev-browser-mcp"` e `args: []`.
47
+ Para atualizar, rode `npm install --global
48
+ @diegosouzacdv/jev-browser-mcp@<versão>` e reinicie o processo do harness.
49
+
50
+ O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
51
+ configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
52
+ pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.6.1 --install-browser`.
53
+
54
+ O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
55
+ persistente exclusivo em `browser.computer_user_data_dir`. No modo `harness`, a
56
+ instalação baixa uma vez o Chrome/Edge que o Playwright controlará. Personalize
57
+ as escolhas com `JEV_BROWSER_MODE`, `JEV_BROWSER_CHANNEL` e
58
58
  `JEV_BROWSER_PROFILE`. O browser permanece aquecido enquanto o processo MCP
59
59
  estiver ativo e fecha quando o harness encerra o processo. `JEV_PROVIDER_URL`
60
60
  e `JEV_MODEL` podem substituir os valores centrais; a credencial continua no
@@ -64,35 +64,41 @@ Uma aplicação Node também pode importar `createJevBrowserServer` por
64
64
  `@diegosouzacdv/jev-browser-mcp/server` e conectar o servidor ao transporte MCP
65
65
  que ela já utiliza.
66
66
 
67
- O pacote é montado em uma pasta temporária isolada: o publicador usa o campo
68
- `files` do `package.json` para copiar somente o código Node, a configuração
69
- compartilhada e esta documentação, que também vira o `README.md` da raiz do
70
- pacote. Assim, o npm não inclui o README geral do orquestrador na página do MCP.
71
- Para gerar e conferir o pacote antes de publicar, execute
72
- `npm run pack:jev-browser-mcp`; para publicar uma versão já autenticada no npm, execute
73
- `npm run publish:jev-browser-mcp`. A instalação por npm é a recomendada; use a
74
- referência GitHub somente quando precisar experimentar uma revisão ainda não
75
- publicada.
67
+ O pacote é montado em uma pasta temporária isolada: o publicador usa o campo
68
+ `files` do `package.json` para copiar somente o código Node, a configuração
69
+ compartilhada e esta documentação, que também vira o `README.md` da raiz do
70
+ pacote. Assim, o npm não inclui o README geral do orquestrador na página do MCP.
71
+ Para gerar e conferir o pacote antes de publicar, execute
72
+ `npm run pack:jev-browser-mcp`; para publicar uma versão já autenticada no npm, execute
73
+ `npm run publish:jev-browser-mcp`. A instalação por npm é a recomendada; use a
74
+ referência GitHub somente quando precisar experimentar uma revisão ainda não
75
+ publicada.
76
76
 
77
77
  ### Contrato do pacote
78
78
 
79
- O executável oferece `choose_next_action` e `run_browser_flow`, mantém uma
79
+ O executável oferece `browser_health`, `choose_next_action` e `run_browser_flow`, mantém uma
80
80
  sessão do browser por processo e reutiliza essa sessão entre chamadas. O plano
81
81
  passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
82
82
  hover, espera, teclas aprovadas, asserções por elemento, upload restrito a uma
83
83
  raiz local configurada e reações idempotentes a um comentário único. Também
84
- aceita um nome de iframe para as ações que ocorrem dentro dele. Não aceita
85
- JavaScript enviado pelo harness nem coordenadas. Além de papel/nome acessível,
86
- aceita `label`, `placeholder`, `title`, `text`, `test_id` e `selector`; CSS/XPath
87
- são o último recurso e geram um aviso no resultado. Ele usa a
88
- biblioteca Playwright diretamente, sem iniciar um segundo servidor MCP do
84
+ aceita um nome de iframe para as ações que ocorrem dentro dele. Não aceita
85
+ JavaScript enviado pelo harness nem coordenadas. Além de papel/nome acessível,
86
+ aceita `label`, `placeholder`, `title`, `text`, `test_id` e `selector`; CSS/XPath
87
+ são o último recurso e geram um aviso no resultado. Ele usa a
88
+ biblioteca Playwright diretamente, sem iniciar um segundo servidor MCP do
89
89
  Playwright. O transporte MCP usa `stdio`; toda saída de diagnóstico vai para
90
90
  `stderr` para não misturar com JSON-RPC.
91
91
 
92
92
  O modo `computer` grava cookies no perfil exclusivo configurado, e conteúdo da
93
93
  página pode conter instruções maliciosas. O Jev recebe a captura acessível com
94
94
  uma instrução para tratar esse conteúdo como dado não confiável; não inclua
95
- segredos no fluxo, no resultado esperado ou nas descrições dos planos.
95
+ segredos no fluxo, no resultado esperado ou nas descrições dos planos. Antes de
96
+ enviar contexto ao provedor, o cliente mascara valores de campos e padrões
97
+ detectados de CPF/CNPJ, email, telefone, nome de cliente e valores monetários.
98
+ Isso reduz exposição acidental, mas não substitui o cuidado com os dados que o
99
+ harness escolhe incluir no fluxo. Use `local_only: true` quando nenhuma chamada
100
+ externa ao Jev puder ocorrer; esse modo recusa fluxos que precisam escolher
101
+ entre vários planos.
96
102
 
97
103
  Para um fluxo conhecido, o LLM do harness procura o cenário e os critérios de
98
104
  aceitação no projeto e chama `jev_browser.run_browser_flow` com planos
@@ -101,111 +107,132 @@ a página inicial, captura o snapshot acessível e pede ao Jev que escolha um
101
107
  plano. Em seguida, executa o plano inteiro na mesma sessão e confere o
102
108
  resultado esperado na tela.
103
109
 
104
- Cada plano pode usar:
105
-
106
- - `click`, `type`, `hover`, `select_option`, `press`, `assert_*` e upload com
107
- papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
108
- `text`, `test_id` ou `selector`;
109
- - `near: {"text":"..."}` para localizar o controle logo depois de um texto,
110
- `within: {"row_containing":"..."}` para limitar por trecho e
111
- `within: {"row_containing_exact":"..."}` para exigir um elemento com o
112
- texto exato na linha, sem casar com `15287210` ao procurar `1528721`;
113
- - `within: {"role":"dialog"}` sem `name` para usar o único diálogo visível;
114
- o MCP ignora diálogos visualmente ocultos, inclusive os que ficaram no DOM
115
- com `opacity: 0`;
116
- - `name: ""` com `index` não negativo para controles sem nome. O resultado
117
- inclui um aviso porque a posição pode mudar entre execuções. O índice é
118
- zero-based para o mesmo papel e inclui nomes vazios ou compostos só por
119
- espaços/glyphs de uso privado, como ícones Font Awesome; controles
120
- desabilitados não aparecem no diagnóstico, mas continuam contando para que o
121
- índice aponte ao controle correto;
122
- - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
123
- em `warnings`; não é permitido enviar JavaScript nem coordenadas;
124
- - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
125
- - `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
126
- `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
127
- valor apareça nas evidências. Nesse modo, `\n` envia Enter e `\t` envia Tab;
128
- - `wait_for_text` e `wait_for_condition` (`network_idle`, `hidden` ou
129
- `text_hidden`). `wait_for_text` aceita `fail_on: {"role":"alert"}` para
130
- interromper a espera assim que um alerta visível aparecer e incluir seu texto
131
- no erro. Se o alerta contiver o texto esperado, a etapa passa; caso contrário,
132
- o alerta interrompe a espera. `network_idle` aceita `url_contains` para
133
- aguardar só as requisições correspondentes;
134
- - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
135
- `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
136
- envia a tecla ao elemento focado; com alvo, usa o localizador informado;
137
- - `assert_text`, `assert_value`, `assert_visible` e `assert_hidden`; `assert_text`
138
- pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
110
+ Cada plano pode usar:
111
+
112
+ - `click`, `type`, `hover`, `select_option`, `press`, `assert_*` e upload com
113
+ papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
114
+ `text`, `test_id` ou `selector`;
115
+ - `near: {"text":"..."}` para localizar o controle logo depois de um texto,
116
+ `within: {"row_containing":"..."}` para limitar por trecho e
117
+ `within: {"row_containing_exact":"..."}` para exigir um elemento com o
118
+ texto exato na linha, sem casar com `15287210` ao procurar `1528721`;
119
+ - `within: {"role":"dialog"}` sem `name` para usar o único diálogo visível;
120
+ o MCP ignora diálogos visualmente ocultos, inclusive os que ficaram no DOM
121
+ com `opacity: 0`;
122
+ - `name: ""` com `index` não negativo para controles sem nome. O resultado
123
+ inclui um aviso porque a posição pode mudar entre execuções. O índice é
124
+ zero-based para o mesmo papel e inclui nomes vazios ou compostos só por
125
+ espaços/glyphs de uso privado, como ícones Font Awesome; controles
126
+ desabilitados não aparecem no diagnóstico, mas continuam contando para que o
127
+ índice aponte ao controle correto;
128
+ - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
129
+ em `warnings`; não é permitido enviar JavaScript nem coordenadas;
130
+ - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
131
+ - `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
132
+ `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
133
+ valor apareça nas evidências. Nesse modo, `\n` envia Enter e `\t` envia Tab;
134
+ - `wait_for_text`, `wait_for_value`, `wait_for_enabled` e `wait_for_condition`
135
+ (`network_idle`, `hidden`, `text_hidden` ou `angular_idle`). `wait` recebe
136
+ `ms` para uma pausa curta e limitada. `angular_idle` aguarda requisições
137
+ `$http` e digest do AngularJS. `wait_for_text` aceita `fail_on: {"role":"alert"}` para
138
+ interromper a espera assim que um alerta visível aparecer e incluir seu texto
139
+ no erro. Se o alerta contiver o texto esperado, a etapa passa; caso contrário,
140
+ o alerta interrompe a espera. `network_idle` aceita `url_contains` para
141
+ aguardar só as requisições correspondentes;
142
+ - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
143
+ `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
144
+ envia a tecla ao elemento focado; com alvo, usa o localizador informado;
145
+ - `assert_text`, `assert_value`, `assert_visible`, `assert_hidden` e
146
+ `assert_enabled`; `assert_text`
147
+ pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
139
148
  - `upload_file` para input rotulado, botão que abre o seletor de arquivo ou
140
149
  dropzone;
141
150
  - `audit_accessibility` com axe-core para WCAG 2.1 A/AA;
142
- - `like_comment` e `unlike_comment`, que localizam uma linha pelo autor e texto,
143
- não repetem uma reação já no estado pedido e distinguem `Curtir` de
144
- `Descurtir`.
145
-
146
- As proteções e evidências por etapa usam estes campos:
147
-
148
- - `confirm_dialog` recebe `expected_text` e `button`. O MCP exige um diálogo
149
- visível único e confere se ele contém o texto esperado antes de clicar; se o
150
- alerta mudou, a etapa falha sem clicar no botão. Reserve `click` comum para
151
- ações que não dependem do conteúdo de uma confirmação;
152
- - `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
153
- Com `options.dry_run: true`, o fluxo para imediatamente antes da primeira
154
- etapa marcada e retorna `dry_run_stopped_before_step` e `mutating_steps`.
155
- Marque toda ação que grava ou envia algo, mesmo quando não for um botão
156
- chamado Salvar;
157
- - `duration_ms` aparece em cada etapa concluída ou falha. `mutating_steps`
158
- lista as etapas marcadas e informa quais foram executadas;
159
- - `screenshot: true` salva uma captura depois da etapa e inclui seu caminho na
160
- evidência da etapa;
161
- - `options.report_path` grava um resumo `.md` ou JUnit `.xml`. O caminho deve
162
- ser absoluto e estar dentro de `JEV_BROWSER_ARTIFACT_DIR` (ou do diretório de
163
- artefatos configurado). O relatório resume versão/status, duração, alvo e
164
- `resolved_target`, asserções de rede, falhas de rede e caminhos das capturas.
165
-
166
- `run_browser_flow` também aceita `params` como mapa de texto, números e
167
- booleanos. Use `{pedido}` em `flow`, `expected_outcome` e nos campos textuais do
168
- plano para reutilizar um valor sem editar o roteiro em vários lugares. A ação
169
- `extract` lê `text` (padrão), `value` ou `attribute` de um elemento e salva o
170
- resultado na variável indicada por `as`; etapas seguintes podem usar
171
- `{documento}`. O valor extraído é tratado como sensível e fica oculto no
172
- resultado por padrão; use `sensitive: false` só quando for apropriado exibi-lo.
173
- `resolved_target.match_strategy` informa quando um rótulo foi
174
- associado por proximidade (`label-proximity`) em vez de um `label[for]` direto.
175
-
176
- A ação `assert_network` verifica respostas observadas depois da etapa anterior,
177
- incluindo respostas 2xx ou erros esperados como 404. Exemplo:
178
-
179
- ```json
180
- {
181
- "action": "assert_network",
182
- "url_contains": "/documentoFinanceiro/atualizar",
183
- "method": "PUT",
184
- "status": 404,
185
- "message_contains": "Boleto não encontrado"
186
- }
187
- ```
188
-
189
- Essa asserção aparece na evidência como `response_status`, separado do campo
190
- `status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
191
- da mesma origem e respeita o limite configurado para captura de corpos.
192
-
193
- Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
194
- com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
195
- `{"action":"extract","role":"cell","name":"{pedido}","within":{"row_containing_exact":"{pedido}"},"as":"documento"}`.
196
- A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
197
-
198
- Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
199
- localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
200
- aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
201
- `url_contains`; o MCP precisa observar a requisição depois da etapa anterior e
202
- esperar que ela termine.
203
-
204
- Quando vários controles têm o mesmo papel e nome, `within` limita a busca a um
205
- container acessível único, como uma linha, card ou diálogo. `index` escolhe uma
206
- ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
207
- um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
208
- controle próximo ao texto visível do rótulo.
151
+ - `like_comment` e `unlike_comment`, que localizam uma linha pelo autor e texto,
152
+ não repetem uma reação já no estado pedido e distinguem `Curtir` de
153
+ `Descurtir`.
154
+
155
+ As proteções e evidências por etapa usam estes campos:
156
+
157
+ - `confirm_dialog` recebe `expected_text` e `button`. Em diálogos HTML, o MCP
158
+ confere o texto antes de localizar e clicar no botão. Também trata diálogos
159
+ nativos `alert`/`confirm`: precisa haver uma etapa `confirm_dialog` logo após
160
+ o clique que os abre, o texto deve corresponder e um diálogo inesperado é
161
+ fechado sem aceitar;
162
+ - `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
163
+ O MCP também classifica botões conhecidos como `Salvar`, `Emitir`, `Cancelar`
164
+ ou `Sim` pelo nome e pelo controle resolvido, inclusive quando o plano usa um
165
+ seletor CSS. `options.dry_run: true` executa até a primeira etapa mutável e
166
+ para antes dela; retorna `dry_run_stopped_before_step` e um
167
+ `confirmation_token` temporário, de uso único e vinculado ao fluxo e à página.
168
+ Reenvie a mesma chamada com `options.confirmation_token` para autorizar essa
169
+ etapa. O MCP pausa novamente antes de cada outra etapa mutável. Sem `dry_run`,
170
+ o primeiro pedido de ação mutável também retorna `status: "confirmation_required"`
171
+ e token; nenhuma etapa mutável roda sem essa autorização. O token expira após
172
+ dez minutos por padrão;
173
+ - `duration_ms` aparece em cada etapa concluída ou falha. `mutating_steps`
174
+ lista etapas mutáveis que foram executadas ou falharam;
175
+ - `screenshot: true` salva uma captura depois da etapa e inclui seu caminho na
176
+ evidência da etapa;
177
+ - `options.report_path` grava um resumo `.md` ou JUnit `.xml`. O caminho deve
178
+ ser absoluto e estar dentro de `JEV_BROWSER_ARTIFACT_DIR` (ou do diretório de
179
+ artefatos configurado). O relatório resume versão/status, duração, alvo e
180
+ `resolved_target`, asserções de rede, falhas de rede e caminhos das capturas.
181
+
182
+ `run_browser_flow` também aceita `params` como mapa de texto, números e
183
+ booleanos. Use `{pedido}` em `flow`, `expected_outcome` e nos campos textuais do
184
+ plano para reutilizar um valor sem editar o roteiro em vários lugares. A ação
185
+ `extract` lê `text` (padrão), `value` ou `attribute` de um elemento e salva o
186
+ resultado na variável indicada por `as`; etapas seguintes podem usar
187
+ `{documento}`. O valor extraído é tratado como sensível e fica oculto no
188
+ resultado por padrão; use `sensitive: false` só quando for apropriado exibi-lo.
189
+ `resolved_target.match_strategy` informa quando um rótulo foi
190
+ associado por proximidade (`label-proximity`) em vez de um `label[for]` direto.
191
+
192
+ A ação `assert_network` verifica respostas observadas depois da etapa anterior,
193
+ incluindo respostas 2xx ou erros esperados como 404. Exemplo:
194
+
195
+ ```json
196
+ {
197
+ "action": "assert_network",
198
+ "url_contains": "/documentoFinanceiro/atualizar",
199
+ "method": "PUT",
200
+ "status": 404,
201
+ "message_contains": "Boleto não encontrado"
202
+ }
203
+ ```
204
+
205
+ Essa asserção aparece na evidência como `response_status`, separado do campo
206
+ `status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
207
+ da mesma origem e respeita o limite configurado para captura de corpos.
208
+
209
+ Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
210
+ com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
211
+ `{"action":"extract","role":"cell","name":"{pedido}","within":{"row_containing_exact":"{pedido}"},"as":"documento"}`.
212
+ A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
213
+
214
+ Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
215
+ localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
216
+ aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
217
+ `url_contains`; o MCP precisa observar a requisição depois da etapa anterior e
218
+ esperar que ela termine.
219
+
220
+ Quando vários controles têm o mesmo papel e nome, `within` limita a busca a um
221
+ container acessível único, como uma linha, card ou diálogo. `index` escolhe uma
222
+ ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
223
+ um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
224
+ controle próximo ao texto visível do rótulo.
225
+
226
+ `within` pode combinar um container e uma linha. Use, por exemplo,
227
+ `{"role":"cell","name":"Documento A","within":{"role":"table","row_containing_word":"1528721"}}`.
228
+ `row_containing_word` usa limites de palavra para não confundir `1528721` com
229
+ `15287210`; `row_containing_exact` continua disponível para texto de célula
230
+ exato. `check` e `uncheck` alteram checkboxes, e `select_option` aceita rótulo
231
+ exato (`option`), valor (`value`) ou rótulo parcial único (`label_contains`).
232
+ `navigate_menu` percorre uma lista de rótulos exatos e abre `#open_btn` quando o
233
+ primeiro item ainda está oculto. Se vários itens visíveis tiverem o mesmo
234
+ rótulo, seleciona a última ocorrência, útil quando o submenu recém-aberto
235
+ repete o nome da categoria pai.
209
236
 
210
237
  ```json
211
238
  {
@@ -217,51 +244,52 @@ controle próximo ao texto visível do rótulo.
217
244
  ```
218
245
 
219
246
  ```json
220
- {"action":"click","role":"button","name":"Add to cart","index":0}
221
- ```
222
-
223
- Exemplos para controles legados sem nome acessível:
224
-
225
- ```json
226
- {"action":"type","role":"textbox","label":"Vencimento","text":"05/10/2026"}
227
- {"action":"type","role":"textbox","target_text":"Vencimento","text":"05/10/2026"}
228
- {"action":"click","role":"link","title":"Editar documento","within":{"row_containing":"1528721"}}
229
- {"action":"press","key":"Enter","role":"textbox","placeholder":"Busca rápida"}
230
- {"action":"click","role":"button","name":"","index":0}
231
- {"action":"click","selector":"#save-document"}
232
- ```
233
-
234
- O reconhecimento retorna `unnamed_controls_initial` e
235
- `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
236
- mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
237
- sem nome. Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode
238
- de uso privado (como ícones Font Awesome) entram nessa lista e podem ser
239
- selecionados com `name: ""` e o mesmo índice. `unnamed_controls` continua
240
- disponível como alias da lista final. O placeholder conta como nome acessível.
241
- O snapshot também resume campos de formulário com `id`, `name`, valor, estado
242
- desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
243
- sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
244
- é `false` por padrão; defina `true` somente quando precisar inspecionar campos
245
- ocultos também.
246
-
247
- Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
248
- localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
249
- `textbox`, `searchbox` ou `combobox`.
250
-
251
- Por padrão, o MCP executa todos os passos antes de avaliar `expected_outcome`.
252
- Valores dentro de campos não contam como resultado visível. `stop_on_expected:
253
- true` habilita parada antecipada quando o texto esperado aparece fora dos
254
- campos; mantenha `false` para fluxos com várias etapas.
255
-
256
- Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
257
- de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
258
- e erro.
247
+ {"action":"click","role":"button","name":"Add to cart","index":0}
248
+ ```
249
+
250
+ Exemplos para controles legados sem nome acessível:
251
+
252
+ ```json
253
+ {"action":"type","role":"textbox","label":"Vencimento","text":"05/10/2026"}
254
+ {"action":"type","role":"textbox","target_text":"Vencimento","text":"05/10/2026"}
255
+ {"action":"click","role":"link","title":"Editar documento","within":{"row_containing":"1528721"}}
256
+ {"action":"press","key":"Enter","role":"textbox","placeholder":"Busca rápida"}
257
+ {"action":"click","role":"button","name":"","index":0}
258
+ {"action":"click","selector":"#save-document"}
259
+ ```
260
+
261
+ O reconhecimento retorna `unnamed_controls_initial` e
262
+ `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
263
+ mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
264
+ sem nome. Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode
265
+ de uso privado (como ícones Font Awesome) entram nessa lista e podem ser
266
+ selecionados com `name: ""` e o mesmo índice. `unnamed_controls` continua
267
+ disponível como alias da lista final. O placeholder conta como nome acessível.
268
+ O snapshot também resume campos de formulário com `id`, `name`, valor, estado
269
+ desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
270
+ sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
271
+ é `false` por padrão; defina `true` somente quando precisar inspecionar campos
272
+ ocultos também.
273
+
274
+ Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
275
+ localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
276
+ `textbox`, `searchbox` ou `combobox`.
277
+
278
+ Por padrão, o MCP executa todos os passos antes de avaliar `expected_outcome`.
279
+ Valores dentro de campos não contam como resultado visível. `stop_on_expected:
280
+ true` habilita parada antecipada quando o texto esperado aparece fora dos
281
+ campos; mantenha `false` para fluxos com várias etapas.
282
+
283
+ Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
284
+ de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
285
+ e erro.
259
286
 
260
287
  ### Captura de downloads
261
288
 
262
289
  Marque o clique que deve iniciar um download com `expect_download: true`. O
263
- Playwright começa a aguardar o evento antes do clique; após a transferência
264
- terminar, o MCP verifica o tamanho, sanitiza o nome sugerido e copia o arquivo
290
+ Playwright começa a aguardar o evento antes do clique; isso também captura
291
+ downloads gerados por `URL.createObjectURL` (por exemplo, PDFs Blob). Após a
292
+ transferência terminar, o MCP verifica o tamanho, sanitiza o nome sugerido e copia o arquivo
265
293
  para `JEV_BROWSER_ARTIFACT_DIR` (ou para o diretório de artefatos configurado).
266
294
  O resultado inclui a lista `downloaded_files`, com nome, caminho local e bytes;
267
295
  cada passo também contém o arquivo capturado. Os limites contam arquivos e bytes
@@ -292,13 +320,13 @@ trechos da página. Qualquer violação reprova esse fluxo. A auditoria automát
292
320
  encontra problemas comuns, mas não comprova conformidade WCAG completa; combine-a
293
321
  com revisão manual e testes com usuários assistivos.
294
322
 
295
- Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
296
- corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
297
- conteúdo acessível dos iframes nomeados dentro do escopo, limitado pela
298
- configuração. Se um alvo estiver ausente, o erro inclui até três nomes acessíveis
299
- próximos quando o snapshot os encontrar. CSS/XPath são permitidos somente como
300
- localizadores explícitos de último recurso e geram aviso. O plano não aceita
301
- JavaScript enviado pelo harness nem coordenadas.
323
+ Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
324
+ corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
325
+ conteúdo acessível dos iframes nomeados dentro do escopo, limitado pela
326
+ configuração. Se um alvo estiver ausente, o erro inclui até três nomes acessíveis
327
+ próximos quando o snapshot os encontrar. CSS/XPath são permitidos somente como
328
+ localizadores explícitos de último recurso e geram aviso. O plano não aceita
329
+ JavaScript enviado pelo harness nem coordenadas.
302
330
 
303
331
  Os aliases `value` → `text` em `type`/`wait_for_text` e `value` → `expected` em
304
332
  asserções são aceitos. `comment` também é aceito em planos e passos, mas é
@@ -381,9 +409,9 @@ do pacote Node ficam no bloco opcional `jev_browser_mcp`, que não altera o
381
409
  contrato lido pelo servidor Python. Preserve a estrutura completa exigida pelos
382
410
  validadores.
383
411
 
384
- `browser.mode` aceita `harness` ou `computer`; o padrão é `computer`:
412
+ `browser.mode` aceita `harness` ou `computer`; o padrão é `computer`:
385
413
 
386
- - `harness` usa Chrome headless e contexto isolado, adequado a execuções do
414
+ - `harness` usa Chrome headless e contexto isolado, adequado a execuções do
387
415
  harness e CI; o estado de autenticação é descartado ao final da chamada.
388
416
  - `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
389
417
  persistente `browser.computer_user_data_dir`, separado por navegador. Não
@@ -392,23 +420,23 @@ validadores.
392
420
 
393
421
  `browser.max_flow_steps` limita a soma de passos declarados entre os planos e
394
422
  `browser.max_text_entry_chars` limita cada valor digitado. O resultado contém
395
- `status`, o plano escolhido, as ações executadas, a última captura acessível e
396
- se o critério esperado apareceu. Quando existem asserções explícitas, `status`
397
- também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
398
- esse resultado e `expected_outcome_visible` continua descrevendo somente o
399
- texto global. `incomplete` significa que nenhum critério foi comprovado;
400
- confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
401
- espera da SPA; `warnings` registra capturas vazias durante transições; e
402
- `failed_step` identifica índice, ação, localizador, timeout e erro resumido
403
- quando uma etapa falha. Cada etapa executada também registra a composição do
404
- localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel,
405
- nome acessível, `title` casado e `href` sanitizado do elemento resolvido.
406
- Etapas `type` só incluem o valor final do campo quando `sensitive: false`.
407
-
408
- Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
409
- origem são capturadas mesmo quando usam transferência chunked e não enviam
410
- `Content-Length`. Corpos acima do limite, com formato inválido ou que não
411
- podem ser lidos com segurança são omitidos e explicados em `warnings`.
423
+ `status`, o plano escolhido, as ações executadas, a última captura acessível e
424
+ se o critério esperado apareceu. Quando existem asserções explícitas, `status`
425
+ também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
426
+ esse resultado e `expected_outcome_visible` continua descrevendo somente o
427
+ texto global. `incomplete` significa que nenhum critério foi comprovado;
428
+ confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
429
+ espera da SPA; `warnings` registra capturas vazias durante transições; e
430
+ `failed_step` identifica índice, ação, localizador, timeout e erro resumido
431
+ quando uma etapa falha. Cada etapa executada também registra a composição do
432
+ localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel,
433
+ nome acessível, `title` casado e `href` sanitizado do elemento resolvido.
434
+ Etapas `type` só incluem o valor final do campo quando `sensitive: false`.
435
+
436
+ Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
437
+ origem são capturadas mesmo quando usam transferência chunked e não enviam
438
+ `Content-Length`. Corpos acima do limite, com formato inválido ou que não
439
+ podem ser lidos com segurança são omitidos e explicados em `warnings`.
412
440
 
413
441
  `jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
414
442
  seletores e condições. `JEV_BROWSER_UPLOAD_ROOT` libera uploads somente dentro
@@ -424,54 +452,76 @@ Os limites de download ficam no mesmo bloco: `max_download_files`,
424
452
  limita quantas descrições de violações axe entram no resultado; a contagem total
425
453
  continua informada mesmo quando a lista é truncada.
426
454
 
427
- O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
428
- `block_trackers`, `capture_console_errors`, `capture_network_errors`,
429
- `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
430
- `ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
431
- `trace_on_failure`, `snapshot_include_hidden`, `stop_on_expected`, `dry_run` e
432
- `report_path`. Sem override,
433
- os padrões são lidos de `jev_browser_mcp` em
434
- `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
435
- captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
436
- de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
437
- acrescentados ao snapshot. O browser espera a SPA renderizar uma captura
438
- acessível estável. `ready_text` pode identificar o conteúdo que marca a
439
- prontidão. `reuse_page: true` pula a navegação somente quando a página e
440
- `initial_url` têm a mesma origem. `snapshot_scope` aceita `body`, `main` ou
441
- `dialog`.
442
-
443
- `block_trackers: true` bloqueia os domínios e tipos de recurso listados na
444
- configuração (analytics, Hotjar, fontes externas e mídia). Isso pode alterar o
445
- layout ou o comportamento do site, então a opção é desligada por padrão.
455
+ O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
456
+ `block_trackers`, `block_fonts`, `local_only`, `busy_selectors`,
457
+ `auto_angular_idle`, `login_url_contains`, `login_text`, `capture_console_errors`,
458
+ `capture_network_errors`, `capture_network_error_bodies`, `ready_timeout_seconds`,
459
+ `ready_network_idle`, `ready_stable_ms`, `ready_text`, `continue_from_current_page`,
460
+ `reuse_page`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
461
+ `screenshot_on_failure`, `trace_on_failure`, `snapshot_include_hidden`,
462
+ `stop_on_expected`, `dry_run`, `confirmation_token` e `report_path`. Sem override,
463
+ os padrões são lidos de `jev_browser_mcp` em
464
+ `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
465
+ captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
466
+ de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
467
+ acrescentados ao snapshot. O browser espera a SPA renderizar uma captura
468
+ acessível estável na navegação inicial. Depois, a continuidade fica ligada por
469
+ padrão: `continue_from_current_page: true` mantém a página e seu estado entre
470
+ chamadas na mesma origem, não repete `page.goto` e consulta um snapshot atual
471
+ sem esperar novamente por `load`/`networkidle`. As etapas continuam aguardando
472
+ seus próprios alvos e condições. `reuse_page` segue como alias legado; defina
473
+ `continue_from_current_page: false` para iniciar cada chamada em `initial_url`.
474
+ Se a página atual e `initial_url` tiverem origens diferentes, o MCP navega para
475
+ `initial_url`. Se forem da mesma origem, continua a página atual e avisa quando
476
+ as URLs completas forem diferentes. `snapshot_scope` aceita `body`, `main` ou
477
+ `dialog`; se `main` não existir, o snapshot usa `body`.
478
+
479
+ `block_trackers: true` bloqueia analytics/trackers e os tipos de recurso
480
+ configurados. Fontes ficam habilitadas por padrão para preservar ícones e
481
+ glyphs; `block_fonts: true` bloqueia fontes separadamente. `busy_selectors`
482
+ complementa `aria-busy="true"` ao aguardar overlays de carregamento.
483
+ `auto_angular_idle` aguarda AngularJS depois de cliques e digitação quando a
484
+ página expõe o injector. `login_url_contains` e `login_text` substituem a
485
+ detecção padrão de autenticação. `local_only: true` recusa qualquer etapa que
486
+ precisaria chamar o provedor Jev; use exatamente um plano com `fast_path: true`.
487
+ `step_timeout_seconds` define o timeout padrão por etapa e cada etapa pode
488
+ substituí-lo com `timeout_seconds`. `max_flow_steps` reduz o limite por chamada,
489
+ sem superar o teto da configuração. `return_snapshot` aceita `full`, `diff` ou
490
+ `none`; `diff` retorna linhas acessíveis novas desde o snapshot inicial.
446
491
 
447
492
  Com `capture_console_errors` e `capture_network_errors`, o retorno traz
448
493
  `console_errors` e `network_failures`, limitados em quantidade e tamanho.
449
- Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
450
- fragmentos, valores de formulário e nomes de arquivo são removidos ou
451
- sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
452
- 4xx/5xx da mesma origem, limita o corpo e inclui apenas o campo textual
453
- `message`, também sanitizado. Em falhas, `screenshot_on_failure` salva
454
- screenshot local e retorna
494
+ Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
495
+ fragmentos, valores de formulário e nomes de arquivo são removidos ou
496
+ sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
497
+ 4xx/5xx da mesma origem, limita o corpo e inclui apenas o campo textual
498
+ `message`, também sanitizado. Em falhas, `screenshot_on_failure` salva
499
+ screenshot local e retorna
455
500
  `screenshot_path`. `trace_on_failure: true` também grava um `.zip` compatível
456
501
  com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
457
502
  `~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
458
503
  substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
459
504
  conter dados visíveis da aplicação: mantenha o diretório local protegido e
460
- compartilhe os arquivos somente se o teste permitir.
461
-
462
- Screenshots por etapa usam `screenshot: true` no próprio passo; o MCP os grava
463
- depois que a ação termina. `options.report_path` pode apontar para `.md` ou
464
- JUnit `.xml` dentro da raiz de artefatos. O relatório inclui a versão, tempos,
465
- localizadores resolvidos, respostas verificadas por `assert_network`, falhas de
466
- rede e caminhos dos screenshots, para anexar a um PR ou card.
467
-
468
- Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
469
- identifica o PID que o mantém ocupado quando o sistema consegue associar o
470
- perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
471
- Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. Configure
472
- `JEV_BROWSER_PROFILE` com outro diretório absoluto para usar uma sessão isolada.
473
- Resultados MCP incluem `server_version`; erros também começam com a versão do
474
- servidor para facilitar a comparação entre instalações.
505
+ compartilhe os arquivos somente se o teste permitir.
506
+
507
+ Screenshots por etapa usam `screenshot: true` no próprio passo; o MCP os grava
508
+ depois que a ação termina. `options.report_path` pode apontar para `.md` ou
509
+ JUnit `.xml` dentro da raiz de artefatos. O relatório inclui a versão, tempos,
510
+ localizadores resolvidos, respostas verificadas por `assert_network`, falhas de
511
+ rede e caminhos dos screenshots, para anexar a um PR ou card.
512
+
513
+ Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
514
+ identifica o PID que o mantém ocupado quando o sistema consegue associar o
515
+ perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
516
+ Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. Configure
517
+ `JEV_BROWSER_PROFILE` com outro diretório absoluto para usar uma sessão isolada.
518
+ Resultados MCP incluem `server_version`; erros também começam com a versão do
519
+ servidor para facilitar a comparação entre instalações. A ferramenta
520
+ `browser_health` informa se a sessão está ativa e tenta reconectar um browser
521
+ que encerrou desde a chamada anterior. Passe `{"restart":true}` para fechar e
522
+ reiniciar somente o navegador administrado por este processo MCP. Um fluxo pode
523
+ ser repetido automaticamente uma vez após `BROWSER_DISCONNECTED` quando nenhuma
524
+ etapa mutável foi executada.
475
525
 
476
526
  `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
477
527
  `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;