@diegosouzacdv/jev-browser-mcp 0.4.2 → 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,15 +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
117
  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;
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;
107
122
  - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
108
123
  em `warnings`; não é permitido enviar JavaScript nem coordenadas;
109
124
  - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
@@ -113,8 +128,9 @@ Cada plano pode usar:
113
128
  - `wait_for_text` e `wait_for_condition` (`network_idle`, `hidden` ou
114
129
  `text_hidden`). `wait_for_text` aceita `fail_on: {"role":"alert"}` para
115
130
  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;
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;
118
134
  - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
119
135
  `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
120
136
  envia a tecla ao elemento focado; com alvo, usa o localizador informado;
@@ -127,6 +143,58 @@ Cada plano pode usar:
127
143
  não repetem uma reação já no estado pedido e distinguem `Curtir` de
128
144
  `Descurtir`.
129
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
+
130
198
  Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
131
199
  localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
132
200
  aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
@@ -166,9 +234,11 @@ Exemplos para controles legados sem nome acessível:
166
234
  O reconhecimento retorna `unnamed_controls_initial` e
167
235
  `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
168
236
  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
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
172
242
  desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
173
243
  sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
174
244
  é `false` por padrão; defina `true` somente quando precisar inspecionar campos
@@ -331,9 +401,9 @@ confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede
331
401
  espera da SPA; `warnings` registra capturas vazias durante transições; e
332
402
  `failed_step` identifica índice, ação, localizador, timeout e erro resumido
333
403
  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`.
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`.
337
407
 
338
408
  Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
339
409
  origem são capturadas mesmo quando usam transferência chunked e não enviam
@@ -358,7 +428,8 @@ O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
358
428
  `block_trackers`, `capture_console_errors`, `capture_network_errors`,
359
429
  `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
360
430
  `ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
361
- `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,
362
433
  os padrões são lidos de `jev_browser_mcp` em
363
434
  `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
364
435
  captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
@@ -386,7 +457,21 @@ com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
386
457
  `~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
387
458
  substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
388
459
  conter dados visíveis da aplicação: mantenha o diretório local protegido e
389
- 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.
390
475
 
391
476
  `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
392
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,15 +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
117
  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;
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;
107
122
  - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
108
123
  em `warnings`; não é permitido enviar JavaScript nem coordenadas;
109
124
  - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
@@ -113,8 +128,9 @@ Cada plano pode usar:
113
128
  - `wait_for_text` e `wait_for_condition` (`network_idle`, `hidden` ou
114
129
  `text_hidden`). `wait_for_text` aceita `fail_on: {"role":"alert"}` para
115
130
  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;
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;
118
134
  - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
119
135
  `Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
120
136
  envia a tecla ao elemento focado; com alvo, usa o localizador informado;
@@ -127,6 +143,58 @@ Cada plano pode usar:
127
143
  não repetem uma reação já no estado pedido e distinguem `Curtir` de
128
144
  `Descurtir`.
129
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
+
130
198
  Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
131
199
  localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
132
200
  aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
@@ -166,9 +234,11 @@ Exemplos para controles legados sem nome acessível:
166
234
  O reconhecimento retorna `unnamed_controls_initial` e
167
235
  `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
168
236
  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
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
172
242
  desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
173
243
  sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
174
244
  é `false` por padrão; defina `true` somente quando precisar inspecionar campos
@@ -331,9 +401,9 @@ confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede
331
401
  espera da SPA; `warnings` registra capturas vazias durante transições; e
332
402
  `failed_step` identifica índice, ação, localizador, timeout e erro resumido
333
403
  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`.
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`.
337
407
 
338
408
  Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
339
409
  origem são capturadas mesmo quando usam transferência chunked e não enviam
@@ -358,7 +428,8 @@ O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
358
428
  `block_trackers`, `capture_console_errors`, `capture_network_errors`,
359
429
  `capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
360
430
  `ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
361
- `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,
362
433
  os padrões são lidos de `jev_browser_mcp` em
363
434
  `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
364
435
  captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
@@ -386,7 +457,21 @@ com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
386
457
  `~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
387
458
  substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
388
459
  conter dados visíveis da aplicação: mantenha o diretório local protegido e
389
- 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.
390
475
 
391
476
  `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
392
477
  `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;