@diegosouzacdv/jev-browser-mcp 0.6.2 → 0.7.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.6.2"],
20
+ "args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.7.0"],
21
21
  "env": {
22
22
  "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}",
23
23
  "JEV_BROWSER_MODE": "computer"
@@ -32,7 +32,7 @@ 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
34
  ```sh
35
- npm install @diegosouzacdv/jev-browser-mcp@0.6.2
35
+ npm install @diegosouzacdv/jev-browser-mcp@0.7.0
36
36
  ```
37
37
 
38
38
  Se o harness executa o MCP repetidamente nesta máquina, instale uma versão
@@ -40,7 +40,7 @@ fixa globalmente para evitar a resolução e o download feitos pelo `npx` em cad
40
40
  inicialização:
41
41
 
42
42
  ```sh
43
- npm install --global @diegosouzacdv/jev-browser-mcp@0.6.2
43
+ npm install --global @diegosouzacdv/jev-browser-mcp@0.7.0
44
44
  ```
45
45
 
46
46
  Depois configure o servidor MCP com `command: "jev-browser-mcp"` e `args: []`.
@@ -49,14 +49,23 @@ Para atualizar, rode `npm install --global
49
49
 
50
50
  O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
51
51
  configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
52
- pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.6.2 --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
- `JEV_BROWSER_PROFILE`. O browser permanece aquecido enquanto o processo MCP
59
- estiver ativo e fecha quando o harness encerra o processo. `JEV_PROVIDER_URL`
52
+ pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.7.0 --install-browser`.
53
+
54
+ O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
55
+ persistente exclusivo por processo MCP em `browser.computer_user_data_dir`. O
56
+ template aceita `{browser}` e `{session}`; por padrão, `{session}` é `pid-<PID>`.
57
+ Use um `JEV_BROWSER_SESSION_ID` único por instância para manter um nome estável
58
+ entre reinicializações. Um
59
+ `JEV_BROWSER_PROFILE` explícito também recebe o sufixo da sessão, a menos que o
60
+ caminho contenha `{session}`. Assim, processos MCP independentes não disputam o
61
+ mesmo perfil. Clientes conectados ao mesmo processo MCP compartilham a sessão;
62
+ para isolamento entre harnesses, execute uma instância por sessão. No modo
63
+ `harness`, a instalação baixa uma vez o Chrome/Edge que o Playwright controlará.
64
+ Personalize as escolhas com `JEV_BROWSER_MODE`, `JEV_BROWSER_CHANNEL` e
65
+ `JEV_BROWSER_PROFILE`. Sem um ID estável, o perfil é específico do processo e
66
+ uma reinicialização começa outra sessão. O browser permanece aquecido enquanto
67
+ o processo MCP estiver ativo e fecha quando o harness encerra o processo.
68
+ `JEV_PROVIDER_URL`
60
69
  e `JEV_MODEL` podem substituir os valores centrais; a credencial continua no
61
70
  nome de variável declarado em `jev.credential_env`.
62
71
 
@@ -76,8 +85,12 @@ publicada.
76
85
 
77
86
  ### Contrato do pacote
78
87
 
79
- O executável oferece `browser_health`, `choose_next_action` e `run_browser_flow`, mantém uma
80
- sessão do browser por processo e reutiliza essa sessão entre chamadas. O plano
88
+ O executável oferece `browser_health`, `describe_actions`, `choose_next_action`
89
+ e `run_browser_flow`, mantém uma sessão do browser por processo e reutiliza
90
+ essa sessão entre chamadas. `browser_health` informa versão, sessão e
91
+ capacidades; `describe_actions` publica o schema atual das ações, opções,
92
+ aliases e placeholders. Consulte essas ferramentas antes de construir um plano
93
+ para evitar nomes de campos desatualizados. O plano
81
94
  passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
82
95
  hover, espera, teclas aprovadas, asserções por elemento, upload restrito a uma
83
96
  raiz local configurada e reações idempotentes a um comentário único. Também
@@ -112,9 +125,14 @@ Cada plano pode usar:
112
125
  - `navigate` para mudar de página no meio do fluxo. Com a continuidade ligada,
113
126
  um `initial_url` de mesma origem diferente da URL ativa produz erro claro; use
114
127
  `navigate` ou `continue_from_current_page: false` para escolher o destino;
115
- - `click`, `type`, `clear`, `hover`, `select_option`, `press`, `assert_*` e upload com
116
- papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
117
- `text`, `test_id` ou `selector`;
128
+ - `click`, `check`, `uncheck`, `type`, `clear`, `hover`, `select_option`,
129
+ `press` e `assert_*` aceitam papel/nome acessível ou localizadores como
130
+ `label`, `placeholder`, `title`, `text`, `test_id` e `selector`;
131
+ - `screenshot` e `clear_storage` atuam na página/contexto atual; `upload_file`
132
+ recebe o arquivo e o alvo de upload. Os limites e formatos estão descritos nas
133
+ seções de evidências e upload;
134
+ - `navigate_menu` para percorrer uma sequência de rótulos de menu; veja a seção
135
+ de navegação de menus para o formato e as opções;
118
136
  - `name_match: "exact" | "contains" | "regex"` para controlar a comparação do
119
137
  nome acessível; regex rejeita construções com backtracking excessivo. O papel
120
138
  `switch` funciona em cliques, verificações e asserções;
@@ -131,8 +149,11 @@ Cada plano pode usar:
131
149
  espaços/glyphs de uso privado, como ícones Font Awesome; controles
132
150
  desabilitados não aparecem no diagnóstico, mas continuam contando para que o
133
151
  índice aponte ao controle correto;
134
- - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
135
- em `warnings`; não é permitido enviar JavaScript nem coordenadas;
152
+ - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
153
+ em `warnings`; não é permitido enviar JavaScript nem coordenadas;
154
+ - quando `click` falha porque o alvo está fora da viewport ou não está visível,
155
+ o MCP tenta rolar o alvo até a tela; se isso não bastar, tenta focar o controle
156
+ e enviar `Enter`, sem repetir cegamente o clique;
136
157
  - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
137
158
  - `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
138
159
  `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
@@ -140,7 +161,7 @@ Cada plano pode usar:
140
161
  de ambiente do processo MCP, sem colocá-lo no plano. Nesse modo, `\n` envia
141
162
  Enter e `\t` envia Tab;
142
163
  - `wait_for_text`, `wait_for_value`, `wait_for_enabled` e `wait_for_condition`
143
- (`url`, `network_idle`, `hidden`, `text_hidden` ou `angular_idle`). `wait` recebe
164
+ (`url`, `network_idle`, `hidden` ou `angular_idle`). `wait` recebe
144
165
  `ms` para uma pausa curta e limitada. `angular_idle` aguarda requisições
145
166
  `$http` e digest do AngularJS. `wait_for_text` aceita `fail_on: {"role":"alert"}` para
146
167
  interromper a espera assim que um alerta visível aparecer e incluir seu texto
@@ -150,10 +171,34 @@ Cada plano pode usar:
150
171
  `ready_stable_ms`; WebSocket, EventSource e polling não relacionado não
151
172
  bloqueiam a espera. Se não surgir requisição correspondente, o passo conclui
152
173
  após a janela de silêncio;
174
+ - `assert_network` valida resposta HTTP observada (inclusive sucesso 2xx ou erro
175
+ esperado); `wait_for_request` aguarda uma resposta usando `*` como curinga na
176
+ URL e filtros opcionais de método/status; `assert_ws` confere texto, pares
177
+ JSON esperados ou código de fechamento de WebSocket;
178
+ - `evaluate` lê somente caminhos de propriedades como `navigator.mediaDevices`,
179
+ `document.readyState` ou `location.pathname`. Não aceita código, chamadas de
180
+ função, armazenamento local ou propriedades de credenciais. Strings e números
181
+ voltam diretamente; objetos e arrays retornam somente tipo, chaves e tamanho,
182
+ sem despejar seus valores;
183
+ - `new_tab`, `switch_tab` e `new_context` abrem/selecionam abas e criam contexto
184
+ separado dentro do fluxo; `target_page: "popup"` mantém popups abertos para
185
+ passos posteriores;
186
+ - `if_visible` em um clique torna a ação condicional e
187
+ `when: {"visible":"..."}` em cada plano limita as opções do Jev às que
188
+ correspondem à tela atual;
189
+ - `fill` é alias de `type`, `press_key` de `press`, `duration_ms` de `wait.ms` e
190
+ `value` de campos de texto. `timeout_ms` funciona por etapa. Placeholders usam
191
+ `{nome}`; referências desconhecidas e `{{nome}}` são recusadas antes da
192
+ navegação;
153
193
  - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
154
194
  `Home`, `End`, setas, `Enter`, `Escape`, `Tab`, `Shift+Tab`, `Space`,
155
195
  `Backspace` ou `Delete`. `clear` limpa um campo sem exigir texto. Sem alvo,
156
196
  `press` envia a tecla ao elemento focado; com alvo, usa o localizador informado;
197
+ - `screenshot` grava uma imagem local; `full_page: true` inclui a página inteira.
198
+ Também é possível pedir uma captura após qualquer etapa com `screenshot: true`;
199
+ - `clear_storage` limpa cookies, local/session storage, IndexedDB, Cache Storage
200
+ e service workers do contexto atual. Como opção de fluxo,
201
+ `options.clear_storage: true` também recarrega a página antes do snapshot inicial;
157
202
  - `assert_text`, `assert_value`, `assert_visible`, `assert_hidden` e
158
203
  `assert_enabled`; `assert_text`
159
204
  pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
@@ -169,19 +214,25 @@ Cada plano pode usar:
169
214
 
170
215
  As proteções e evidências por etapa usam estes campos:
171
216
 
172
- - `confirm_dialog` recebe `expected_text` e `button`. Em diálogos HTML, o MCP
173
- confere o texto antes de localizar e clicar no botão. Também trata diálogos
174
- nativos `alert`/`confirm`: precisa haver uma etapa `confirm_dialog` logo após
175
- o clique que os abre, o texto deve corresponder e um diálogo inesperado é
176
- fechado sem aceitar;
177
- - `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
217
+ - `confirm_dialog` recebe `expected_text` e `button`. Em diálogos HTML, o MCP
218
+ confere o texto antes de localizar e clicar no botão. Também trata diálogos
219
+ nativos `alert`/`confirm`: precisa haver uma etapa `confirm_dialog` logo após
220
+ o clique que os abre, o texto deve corresponder e um diálogo inesperado é
221
+ fechado sem aceitar;
222
+ - `confirm_modal` combina o clique no gatilho, a conferência do texto e o clique
223
+ afirmativo em uma única etapa protegida. Também aceita os aliases
224
+ `trigger`/`confirm`, por exemplo
225
+ `{"action":"confirm_modal","trigger":"Salvar","expected_text":"Confirma a alteração?","confirm":"OK"}`;
226
+ - `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
178
227
  O MCP também classifica botões conhecidos como `Salvar`, `Emitir`, `Cancelar`
179
228
  ou `Sim` pelo nome e pelo controle resolvido, inclusive quando o plano usa um
180
229
  seletor CSS. `options.dry_run: true` executa até a primeira etapa mutável e
181
230
  para antes dela; retorna `dry_run_stopped_before_step` e um
182
- `confirmation_token` temporário, de uso único e vinculado ao fluxo e à página.
183
- Reenvie a mesma chamada com `options.confirmation_token` para autorizar essa
184
- etapa. O MCP pausa novamente antes de cada outra etapa mutável. Sem `dry_run`,
231
+ `confirmation_token` temporário, de uso único e vinculado ao fluxo e à página.
232
+ Reenvie a mesma chamada com `options.confirmation_token` para retomar no passo
233
+ pausado sem repetir os passos anteriores; o MCP confere a rota e o alvo da
234
+ mutação antes de executá-la. Ele pausa novamente antes de cada outra etapa
235
+ mutável. Sem `dry_run`,
185
236
  o primeiro pedido de ação mutável também retorna `status: "confirmation_required"`
186
237
  e token; nenhuma etapa mutável roda sem essa autorização. O token expira após
187
238
  dez minutos por padrão;
@@ -217,9 +268,23 @@ incluindo respostas 2xx ou erros esperados como 404. Exemplo:
217
268
  }
