@diegosouzacdv/jev-browser-mcp 0.4.2 → 0.6.0

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.4.0"],
20
+ "args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.6.0"],
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,18 +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
- O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
39
- configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
40
- pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp --install-browser`.
41
-
42
- O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
43
- persistente exclusivo em `browser.computer_user_data_dir`. No modo `harness`, a
44
- instalação baixa uma vez o Chrome/Edge que o Playwright controlará. Personalize
45
- as escolhas com `JEV_BROWSER_MODE`, `JEV_BROWSER_CHANNEL` e
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.6.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
46
58
  `JEV_BROWSER_PROFILE`. O browser permanece aquecido enquanto o processo MCP
47
59
  estiver ativo e fecha quando o harness encerra o processo. `JEV_PROVIDER_URL`
48
60
  e `JEV_MODEL` podem substituir os valores centrais; a credencial continua no
@@ -52,28 +64,28 @@ Uma aplicação Node também pode importar `createJevBrowserServer` por
52
64
  `@diegosouzacdv/jev-browser-mcp/server` e conectar o servidor ao transporte MCP
53
65
  que ela já utiliza.
54
66
 
55
- O pacote é montado em uma pasta temporária isolada: o publicador usa o campo
56
- `files` do `package.json` para copiar somente o código Node, a configuração
57
- compartilhada e esta documentação, que também vira o `README.md` da raiz do
58
- pacote. Assim, o npm não inclui o README geral do orquestrador na página do MCP.
59
- Para gerar e conferir o pacote antes de publicar, execute
60
- `npm run pack:jev-browser-mcp`; para publicar uma versão já autenticada no npm, execute
61
- `npm run publish:jev-browser-mcp`. A instalação por npm é a recomendada; use a
62
- referência GitHub somente quando precisar experimentar uma revisão ainda não
63
- 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.
64
76
 
65
77
  ### Contrato do pacote
66
78
 
67
- 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
68
80
  sessão do browser por processo e reutiliza essa sessão entre chamadas. O plano
69
81
  passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
70
82
  hover, espera, teclas aprovadas, asserções por elemento, upload restrito a uma
71
83
  raiz local configurada e reações idempotentes a um comentário único. Também
72
- aceita um nome de iframe para as ações que ocorrem dentro dele. Não aceita
73
- JavaScript enviado pelo harness nem coordenadas. Além de papel/nome acessível,
74
- aceita `label`, `placeholder`, `title`, `text`, `test_id` e `selector`; CSS/XPath
75
- são o último recurso e geram um aviso no resultado. Ele usa a
76
- 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
77
89
  Playwright. O transporte MCP usa `stdio`; toda saída de diagnóstico vai para
78
90
  `stderr` para não misturar com JSON-RPC.
79
91
 
@@ -89,55 +101,114 @@ a página inicial, captura o snapshot acessível e pede ao Jev que escolha um
89
101
  plano. Em seguida, executa o plano inteiro na mesma sessão e confere o
90
102
  resultado esperado na tela.
91
103
 
92
- Cada plano pode usar:
93
-
94
- - `click`, `type`, `hover`, `select_option`, `press`, `assert_*` e upload com
95
- papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
96
- `text`, `test_id` ou `selector`;
97
- - `near: {"text":"..."}` para localizar o controle logo depois de um texto,
98
- e `within: {"row_containing":"..."}` para limitar a ação à linha certa;
99
- - `within: {"role":"dialog"}` sem `name` para usar o único diálogo visível;
100
- o MCP ignora diálogos visualmente ocultos, inclusive os que ficaram no DOM
101
- com `opacity: 0`;
102
- - `name: ""` com `index` não negativo para controles sem nome. O resultado
103
- inclui um aviso porque a posição pode mudar entre execuções. O índice é
104
- zero-based para o mesmo papel e segue o localizador Playwright
105
- `{role, name: ""}`; controles desabilitados não aparecem no diagnóstico, mas
106
- continuam contando para que o índice aponte ao controle correto;
107
- - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
108
- em `warnings`; não é permitido enviar JavaScript nem coordenadas;
109
- - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
110
- - `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
111
- `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
112
- valor apareça nas evidências. Nesse modo, `\n` envia Enter e `\t` envia Tab;
113
- - `wait_for_text` e `wait_for_condition` (`network_idle`, `hidden` ou
114
- `text_hidden`). `wait_for_text` aceita `fail_on: {"role":"alert"}` para
115
- interromper a espera assim que um alerta visível aparecer e incluir seu texto
116
- no erro. `network_idle` aceita `url_contains` para aguardar só as requisições
117
- correspondentes;
118
- - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
119
- `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
120
- envia a tecla ao elemento focado; com alvo, usa o localizador informado;
121
- - `assert_text`, `assert_value`, `assert_visible` e `assert_hidden`; `assert_text`
122
- pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
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`, `wait_for_value`, `wait_for_enabled` e `wait_for_condition`
129
+ (`network_idle`, `hidden`, `text_hidden` ou `angular_idle`). `wait` recebe
130
+ `ms` para uma pausa curta e limitada. `angular_idle` aguarda requisições
131
+ `$http` e digest do AngularJS. `wait_for_text` aceita `fail_on: {"role":"alert"}` para
132
+ interromper a espera assim que um alerta visível aparecer e incluir seu texto
133
+ no erro. Se o alerta contiver o texto esperado, a etapa passa; caso contrário,
134
+ o alerta interrompe a espera. `network_idle` aceita `url_contains` para
135
+ aguardar só as requisições correspondentes;
136
+ - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
137
+ `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
138
+ envia a tecla ao elemento focado; com alvo, usa o localizador informado;
139
+ - `assert_text`, `assert_value`, `assert_visible`, `assert_hidden` e
140
+ `assert_enabled`; `assert_text`
141
+ pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
123
142
  - `upload_file` para input rotulado, botão que abre o seletor de arquivo ou
