@diegosouzacdv/jev-browser-mcp 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,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.1"],
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.1
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.1
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.1 --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,14 @@ 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, placeholders, campos obrigatórios de `flow`/plano e requisitos
93
+ condicionais por ação. `run_browser_flow` agrega campos obrigatórios ausentes
94
+ em todos os planos e etapas antes de abrir o navegador. Consulte essas ferramentas
95
+ antes de construir um plano para evitar nomes de campos desatualizados. O plano
81
96
  passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
82
97
  hover, espera, teclas aprovadas, asserções por elemento, upload restrito a uma
83
98
  raiz local configurada e reações idempotentes a um comentário único. Também
@@ -112,9 +127,14 @@ Cada plano pode usar:
112
127
  - `navigate` para mudar de página no meio do fluxo. Com a continuidade ligada,
113
128
  um `initial_url` de mesma origem diferente da URL ativa produz erro claro; use
114
129
  `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`;
130
+ - `click`, `check`, `uncheck`, `type`, `clear`, `hover`, `select_option`,
131
+ `press` e `assert_*` aceitam papel/nome acessível ou localizadores como
132
+ `label`, `placeholder`, `title`, `text`, `test_id` e `selector`;
133
+ - `screenshot` e `clear_storage` atuam na página/contexto atual; `upload_file`
134
+ recebe o arquivo e o alvo de upload. Os limites e formatos estão descritos nas
135
+ seções de evidências e upload;
136
+ - `navigate_menu` para percorrer uma sequência de rótulos de menu; veja a seção
137
+ de navegação de menus para o formato e as opções;
118
138
  - `name_match: "exact" | "contains" | "regex"` para controlar a comparação do
119
139
  nome acessível; regex rejeita construções com backtracking excessivo. O papel
120
140
  `switch` funciona em cliques, verificações e asserções;
@@ -131,8 +151,11 @@ Cada plano pode usar:
131
151
  espaços/glyphs de uso privado, como ícones Font Awesome; controles
132
152
  desabilitados não aparecem no diagnóstico, mas continuam contando para que o
133
153
  í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;
154
+ - `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
155
+ em `warnings`; não é permitido enviar JavaScript nem coordenadas;
156
+ - quando `click` falha porque o alvo está fora da viewport ou não está visível,
157
+ o MCP tenta rolar o alvo até a tela; se isso não bastar, tenta focar o controle
158
+ e enviar `Enter`, sem repetir cegamente o clique;
136
159
  - `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
137
160
  - `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
138
161
  `blur: true` para desfocar o campo e `sensitive: false` para permitir que o
@@ -140,7 +163,7 @@ Cada plano pode usar:
140
163
  de ambiente do processo MCP, sem colocá-lo no plano. Nesse modo, `\n` envia
141
164
  Enter e `\t` envia Tab;
142
165
  - `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
166
+ (`url`, `network_idle`, `hidden` ou `angular_idle`). `wait` recebe
144
167
  `ms` para uma pausa curta e limitada. `angular_idle` aguarda requisições
145
168
  `$http` e digest do AngularJS. `wait_for_text` aceita `fail_on: {"role":"alert"}` para
146
169
  interromper a espera assim que um alerta visível aparecer e incluir seu texto
@@ -150,10 +173,48 @@ Cada plano pode usar:
150
173
  `ready_stable_ms`; WebSocket, EventSource e polling não relacionado não
151
174
  bloqueiam a espera. Se não surgir requisição correspondente, o passo conclui
152
175
  após a janela de silêncio;