218
269
  ```
219
270
 
220
- Essa asserção aparece na evidência como `response_status`, separado do campo
221
- `status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
222
- da mesma origem e respeita o limite configurado para captura de corpos.
271
+ Essa asserção aparece na evidência como `response_status`, separado do campo
272
+ `status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
273
+ da mesma origem e respeita o limite configurado para captura de corpos.
274
+ `assert_network`, `wait_for_request` e `expected_outcome.request` consultam o
275
+ histórico limitado de respostas depois do marcador da etapa ou do início do
276
+ fluxo. O limite vem de `jev_browser_mcp.browser.max_network_history_events` e
277
+ está em 4096 eventos nesta configuração; assim, chamadas anteriores ao marcador
278
+ não satisfazem a asserção.
279
+
280
+ Para aguardar a API antes de abrir a interface, passe
281
+ `options.wait_for_http: {"url":"http://localhost:8000/health","timeout_ms":30000}`.
282
+ Também aceita apenas a URL como string ou `{ "url": "...", "timeout_seconds": 30 }`.
283
+ O probe faz GET e tenta novamente até o limite; qualquer resposta abaixo de 500
284
+ indica que o servidor respondeu (inclusive 4xx), enquanto 5xx e erros de conexão
285
+ são repetidos. Ao expirar, `reason` inclui a última causa. Por segurança, a URL
286
+ precisa ser loopback ou usar o mesmo host de `initial_url`; isso permite, por
287
+ exemplo, Vite em `localhost:5173` e API em `localhost:8000`.
223
288
 
224
289
  Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
225
290
  com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
@@ -227,8 +292,10 @@ com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
227
292
  A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
228
293
 
229
294
  Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
230
- localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
231
- aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
295
+ localizadores, `near` ou `within`; para esperar texto desaparecer, use
296
+ `{"condition":"hidden","text":"Carregando..."}`. Para esperar que texto suma
297
+ antes do primeiro passo, use `options.ready: {"hidden_text":"Carregando..."}`.
298
+ Para aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
232
299
  `url_contains`. O filtro considera somente a atividade correspondente e termina
233
300
  após a janela configurada sem atividade; também termina caso nenhuma requisição
234
301
  correspondente apareça. Para validar status e corpo, prefira `assert_network`.
@@ -239,7 +306,7 @@ ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
239
306
  um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
240
307
  controle próximo ao texto visível do rótulo.
241
308
 
242
- `within` pode combinar um container e uma linha. Use, por exemplo,
309
+ `within` pode combinar um container e uma linha. Use, por exemplo,
243
310
  `{"role":"cell","name":"Documento A","within":{"role":"table","row_containing_word":"1528721"}}`.
244
311
  `row_containing_word` usa limites de palavra para não confundir `1528721` com
245
312
  `15287210`; `row_containing_exact` continua disponível para texto de célula
@@ -274,13 +341,14 @@ Exemplos para controles legados sem nome acessível:
274
341
  {"action":"click","selector":"#save-document"}
275
342
  ```