124
143
  dropzone;
125
144
  - `audit_accessibility` com axe-core para WCAG 2.1 A/AA;
126
- - `like_comment` e `unlike_comment`, que localizam uma linha pelo autor e texto,
127
- não repetem uma reação já no estado pedido e distinguem `Curtir` de
128
- `Descurtir`.
129
-
130
- Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
131
- localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
132
- aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
133
- `url_contains`; o MCP precisa observar a requisição depois da etapa anterior e
134
- esperar que ela termine.
135
-
136
- Quando vários controles têm o mesmo papel e nome, `within` limita a busca a um
137
- container acessível único, como uma linha, card ou diálogo. `index` escolhe uma
138
- ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
139
- um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
140
- controle próximo ao texto visível do rótulo.
145
+ - `like_comment` e `unlike_comment`, que localizam uma linha pelo autor e texto,
146
+ não repetem uma reação já no estado pedido e distinguem `Curtir` de
147
+ `Descurtir`.
148
+
149
+ As proteções e evidências por etapa usam estes campos:
150
+
151
+ - `confirm_dialog` recebe `expected_text` e `button`. O MCP exige um diálogo
152
+ visível único e confere se ele contém o texto esperado antes de clicar; se o
153
+ alerta mudou, a etapa falha sem clicar no botão. Reserve `click` comum para
154
+ ações que não dependem do conteúdo de uma confirmação;
155
+ - `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
156
+ Com `options.dry_run: true`, o fluxo para imediatamente antes da primeira
157
+ etapa marcada e retorna `dry_run_stopped_before_step` e `mutating_steps`.
158
+ Marque toda ação que grava ou envia algo, mesmo quando não for um botão
159
+ chamado Salvar;
160
+ - `duration_ms` aparece em cada etapa concluída ou falha. `mutating_steps`
161
+ lista as etapas marcadas e informa quais foram executadas;
162
+ - `screenshot: true` salva uma captura depois da etapa e inclui seu caminho na
163
+ evidência da etapa;
164
+ - `options.report_path` grava um resumo `.md` ou JUnit `.xml`. O caminho deve
165
+ ser absoluto e estar dentro de `JEV_BROWSER_ARTIFACT_DIR` (ou do diretório de
166
+ artefatos configurado). O relatório resume versão/status, duração, alvo e
167
+ `resolved_target`, asserções de rede, falhas de rede e caminhos das capturas.
168
+
169
+ `run_browser_flow` também aceita `params` como mapa de texto, números e
170
+ booleanos. Use `{pedido}` em `flow`, `expected_outcome` e nos campos textuais do
171
+ plano para reutilizar um valor sem editar o roteiro em vários lugares. A ação
172
+ `extract` lê `text` (padrão), `value` ou `attribute` de um elemento e salva o
173
+ resultado na variável indicada por `as`; etapas seguintes podem usar
174
+ `{documento}`. O valor extraído é tratado como sensível e fica oculto no
175
+ resultado por padrão; use `sensitive: false` só quando for apropriado exibi-lo.
176
+ `resolved_target.match_strategy` informa quando um rótulo foi
177
+ associado por proximidade (`label-proximity`) em vez de um `label[for]` direto.
178
+
179
+ A ação `assert_network` verifica respostas observadas depois da etapa anterior,
180
+ incluindo respostas 2xx ou erros esperados como 404. Exemplo:
181
+
182
+ ```json
183
+ {
184
+ "action": "assert_network",
185
+ "url_contains": "/documentoFinanceiro/atualizar",
186
+ "method": "PUT",
187
+ "status": 404,
188
+ "message_contains": "Boleto não encontrado"
189
+ }
190
+ ```
191
+
192
+ Essa asserção aparece na evidência como `response_status`, separado do campo
193
+ `status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
194
+ da mesma origem e respeita o limite configurado para captura de corpos.
195
+
196
+ Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
197
+ com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
198
+ `{"action":"extract","role":"cell","name":"{pedido}","within":{"row_containing_exact":"{pedido}"},"as":"documento"}`.
199
+ A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
200
+
201
+ Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
202
+ localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
203
+ aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
204
+ `url_contains`; o MCP precisa observar a requisição depois da etapa anterior e
205
+ esperar que ela termine.
206
+
207
+ Quando vários controles têm o mesmo papel e nome, `within` limita a busca a um
208
+ container acessível único, como uma linha, card ou diálogo. `index` escolhe uma
209
+ ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
210
+ um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
211
+ controle próximo ao texto visível do rótulo.
141
212
 