176
+ - `assert_network` valida resposta HTTP observada (inclusive sucesso 2xx ou erro
177
+ esperado); `wait_for_request` aguarda uma resposta usando `*` como curinga na
178
+ URL e filtros opcionais de método/status; `assert_ws` confere texto, pares
179
+ JSON esperados ou código de fechamento de WebSocket. `wait_for_request`
180
+ consulta o histórico desde o começo da chamada, inclusive requisições feitas
181
+ durante a navegação inicial e dentro de iframes; URLs cobertas por uma
182
+ asserção ficam retidas mesmo quando a SPA excede o buffer circular;
183
+ - `evaluate` lê somente caminhos de propriedades como `navigator.mediaDevices`,
184
+ `document.readyState` ou `location.pathname`. Não aceita código, chamadas de
185
+ função, armazenamento local ou propriedades de credenciais. Strings e números
186
+ voltam diretamente; objetos e arrays retornam somente tipo, chaves e tamanho,
187
+ sem despejar seus valores;
188
+ - `http_request` executa somente GET com a sessão da página; `inspect_cookies`
189
+ retorna apenas metadados e valores redigidos; `read_angular_state` devolve o
190
+ nome do estado e nomes dos parâmetros, sem valores. As três ações exigem
191
+ `local_only: true` e página em loopback. `http_request` fica restrito à mesma
192
+ origem, não segue redirecionamentos e limita/redige o corpo opcional;
193
+ - `frame: "first"` seleciona o primeiro iframe; `frame: {"url_contains":"..."}`
194
+ localiza um iframe pela URL. Uma string diferente continua buscando o nome ou
195
+ título exato do frame;
196
+ - `navigate_menu` aceita `path` para menus acessíveis ou `screen` para procurar
197
+ código/nome pela tela Acesso Rápido do SAFI. O segundo caminho usa a interface
198
+ do SAFI e preserva as verificações de acesso do próprio aplicativo;
199
+ - `new_tab`, `switch_tab` e `new_context` abrem/selecionam abas e criam contexto
200
+ separado dentro do fluxo; `target_page: "popup"` mantém popups abertos para
201
+ passos posteriores;
202
+ - `if_visible` em um clique torna a ação condicional e
203
+ `when: {"visible":"..."}` em cada plano limita as opções do Jev às que
204
+ correspondem à tela atual;
205
+ - `fill` é alias de `type`, `press_key` de `press`, `duration_ms` de `wait.ms` e
206
+ `value` de campos de texto. `timeout_ms` funciona por etapa. Placeholders usam
207
+ `{nome}`; referências desconhecidas e `{{nome}}` são recusadas antes da
208
+ navegação;
153
209
  - `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
154
210
  `Home`, `End`, setas, `Enter`, `Escape`, `Tab`, `Shift+Tab`, `Space`,
155
211
  `Backspace` ou `Delete`. `clear` limpa um campo sem exigir texto. Sem alvo,
156
212
  `press` envia a tecla ao elemento focado; com alvo, usa o localizador informado;
213
+ - `screenshot` grava uma imagem local; `full_page: true` inclui a página inteira.
214
+ Também é possível pedir uma captura após qualquer etapa com `screenshot: true`;
215
+ - `clear_storage` limpa cookies, local/session storage, IndexedDB, Cache Storage
216
+ e service workers do contexto atual. Como opção de fluxo,
217
+ `options.clear_storage: true` também recarrega a página antes do snapshot inicial;
157
218
  - `assert_text`, `assert_value`, `assert_visible`, `assert_hidden` e
158
219
  `assert_enabled`; `assert_text`
159
220
  pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
@@ -169,19 +230,25 @@ Cada plano pode usar:
169
230
 
170
231
  As proteções e evidências por etapa usam estes campos:
171
232
 
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.
233
+ - `confirm_dialog` recebe `expected_text` e `button`. Em diálogos HTML, o MCP
234
+ confere o texto antes de localizar e clicar no botão. Também trata diálogos
235
+ nativos `alert`/`confirm`: precisa haver uma etapa `confirm_dialog` logo após
236
+ o clique que os abre, o texto deve corresponder e um diálogo inesperado é
237
+ fechado sem aceitar;
238
+ - `confirm_modal` combina o clique no gatilho, a conferência do texto e o clique
239
+ afirmativo em uma única etapa protegida. Também aceita os aliases
240
+ `trigger`/`confirm`, por exemplo
241
+ `{"action":"confirm_modal","trigger":"Salvar","expected_text":"Confirma a alteração?","confirm":"OK"}`;
242
+ - `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
178
243
  O MCP também classifica botões conhecidos como `Salvar`, `Emitir`, `Cancelar`
179
244
  ou `Sim` pelo nome e pelo controle resolvido, inclusive quando o plano usa um
180
245
  seletor CSS. `options.dry_run: true` executa até a primeira etapa mutável e