276
343
 
277
- O reconhecimento retorna `unnamed_controls_initial` e
278
- `unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
279
- mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
280
- sem nome. Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode
281
- de uso privado (como ícones Font Awesome) entram nessa lista e podem ser
282
- selecionados com `name: ""` e o mesmo índice. `unnamed_controls` continua
283
- disponível como alias da lista final. O placeholder conta como nome acessível.
344
+ Por padrão, controles sem nome não são devolvidos em listas separadas. Defina
345
+ `options.include_unnamed_controls: true` para receber
346
+ `unnamed_controls_initial` e `unnamed_controls_final`, cada uma com papel,
347
+ índice Playwright por papel, rótulo mais próximo e um trecho HTML sanitizado.
348
+ Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode de uso
349
+ privado (como ícones Font Awesome) entram nessa lista e podem ser selecionados
350
+ com `name: ""` e o mesmo índice. O alias redundante `unnamed_controls` foi
351
+ removido. O placeholder conta como nome acessível.
284
352
  O snapshot também resume campos de formulário com `id`, `name`, valor, estado
285
353
  desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
286
354
  sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
@@ -291,10 +359,14 @@ Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
291
359
  localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
292
360
  `textbox`, `searchbox` ou `combobox`.
293
361
 
294
- Por padrão, o MCP executa todos os passos antes de avaliar `expected_outcome`.
295
- Valores dentro de campos não contam como resultado visível. `stop_on_expected:
296
- true` habilita parada antecipada quando o texto esperado aparece fora dos
297
- campos; mantenha `false` para fluxos com várias etapas.
362
+ Por padrão, o MCP executa todos os passos antes de avaliar os critérios.
363
+ `expected_outcome` aceita texto descritivo ou uma asserção estruturada, por
364
+ exemplo `{"text":"Tecnologia atualizada com sucesso."}` ou
365
+ `{"request":"PUT */api/tecnologia","status":200}`. A forma estruturada pode
366
+ incluir `message_contains` e reprova se a resposta correspondente não for
367
+ observada. Valores dentro de campos não contam como texto visível.
368
+ `stop_on_expected: true` habilita parada antecipada quando o texto esperado
369
+ aparece fora dos campos; mantenha `false` para fluxos com várias etapas.
298
370
 
299
371
  Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
300
372
  de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
@@ -330,11 +402,13 @@ verificar:
330
402
  {"action":"audit_accessibility","standard":"wcag2aa"}
331
403
  ```