142
213
  ```json
143
214
  {
@@ -149,49 +220,52 @@ controle próximo ao texto visível do rótulo.
149
220
  ```
150
221
 
151
222
  ```json
152
- {"action":"click","role":"button","name":"Add to cart","index":0}
153
- ```
154
-
155
- Exemplos para controles legados sem nome acessível:
156
-
157
- ```json
158
- {"action":"type","role":"textbox","label":"Vencimento","text":"05/10/2026"}
159
- {"action":"type","role":"textbox","target_text":"Vencimento","text":"05/10/2026"}
160
- {"action":"click","role":"link","title":"Editar documento","within":{"row_containing":"1528721"}}
161
- {"action":"press","key":"Enter","role":"textbox","placeholder":"Busca rápida"}
162
- {"action":"click","role":"button","name":"","index":0}
163
- {"action":"click","selector":"#save-document"}
164
- ```
165
-
166
- O reconhecimento retorna `unnamed_controls_initial` e
167
- `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
168
- mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
169
- sem nome. `unnamed_controls` continua disponível como alias da lista final. O
170
- placeholder conta como nome acessível. O snapshot também resume campos de
171
- formulário com `id`, `name`, valor, estado
172
- desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
173
- sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
174
- é `false` por padrão; defina `true` somente quando precisar inspecionar campos
175
- ocultos também.
176
-
177
- Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
178
- localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
179
- `textbox`, `searchbox` ou `combobox`.
180
-
181
- Por padrão, o MCP executa todos os passos antes de avaliar `expected_outcome`.
182
- Valores dentro de campos não contam como resultado visível. `stop_on_expected:
183
- true` habilita parada antecipada quando o texto esperado aparece fora dos
184
- campos; mantenha `false` para fluxos com várias etapas.
185
-
186
- Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
187
- de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
188
- e erro.
223
+ {"action":"click","role":"button","name":"Add to cart","index":0}
224
+ ```
225
+
226
+ Exemplos para controles legados sem nome acessível:
227
+
228
+ ```json
229
+ {"action":"type","role":"textbox","label":"Vencimento","text":"05/10/2026"}
230
+ {"action":"type","role":"textbox","target_text":"Vencimento","text":"05/10/2026"}
231
+ {"action":"click","role":"link","title":"Editar documento","within":{"row_containing":"1528721"}}
232
+ {"action":"press","key":"Enter","role":"textbox","placeholder":"Busca rápida"}
233
+ {"action":"click","role":"button","name":"","index":0}
234
+ {"action":"click","selector":"#save-document"}
235
+ ```
236
+
237
+ O reconhecimento retorna `unnamed_controls_initial` e
238
+ `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
239
+ mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
240
+ sem nome. Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode
241
+ de uso privado (como ícones Font Awesome) entram nessa lista e podem ser
242
+ selecionados com `name: ""` e o mesmo índice. `unnamed_controls` continua
243
+ disponível como alias da lista final. O placeholder conta como nome acessível.
244
+ O snapshot também resume campos de formulário com `id`, `name`, valor, estado
245
+ desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
246
+ sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
247
+ é `false` por padrão; defina `true` somente quando precisar inspecionar campos
248
+ ocultos também.
249
+
250
+ Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
251
+ localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
252
+ `textbox`, `searchbox` ou `combobox`.
253
+
254
+ Por padrão, o MCP executa todos os passos antes de avaliar `expected_outcome`.
255
+ Valores dentro de campos não contam como resultado visível. `stop_on_expected:
256
+ true` habilita parada antecipada quando o texto esperado aparece fora dos
257
+ campos; mantenha `false` para fluxos com várias etapas.
258
+
259
+ Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
260
+ de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
261
+ e erro.
189
262
 
190
263
  ### Captura de downloads
191
264
 
192
265
  Marque o clique que deve iniciar um download com `expect_download: true`. O
193
- Playwright começa a aguardar o evento antes do clique; após a transferência
194
- terminar, o MCP verifica o tamanho, sanitiza o nome sugerido e copia o arquivo
266
+ Playwright começa a aguardar o evento antes do clique; isso também captura
267
+ downloads gerados por `URL.createObjectURL` (por exemplo, PDFs Blob). Após a
268
+ transferência terminar, o MCP verifica o tamanho, sanitiza o nome sugerido e copia o arquivo
195
269
  para `JEV_BROWSER_ARTIFACT_DIR` (ou para o diretório de artefatos configurado).
196
270
  O resultado inclui a lista `downloaded_files`, com nome, caminho local e bytes;
197
271
  cada passo também contém o arquivo capturado. Os limites contam arquivos e bytes
@@ -222,13 +296,13 @@ trechos da página. Qualquer violação reprova esse fluxo. A auditoria automát
222
296
  encontra problemas comuns, mas não comprova conformidade WCAG completa; combine-a
223
297
  com revisão manual e testes com usuários assistivos.
224
298
 
225
- Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
226
- corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
227
- conteúdo acessível dos iframes nomeados dentro do escopo, limitado pela
228
- configuração. Se um alvo estiver ausente, o erro inclui até três nomes acessíveis
229
- próximos quando o snapshot os encontrar. CSS/XPath são permitidos somente como
230
- localizadores explícitos de último recurso e geram aviso. O plano não aceita
231
- JavaScript enviado pelo harness nem coordenadas.
299
+ Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
300
+ corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
301
+ conteúdo acessível dos iframes nomeados dentro do escopo, limitado pela
302
+ configuração. Se um alvo estiver ausente, o erro inclui até três nomes acessíveis
303
+ próximos quando o snapshot os encontrar. CSS/XPath são permitidos somente como
304
+ localizadores explícitos de último recurso e geram aviso. O plano não aceita
305
+ JavaScript enviado pelo harness nem coordenadas.
232
306
 
233
307
  Os aliases `value` → `text` em `type`/`wait_for_text` e `value` → `expected` em
234
308
  asserções são aceitos. `comment` também é aceito em planos e passos, mas é
@@ -311,9 +385,9 @@ do pacote Node ficam no bloco opcional `jev_browser_mcp`, que não altera o
311
385
  contrato lido pelo servidor Python. Preserve a estrutura completa exigida pelos
312
386
  validadores.
313
387
 
314
- `browser.mode` aceita `harness` ou `computer`; o padrão é `computer`:
388
+ `browser.mode` aceita `harness` ou `computer`; o padrão é `computer`:
315
389
 
316
- - `harness` usa Chrome headless e contexto isolado, adequado a execuções do
390
+ - `harness` usa Chrome headless e contexto isolado, adequado a execuções do
317
391
  harness e CI; o estado de autenticação é descartado ao final da chamada.
318
392
  - `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