181
246
  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`,
247
+ `confirmation_token` temporário, de uso único e vinculado ao fluxo e à página.
248
+ Reenvie a mesma chamada com `options.confirmation_token` para retomar no passo
249
+ pausado sem repetir os passos anteriores; o MCP confere a rota e o alvo da
250
+ mutação antes de executá-la. Ele pausa novamente antes de cada outra etapa
251
+ mutável. Sem `dry_run`,
185
252
  o primeiro pedido de ação mutável também retorna `status: "confirmation_required"`
186
253
  e token; nenhuma etapa mutável roda sem essa autorização. O token expira após
187
254
  dez minutos por padrão;
@@ -217,9 +284,34 @@ incluindo respostas 2xx ou erros esperados como 404. Exemplo:
217
284
  }
218
285
  ```
219
286
 
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.
287
+ Essa asserção aparece na evidência como `response_status`, separado do campo
288
+ `status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
289
+ da mesma origem e respeita o limite configurado para captura de corpos.
290
+ `assert_network` consulta respostas desde o marcador da etapa e usa a resposta
291
+ da navegação inicial como fallback quando nenhuma resposta posterior corresponde.
292
+ `wait_for_request` e `expected_outcome.request` consultam desde o início do fluxo.
293
+ URLs cobertas por uma asserção são retidas em um buffer separado limitado por
294
+ `jev_browser_mcp.browser.max_network_history_events` (4096 eventos nesta
295
+ configuração). A captura de página também observa requisições de iframes.
296
+ Um único plano `fast_path` composto apenas por `assert_network` e
297
+ `wait_for_request` não espera um snapshot visual, então endpoints que respondem
298
+ sem HTML também podem ser verificados. `navigation_http_status` registra um
299
+ status HTTP de erro recebido pela navegação inicial; ele não é uma falha de rede.
300
+
301
+ `options.capture_network: "all"` inclui até o limite de diagnóstico eventos
302
+ com URL sem query string, método, status, tipo de recurso, duração e cabeçalhos
303
+ de resposta de uma allowlist. `capture_network_url_contains` filtra as URLs.
304
+ Quando o Chromium informa cookies bloqueados, `blocked_cookies` mostra nome,
305
+ domínio, caminho, flags e motivo, sem revelar valores.
306
+
307
+ Para aguardar a API antes de abrir a interface, passe
308
+ `options.wait_for_http: {"url":"http://localhost:8000/health","timeout_ms":30000}`.
309
+ Também aceita apenas a URL como string ou `{ "url": "...", "timeout_seconds": 30 }`.
310
+ O probe faz GET e tenta novamente até o limite; qualquer resposta abaixo de 500
311
+ indica que o servidor respondeu (inclusive 4xx), enquanto 5xx e erros de conexão
312
+ são repetidos. Ao expirar, `reason` inclui a última causa. Por segurança, a URL
313
+ precisa ser loopback ou usar o mesmo host de `initial_url`; isso permite, por
314
+ exemplo, Vite em `localhost:5173` e API em `localhost:8000`.
223
315
 
224
316
  Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
225
317
  com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
@@ -227,8 +319,10 @@ com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
227
319
  A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
228
320
 
229
321
  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
322
+ localizadores, `near` ou `within`; para esperar texto desaparecer, use
323
+ `{"condition":"hidden","text":"Carregando..."}`. Para esperar que texto suma
324
+ antes do primeiro passo, use `options.ready: {"hidden_text":"Carregando..."}`.
325
+ Para aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
232
326
  `url_contains`. O filtro considera somente a atividade correspondente e termina
233
327
  após a janela configurada sem atividade; também termina caso nenhuma requisição
234
328
  correspondente apareça. Para validar status e corpo, prefira `assert_network`.
@@ -239,16 +333,44 @@ ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
239
333
  um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
240
334
  controle próximo ao texto visível do rótulo.
241
335
 
242
- `within` pode combinar um container e uma linha. Use, por exemplo,
336
+ `within` pode combinar um container e uma linha. Use, por exemplo,
243
337
  `{"role":"cell","name":"Documento A","within":{"role":"table","row_containing_word":"1528721"}}`.
244
338
  `row_containing_word` usa limites de palavra para não confundir `1528721` com
245
339
  `15287210`; `row_containing_exact` continua disponível para texto de célula
246
340
  exato. `check` e `uncheck` alteram checkboxes, e `select_option` aceita rótulo
247
341
  exato (`option`), valor (`value`) ou rótulo parcial único (`label_contains`).
248
- `navigate_menu` percorre uma lista de rótulos exatos e abre `#open_btn` quando o
249
- primeiro item ainda está oculto. Se vários itens visíveis tiverem o mesmo
250
- rótulo, seleciona a última ocorrência, útil quando o submenu recém-aberto
251
- repete o nome da categoria pai.
342
+ `navigate_menu` percorre uma lista de rótulos exatos e abre `#open_btn` quando o
343
+ primeiro item ainda está oculto. Se vários itens visíveis tiverem o mesmo
344
+ rótulo, seleciona a última ocorrência, útil quando o submenu recém-aberto
345
+ repete o nome da categoria pai. Para o SAFI, `screen` pesquisa o nome ou código
346
+ na tela Acesso Rápido, exige um resultado único e clica no link oficial da linha;
347
+ por exemplo, `{"action":"navigate_menu","screen":"TCN00022"}`.
348
+
349
+ Em uma instância local do SAFI, `http_request` pode obter a lista de telas pela
350
+ sessão já aberta sem ler o HTML:
351
+
352
+ ```json
353
+ {
354
+ "flow": "Consultar telas disponíveis no perfil atual do SAFI",
355
+ "initial_url": "http://localhost:8011/safi/",
356
+ "candidate_plans": {
357
+ "inspect": {
358
+ "description": "Ler a lista de telas do SAFI no ambiente local",
359
+ "steps": [{
360
+ "action": "http_request",
361
+ "url": "/safi/api/menu/telas_menu",
362
+ "include_body": true
363
+ }]
364
+ }
365
+ },
366
+ "options": { "local_only": true, "fast_path": true }
367
+ }
368
+ ```
369
+
370
+ O endpoint usa a sessão atual e pode retornar uma lista específica do perfil.
371
+ Os valores de cookies nunca são retornados. O acesso ao menu continua sujeito
372
+ às permissões verificadas pela própria interface; não use esse diagnóstico
373
+ contra produção.
252
374
 