332
404
 
333
- O MCP usa `@axe-core/playwright` com as tags WCAG 2.0 e 2.1 A/AA. O retorno
334
- resume as violações por regra, impacto e quantidade de nós, sem copiar HTML ou
335
- trechos da página. Qualquer violação reprova esse fluxo. A auditoria automática
336
- encontra problemas comuns, mas não comprova conformidade WCAG completa; combine-a
337
- com revisão manual e testes com usuários assistivos.
405
+ O MCP usa `@axe-core/playwright` com as tags WCAG 2.0 e 2.1 A/AA. O retorno
406
+ resume as violações por regra, impacto e quantidade de nós, sem copiar HTML ou
407
+ trechos da página. A etapa falha quando encontra violações no impacto definido
408
+ por `fail_on_impact`; o padrão é `minor`, e níveis abaixo do limite são relatados
409
+ sem bloquear o fluxo. A auditoria automática encontra problemas comuns, mas não
410
+ comprova conformidade WCAG completa; combine-a com revisão manual e testes com
411
+ usuários assistivos.
338
412
 
339
413
  Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
340
414
  corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
@@ -431,25 +505,63 @@ validadores.
431
505
  harness e CI. O processo MCP conserva browser, contexto e página entre
432
506
  chamadas; cookies, local storage e estado da página permanecem enquanto o
433
507
  processo estiver ativo. Encerre o processo para descartar o contexto isolado.