319
393
  persistente `browser.computer_user_data_dir`, separado por navegador. Não
@@ -322,23 +396,23 @@ validadores.
322
396
 
323
397
  `browser.max_flow_steps` limita a soma de passos declarados entre os planos e
324
398
  `browser.max_text_entry_chars` limita cada valor digitado. O resultado contém
325
- `status`, o plano escolhido, as ações executadas, a última captura acessível e
326
- se o critério esperado apareceu. Quando existem asserções explícitas, `status`
327
- também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
328
- esse resultado e `expected_outcome_visible` continua descrevendo somente o
329
- texto global. `incomplete` significa que nenhum critério foi comprovado;
330
- confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
331
- espera da SPA; `warnings` registra capturas vazias durante transições; e
332
- `failed_step` identifica índice, ação, localizador, timeout e erro resumido
333
- quando uma etapa falha. Cada etapa executada também registra a composição do
334
- localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel
335
- e nome acessível do elemento resolvido. Etapas `type` só incluem o valor final
336
- do campo quando `sensitive: false`.
337
-
338
- Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
339
- origem são capturadas mesmo quando usam transferência chunked e não enviam
340
- `Content-Length`. Corpos acima do limite, com formato inválido ou que não
341
- podem ser lidos com segurança são omitidos e explicados em `warnings`.
399
+ `status`, o plano escolhido, as ações executadas, a última captura acessível e
400
+ se o critério esperado apareceu. Quando existem asserções explícitas, `status`
401
+ também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
402
+ esse resultado e `expected_outcome_visible` continua descrevendo somente o
403
+ texto global. `incomplete` significa que nenhum critério foi comprovado;
404
+ confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
405
+ espera da SPA; `warnings` registra capturas vazias durante transições; e
406
+ `failed_step` identifica índice, ação, localizador, timeout e erro resumido
407
+ quando uma etapa falha. Cada etapa executada também registra a composição do
408
+ localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel,
409
+ nome acessível, `title` casado e `href` sanitizado do elemento resolvido.
410
+ Etapas `type` só incluem o valor final do campo quando `sensitive: false`.
411
+
412
+ Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
413
+ origem são capturadas mesmo quando usam transferência chunked e não enviam
414
+ `Content-Length`. Corpos acima do limite, com formato inválido ou que não
415
+ podem ser lidos com segurança são omitidos e explicados em `warnings`.
342
416
 
