sincron-auto 1.0.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/LICENSE +20 -0
- package/README.md +195 -0
- package/agents/avaliador.md +290 -0
- package/agents/construtor.md +149 -0
- package/agents/estrutura.md +79 -0
- package/agents/gestor-projeto.md +195 -0
- package/agents/orquestrador.md +109 -0
- package/bin/install.js +449 -0
- package/commands/sincron-auto.md +406 -0
- package/docs/arquitetura.md +397 -0
- package/docs/cenarios-uso.md +292 -0
- package/docs/duvidas.md +170 -0
- package/docs/estruturas-dados.md +377 -0
- package/docs/exemplos-playwright.md +497 -0
- package/docs/fluxo-mensagens.md +180 -0
- package/docs/installation-guide.md +535 -0
- package/docs/mcp-instalacao.md +118 -0
- package/docs/metricas-performance.md +371 -0
- package/docs/relatorio-final-exemplo.md +200 -0
- package/docs/skills-vs-agents.md +107 -0
- package/docs/template-permissoes.json +83 -0
- package/package.json +34 -0
- package/skills/autorizacao/SKILL.md +78 -0
- package/skills/avaliacao/SKILL.md +55 -0
- package/skills/gerenciar/SKILL.md +60 -0
- package/skills/instalar-mcp/SKILL.md +59 -0
- package/skills/projetar/SKILL.md +53 -0
- package/skills/relatorio-final/SKILL.md +269 -0
- package/templates/settings-nenhuma.json +5 -0
- package/templates/settings-parcial.json +17 -0
- package/templates/settings-total.json +23 -0
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
# Exemplos de Comandos Playwright MCP
|
|
2
|
+
|
|
3
|
+
Este documento fornece exemplos práticos de como usar os comandos Playwright MCP para testes visuais e funcionais.
|
|
4
|
+
|
|
5
|
+
## Navegação
|
|
6
|
+
|
|
7
|
+
### Navegar para uma URL
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
mcp__playwright__navigate({
|
|
11
|
+
url: "http://localhost:3000"
|
|
12
|
+
})
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Aguardar navegação para URL específica
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
mcp__playwright__wait_for_url({
|
|
19
|
+
url: "/dashboard",
|
|
20
|
+
timeout: 5000 // opcional, em ms
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Query de Elementos
|
|
25
|
+
|
|
26
|
+
### Buscar elemento por seletor
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
mcp__playwright__query_selector({
|
|
30
|
+
selector: "#btn-submit"
|
|
31
|
+
})
|
|
32
|
+
// Retorna: elemento encontrado ou erro se não existir
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Buscar múltiplos elementos
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
mcp__playwright__query_selector_all({
|
|
39
|
+
selector: ".task-item"
|
|
40
|
+
})
|
|
41
|
+
// Retorna: array de elementos
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Interações
|
|
45
|
+
|
|
46
|
+
### Clicar em elemento
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
mcp__playwright__click({
|
|
50
|
+
selector: "#btn-submit",
|
|
51
|
+
timeout: 5000 // opcional
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Preencher campo de input
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
mcp__playwright__fill({
|
|
59
|
+
selector: "#email",
|
|
60
|
+
value: "usuario@exemplo.com"
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Digitar texto (simula digitação real)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
mcp__playwright__type({
|
|
68
|
+
selector: "#search",
|
|
69
|
+
text: "buscar produto",
|
|
70
|
+
delay: 100 // delay entre teclas em ms
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Pressionar tecla
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
mcp__playwright__press({
|
|
78
|
+
selector: "#search",
|
|
79
|
+
key: "Enter"
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Selecionar opção em dropdown
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
mcp__playwright__select_option({
|
|
87
|
+
selector: "#country",
|
|
88
|
+
value: "BR"
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Marcar/desmarcar checkbox
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
mcp__playwright__check({
|
|
96
|
+
selector: "#accept-terms"
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
mcp__playwright__uncheck({
|
|
100
|
+
selector: "#newsletter"
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Captura de Tela
|
|
105
|
+
|
|
106
|
+
### Screenshot de página inteira
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
mcp__playwright__screenshot({
|
|
110
|
+
path: "./screenshots/full-page.png",
|
|
111
|
+
fullPage: true
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Screenshot de elemento específico
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
mcp__playwright__screenshot({
|
|
119
|
+
path: "./screenshots/login-form.png",
|
|
120
|
+
selector: "#login-form"
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Verificação de CSS e Estilos
|
|
125
|
+
|
|
126
|
+
### Obter propriedade computada de CSS
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
mcp__playwright__eval({
|
|
130
|
+
expression: "getComputedStyle(document.querySelector('#btn-submit')).backgroundColor"
|
|
131
|
+
})
|
|
132
|
+
// Retorna: "rgb(37, 99, 235)"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Verificar múltiplas propriedades
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
mcp__playwright__eval({
|
|
139
|
+
expression: `
|
|
140
|
+
const btn = document.querySelector('#btn-submit');
|
|
141
|
+
const style = getComputedStyle(btn);
|
|
142
|
+
return {
|
|
143
|
+
backgroundColor: style.backgroundColor,
|
|
144
|
+
color: style.color,
|
|
145
|
+
fontSize: style.fontSize,
|
|
146
|
+
fontFamily: style.fontFamily,
|
|
147
|
+
padding: style.padding
|
|
148
|
+
};
|
|
149
|
+
`
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Verificar alinhamento
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
mcp__playwright__eval({
|
|
157
|
+
expression: `
|
|
158
|
+
const elem = document.querySelector('#login-form');
|
|
159
|
+
const rect = elem.getBoundingClientRect();
|
|
160
|
+
const parent = elem.parentElement.getBoundingClientRect();
|
|
161
|
+
|
|
162
|
+
// Check if horizontally centered
|
|
163
|
+
const horizontalCenter = Math.abs(
|
|
164
|
+
(parent.width / 2) - (rect.left - parent.left + rect.width / 2)
|
|
165
|
+
) < 5;
|
|
166
|
+
|
|
167
|
+
// Check if vertically centered
|
|
168
|
+
const verticalCenter = Math.abs(
|
|
169
|
+
(parent.height / 2) - (rect.top - parent.top + rect.height / 2)
|
|
170
|
+
) < 5;
|
|
171
|
+
|
|
172
|
+
return { horizontalCenter, verticalCenter };
|
|
173
|
+
`
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Responsividade
|
|
178
|
+
|
|
179
|
+
### Definir viewport (tamanho da tela)
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// Mobile
|
|
183
|
+
mcp__playwright__set_viewport({
|
|
184
|
+
width: 320,
|
|
185
|
+
height: 568
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// Tablet
|
|
189
|
+
mcp__playwright__set_viewport({
|
|
190
|
+
width: 768,
|
|
191
|
+
height: 1024
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
// Desktop
|
|
195
|
+
mcp__playwright__set_viewport({
|
|
196
|
+
width: 1920,
|
|
197
|
+
height: 1080
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Testar responsividade completa
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// 1. Definir viewport mobile
|
|
205
|
+
mcp__playwright__set_viewport({ width: 320, height: 568 })
|
|
206
|
+
|
|
207
|
+
// 2. Capturar screenshot
|
|
208
|
+
mcp__playwright__screenshot({ path: "./mobile.png" })
|
|
209
|
+
|
|
210
|
+
// 3. Verificar se menu mobile está visível
|
|
211
|
+
mcp__playwright__eval({
|
|
212
|
+
expression: `
|
|
213
|
+
const mobileMenu = document.querySelector('.mobile-menu');
|
|
214
|
+
return mobileMenu && getComputedStyle(mobileMenu).display !== 'none';
|
|
215
|
+
`
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
// 4. Mudar para desktop
|
|
219
|
+
mcp__playwright__set_viewport({ width: 1920, height: 1080 })
|
|
220
|
+
|
|
221
|
+
// 5. Verificar se menu desktop está visível
|
|
222
|
+
mcp__playwright__eval({
|
|
223
|
+
expression: `
|
|
224
|
+
const desktopMenu = document.querySelector('.desktop-menu');
|
|
225
|
+
return desktopMenu && getComputedStyle(desktopMenu).display !== 'none';
|
|
226
|
+
`
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Detecção de Problemas Visuais
|
|
231
|
+
|
|
232
|
+
### Detectar sobreposições
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
mcp__playwright__eval({
|
|
236
|
+
expression: `
|
|
237
|
+
function checkOverlaps() {
|
|
238
|
+
const elements = Array.from(document.querySelectorAll('body *'));
|
|
239
|
+
let overlaps = [];
|
|
240
|
+
|
|
241
|
+
for (let i = 0; i < elements.length; i++) {
|
|
242
|
+
const rect1 = elements[i].getBoundingClientRect();
|
|
243
|
+
if (rect1.width === 0 || rect1.height === 0) continue;
|
|
244
|
+
|
|
245
|
+
for (let j = i + 1; j < elements.length; j++) {
|
|
246
|
+
const rect2 = elements[j].getBoundingClientRect();
|
|
247
|
+
if (rect2.width === 0 || rect2.height === 0) continue;
|
|
248
|
+
|
|
249
|
+
// Check if rectangles overlap
|
|
250
|
+
const overlap = !(
|
|
251
|
+
rect1.right < rect2.left ||
|
|
252
|
+
rect1.left > rect2.right ||
|
|
253
|
+
rect1.bottom < rect2.top ||
|
|
254
|
+
rect1.top > rect2.bottom
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (overlap && !elements[i].contains(elements[j]) && !elements[j].contains(elements[i])) {
|
|
258
|
+
overlaps.push({
|
|
259
|
+
element1: elements[i].tagName + (elements[i].id ? '#' + elements[i].id : ''),
|
|
260
|
+
element2: elements[j].tagName + (elements[j].id ? '#' + elements[j].id : '')
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return overlaps;
|
|
267
|
+
}
|
|
268
|
+
checkOverlaps();
|
|
269
|
+
`
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Detectar barras de rolagem duplas
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
mcp__playwright__eval({
|
|
277
|
+
expression: `
|
|
278
|
+
const scrollableElements = Array.from(document.querySelectorAll('*')).filter(el => {
|
|
279
|
+
const style = getComputedStyle(el);
|
|
280
|
+
return (
|
|
281
|
+
style.overflow === 'auto' ||
|
|
282
|
+
style.overflow === 'scroll' ||
|
|
283
|
+
style.overflowX === 'auto' ||
|
|
284
|
+
style.overflowX === 'scroll' ||
|
|
285
|
+
style.overflowY === 'auto' ||
|
|
286
|
+
style.overflowY === 'scroll'
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
count: scrollableElements.length,
|
|
292
|
+
elements: scrollableElements.map(el => ({
|
|
293
|
+
tag: el.tagName,
|
|
294
|
+
id: el.id,
|
|
295
|
+
class: el.className
|
|
296
|
+
}))
|
|
297
|
+
};
|
|
298
|
+
`
|
|
299
|
+
})
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Verificar elementos fora da viewport
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
mcp__playwright__eval({
|
|
306
|
+
expression: `
|
|
307
|
+
const viewportWidth = window.innerWidth;
|
|
308
|
+
const viewportHeight = window.innerHeight;
|
|
309
|
+
|
|
310
|
+
const elementsOutside = Array.from(document.querySelectorAll('body *')).filter(el => {
|
|
311
|
+
const rect = el.getBoundingClientRect();
|
|
312
|
+
return (
|
|
313
|
+
rect.right < 0 ||
|
|
314
|
+
rect.left > viewportWidth ||
|
|
315
|
+
rect.bottom < 0 ||
|
|
316
|
+
rect.top > viewportHeight
|
|
317
|
+
);
|
|
318
|
+
}).map(el => ({
|
|
319
|
+
tag: el.tagName,
|
|
320
|
+
id: el.id,
|
|
321
|
+
class: el.className,
|
|
322
|
+
position: el.getBoundingClientRect()
|
|
323
|
+
}));
|
|
324
|
+
|
|
325
|
+
return elementsOutside;
|
|
326
|
+
`
|
|
327
|
+
})
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Acessibilidade
|
|
331
|
+
|
|
332
|
+
### Verificar contraste de cores (WCAG)
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
mcp__playwright__eval({
|
|
336
|
+
expression: `
|
|
337
|
+
function getLuminance(r, g, b) {
|
|
338
|
+
const [rs, gs, bs] = [r, g, b].map(c => {
|
|
339
|
+
c = c / 255;
|
|
340
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
341
|
+
});
|
|
342
|
+
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function getContrastRatio(rgb1, rgb2) {
|
|
346
|
+
const l1 = getLuminance(...rgb1);
|
|
347
|
+
const l2 = getLuminance(...rgb2);
|
|
348
|
+
const lighter = Math.max(l1, l2);
|
|
349
|
+
const darker = Math.min(l1, l2);
|
|
350
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function rgbStringToArray(rgb) {
|
|
354
|
+
const match = rgb.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);
|
|
355
|
+
return match ? [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])] : null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const btn = document.querySelector('button');
|
|
359
|
+
const style = getComputedStyle(btn);
|
|
360
|
+
const fg = rgbStringToArray(style.color);
|
|
361
|
+
const bg = rgbStringToArray(style.backgroundColor);
|
|
362
|
+
|
|
363
|
+
if (fg && bg) {
|
|
364
|
+
const ratio = getContrastRatio(fg, bg);
|
|
365
|
+
return {
|
|
366
|
+
ratio: ratio.toFixed(2),
|
|
367
|
+
wcagAA: ratio >= 4.5,
|
|
368
|
+
wcagAAA: ratio >= 7
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return { error: 'Could not parse colors' };
|
|
372
|
+
`
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Verificar área mínima de toque (44x44px)
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
mcp__playwright__eval({
|
|
380
|
+
expression: `
|
|
381
|
+
const interactiveElements = document.querySelectorAll('button, a, input, select, textarea');
|
|
382
|
+
const tooSmall = Array.from(interactiveElements).filter(el => {
|
|
383
|
+
const rect = el.getBoundingClientRect();
|
|
384
|
+
return rect.width < 44 || rect.height < 44;
|
|
385
|
+
}).map(el => ({
|
|
386
|
+
tag: el.tagName,
|
|
387
|
+
id: el.id,
|
|
388
|
+
width: el.getBoundingClientRect().width,
|
|
389
|
+
height: el.getBoundingClientRect().height
|
|
390
|
+
}));
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
total: interactiveElements.length,
|
|
394
|
+
tooSmall: tooSmall.length,
|
|
395
|
+
details: tooSmall
|
|
396
|
+
};
|
|
397
|
+
`
|
|
398
|
+
})
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Aguardar Condições
|
|
402
|
+
|
|
403
|
+
### Aguardar elemento estar visível
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
mcp__playwright__wait_for_selector({
|
|
407
|
+
selector: "#success-message",
|
|
408
|
+
state: "visible",
|
|
409
|
+
timeout: 5000
|
|
410
|
+
})
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Aguardar elemento ser removido
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
mcp__playwright__wait_for_selector({
|
|
417
|
+
selector: ".loading-spinner",
|
|
418
|
+
state: "detached",
|
|
419
|
+
timeout: 10000
|
|
420
|
+
})
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Fluxo Completo: Teste de Formulário de Login
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
// 1. Navegar para página
|
|
427
|
+
mcp__playwright__navigate({ url: "http://localhost:3000/login" })
|
|
428
|
+
|
|
429
|
+
// 2. Verificar elementos existem
|
|
430
|
+
mcp__playwright__query_selector({ selector: "#email" })
|
|
431
|
+
mcp__playwright__query_selector({ selector: "#password" })
|
|
432
|
+
mcp__playwright__query_selector({ selector: "#btn-submit" })
|
|
433
|
+
|
|
434
|
+
// 3. Capturar screenshot inicial
|
|
435
|
+
mcp__playwright__screenshot({ path: "./login-initial.png" })
|
|
436
|
+
|
|
437
|
+
// 4. Preencher formulário
|
|
438
|
+
mcp__playwright__fill({ selector: "#email", value: "usuario@teste.com" })
|
|
439
|
+
mcp__playwright__fill({ selector: "#password", value: "senha123" })
|
|
440
|
+
|
|
441
|
+
// 5. Verificar botão está habilitado
|
|
442
|
+
mcp__playwright__eval({
|
|
443
|
+
expression: "!document.querySelector('#btn-submit').disabled"
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
// 6. Clicar em submit
|
|
447
|
+
mcp__playwright__click({ selector: "#btn-submit" })
|
|
448
|
+
|
|
449
|
+
// 7. Aguardar navegação
|
|
450
|
+
mcp__playwright__wait_for_url({ url: "/dashboard" })
|
|
451
|
+
|
|
452
|
+
// 8. Capturar screenshot final
|
|
453
|
+
mcp__playwright__screenshot({ path: "./login-success.png" })
|
|
454
|
+
|
|
455
|
+
// 9. Verificar estética do formulário
|
|
456
|
+
mcp__playwright__set_viewport({ width: 320, height: 568 })
|
|
457
|
+
mcp__playwright__eval({
|
|
458
|
+
expression: `
|
|
459
|
+
const form = document.querySelector('form');
|
|
460
|
+
const style = getComputedStyle(form);
|
|
461
|
+
return {
|
|
462
|
+
centered: style.margin === 'auto' || style.justifyContent === 'center',
|
|
463
|
+
noOverflow: style.overflow !== 'scroll',
|
|
464
|
+
appropriatePadding: parseInt(style.padding) >= 16
|
|
465
|
+
};
|
|
466
|
+
`
|
|
467
|
+
})
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## Dicas e Boas Práticas
|
|
471
|
+
|
|
472
|
+
### 1. Sempre usar timeouts apropriados
|
|
473
|
+
- Operações rápidas (clicks): 5000ms
|
|
474
|
+
- Navegação: 10000ms
|
|
475
|
+
- Carregamento de dados: 15000ms
|
|
476
|
+
|
|
477
|
+
### 2. Capturar screenshots em pontos-chave
|
|
478
|
+
- Estado inicial
|
|
479
|
+
- Após cada interação importante
|
|
480
|
+
- Estados de erro
|
|
481
|
+
- Estado final
|
|
482
|
+
|
|
483
|
+
### 3. Testar em múltiplas resoluções
|
|
484
|
+
- Mobile: 320x568, 375x667, 414x896
|
|
485
|
+
- Tablet: 768x1024, 1024x768
|
|
486
|
+
- Desktop: 1366x768, 1920x1080, 2560x1440
|
|
487
|
+
|
|
488
|
+
### 4. Verificar estados interativos
|
|
489
|
+
- Hover (não disponível via Playwright MCP, verificar CSS)
|
|
490
|
+
- Active (verificar após click)
|
|
491
|
+
- Focus (verificar após navegação por teclado)
|
|
492
|
+
- Disabled (verificar propriedade)
|
|
493
|
+
|
|
494
|
+
### 5. Documentar falhas com evidências
|
|
495
|
+
- Sempre incluir screenshot quando teste falhar
|
|
496
|
+
- Incluir valores esperados vs obtidos
|
|
497
|
+
- Registrar seletor usado e resultado
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Fluxo de Mensagens entre Agentes
|
|
2
|
+
|
|
3
|
+
## Notificações e Comunicação
|
|
4
|
+
|
|
5
|
+
### 1. Orquestrador → Estrutura
|
|
6
|
+
**Momento**: Primeira execução (quando `sincron-auto-state` não existe)
|
|
7
|
+
**Mensagem**: Demanda do usuário
|
|
8
|
+
**Ação**: Estrutura configura permissões
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
### 2. Estrutura → Gestor Projeto
|
|
13
|
+
**Momento**: Após configurar permissões
|
|
14
|
+
**Mensagem**: Demanda do usuário + configuração completa
|
|
15
|
+
**Ação**: Gestor Projeto cria `sincron-auto-state` e inicia planejamento
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
### 3. Orquestrador → Gestor Projeto
|
|
20
|
+
**Momento**: Quando `sincron-auto-state` já existe
|
|
21
|
+
**Mensagem**: Demanda do usuário
|
|
22
|
+
**Ação**: Gestor Projeto interpreta tipo de demanda
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### 4. Gestor Projeto → Construtor
|
|
27
|
+
**Momento**: Após Skill Gerenciar identificar próxima task
|
|
28
|
+
**Ação prévia**: Gestor atualiza status da task de `pendente` para `em execução`
|
|
29
|
+
**Mensagem**:
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"task_id": "task-001",
|
|
33
|
+
"name": "Nome da Task",
|
|
34
|
+
"description": "Descrição do que fazer",
|
|
35
|
+
"user_stories": ["..."],
|
|
36
|
+
"acceptance_criteria": ["..."],
|
|
37
|
+
"status": "em execução"
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
**Ação**: Construtor implementa a task
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### 5. Construtor → Avaliador
|
|
45
|
+
**Momento**: Após concluir construção da task
|
|
46
|
+
**Mensagem**:
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"task_id": "task-001",
|
|
50
|
+
"status": "ready_for_evaluation",
|
|
51
|
+
"files_changed": ["file1.js", "file2.html"],
|
|
52
|
+
"summary": "Resumo do que foi implementado"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
**Ação**: Avaliador inicia processo de avaliação
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### 6a. Avaliador → Construtor (Task Rejeitada)
|
|
60
|
+
**Momento**: Quando task não passa na avaliação
|
|
61
|
+
**Mensagem**:
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"task_id": "task-001",
|
|
65
|
+
"status": "rejected",
|
|
66
|
+
"evaluation_number": 1,
|
|
67
|
+
"issues_found": [
|
|
68
|
+
{
|
|
69
|
+
"type": "functional | visual",
|
|
70
|
+
"severity": "critical | high | medium | low",
|
|
71
|
+
"description": "Descrição do problema",
|
|
72
|
+
"recommendation": "Como corrigir",
|
|
73
|
+
"related_criteria": "Critério não atendido"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
**Ação**: Construtor corrige problemas e reenvia para Avaliador
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### 6b. Avaliador → Gestor Projeto (Task Aprovada)
|
|
83
|
+
**Momento**: Quando task passa em todos os critérios
|
|
84
|
+
**Mensagem**:
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"task_id": "task-001",
|
|
88
|
+
"status": "approved",
|
|
89
|
+
"evaluation_number": 2,
|
|
90
|
+
"summary": "Task aprovada após 2 iterações"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
**Ação**:
|
|
94
|
+
- Gestor Projeto atualiza status da task de `em execução` para `completo`
|
|
95
|
+
- Identifica próxima task (por FIFO - ordem de criação)
|
|
96
|
+
- Se houver próxima: atualiza para `em execução` e envia para Construtor
|
|
97
|
+
- Se não houver: notifica Orquestrador
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### 7. Gestor Projeto → Orquestrador
|
|
102
|
+
**Momento**: Quando todas as tasks estão `completo`
|
|
103
|
+
**Mensagem**:
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"status": "all_tasks_completed",
|
|
107
|
+
"total_tasks": 15,
|
|
108
|
+
"completed_tasks": 15,
|
|
109
|
+
"timestamp": "2026-01-26T18:30:00Z"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
**Ação**: Orquestrador compila relatório final
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Ciclo Completo de Uma Task
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Gestor Projeto
|
|
120
|
+
↓ (envia task)
|
|
121
|
+
Construtor
|
|
122
|
+
↓ (ready_for_evaluation)
|
|
123
|
+
Avaliador
|
|
124
|
+
↓
|
|
125
|
+
├─ (rejected) → Construtor → (ready_for_evaluation) → Avaliador
|
|
126
|
+
└─ (approved) → Gestor Projeto
|
|
127
|
+
↓
|
|
128
|
+
(atualiza para completo)
|
|
129
|
+
↓
|
|
130
|
+
(pega próxima task ou notifica Orquestrador)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Estados e Transições
|
|
136
|
+
|
|
137
|
+
### Task Status Flow
|
|
138
|
+
```
|
|
139
|
+
pendente
|
|
140
|
+
↓
|
|
141
|
+
(Gestor envia para Construtor)
|
|
142
|
+
↓
|
|
143
|
+
em execução
|
|
144
|
+
↓
|
|
145
|
+
(Construtor envia para Avaliador)
|
|
146
|
+
↓
|
|
147
|
+
├─ Avaliação: REJEITADA
|
|
148
|
+
│ ↓
|
|
149
|
+
│ (volta para Construtor)
|
|
150
|
+
│ ↓
|
|
151
|
+
│ (Construtor corrige)
|
|
152
|
+
│ ↓
|
|
153
|
+
│ (reenvia para Avaliador)
|
|
154
|
+
│ ↓
|
|
155
|
+
└─ Avaliação: APROVADA
|
|
156
|
+
↓
|
|
157
|
+
(notifica Gestor)
|
|
158
|
+
↓
|
|
159
|
+
completo
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Responsabilidades de Atualização
|
|
165
|
+
|
|
166
|
+
| Arquivo | Quem Cria | Quem Atualiza | Quando Atualiza |
|
|
167
|
+
|---------|-----------|---------------|-----------------|
|
|
168
|
+
| `sincron-auto-state` | Gestor Projeto | Gestor Projeto | - Ao criar tasks (Skill Projetar)<br>- `pendente` → `em execução` (ao enviar para Construtor)<br>- `em execução` → `completo` (após aprovação do Avaliador) |
|
|
169
|
+
| `relatorio-avaliacao.json` | Avaliador | Avaliador | - A cada avaliação (aprovada ou rejeitada)<br>- Incrementa evaluation_number em reavaliações |
|
|
170
|
+
| `settings.local.json` | Estrutura | Estrutura | - Uma única vez na configuração inicial |
|
|
171
|
+
| `reports/relatorio-*.md` | Orquestrador | Orquestrador | - Ao finalizar todas as tasks do projeto |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Perguntas em Aberto
|
|
176
|
+
|
|
177
|
+
1. O Construtor notifica alguém quando inicia a construção?
|
|
178
|
+
2. Há timeout para construção/avaliação?
|
|
179
|
+
3. Como lidar com erros/crashes de um agente?
|
|
180
|
+
4. Sistema deve ter logs de todas as comunicações?
|