434
- - `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
435
- persistente `browser.computer_user_data_dir`, separado por navegador. Não
436
- reutiliza o perfil pessoal já aberto. Faça login uma vez nesse perfil; os
437
- cookies permanecem nele entre chamadas.
508
+ - `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
509
+ persistente `browser.computer_user_data_dir`, separado por navegador e por
510
+ processo MCP. Não
511
+ reutiliza o perfil pessoal já aberto. Faça login uma vez nesse perfil; os
512
+ cookies permanecem nele entre chamadas.
513
+
514
+ `fresh_context: true` abre um contexto descartável, sem cookies nem storage do
515
+ perfil persistente; requer `initial_url` e fecha esse contexto ao terminar. Use
516
+ `clear_storage: true` para limpar cookies, local/session storage, IndexedDB,
517
+ Cache Storage e service workers antes de recarregar a página atual. Para salvar
518
+ e reutilizar o estado de autenticação de uma conta de teste, use um nome simples
519
+ em `storage_state`:
520
+
521
+ ```json
522
+ {"options":{"storage_state":"aluno-a"}}
523
+ ```
524
+
525
+ O estado fica em `storage-state/<nome>.json` dentro da pasta de artefatos, com
526
+ permissões restritas no sistema operacional; não use uma conta real nem
527
+ compartilhe esse arquivo. `storage_state` não pode ser combinado com
528
+ `fresh_context` ou `clear_storage`.
438
529
 
439
530
  `browser.max_flow_steps` limita os passos de cada plano candidato; os planos
440
- não são somados. `browser.max_text_entry_chars` limita cada valor digitado. O resultado contém
441
- `status`, o plano escolhido, as ações executadas, a última captura acessível e
442
- se o critério esperado apareceu. Quando existem asserções explícitas, `status`
443
- também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
444
- esse resultado e `expected_outcome_visible` continua descrevendo somente o
445
- texto global. `incomplete` significa que nenhum critério foi comprovado;
446
- confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
447
- espera da SPA; `warnings` registra capturas vazias durante transições; e
448
- `failed_step` identifica índice, ação, localizador, timeout e erro resumido
449
- quando uma etapa falha. Cada etapa executada também registra a composição do
450
- localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel,
451
- nome acessível, `title` casado e `href` sanitizado do elemento resolvido.
452
- Etapas `type` só incluem o valor final do campo quando `sensitive: false`.
531
+ não são somados. `browser.max_text_entry_chars` limita cada valor digitado. O
532
+ resultado contém `status`, o plano escolhido, as ações executadas, a última
533
+ captura acessível e se o texto descritivo esperado apareceu. `expected_outcome`
534
+ como string é descrição, não uma asserção: `expected_outcome_visible` é
535
+ informado separadamente, e um plano concluído pode passar mesmo se a frase não
536
+ estiver visível. Use `{ "text": "..." }` ou
537
+ `{ "request": "...", "status": 200 }` para exigir uma condição; as
538
+ verificações ficam em `expected_outcome_checks`, e uma condição não satisfeita
539
+ reprova o fluxo. As asserções `assert_*`, auditorias de acessibilidade e
540
+ downloads também aparecem em campos próprios do resultado.
541
+
542
+ Os status do fluxo incluem `passed`, `failed`, `incomplete`, `environment_error`,
543
+ `dry_run` e `confirmation_required`. O fluxo fica `passed` se não houve falha ou
544
+ pausa de mutação e o texto esperado apareceu, uma asserção/auditoria/download
545
+ passou ou todas as etapas do plano foram executadas. `incomplete` é devolvido
546
+ quando nenhuma dessas condições se aplica; confiança do Jev, sozinha, não
547
+ comprova o resultado. `environment_error` identifica falha de
548
+ navegação, autenticação ou sessão do browser; `navigation_error` contém o código
549
+ detectado, como `ERR_CONNECTION_REFUSED`, `AUTHENTICATION_REQUIRED` ou
550
+ `BROWSER_DISCONNECTED`, e `reason` orienta a recuperação. Se uma navegação falhar
551
+ e a chamada seguinte tentar reutilizar a página, o MCP informa que a navegação
552
+ anterior não carregou; reinicie a navegação com
553
+ `continue_from_current_page: false` (ou o alias `reuse_page: false`). Uma sessão
554
+ desconectada pode ser reaberta por `browser_health`; o fluxo só é repetido
555
+ automaticamente uma vez se nenhuma etapa mutável tiver sido executada.
556
+
557
+ `current_url` é devolvido para diagnóstico sem query string nem fragmento; IDs
558
+ longos no caminho também podem ser redigidos. `timings_ms.ready_ms` mede a espera
559
+ da SPA; `warnings` registra capturas vazias durante transições; e `failed_step`
560
+ identifica índice, ação, localizador, timeout e erro resumido quando uma etapa
561
+ falha. Cada etapa executada também registra a composição do localizador usado
562
+ e, quando disponível, `resolved_target` com tag, `id`, papel, nome acessível,
563
+ `title` casado e `href` sanitizado do elemento resolvido. Etapas `type` só
564
+ incluem o valor final do campo quando `sensitive: false`.
453
565
 
454
566
  Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
455
567
  origem são capturadas mesmo quando usam transferência chunked e não enviam
@@ -473,29 +585,34 @@ continua informada mesmo quando a lista é truncada.
473
585
  O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
