@diegosouzacdv/jev-browser-mcp 0.4.1 → 0.5.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,7 +17,7 @@ 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.5.0"],
21
21
  "env": {
22
22
  "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}",
23
23
  "JEV_BROWSER_MODE": "computer"
@@ -35,6 +35,18 @@ de configuração. Para instalar no projeto Node do próprio harness:
35
35
  npm install @diegosouzacdv/jev-browser-mcp
36
36
  ```
37
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
+
38
50
  O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
39
51
  configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
40
52
  pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp --install-browser`.
@@ -95,12 +107,18 @@ Cada plano pode usar:
95
107
  papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
96
108
  `text`, `test_id` ou `selector`;
97
109
  - `near: {"text":"..."}` para localizar o controle logo depois de um texto,
98
- e `within: {"row_containing":"..."}` para limitar a ação à linha certa;
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`;
99
113
  - `within: {"role":"dialog"}` sem `name` para usar o único diálogo visível;
100
114
  o MCP ignora diálogos visualmente ocultos, inclusive os que ficaram no DOM
101
115
  com `opacity: 0`;
102
116
  - `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;
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;
104
122
  - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
105
123
  em `warnings`; não é permitido enviar JavaScript nem coordenadas;
106
124
  - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
@@ -108,8 +126,11 @@ Cada plano pode usar:
108
126
  `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
109
127
  valor apareça nas evidências. Nesse modo, `\n` envia Enter e `\t` envia Tab;
110
128
  - `wait_for_text` e `wait_for_condition` (`network_idle`, `hidden` ou
111
- `text_hidden`); `network_idle` aceita `url_contains` para aguardar só as
112
- requisições correspondentes;
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;
113
134
  - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
114
135
  `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
115
136
  envia a tecla ao elemento focado; com alvo, usa o localizador informado;
@@ -122,6 +143,58 @@ Cada plano pode usar:
122
143
  não repetem uma reação já no estado pedido e distinguem `Curtir` de
123
144
  `Descurtir`.
124
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
+
125
198
  Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
126
199
  localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
127
200
  aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
@@ -158,9 +231,14 @@ Exemplos para controles legados sem nome acessível:
158
231
  {"action":"click","selector":"#save-document"}
159
232
  ```
160
233
 
161
- O reconhecimento retorna `unnamed_controls` com papel, posição, rótulo mais
162
- próximo e um trecho HTML sanitizado dos controles interativos sem nome. O
163
- snapshot também resume campos de formulário com `id`, `name`, valor, estado
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
164
242
  desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
165
243
  sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
166
244
  é `false` por padrão; defina `true` somente quando precisar inspecionar campos
@@ -321,8 +399,16 @@ esse resultado e `expected_outcome_visible` continua descrevendo somente o
321
399
  texto global. `incomplete` significa que nenhum critério foi comprovado;
322
400
  confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
323
401
  espera da SPA; `warnings` registra capturas vazias durante transições; e
324
- `failed_step` identifica índice, ação, alvo, timeout e erro resumido quando uma
325
- etapa falha.
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`.
326
412
 
327
413
  `jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
328
414
  seletores e condições. `JEV_BROWSER_UPLOAD_ROOT` libera uploads somente dentro
@@ -342,7 +428,8 @@ O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
342
428
  `block_trackers`, `capture_console_errors`, `capture_network_errors`,
343
429
  `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
344
430
  `ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
345
- `trace_on_failure`, `snapshot_include_hidden` e `stop_on_expected`. Sem override,
431
+ `trace_on_failure`, `snapshot_include_hidden`, `stop_on_expected`, `dry_run` e
432
+ `report_path`. Sem override,
346
433
  os padrões são lidos de `jev_browser_mcp` em
347
434
  `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
348
435
  captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
@@ -370,7 +457,21 @@ com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
370
457
  `~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
371
458
  substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
372
459
  conter dados visíveis da aplicação: mantenha o diretório local protegido e
373
- compartilhe os arquivos somente se o teste permitir.
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.
374
475
 
375
476
  `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
376
477
  `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;
@@ -17,7 +17,7 @@ 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.5.0"],
21
21
  "env": {
22
22
  "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}",
23
23
  "JEV_BROWSER_MODE": "computer"
@@ -35,6 +35,18 @@ de configuração. Para instalar no projeto Node do próprio harness:
35
35
  npm install @diegosouzacdv/jev-browser-mcp
36
36
  ```
37
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
+
38
50
  O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
39
51
  configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
40
52
  pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp --install-browser`.
@@ -95,12 +107,18 @@ Cada plano pode usar:
95
107
  papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
96
108
  `text`, `test_id` ou `selector`;
97
109
  - `near: {"text":"..."}` para localizar o controle logo depois de um texto,
98
- e `within: {"row_containing":"..."}` para limitar a ação à linha certa;
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`;
99
113
  - `within: {"role":"dialog"}` sem `name` para usar o único diálogo visível;
100
114
  o MCP ignora diálogos visualmente ocultos, inclusive os que ficaram no DOM
101
115
  com `opacity: 0`;
102
116
  - `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;
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;
104
122
  - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
105
123
  em `warnings`; não é permitido enviar JavaScript nem coordenadas;
106
124
  - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
@@ -108,8 +126,11 @@ Cada plano pode usar:
108
126
  `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
109
127
  valor apareça nas evidências. Nesse modo, `\n` envia Enter e `\t` envia Tab;
110
128
  - `wait_for_text` e `wait_for_condition` (`network_idle`, `hidden` ou
111
- `text_hidden`); `network_idle` aceita `url_contains` para aguardar só as
112
- requisições correspondentes;
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;
113
134
  - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
114
135
  `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
115
136
  envia a tecla ao elemento focado; com alvo, usa o localizador informado;
@@ -122,6 +143,58 @@ Cada plano pode usar:
122
143
  não repetem uma reação já no estado pedido e distinguem `Curtir` de
123
144
  `Descurtir`.
124
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
+
125
198
  Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
126
199
  localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
127
200
  aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
@@ -158,9 +231,14 @@ Exemplos para controles legados sem nome acessível:
158
231
  {"action":"click","selector":"#save-document"}
159
232
  ```
160
233
 
161
- O reconhecimento retorna `unnamed_controls` com papel, posição, rótulo mais
162
- próximo e um trecho HTML sanitizado dos controles interativos sem nome. O
163
- snapshot também resume campos de formulário com `id`, `name`, valor, estado
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
164
242
  desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
165
243
  sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
166
244
  é `false` por padrão; defina `true` somente quando precisar inspecionar campos
@@ -321,8 +399,16 @@ esse resultado e `expected_outcome_visible` continua descrevendo somente o
321
399
  texto global. `incomplete` significa que nenhum critério foi comprovado;
322
400
  confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
323
401
  espera da SPA; `warnings` registra capturas vazias durante transições; e
324
- `failed_step` identifica índice, ação, alvo, timeout e erro resumido quando uma
325
- etapa falha.
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`.
326
412
 
327
413
  `jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
328
414
  seletores e condições. `JEV_BROWSER_UPLOAD_ROOT` libera uploads somente dentro
@@ -342,7 +428,8 @@ O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
342
428
  `block_trackers`, `capture_console_errors`, `capture_network_errors`,
343
429
  `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
344
430
  `ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
345
- `trace_on_failure`, `snapshot_include_hidden` e `stop_on_expected`. Sem override,
431
+ `trace_on_failure`, `snapshot_include_hidden`, `stop_on_expected`, `dry_run` e
432
+ `report_path`. Sem override,
346
433
  os padrões são lidos de `jev_browser_mcp` em
347
434
  `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
348
435
  captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
@@ -370,7 +457,21 @@ com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
370
457
  `~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
371
458
  substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
372
459
  conter dados visíveis da aplicação: mantenha o diretório local protegido e
373
- compartilhe os arquivos somente se o teste permitir.
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.
374
475
 
375
476
  `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
376
477
  `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;