253
375
  ```json
254
376
  {
@@ -274,13 +396,14 @@ Exemplos para controles legados sem nome acessível:
274
396
  {"action":"click","selector":"#save-document"}
275
397
  ```
276
398
 
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.
399
+ Por padrão, controles sem nome não são devolvidos em listas separadas. Defina
400
+ `options.include_unnamed_controls: true` para receber
401
+ `unnamed_controls_initial` e `unnamed_controls_final`, cada uma com papel,
402
+ índice Playwright por papel, rótulo mais próximo e um trecho HTML sanitizado.
403
+ Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode de uso
404
+ privado (como ícones Font Awesome) entram nessa lista e podem ser selecionados
405
+ com `name: ""` e o mesmo índice. O alias redundante `unnamed_controls` foi
406
+ removido. O placeholder conta como nome acessível.
284
407
  O snapshot também resume campos de formulário com `id`, `name`, valor, estado
285
408
  desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
286
409
  sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
@@ -291,10 +414,14 @@ Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
291
414
  localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
292
415
  `textbox`, `searchbox` ou `combobox`.
293
416
 
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.
417
+ Por padrão, o MCP executa todos os passos antes de avaliar os critérios.
418
+ `expected_outcome` aceita texto descritivo ou uma asserção estruturada, por
419
+ exemplo `{"text":"Tecnologia atualizada com sucesso."}` ou
420
+ `{"request":"PUT */api/tecnologia","status":200}`. A forma estruturada pode
421
+ incluir `message_contains` e reprova se a resposta correspondente não for
422
+ observada. Valores dentro de campos não contam como texto visível.
423
+ `stop_on_expected: true` habilita parada antecipada quando o texto esperado
424
+ aparece fora dos campos; mantenha `false` para fluxos com várias etapas.
298
425
 
299
426
  Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
300
427
  de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
@@ -330,11 +457,13 @@ verificar:
330
457
  {"action":"audit_accessibility","standard":"wcag2aa"}