474
586
  `block_trackers`, `block_fonts`, `local_only`, `busy_selectors`,
475
587
  `auto_angular_idle`, `login_url_contains`, `login_text`, `capture_console_errors`,
476
- `capture_network_errors`, `capture_network_error_bodies`, `ready_timeout_seconds`,
477
- `ready_network_idle`, `ready_stable_ms`, `ready_text`, `continue_from_current_page`,
478
- `reuse_page`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
588
+ `capture_network_errors`, `capture_network_error_bodies`, `ready_timeout_seconds`,
589
+ `ready_network_idle`, `ready_stable_ms`, `ready_text`, `ready`, `continue_from_current_page`,
590
+ `reuse_page`, `reuse_page_match`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
479
591
  `screenshot_on_failure`, `screenshot_on_success`, `trace_on_failure`,
480
- `trace_on_success`, `record_video`, `snapshot_include_hidden`, `stop_on_expected`,
592
+ `trace_on_success`, `record_video`, `snapshot_include_hidden`, `include_unnamed_controls`, `stop_on_expected`,
481
593
  `dry_run`, `confirmation_token`, `report_path`, `permissions`, `fake_media`,
482
594
  `viewport`, `mobile`, `device_scale_factor`, `locale`, `timezone_id`,
483
- `color_scheme`, `geolocation` e `allow_mutations`. Sem override,
484
- os padrões são lidos de `jev_browser_mcp` em
485
- `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
486
- captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
487
- de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
488
- acrescentados ao snapshot. O browser espera a SPA renderizar uma captura
489
- acessível estável na navegação inicial. Depois, a continuidade fica ligada por
595
+ `color_scheme`, `geolocation`, `console_levels`, `fresh_context`,
596
+ `clear_storage`, `storage_state`, `wait_for_http` e `allow_mutations`. Sem override,
597
+ os padrões são lidos de `jev_browser_mcp` em
598
+ `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
599
+ captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
600
+ de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
601
+ acrescentados ao snapshot. `return_snapshot: "diff"` é o padrão, e as listas de
602
+ controles sem nome só aparecem com `include_unnamed_controls: true`. O browser
603
+ espera a SPA renderizar uma captura acessível estável na navegação inicial.
604
+ Depois, a continuidade fica ligada por
490
605
  padrão: `continue_from_current_page: true` mantém a página e seu estado entre
491
606
  chamadas na mesma origem, não repete `page.goto` e consulta um snapshot atual
492
607
  sem esperar novamente por `load`/`networkidle`. As etapas continuam aguardando
493
608
  seus próprios alvos e condições. `reuse_page` segue como alias legado; defina
494
609
  `continue_from_current_page: false` para iniciar cada chamada em `initial_url`.
495
610
  Se a página atual e `initial_url` tiverem origens diferentes, o MCP navega para
496
- `initial_url`. Se forem da mesma origem mas URLs completas diferentes, o MCP
497
- recusa continuar silenciosamente e pede uma etapa `navigate` ou
498
- `continue_from_current_page: false`. `snapshot_scope` aceita `body`, `main` ou
611
+ `initial_url`. URLs da mesma origem são comparadas após normalizar e ordenar a
612
+ query string. Se a rota normalizada diferir, o MCP pede uma etapa `navigate` ou
613
+ `continue_from_current_page: false`. `reuse_page_match: "path"` ignora a query;
614
+ um plano cuja primeira etapa seja `navigate` pode trocar a rota explicitamente.
615
+ `snapshot_scope` aceita `body`, `main` ou
499
616
  `dialog`; se `main` não existir, o snapshot usa `body`.
500
617
 
501
618
  `block_trackers: true` bloqueia analytics/trackers e os tipos de recurso
@@ -511,14 +628,27 @@ precisaria chamar o provedor Jev; use exatamente um plano com `fast_path: true`.
511
628
  `allow_mutations: true` pula a confirmação humana somente para URLs em
512
629
  `localhost`, `127.0.0.1` ou `::1`; use esse modo apenas em ambientes locais
513
630
  controlados.