343
417
  `jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
344
418
  seletores e condições. `JEV_BROWSER_UPLOAD_ROOT` libera uploads somente dentro
@@ -354,20 +428,26 @@ Os limites de download ficam no mesmo bloco: `max_download_files`,
354
428
  limita quantas descrições de violações axe entram no resultado; a contagem total
355
429
  continua informada mesmo quando a lista é truncada.
356
430
 
357
- O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
358
- `block_trackers`, `capture_console_errors`, `capture_network_errors`,
359
- `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
360
- `ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
361
- `trace_on_failure`, `snapshot_include_hidden` e `stop_on_expected`. Sem override,
362
- os padrões são lidos de `jev_browser_mcp` em
363
- `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
364
- captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
365
- de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
366
- acrescentados ao snapshot. O browser espera a SPA renderizar uma captura
367
- acessível estável. `ready_text` pode identificar o conteúdo que marca a
368
- prontidão. `reuse_page: true` pula a navegação somente quando a página e
369
- `initial_url` têm a mesma origem. `snapshot_scope` aceita `body`, `main` ou
370
- `dialog`.
431
+ O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
432
+ `block_trackers`, `capture_console_errors`, `capture_network_errors`,
433
+ `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
434
+ `ready_stable_ms`, `ready_text`, `continue_from_current_page`, `reuse_page`, `screenshot_on_failure`,
435
+ `trace_on_failure`, `snapshot_include_hidden`, `stop_on_expected`, `dry_run` e
436
+ `report_path`. Sem override,
437
+ os padrões são lidos de `jev_browser_mcp` em
438
+ `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
439
+ captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
440
+ de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
441
+ acrescentados ao snapshot. O browser espera a SPA renderizar uma captura
442
+ acessível estável na navegação inicial. Depois, a continuidade fica ligada por
443
+ padrão: `continue_from_current_page: true` mantém a página e seu estado entre
444
+ chamadas na mesma origem, não repete `page.goto` e consulta um snapshot atual
445
+ sem esperar novamente por `load`/`networkidle`. As etapas continuam aguardando
446
+ seus próprios alvos e condições. `reuse_page` segue como alias legado; defina
447
+ `continue_from_current_page: false` para iniciar cada chamada em `initial_url`.
448
+ Se a página atual e `initial_url` tiverem origens diferentes, o MCP navega para
449
+ `initial_url`. `snapshot_scope` aceita `body`, `main` ou `dialog`; se `main` não
450
+ existir, o snapshot usa `body`.
371
451
 
372
452
  `block_trackers: true` bloqueia os domínios e tipos de recurso listados na
373
453
  configuração (analytics, Hotjar, fontes externas e mídia). Isso pode alterar o
@@ -375,12 +455,12 @@ layout ou o comportamento do site, então a opção é desligada por padrão.
375
455
 
376
456
  Com `capture_console_errors` e `capture_network_errors`, o retorno traz