331
458
  ```
332
459
 
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.
460
+ O MCP usa `@axe-core/playwright` com as tags WCAG 2.0 e 2.1 A/AA. O retorno
461
+ resume as violações por regra, impacto e quantidade de nós, sem copiar HTML ou
462
+ trechos da página. A etapa falha quando encontra violações no impacto definido
463
+ por `fail_on_impact`; o padrão é `minor`, e níveis abaixo do limite são relatados
464
+ sem bloquear o fluxo. A auditoria automática encontra problemas comuns, mas não
465
+ comprova conformidade WCAG completa; combine-a com revisão manual e testes com
466
+ usuários assistivos.
338
467
 
339
468
  Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
340
469
  corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
@@ -431,25 +560,68 @@ validadores.
431
560
  harness e CI. O processo MCP conserva browser, contexto e página entre
432
561
  chamadas; cookies, local storage e estado da página permanecem enquanto o
433
562
  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.
563
+ - `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
564
+ persistente `browser.computer_user_data_dir`, separado por navegador e por
565
+ processo MCP. Não
566
+ reutiliza o perfil pessoal já aberto. Faça login uma vez nesse perfil; os
567
+ cookies permanecem nele entre chamadas.
568
+
569
+ `fresh_context: true` abre um contexto descartável, sem cookies nem storage do
570
+ perfil persistente; requer `initial_url` e fecha esse contexto ao terminar. Use
571
+ `clear_storage: true` para limpar cookies, local/session storage, IndexedDB,
572
+ Cache Storage e service workers antes de recarregar a página atual. Para salvar
573
+ e reutilizar o estado de autenticação de uma conta de teste, use um nome simples
574
+ em `storage_state`:
575
+
576
+ ```json
577
+ {"options":{"storage_state":"aluno-a"}}
578
+ ```
579
+
580
+ O estado fica em `storage-state/<nome>.json` dentro da pasta de artefatos, com
581
+ permissões restritas no sistema operacional; não use uma conta real nem
582
+ compartilhe esse arquivo. `storage_state` não pode ser combinado com
583
+ `fresh_context` ou `clear_storage`.
438
584
 
439
585
  `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`.
586
+ não são somados. `browser.max_text_entry_chars` limita cada valor digitado. O
587
+ resultado contém `status`, o plano escolhido, as ações executadas, a última
588
+ captura acessível e se o texto descritivo esperado apareceu. `expected_outcome`
589
+ como string é descrição, não uma asserção: `expected_outcome_visible` é
590
+ informado separadamente, e um plano concluído pode passar mesmo se a frase não
591
+ estiver visível. Use `{ "text": "..." }` ou
592
+ `{ "request": "...", "status": 200 }` para exigir uma condição; as
593
+ verificações ficam em `expected_outcome_checks`, e uma condição não satisfeita
594
+ reprova o fluxo. As asserções `assert_*`, auditorias de acessibilidade e
595
+ downloads também aparecem em campos próprios do resultado.
596
+
597
+ Os status do fluxo incluem `passed`, `failed`, `incomplete`, `environment_error`,
598
+ `dry_run` e `confirmation_required`. O fluxo fica `passed` se não houve falha ou
599
+ pausa de mutação e o texto esperado apareceu, uma asserção/auditoria/download
600
+ passou ou todas as etapas do plano foram executadas. `incomplete` é devolvido
601
+ quando nenhuma dessas condições se aplica; confiança do Jev, sozinha, não
602
+ comprova o resultado. `environment_error` identifica falha de
603
+ navegação, autenticação ou sessão do browser; `navigation_error` contém o código
604
+ detectado, como `ERR_CONNECTION_REFUSED`, `AUTHENTICATION_REQUIRED` ou
605
+ `BROWSER_DISCONNECTED`, `BROWSER_PAGE_NOT_RESTORED` ou
606
+ `BROWSER_PROFILE_IN_USE`, e `reason` orienta a recuperação. Se uma navegação falhar
607
+ e a chamada seguinte tentar reutilizar a página, o MCP informa que a navegação
608
+ anterior não carregou; reinicie a navegação com
609
+ `continue_from_current_page: false` (ou o alias `reuse_page: false`). Uma sessão
610
+ desconectada pode ser reaberta por `browser_health`. `run_browser_flow` também
611
+ tenta reconectar e repetir uma vez quando a desconexão acontece antes da primeira
612
+ etapa; a repetição exige `initial_url`. Sem essa URL, o resultado informa
613
+ `BROWSER_PAGE_NOT_RESTORED`, e chamadas posteriores em `reuse_page` continuam
614
+ recusadas até uma nova navegação explícita. Se qualquer etapa já executou ou
615
+ há token de confirmação de mutação, o MCP não repete o fluxo automaticamente.
616
+
617
+ `current_url` é devolvido para diagnóstico sem query string nem fragmento; IDs
618
+ longos no caminho também podem ser redigidos. `timings_ms.ready_ms` mede a espera
619
+ da SPA; `warnings` registra capturas vazias durante transições; e `failed_step`
620
+ identifica índice, ação, localizador, timeout e erro resumido quando uma etapa
621
+ falha. Cada etapa executada também registra a composição do localizador usado
622
+ e, quando disponível, `resolved_target` com tag, `id`, papel, nome acessível,
623
+ `title` casado e `href` sanitizado do elemento resolvido. Etapas `type` só
624
+ incluem o valor final do campo quando `sensitive: false`.
453
625
 