514
- `step_timeout_seconds` define o timeout padrão por etapa e cada etapa pode
515
- substituí-lo com `timeout_seconds`. `max_flow_steps` reduz o limite por chamada,
516
- sem superar o teto da configuração. `return_snapshot` aceita `full`, `diff` ou
517
- `none`; `diff` retorna linhas acessíveis novas desde o snapshot inicial.
518
-
519
- Com `capture_console_errors` e `capture_network_errors`, o retorno traz
520
- `console_errors` e `network_failures`, limitados em quantidade e tamanho.
521
- Mensagens de erro idênticas do console são agrupadas em uma entrada com `count`.
631
+ `step_timeout_seconds` define o timeout padrão por etapa e cada etapa pode
632
+ substituí-lo com `timeout_seconds`. `max_flow_steps` reduz o limite por chamada,
633
+ sem superar o teto da configuração. `return_snapshot` aceita `diff`, `full` ou
634
+ `none`; `diff` retorna linhas acessíveis novas desde o snapshot inicial.
635
+
636
+ `options.ready` aguarda condições da aplicação antes do primeiro snapshot e da
637
+ seleção do plano. Aceita `"network_idle"`,
638
+ `{"hidden_text":"Aguarde."}` e `{"selector":"#cdTecnologia","has_value":true}`;
639
+ uma lista combina condições, e todas precisam passar. `has_value` aceita
640
+ `true` (valor não vazio), `false` (vazio) ou o valor textual exato.
641
+ `ready_text` também pode exigir uma frase no snapshot inicial;
642
+ `ready_network_idle: true` solicita uma espera best-effort por `networkidle`.
643
+ `ready_timeout_seconds` limita a espera de inicialização e `ready_stable_ms`
644
+ define a janela usada para considerar o snapshot estável.
645
+
646
+ `console_levels` aceita `log`, `info`, `debug`, `warn` e `error`. Com
647
+ `console_levels: ["log","warn","error"]` e `capture_network_errors`, o retorno
648
+ traz mensagens do console agrupadas por texto e nível (`console_messages` com
649
+ `count`), além de `console_errors` para compatibilidade. `network_failures`
650
+ contém eventos limitados em quantidade e tamanho. Mensagens idênticas do console
651
+ são agrupadas em uma entrada com `count`.
522
652
  Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
523
653
  fragmentos, valores de formulário e nomes de arquivo são removidos ou
524
654
  sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
@@ -552,15 +682,18 @@ Para testar microfone, conceda permissão no escopo da chamada:
552
682
  {
553
683
  "options": {
554
684
  "permissions": ["microphone"],
555
- "fake_media": "fixtures/resposta-aluno.wav",
685
+ "fake_media": {"audio":"fixtures/resposta-aluno.wav"},
556
686
  "block_trackers": true
557
687
  }
558
688
  }
559
689
  ```
560
690
 
561
- `fake_media` exige um WAV RIFF válido dentro de `JEV_BROWSER_UPLOAD_ROOT` e
562
- respeita os mesmos limites de upload. O MCP adiciona as opções de dispositivo
563
- falso do Chromium e concede permissão ao contexto. Sem esse arquivo, a
691
+ `fake_media` aceita tanto o caminho WAV direto quanto o objeto
692
+ `{"audio":"caminho.wav"}`. Exige um WAV RIFF válido dentro de
693
+ `JEV_BROWSER_UPLOAD_ROOT` e respeita os mesmos limites de upload. Ao informar
694
+ `fake_media`, o MCP concede automaticamente a permissão `microphone`, adiciona
695
+ as opções de dispositivo falso do Chromium e usa o arquivo como entrada de
696
+ áudio. Sem esse arquivo, a
564
697
  permissão de microfone usa o dispositivo autorizado pelo browser; no modo
565
698
  `computer`, o sistema operacional ainda pode pedir acesso ao dispositivo.
566
699
 
@@ -580,9 +713,10 @@ andamento, sem repetir o clique.
580
713
 
581
714
  Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
582
715
  identifica o PID que o mantém ocupado quando o sistema consegue associar o
583
- perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
584
- Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. Configure
585
- `JEV_BROWSER_PROFILE` com outro diretório absoluto para usar uma sessão isolada.
716
+ perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
717
+ Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. O caminho
718
+ padrão já separa processos por PID; configure `JEV_BROWSER_PROFILE` para mudar
719
+ a raiz e `JEV_BROWSER_SESSION_ID` para nomear a instância.
586
720
  Resultados MCP incluem `server_version`; erros também começam com a versão do
587
721
  servidor para facilitar a comparação entre instalações. A ferramenta
588
722
  `browser_health` informa se a sessão está ativa e tenta reconectar um browser
@@ -591,11 +725,50 @@ reiniciar somente o navegador administrado por este processo MCP. Um fluxo pode
591
725
  ser repetido automaticamente uma vez após `BROWSER_DISCONNECTED` quando nenhuma
592
726
  etapa mutável foi executada.
593
727
 
594
- `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
595
- `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;
596
- o diretório persistente armazena dados de login e é resolvido sob a pasta home
597
- do usuário quando começa com `~`. O Playwright MCP fica desabilitado até
598
- `ORQUESTRADOR_MCP_PLAYWRIGHT_ENABLED=1` ser configurado no ambiente do harness.
728
+ `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
729
+ `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}` e
730
+ `{session}`;
731
+ o diretório persistente armazena dados de login e é resolvido sob a pasta home
732
+ do usuário quando começa com `~`. O Playwright MCP fica desabilitado até
733
+ `ORQUESTRADOR_MCP_PLAYWRIGHT_ENABLED=1` ser configurado no ambiente do harness.
734
+
735
+ ## Preparar smoke autenticado local
736
+
737
+ O MCP não cria a identidade nem os dados do sistema testado. Para um smoke de
738
+ administração, suba a API e a UI locais, use um banco descartável com dados
739
+ fictícios e uma identidade OIDC de teste que tenha explicitamente a claim
740
+ `administrator`. Mantenha as regras de autorização de produção iguais; um token
741
+ de operador legado não deve ser promovido para admin só para fazer o smoke.
742
+
743
+ Faça o preflight nesta ordem:
744
+
745
+ 1. `browser_health` confirma a versão, o perfil/sessão e a conexão do navegador.
746
+ Se o perfil estiver ocupado, use outro `JEV_BROWSER_SESSION_ID` ou
747
+ `JEV_BROWSER_PROFILE`; não encerre o Chrome do operador.
748
+ 2. `options.wait_for_http` aguarda a API local responder antes de abrir a UI.
749
+ Informe a URL da interface em `initial_url` e a rota de health da API no
750
+ probe.
751
+ 3. `run_browser_flow` confirma que a tela administrativa esperada está visível
752
+ e que a identidade abriu com papel administrativo. Se aparecer a tela de
753
+ login, configure a conta de teste ou o provedor OIDC local; não copie o token
754
+ para `flow`, `params` ou logs. Use `text_env` para campos secretos.
755
+ 4. Valide primeiro uma prévia read-only com `assert_*`, `assert_network` e
756
+ captura de evidência. Para um fluxo que poderia gravar dados, use
757
+ `dry_run: true`; ele para antes da primeira etapa marcada como mutável.
758
+ 5. Só execute o passo de gravação em dados fictícios, depois de conferir o texto
759
+ do diálogo com `confirm_modal`/`confirm_dialog` e autorizar o token de
760
+ confirmação. Reinicializações de serviços e consultas diretas ao banco ficam
761
+ fora do smoke de tela.
762
+
763
+ Esse preflight é um roteiro composto por `browser_health`, `wait_for_http` e
764
+ asserções da própria aplicação; não há uma ferramenta genérica que valide a
765
+ claim OIDC `administrator`. A checagem do papel precisa usar um sinal visível ou
766
+ uma asserção específica do sistema consumidor.
767
+
768
+ Um `expected_outcome` descreve o objetivo; o resultado `passed` vem das
769
+ asserções explícitas ou da conclusão do plano. Verifique
770
+ `expected_outcome_visible` separadamente quando a frase global fizer parte do
771
+ critério do teste.
599
772
 