377
457
  `console_errors` e `network_failures`, limitados em quantidade e tamanho.
378
- Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
379
- fragmentos, valores de formulário e nomes de arquivo são removidos ou
380
- sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
381
- 4xx/5xx da mesma origem, limita o corpo e inclui apenas o campo textual
382
- `message`, também sanitizado. Em falhas, `screenshot_on_failure` salva
383
- screenshot local e retorna
458
+ Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
459
+ fragmentos, valores de formulário e nomes de arquivo são removidos ou
460
+ sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
461
+ 4xx/5xx da mesma origem, limita o corpo e inclui apenas o campo textual
462
+ `message`, também sanitizado. Em falhas, `screenshot_on_failure` salva
463
+ screenshot local e retorna
384
464
  `screenshot_path`. `trace_on_failure: true` também grava um `.zip` compatível
385
465
  com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
386
466
  `~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
@@ -388,6 +468,22 @@ substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
388
468
  conter dados visíveis da aplicação: mantenha o diretório local protegido e
389
469
  compartilhe os arquivos somente se o teste permitir.
390
470
 
471
+ Screenshots por etapa usam `screenshot: true` no próprio passo; o MCP os grava
472
+ depois que a ação termina. `options.report_path` pode apontar para `.md` ou
473
+ JUnit `.xml` dentro da raiz de artefatos. O relatório inclui a versão, tempos,
474
+ localizadores resolvidos, respostas verificadas por `assert_network`, falhas de
475
+ rede e caminhos dos screenshots, para anexar a um PR ou card.
476
+
477
+ Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
478
+ identifica o PID que o mantém ocupado quando o sistema consegue associar o
479
+ perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
480
+ Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. Configure
481
+ `JEV_BROWSER_PROFILE` com outro diretório absoluto para usar uma sessão isolada.
482
+ Resultados MCP incluem `server_version`; erros também começam com a versão do
483
+ servidor para facilitar a comparação entre instalações. A ferramenta
484
+ `browser_health` informa se a sessão está ativa e tenta reconectar um browser
485
+ que encerrou desde a chamada anterior.
486
+
391
487
  `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
392
488
  `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;
393
489
  o diretório persistente armazena dados de login e é resolvido sob a pasta home
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 1,
3
3
  "browser": {
4
- "mode": "computer",
4
+ "mode": "computer",
5
5
  "harness_browser": "chrome",
6
6
  "playwright_mcp_package": "@playwright/mcp@0.0.79",
7
7
  "computer_browser": "chrome",
@@ -22,23 +22,23 @@
22
22
  },
23
23
  "jev_browser_mcp": {
24
24
  "browser": {
25
- "max_action_timeout_seconds": 8,
26
- "ready_timeout_seconds_default": 15,
27
- "max_ready_timeout_seconds": 60,
28
- "ready_network_idle_default": true,
29
- "ready_stable_ms_default": 400,
30
- "max_ready_stable_ms": 2000,
31
- "post_step_ready_timeout_seconds_default": 5,
32
- "max_step_timeout_seconds": 60,
33
- "key_delay_ms_default": 30,
34
- "reuse_page_default": false,
35
- "stop_on_expected_default": false,
36
- "snapshot_include_hidden_default": false,
37
- "visibility_poll_interval_ms_default": 50,
38
- "capture_network_error_bodies_default": false,
39
- "max_network_error_body_bytes": 65536,
40
- "max_network_error_message_chars": 300,
41
- "max_upload_files": 5,
25
+ "max_action_timeout_seconds": 8,
26
+ "ready_timeout_seconds_default": 15,
27
+ "max_ready_timeout_seconds": 60,
28
+ "ready_network_idle_default": true,
29
+ "ready_stable_ms_default": 400,
30
+ "max_ready_stable_ms": 2000,
31
+ "post_step_ready_timeout_seconds_default": 5,
32
+ "max_step_timeout_seconds": 300,
33
+ "key_delay_ms_default": 30,
34
+ "reuse_page_default": true,
35
+ "stop_on_expected_default": false,
36
+ "snapshot_include_hidden_default": false,
37
+ "visibility_poll_interval_ms_default": 50,
38
+ "capture_network_error_bodies_default": false,
39
+ "max_network_error_body_bytes": 65536,
40
+ "max_network_error_message_chars": 300,
41
+ "max_upload_files": 5,
42
42
  "max_upload_path_chars": 4096,
43
43
  "max_upload_file_bytes": 10485760,
44
44
  "max_upload_total_bytes": 26214400,