454
626
  Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
455
627
  origem são capturadas mesmo quando usam transferência chunked e não enviam
@@ -472,30 +644,36 @@ continua informada mesmo quando a lista é truncada.
472
644
 
473
645
  O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
474
646
  `block_trackers`, `block_fonts`, `local_only`, `busy_selectors`,
475
- `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`,
647
+ `auto_angular_idle`, `login_url_contains`, `login_text`, `capture_console_errors`,
648
+ `capture_network_errors`, `capture_network_error_bodies`, `capture_network`,
649
+ `capture_network_url_contains`, `ready_timeout_seconds`,
650
+ `ready_network_idle`, `ready_stable_ms`, `ready_text`, `ready`, `continue_from_current_page`,
651
+ `reuse_page`, `reuse_page_match`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
479
652
  `screenshot_on_failure`, `screenshot_on_success`, `trace_on_failure`,
480
- `trace_on_success`, `record_video`, `snapshot_include_hidden`, `stop_on_expected`,
653
+ `trace_on_success`, `record_video`, `snapshot_include_hidden`, `include_unnamed_controls`, `stop_on_expected`,
481
654
  `dry_run`, `confirmation_token`, `report_path`, `permissions`, `fake_media`,
482
655
  `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
656
+ `color_scheme`, `geolocation`, `console_levels`, `fresh_context`,
657
+ `clear_storage`, `storage_state`, `wait_for_http` e `allow_mutations`. Sem override,
658
+ os padrões são lidos de `jev_browser_mcp` em
659
+ `config/ui-testing.json`: um plano candidato pula a chamada Decisions;
660
+ captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
661
+ de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
662
+ acrescentados ao snapshot. `return_snapshot: "diff"` é o padrão, e as listas de
663
+ controles sem nome só aparecem com `include_unnamed_controls: true`. O browser
664
+ espera a SPA renderizar uma captura acessível estável na navegação inicial.
665
+ Depois, a continuidade fica ligada por
490
666
  padrão: `continue_from_current_page: true` mantém a página e seu estado entre
491
667
  chamadas na mesma origem, não repete `page.goto` e consulta um snapshot atual
492
668
  sem esperar novamente por `load`/`networkidle`. As etapas continuam aguardando
493
669
  seus próprios alvos e condições. `reuse_page` segue como alias legado; defina
494
670
  `continue_from_current_page: false` para iniciar cada chamada em `initial_url`.
495
671
  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
672
+ `initial_url`. URLs da mesma origem são comparadas após normalizar e ordenar a
673
+ query string. Se a rota normalizada diferir, o MCP pede uma etapa `navigate` ou
674
+ `continue_from_current_page: false`. `reuse_page_match: "path"` ignora a query;
675
+ um plano cuja primeira etapa seja `navigate` pode trocar a rota explicitamente.
676
+ `snapshot_scope` aceita `body`, `main` ou
499
677
  `dialog`; se `main` não existir, o snapshot usa `body`.
500
678
 
501
679
  `block_trackers: true` bloqueia analytics/trackers e os tipos de recurso
@@ -511,14 +689,29 @@ precisaria chamar o provedor Jev; use exatamente um plano com `fast_path: true`.
511
689
  `allow_mutations: true` pula a confirmação humana somente para URLs em
512
690
  `localhost`, `127.0.0.1` ou `::1`; use esse modo apenas em ambientes locais
513
691
  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`.