600
773
  Defina o valor secreto na variável indicada por `jev.credential_env`, usando o
601
774
  secret manager ou ambiente do processo que inicia o harness. Não grave a chave
@@ -639,10 +812,13 @@ valores dos controles são substituídos e hrefs têm query string e fragmento
639
812
  removidos; padrões de PII também são mascarados. Com fast-path, um plano não
640
813
  gera chamada remota. Os passos, valores digitados, valores esperados pelas
641
814
  asserções, caminhos e conteúdo dos arquivos não são enviados.
642
- Não inclua segredos em `flow`, `expected_outcome` ou nas descrições. A resposta
643
- retorna o plano escolhido quando houver decisão, custo/confiança do provedor
644
- quando disponíveis e o snapshot final sanitizado. O fluxo passa quando o texto
645
- esperado aparece no snapshot ou quando todas as asserções declaradas passam.
815
+ Não inclua segredos em `flow`, `expected_outcome` ou nas descrições. A resposta
816
+ retorna o plano escolhido quando houver decisão, custo/confiança do provedor
817
+ quando disponíveis e o snapshot final sanitizado. Um `expected_outcome` em
818
+ texto simples é descritivo: `expected_outcome_visible` indica separadamente se
819
+ a frase apareceu, e completar o plano pode resultar em `passed` mesmo que ela
820
+ não apareça. Use a forma estruturada para tornar texto ou resposta de rede uma
821
+ condição obrigatória; se ela não passar, o fluxo falha.
646
822
 
647
823
  `network_idle` é uma espera limitada e opcional. Polling e conexões contínuas
648
824
  não relacionadas a `url_contains` não bloqueiam o modo filtrado; prefira
@@ -5,7 +5,7 @@
5
5
  "harness_browser": "chrome",
6
6
  "playwright_mcp_package": "@playwright/mcp@0.0.79",
7
7
  "computer_browser": "chrome",
8
- "computer_user_data_dir": "~/.cache/orquestrador/jev-browser-{browser}",
8
+ "computer_user_data_dir": "~/.cache/orquestrador/jev-browser-{browser}-session-{session}",
9
9
  "max_flow_steps": 24,
10
10
  "max_text_entry_chars": 2000
11
11
  },
@@ -68,7 +68,7 @@
68
68
  "block_fonts_default": false,
69
69
  "local_only_default": false,
70
70
  "auto_angular_idle_default": false,
71
- "return_snapshot_default": "full",
71
+ "return_snapshot_default": "diff",
72
72
  "busy_selectors_default": [],
73
73
  "login_url_contains_default": ["/auth"],
74
74
  "login_text_default": [],