692
+ `step_timeout_seconds` define o timeout padrão por etapa e cada etapa pode
693
+ substituí-lo com `timeout_seconds`. `max_flow_steps` reduz o limite por chamada,
694
+ sem superar o teto da configuração. `return_snapshot` aceita `diff`, `full` ou
695
+ `none`; `diff` retorna linhas acessíveis novas desde o snapshot inicial.
696
+
697
+ `options.ready` aguarda condições da aplicação antes do primeiro snapshot e da
698
+ seleção do plano. Aceita `"network_idle"`,
699
+ `{"hidden_text":"Aguarde."}` e `{"selector":"#cdTecnologia","has_value":true}`;
700
+ uma lista combina condições, e todas precisam passar. `has_value` aceita
701
+ `true` (valor não vazio), `false` (vazio) ou o valor textual exato.
702
+ `ready_text` também pode exigir uma frase no snapshot inicial;
703
+ `ready_network_idle: true` solicita uma espera best-effort por `networkidle`.
704
+ `ready_timeout_seconds` limita a espera de inicialização e `ready_stable_ms`
705
+ define a janela usada para considerar o snapshot estável.
706
+
707
+ `console_levels` aceita `log`, `info`, `debug`, `warn` e `error`. Com
708
+ `console_levels: ["log","warn","error"]` e `capture_network_errors`, o retorno
709
+ traz mensagens do console agrupadas por texto e nível (`console_messages` com
710
+ `count`), além de `console_errors` para compatibilidade. `network_failures`
711
+ contém eventos limitados em quantidade e tamanho. Mensagens idênticas do console
712
+ são agrupadas em uma entrada com `count`.
713
+ Controles sem nome acessível aparecem em um único aviso com a contagem e alguns
714
+ exemplos, em vez de gerar uma mensagem por controle.
522
715
  Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
523
716
  fragmentos, valores de formulário e nomes de arquivo são removidos ou
524
717
  sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
@@ -552,15 +745,18 @@ Para testar microfone, conceda permissão no escopo da chamada:
552
745
  {
553
746
  "options": {
554
747
  "permissions": ["microphone"],
555
- "fake_media": "fixtures/resposta-aluno.wav",
748
+ "fake_media": {"audio":"fixtures/resposta-aluno.wav"},
556
749
  "block_trackers": true
557
750
  }
558
751
  }
559
752
  ```
560
753
 
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
754
+ `fake_media` aceita tanto o caminho WAV direto quanto o objeto
755
+ `{"audio":"caminho.wav"}`. Exige um WAV RIFF válido dentro de
756
+ `JEV_BROWSER_UPLOAD_ROOT` e respeita os mesmos limites de upload. Ao informar
757
+ `fake_media`, o MCP concede automaticamente a permissão `microphone`, adiciona
758
+ as opções de dispositivo falso do Chromium e usa o arquivo como entrada de
759
+ áudio. Sem esse arquivo, a
564
760
  permissão de microfone usa o dispositivo autorizado pelo browser; no modo
565
761
  `computer`, o sistema operacional ainda pode pedir acesso ao dispositivo.
566
762
 
@@ -580,22 +776,62 @@ andamento, sem repetir o clique.
580
776
 
581
777
  Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
582
778
  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.
779
+ perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
780
+ Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. O caminho
781
+ padrão já separa processos por PID; configure `JEV_BROWSER_PROFILE` para mudar
782
+ a raiz e `JEV_BROWSER_SESSION_ID` para nomear a instância.
586
783
  Resultados MCP incluem `server_version`; erros também começam com a versão do
587
- servidor para facilitar a comparação entre instalações. A ferramenta
588
- `browser_health` informa se a sessão está ativa e tenta reconectar um browser
589
- que encerrou desde a chamada anterior. Passe `{"restart":true}` para fechar e
590
- reiniciar somente o navegador administrado por este processo MCP. Um fluxo pode
591
- ser repetido automaticamente uma vez após `BROWSER_DISCONNECTED` quando nenhuma
592
- etapa mutável foi executada.
593
-
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.
784
+ servidor para facilitar a comparação entre instalações. A ferramenta
785
+ `browser_health` informa se a sessão está ativa e tenta reconectar um browser
786
+ que encerrou desde a chamada anterior. Passe `{"restart":true}` para fechar e
787
+ reiniciar somente o navegador administrado por este processo MCP. Perfil ocupado
788
+ é devolvido como `BROWSER_PROFILE_IN_USE` com o PID detectado e não provoca
789
+ encerramento do Chrome/Edge existente.
790
+
791
+ `harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
792
+ `computer_user_data_dir` deve ficar fora do repositório e conter `{browser}` e
793
+ `{session}`;
794
+ o diretório persistente armazena dados de login e é resolvido sob a pasta home
795
+ do usuário quando começa com `~`. O Playwright MCP fica desabilitado até
796
+ `ORQUESTRADOR_MCP_PLAYWRIGHT_ENABLED=1` ser configurado no ambiente do harness.
797
+
798
+ ## Preparar smoke autenticado local
799
+
800
+ O MCP não cria a identidade nem os dados do sistema testado. Para um smoke de
801
+ administração, suba a API e a UI locais, use um banco descartável com dados
802
+ fictícios e uma identidade OIDC de teste que tenha explicitamente a claim
803
+ `administrator`. Mantenha as regras de autorização de produção iguais; um token
804
+ de operador legado não deve ser promovido para admin só para fazer o smoke.
805
+
806
+ Faça o preflight nesta ordem:
807
+
808
+ 1. `browser_health` confirma a versão, o perfil/sessão e a conexão do navegador.
809
+ Se o perfil estiver ocupado, use outro `JEV_BROWSER_SESSION_ID` ou
810
+ `JEV_BROWSER_PROFILE`; não encerre o Chrome do operador.
811
+ 2. `options.wait_for_http` aguarda a API local responder antes de abrir a UI.
812
+ Informe a URL da interface em `initial_url` e a rota de health da API no
813
+ probe.
814
+ 3. `run_browser_flow` confirma que a tela administrativa esperada está visível
815
+ e que a identidade abriu com papel administrativo. Se aparecer a tela de
816
+ login, configure a conta de teste ou o provedor OIDC local; não copie o token
817
+ para `flow`, `params` ou logs. Use `text_env` para campos secretos.
818
+ 4. Valide primeiro uma prévia read-only com `assert_*`, `assert_network` e
819
+ captura de evidência. Para um fluxo que poderia gravar dados, use
820
+ `dry_run: true`; ele para antes da primeira etapa marcada como mutável.
821
+ 5. Só execute o passo de gravação em dados fictícios, depois de conferir o texto
822
+ do diálogo com `confirm_modal`/`confirm_dialog` e autorizar o token de
823
+ confirmação. Reinicializações de serviços e consultas diretas ao banco ficam
824
+ fora do smoke de tela.
825
+
826
+ Esse preflight é um roteiro composto por `browser_health`, `wait_for_http` e
827
+ asserções da própria aplicação; não há uma ferramenta genérica que valide a
828
+ claim OIDC `administrator`. A checagem do papel precisa usar um sinal visível ou
829
+ uma asserção específica do sistema consumidor.
830
+
831
+ Um `expected_outcome` descreve o objetivo; o resultado `passed` vem das
832
+ asserções explícitas ou da conclusão do plano. Verifique
833
+ `expected_outcome_visible` separadamente quando a frase global fizer parte do
834
+ critério do teste.
599
835
 
600
836
  Defina o valor secreto na variável indicada por `jev.credential_env`, usando o
601
837
  secret manager ou ambiente do processo que inicia o harness. Não grave a chave
@@ -639,10 +875,13 @@ valores dos controles são substituídos e hrefs têm query string e fragmento
639
875
  removidos; padrões de PII também são mascarados. Com fast-path, um plano não
640
876
  gera chamada remota. Os passos, valores digitados, valores esperados pelas
641
877
  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.
878
+ Não inclua segredos em `flow`, `expected_outcome` ou nas descrições. A resposta
879
+ retorna o plano escolhido quando houver decisão, custo/confiança do provedor
880
+ quando disponíveis e o snapshot final sanitizado. Um `expected_outcome` em
881
+ texto simples é descritivo: `expected_outcome_visible` indica separadamente se
882
+ a frase apareceu, e completar o plano pode resultar em `passed` mesmo que ela
883
+ não apareça. Use a forma estruturada para tornar texto ou resposta de rede uma
884
+ condição obrigatória; se ela não passar, o fluxo falha.
646
885
 
647
886
  `network_idle` é uma espera limitada e opcional. Polling e conexões contínuas
648
887
  não relacionadas a `url_contains` não bloqueiam o modo filtrado; prefira