@maestro-ai/mcp-server 5.6.5 → 6.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/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/content/skills/specialist-api-contract/SKILL.md +98 -0
- package/dist/content/skills/specialist-api-contract/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-api-contract/resources/reference/guide.md +109 -0
- package/dist/content/skills/specialist-architect/SKILL.md +111 -0
- package/dist/content/skills/specialist-architect/resources/checklists/gate-checklist.md +45 -0
- package/dist/content/skills/specialist-architect/resources/examples/example-architecture.md +345 -0
- package/dist/content/skills/specialist-architect/resources/reference/guide.md +86 -0
- package/dist/content/skills/specialist-architect/resources/templates/arquitetura.md +282 -0
- package/dist/content/skills/specialist-backend/SKILL.md +100 -0
- package/dist/content/skills/specialist-backend/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-backend/resources/reference/guide.md +160 -0
- package/dist/content/skills/specialist-design/SKILL.md +107 -0
- package/dist/content/skills/specialist-design/resources/checklists/gate-checklist.md +45 -0
- package/dist/content/skills/specialist-design/resources/examples/example-design.md +294 -0
- package/dist/content/skills/specialist-design/resources/reference/guide.md +67 -0
- package/dist/content/skills/specialist-design/resources/templates/design-doc.md +232 -0
- package/dist/content/skills/specialist-devops/SKILL.md +99 -0
- package/dist/content/skills/specialist-devops/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-devops/resources/reference/guide.md +116 -0
- package/dist/content/skills/specialist-discovery/SKILL.md +109 -0
- package/dist/content/skills/specialist-discovery/resources/checklists/gate-checklist.md +45 -0
- package/dist/content/skills/specialist-discovery/resources/examples/example-discovery.md +179 -0
- package/dist/content/skills/specialist-discovery/resources/reference/guide.md +48 -0
- package/dist/content/skills/specialist-discovery/resources/templates/discovery.md +187 -0
- package/dist/content/skills/specialist-domain/SKILL.md +105 -0
- package/dist/content/skills/specialist-domain/resources/checklists/gate-checklist.md +37 -0
- package/dist/content/skills/specialist-domain/resources/reference/guide.md +80 -0
- package/dist/content/skills/specialist-frontend/SKILL.md +99 -0
- package/dist/content/skills/specialist-frontend/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-frontend/resources/reference/guide.md +90 -0
- package/dist/content/skills/specialist-operations/SKILL.md +109 -0
- package/dist/content/skills/specialist-operations/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-operations/resources/reference/guide.md +129 -0
- package/dist/content/skills/specialist-planning/SKILL.md +100 -0
- package/dist/content/skills/specialist-planning/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-planning/resources/reference/guide.md +88 -0
- package/dist/content/skills/specialist-product/SKILL.md +113 -0
- package/dist/content/skills/specialist-product/resources/checklists/gate-checklist.md +40 -0
- package/dist/content/skills/specialist-product/resources/reference/guide.md +43 -0
- package/dist/content/skills/specialist-product/resources/templates/PRD.md +191 -0
- package/dist/content/skills/specialist-requirements/SKILL.md +107 -0
- package/dist/content/skills/specialist-requirements/resources/checklists/gate-checklist.md +36 -0
- package/dist/content/skills/specialist-requirements/resources/reference/guide.md +66 -0
- package/dist/content/skills/specialist-technical-design/SKILL.md +114 -0
- package/dist/content/skills/specialist-technical-design/resources/checklists/gate-checklist.md +38 -0
- package/dist/content/skills/specialist-technical-design/resources/reference/guide.md +86 -0
- package/dist/flows/types.d.ts +33 -3
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/flows/types.js +288 -309
- package/dist/flows/types.js.map +1 -1
- package/dist/gates/code-validator.d.ts +47 -0
- package/dist/gates/code-validator.d.ts.map +1 -0
- package/dist/gates/code-validator.js +225 -0
- package/dist/gates/code-validator.js.map +1 -0
- package/dist/gates/readiness-gate.d.ts +48 -0
- package/dist/gates/readiness-gate.d.ts.map +1 -0
- package/dist/gates/readiness-gate.js +301 -0
- package/dist/gates/readiness-gate.js.map +1 -0
- package/dist/handlers/code-phase-handler.d.ts +1 -0
- package/dist/handlers/code-phase-handler.d.ts.map +1 -1
- package/dist/handlers/code-phase-handler.js +176 -27
- package/dist/handlers/code-phase-handler.js.map +1 -1
- package/dist/handlers/specialist-phase-handler.d.ts +11 -10
- package/dist/handlers/specialist-phase-handler.d.ts.map +1 -1
- package/dist/handlers/specialist-phase-handler.js +160 -64
- package/dist/handlers/specialist-phase-handler.js.map +1 -1
- package/dist/services/deliverable-gate.service.d.ts +40 -0
- package/dist/services/deliverable-gate.service.d.ts.map +1 -0
- package/dist/services/deliverable-gate.service.js +88 -0
- package/dist/services/deliverable-gate.service.js.map +1 -0
- package/dist/services/phase-config-loader.d.ts +28 -0
- package/dist/services/phase-config-loader.d.ts.map +1 -0
- package/dist/services/phase-config-loader.js +200 -0
- package/dist/services/phase-config-loader.js.map +1 -0
- package/dist/services/scoring-config.d.ts.map +1 -1
- package/dist/services/scoring-config.js +13 -10
- package/dist/services/scoring-config.js.map +1 -1
- package/dist/tools/consolidated/avancar.d.ts.map +1 -1
- package/dist/tools/consolidated/avancar.js +89 -8
- package/dist/tools/consolidated/avancar.js.map +1 -1
- package/dist/tools/iniciar-projeto.d.ts.map +1 -1
- package/dist/tools/iniciar-projeto.js +46 -0
- package/dist/tools/iniciar-projeto.js.map +1 -1
- package/dist/tools/proximo.d.ts +1 -0
- package/dist/tools/proximo.d.ts.map +1 -1
- package/dist/tools/proximo.js +41 -126
- package/dist/tools/proximo.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/phase-config.d.ts +65 -0
- package/dist/types/phase-config.d.ts.map +1 -0
- package/dist/types/phase-config.js +11 -0
- package/dist/types/phase-config.js.map +1 -0
- package/dist/utils/migration-v10.d.ts +31 -0
- package/dist/utils/migration-v10.d.ts.map +1 -0
- package/dist/utils/migration-v10.js +145 -0
- package/dist/utils/migration-v10.js.map +1 -0
- package/dist/utils/prompt-mapper.d.ts +6 -2
- package/dist/utils/prompt-mapper.d.ts.map +1 -1
- package/dist/utils/prompt-mapper.js +72 -91
- package/dist/utils/prompt-mapper.js.map +1 -1
- package/dist/utils/skill-deployer.d.ts +32 -0
- package/dist/utils/skill-deployer.d.ts.map +1 -0
- package/dist/utils/skill-deployer.js +150 -0
- package/dist/utils/skill-deployer.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Readiness Gate — Checkpoint consolidado pré-código (v10.0)
|
|
3
|
+
*
|
|
4
|
+
* Verifica se o CONJUNTO de artefatos de engenharia está coerente
|
|
5
|
+
* antes de permitir entrada nas fases de código (Frontend, Backend, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Cada fase anterior teve seu gate individual, mas o Readiness Gate
|
|
8
|
+
* verifica a coerência do conjunto: PRD existe? Arquitetura definida?
|
|
9
|
+
* Backlog com user stories?
|
|
10
|
+
*
|
|
11
|
+
* Thresholds:
|
|
12
|
+
* - >= 80: auto-approve (prossegue para código)
|
|
13
|
+
* - 60-79: aprovação manual necessária
|
|
14
|
+
* - < 60: bloqueio total — artefatos críticos faltando
|
|
15
|
+
*
|
|
16
|
+
* @since v10.0
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync } from "fs";
|
|
19
|
+
import { readFile } from "fs/promises";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
/**
|
|
22
|
+
* Definição dos artefatos verificados pelo Readiness Gate.
|
|
23
|
+
* Pesos somam 100 para cada nível de complexidade.
|
|
24
|
+
*/
|
|
25
|
+
const ARTIFACT_DEFS = [
|
|
26
|
+
{
|
|
27
|
+
name: "PRD / Discovery",
|
|
28
|
+
weight: 25,
|
|
29
|
+
minChars: 600,
|
|
30
|
+
patterns: [
|
|
31
|
+
"docs/fase-01-*/discovery.md",
|
|
32
|
+
"docs/fase-01-*/PRD.md",
|
|
33
|
+
"docs/01-*/PRD.md",
|
|
34
|
+
"docs/01-*/discovery.md",
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "Requisitos",
|
|
39
|
+
weight: 15,
|
|
40
|
+
minChars: 400,
|
|
41
|
+
patterns: [
|
|
42
|
+
"docs/fase-02-*/requisitos.md",
|
|
43
|
+
"docs/02-*/requisitos.md",
|
|
44
|
+
],
|
|
45
|
+
requiredFor: ["medio", "complexo"],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "Design",
|
|
49
|
+
weight: 15,
|
|
50
|
+
minChars: 400,
|
|
51
|
+
patterns: [
|
|
52
|
+
"docs/fase-*-design/design-doc.md",
|
|
53
|
+
"docs/fase-02-design/design-doc.md",
|
|
54
|
+
"docs/fase-03-design/design-doc.md",
|
|
55
|
+
"docs/*-design/design-doc.md",
|
|
56
|
+
"docs/*-ux-design/design-doc.md",
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "Arquitetura / Design Técnico",
|
|
61
|
+
weight: 25,
|
|
62
|
+
minChars: 600,
|
|
63
|
+
patterns: [
|
|
64
|
+
"docs/fase-*-arquitetura/arquitetura.md",
|
|
65
|
+
"docs/fase-*-technical-design/technical-design.md",
|
|
66
|
+
"docs/fase-03-arquitetura/arquitetura.md",
|
|
67
|
+
"docs/fase-04-*/technical-design.md",
|
|
68
|
+
"docs/fase-05-*/technical-design.md",
|
|
69
|
+
"docs/*-arquitetura/arquitetura.md",
|
|
70
|
+
],
|
|
71
|
+
keywords: ["stack", "ADR"],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "Backlog / Planejamento",
|
|
75
|
+
weight: 15,
|
|
76
|
+
minChars: 300,
|
|
77
|
+
patterns: [
|
|
78
|
+
"docs/fase-*-planejamento/backlog.md",
|
|
79
|
+
"docs/fase-*-backlog/backlog.md",
|
|
80
|
+
"docs/fase-05-*/backlog.md",
|
|
81
|
+
"docs/fase-07-*/backlog.md",
|
|
82
|
+
"docs/*-backlog/backlog.md",
|
|
83
|
+
],
|
|
84
|
+
keywords: ["US-"],
|
|
85
|
+
requiredFor: ["medio", "complexo"],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "Contrato API",
|
|
89
|
+
weight: 5,
|
|
90
|
+
minChars: 200,
|
|
91
|
+
patterns: [
|
|
92
|
+
"docs/fase-*-contrato-api/openapi.yaml",
|
|
93
|
+
"docs/fase-*-api/openapi.yaml",
|
|
94
|
+
"docs/*-api/openapi.yaml",
|
|
95
|
+
],
|
|
96
|
+
requiredFor: ["complexo"],
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
// ============================================================
|
|
100
|
+
// MAIN FUNCTION
|
|
101
|
+
// ============================================================
|
|
102
|
+
/**
|
|
103
|
+
* Executa o Readiness Check — verifica existência real de artefatos no disco.
|
|
104
|
+
*
|
|
105
|
+
* @param estado Estado atual do projeto
|
|
106
|
+
* @param diretorio Diretório raiz do projeto
|
|
107
|
+
* @returns ReadinessResult com score, breakdown e recomendações
|
|
108
|
+
*/
|
|
109
|
+
export async function readinessCheck(estado, diretorio) {
|
|
110
|
+
const nivel = estado.nivel;
|
|
111
|
+
const artifacts = [];
|
|
112
|
+
const gaps = [];
|
|
113
|
+
// Filtrar artefatos relevantes para o nível de complexidade
|
|
114
|
+
const relevantDefs = ARTIFACT_DEFS.filter(def => {
|
|
115
|
+
if (!def.requiredFor)
|
|
116
|
+
return true;
|
|
117
|
+
return def.requiredFor.includes(nivel);
|
|
118
|
+
});
|
|
119
|
+
// Normalizar pesos para somar 100
|
|
120
|
+
const totalWeight = relevantDefs.reduce((sum, d) => sum + d.weight, 0);
|
|
121
|
+
const weightMultiplier = totalWeight > 0 ? 100 / totalWeight : 1;
|
|
122
|
+
for (const def of relevantDefs) {
|
|
123
|
+
const normalizedWeight = Math.round(def.weight * weightMultiplier);
|
|
124
|
+
const result = await checkArtifact(diretorio, def, estado);
|
|
125
|
+
artifacts.push({
|
|
126
|
+
name: def.name,
|
|
127
|
+
exists: result.exists,
|
|
128
|
+
score: result.exists ? normalizedWeight : 0,
|
|
129
|
+
weight: normalizedWeight,
|
|
130
|
+
path: result.path,
|
|
131
|
+
charCount: result.charCount,
|
|
132
|
+
minChars: def.minChars,
|
|
133
|
+
});
|
|
134
|
+
if (!result.exists) {
|
|
135
|
+
gaps.push(def.name);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const score = artifacts.reduce((sum, a) => sum + a.score, 0);
|
|
139
|
+
const approved = score >= 80;
|
|
140
|
+
const requiresManualApproval = score >= 60 && score < 80;
|
|
141
|
+
const recommendation = generateRecommendation(score, gaps, nivel);
|
|
142
|
+
return {
|
|
143
|
+
score,
|
|
144
|
+
approved,
|
|
145
|
+
requiresManualApproval,
|
|
146
|
+
artifacts,
|
|
147
|
+
gaps,
|
|
148
|
+
recommendation,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// ============================================================
|
|
152
|
+
// HELPERS
|
|
153
|
+
// ============================================================
|
|
154
|
+
/**
|
|
155
|
+
* Verifica se um artefato existe no disco e tem conteúdo mínimo.
|
|
156
|
+
* Tenta múltiplos patterns e também busca no estado.entregaveis.
|
|
157
|
+
*/
|
|
158
|
+
async function checkArtifact(diretorio, def, estado) {
|
|
159
|
+
// 1. Buscar nos entregáveis registrados no estado
|
|
160
|
+
for (const [_key, absPath] of Object.entries(estado.entregaveis || {})) {
|
|
161
|
+
const pathLower = absPath.toLowerCase();
|
|
162
|
+
const nameKeywords = def.name.toLowerCase().split(/[\s\/]+/);
|
|
163
|
+
const matches = nameKeywords.some(kw => kw.length > 3 && pathLower.includes(kw));
|
|
164
|
+
if (matches) {
|
|
165
|
+
try {
|
|
166
|
+
const content = await readFile(absPath, "utf-8");
|
|
167
|
+
if (content && content.trim().length >= def.minChars) {
|
|
168
|
+
const keywordsOk = checkKeywords(content, def.keywords);
|
|
169
|
+
if (keywordsOk) {
|
|
170
|
+
return { exists: true, path: absPath, charCount: content.length };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch { /* file not found */ }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// 2. Tentar patterns no filesystem
|
|
178
|
+
const { readdirSync } = await import("fs");
|
|
179
|
+
for (const pattern of def.patterns) {
|
|
180
|
+
const resolved = resolveGlobPattern(diretorio, pattern);
|
|
181
|
+
for (const candidate of resolved) {
|
|
182
|
+
if (existsSync(candidate)) {
|
|
183
|
+
try {
|
|
184
|
+
const content = await readFile(candidate, "utf-8");
|
|
185
|
+
if (content && content.trim().length >= def.minChars) {
|
|
186
|
+
const keywordsOk = checkKeywords(content, def.keywords);
|
|
187
|
+
if (keywordsOk) {
|
|
188
|
+
return { exists: true, path: candidate, charCount: content.length };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch { /* read error */ }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { exists: false, path: null, charCount: 0 };
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Verifica se o conteúdo contém as keywords obrigatórias.
|
|
200
|
+
*/
|
|
201
|
+
function checkKeywords(content, keywords) {
|
|
202
|
+
if (!keywords || keywords.length === 0)
|
|
203
|
+
return true;
|
|
204
|
+
const lower = content.toLowerCase();
|
|
205
|
+
return keywords.some(kw => lower.includes(kw.toLowerCase()));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Resolve padrões glob simples (* only) em caminhos reais.
|
|
209
|
+
* Suporta apenas * em nomes de diretório — não é um glob engine completo.
|
|
210
|
+
*/
|
|
211
|
+
function resolveGlobPattern(diretorio, pattern) {
|
|
212
|
+
const parts = pattern.split("/");
|
|
213
|
+
let candidates = [diretorio];
|
|
214
|
+
for (const part of parts) {
|
|
215
|
+
const nextCandidates = [];
|
|
216
|
+
for (const dir of candidates) {
|
|
217
|
+
if (part.includes("*")) {
|
|
218
|
+
// Wildcard: listar diretórios e filtrar
|
|
219
|
+
try {
|
|
220
|
+
const { readdirSync } = require("fs");
|
|
221
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
222
|
+
const regex = new RegExp("^" + part.replace(/\*/g, ".*") + "$", "i");
|
|
223
|
+
for (const entry of entries) {
|
|
224
|
+
if (regex.test(entry.name)) {
|
|
225
|
+
nextCandidates.push(join(dir, entry.name));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch { /* dir doesn't exist */ }
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
nextCandidates.push(join(dir, part));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
candidates = nextCandidates;
|
|
236
|
+
}
|
|
237
|
+
return candidates;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Gera recomendação textual baseada no score e nos gaps.
|
|
241
|
+
*/
|
|
242
|
+
function generateRecommendation(score, gaps, nivel) {
|
|
243
|
+
if (score >= 80) {
|
|
244
|
+
return "✅ Todos os artefatos de engenharia estão prontos. Pode prosseguir para código.";
|
|
245
|
+
}
|
|
246
|
+
if (score >= 60) {
|
|
247
|
+
return [
|
|
248
|
+
`⚠️ Score ${score}/100 — aprovação manual necessária.`,
|
|
249
|
+
`Artefatos faltando: ${gaps.join(", ")}.`,
|
|
250
|
+
`Opções: (1) Gerar os artefatos faltantes. (2) Aprovar manualmente para prosseguir.`,
|
|
251
|
+
].join("\n");
|
|
252
|
+
}
|
|
253
|
+
return [
|
|
254
|
+
`❌ Score ${score}/100 — bloqueado. Artefatos críticos faltando.`,
|
|
255
|
+
`Faltam: ${gaps.join(", ")}.`,
|
|
256
|
+
`Complete as fases de engenharia antes de iniciar o código.`,
|
|
257
|
+
].join("\n");
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Formata o resultado do Readiness Gate como markdown para exibição.
|
|
261
|
+
*/
|
|
262
|
+
export function formatReadinessResult(result) {
|
|
263
|
+
const lines = [];
|
|
264
|
+
lines.push(`# 🔒 Readiness Gate — Checkpoint Pré-Código\n`);
|
|
265
|
+
lines.push(`## Score: ${result.score}/100\n`);
|
|
266
|
+
// Tabela de artefatos
|
|
267
|
+
lines.push(`| Artefato | Status | Chars | Mínimo | Score |`);
|
|
268
|
+
lines.push(`|----------|--------|-------|--------|-------|`);
|
|
269
|
+
for (const a of result.artifacts) {
|
|
270
|
+
const status = a.exists ? "✅" : "❌";
|
|
271
|
+
const chars = a.exists ? String(a.charCount) : "—";
|
|
272
|
+
lines.push(`| ${a.name} | ${status} | ${chars} | ${a.minChars} | ${a.score}/${a.weight} |`);
|
|
273
|
+
}
|
|
274
|
+
lines.push("");
|
|
275
|
+
// Gaps
|
|
276
|
+
if (result.gaps.length > 0) {
|
|
277
|
+
lines.push(`## ❌ Artefatos Faltando\n`);
|
|
278
|
+
for (const gap of result.gaps) {
|
|
279
|
+
lines.push(`- **${gap}** — gere este documento antes de iniciar o código`);
|
|
280
|
+
}
|
|
281
|
+
lines.push("");
|
|
282
|
+
}
|
|
283
|
+
// Recomendação
|
|
284
|
+
lines.push(`## Recomendação\n`);
|
|
285
|
+
lines.push(result.recommendation);
|
|
286
|
+
lines.push("");
|
|
287
|
+
// Ações
|
|
288
|
+
if (result.requiresManualApproval) {
|
|
289
|
+
lines.push(`## 🔐 Ação Necessária\n`);
|
|
290
|
+
lines.push(`- **Para corrigir** (recomendado): Complete os artefatos faltantes e re-submeta`);
|
|
291
|
+
lines.push(`- **Para aprovar mesmo assim**: Diga "aprovar readiness gate"`);
|
|
292
|
+
lines.push(`\n> ⚠️ A IA NÃO pode aprovar automaticamente. Aguarde decisão do usuário.`);
|
|
293
|
+
}
|
|
294
|
+
else if (!result.approved) {
|
|
295
|
+
lines.push(`## ⛔ Bloqueado\n`);
|
|
296
|
+
lines.push(`Complete as fases de engenharia antes de iniciar o código.`);
|
|
297
|
+
lines.push(`Use \`executar({ acao: "avancar" })\` em cada fase pendente.`);
|
|
298
|
+
}
|
|
299
|
+
return lines.join("\n");
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=readiness-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readiness-gate.js","sourceRoot":"","sources":["../../src/gates/readiness-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-phase-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/code-phase-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"code-phase-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/code-phase-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAWnE,UAAU,aAAa;IACnB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEjE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CA4B9E"}
|
|
@@ -20,19 +20,17 @@ import { readFile } from "fs/promises";
|
|
|
20
20
|
import { join } from "path";
|
|
21
21
|
import { serializarEstado } from "../state/storage.js";
|
|
22
22
|
import { saveFile } from "../utils/persistence.js";
|
|
23
|
-
import { getFaseComStitch } from "../flows/types.js";
|
|
23
|
+
import { getFaseComStitch, isCodePhaseName } from "../flows/types.js";
|
|
24
|
+
import { validateCodePhase, formatCodeValidationResult } from "../gates/code-validator.js";
|
|
24
25
|
import { decomposeBacklogToTasks, getNextTask, getTaskProgress } from "../services/task-decomposer.service.js";
|
|
25
26
|
import { formatMention, detectIDE } from "../utils/ide-paths.js";
|
|
26
27
|
import { getFaseDirName } from "../utils/entregavel-path.js";
|
|
27
|
-
/** Nomes de fases que são de código */
|
|
28
|
-
const CODE_PHASE_NAMES = ['Frontend', 'Backend', 'Integração', 'Deploy Final'];
|
|
29
28
|
/**
|
|
30
29
|
* Verifica se uma fase é de código.
|
|
30
|
+
* v9.0: Delega para isCodePhaseName de flows/types.ts (fonte única de verdade).
|
|
31
31
|
*/
|
|
32
32
|
export function isCodePhase(faseNome) {
|
|
33
|
-
|
|
34
|
-
return false;
|
|
35
|
-
return CODE_PHASE_NAMES.some(k => faseNome.includes(k));
|
|
33
|
+
return isCodePhaseName(faseNome);
|
|
36
34
|
}
|
|
37
35
|
/**
|
|
38
36
|
* Entry point do Code Phase Handler.
|
|
@@ -98,6 +96,11 @@ async function handleSetup(args, codeState, faseInfo) {
|
|
|
98
96
|
const nextTask = getNextTask((estado.tasks || []).filter(t => t.phase === estado.fase_atual));
|
|
99
97
|
// Extrair stack da arquitetura (parsing simplificado)
|
|
100
98
|
const stackInfo = extractStackInfo(arquiteturaContent, faseInfo.nome);
|
|
99
|
+
// v9.0 Sprint 4: Inicializar manifest com stack da arquitetura
|
|
100
|
+
if (!codeState.manifest) {
|
|
101
|
+
codeState.manifest = createEmptyManifest(estado.fase_atual, faseInfo.nome);
|
|
102
|
+
}
|
|
103
|
+
codeState.manifest.stack = extractStackForManifest(arquiteturaContent, faseInfo.nome);
|
|
101
104
|
// Extrair user stories relevantes do backlog
|
|
102
105
|
const relevantStories = extractRelevantStoriesSummary(backlogContent, faseInfo.nome);
|
|
103
106
|
// Extrair endpoints do OpenAPI
|
|
@@ -268,6 +271,10 @@ executar({
|
|
|
268
271
|
}
|
|
269
272
|
/**
|
|
270
273
|
* Handler: GATE — Todas tasks done. Gerar manifest e validar.
|
|
274
|
+
* v9.0: Usa CodeValidator (validação por artefatos) em vez de delegar para proximo.ts textual.
|
|
275
|
+
* Se score >= 70, avança automaticamente via proximo.ts.
|
|
276
|
+
* Se score 50-69, aguarda aprovação manual.
|
|
277
|
+
* Se score < 50, bloqueia com instruções.
|
|
271
278
|
*/
|
|
272
279
|
async function handleGate(args, codeState, faseInfo) {
|
|
273
280
|
const { estado, diretorio } = args;
|
|
@@ -280,6 +287,8 @@ async function handleGate(args, codeState, faseInfo) {
|
|
|
280
287
|
// Escanear arquivos criados no diretório do projeto
|
|
281
288
|
const scannedFiles = scanProjectFiles(diretorio, faseInfo.nome);
|
|
282
289
|
manifest.arquivos_criados = [...new Set([...manifest.arquivos_criados, ...scannedFiles])];
|
|
290
|
+
// v9.0 Sprint 4: Popular user_stories a partir das tasks do estado
|
|
291
|
+
populateManifestUserStories(manifest, estado.tasks || [], estado.fase_atual);
|
|
283
292
|
// Salvar manifest
|
|
284
293
|
const faseDirName = getFaseDirName(estado.fase_atual, faseInfo.nome);
|
|
285
294
|
const manifestPath = join(diretorio, 'docs', faseDirName, 'manifest.json');
|
|
@@ -295,12 +304,42 @@ async function handleGate(args, codeState, faseInfo) {
|
|
|
295
304
|
catch (err) {
|
|
296
305
|
console.warn('[code-phase] Falha ao salvar manifest:', err);
|
|
297
306
|
}
|
|
298
|
-
//
|
|
307
|
+
// v9.0: Validação orientada a artefatos (em vez de keywords textuais)
|
|
308
|
+
const validationResult = validateCodePhase(manifest, diretorio, estado.tasks || [], estado.fase_atual);
|
|
309
|
+
console.log(`[code-phase] v9.0: CodeValidator score=${validationResult.score}/100 approved=${validationResult.approved} (arquivos=${validationResult.breakdown.arquivos}, tasks=${validationResult.breakdown.tasks}, manifest=${validationResult.breakdown.manifest})`);
|
|
310
|
+
// Score < 50: BLOQUEAR
|
|
311
|
+
if (validationResult.score < 50) {
|
|
312
|
+
const feedbackMd = formatCodeValidationResult(validationResult, faseInfo.nome);
|
|
313
|
+
return {
|
|
314
|
+
content: [{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: `# ❌ Gate de Código Bloqueado — ${faseInfo.nome}\n\n${feedbackMd}\n\n---\n\n**Não é possível avançar.** Complete as tasks pendentes, gere os arquivos e tente novamente com \`executar({ acao: "avancar" })\`.`,
|
|
317
|
+
}],
|
|
318
|
+
estado_atualizado: serializarEstado(estado).content,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
// Score 50-69: Aguardar aprovação manual
|
|
322
|
+
if (validationResult.score < 70) {
|
|
323
|
+
estado.aguardando_aprovacao = true;
|
|
324
|
+
estado.motivo_bloqueio = `Gate de código: score ${validationResult.score}/100`;
|
|
325
|
+
estado.score_bloqueado = validationResult.score;
|
|
326
|
+
saveCodePhaseState(estado, codeState);
|
|
327
|
+
await persistState(estado, diretorio);
|
|
328
|
+
const feedbackMd = formatCodeValidationResult(validationResult, faseInfo.nome);
|
|
329
|
+
return {
|
|
330
|
+
content: [{
|
|
331
|
+
type: "text",
|
|
332
|
+
text: `# ⚠️ Aprovação Manual Necessária — ${faseInfo.nome}\n\n${feedbackMd}\n\n---\n\n## 🔐 Ação do Usuário\n\n- **Para corrigir** (recomendado): Complete as tasks pendentes e re-submeta\n- **Para aprovar mesmo assim**: Diga "aprovar o gate"\n\n> ⚠️ A IA NÃO pode aprovar automaticamente.`,
|
|
333
|
+
}],
|
|
334
|
+
estado_atualizado: serializarEstado(estado).content,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
// Score >= 70: Aprovado — marcar como completed e delegar para proximo.ts para avançar fase
|
|
299
338
|
codeState.status = 'completed';
|
|
300
339
|
codeState.manifest = manifest;
|
|
301
340
|
saveCodePhaseState(estado, codeState);
|
|
302
341
|
await persistState(estado, diretorio);
|
|
303
|
-
// Delegar para proximo.ts para
|
|
342
|
+
// Delegar para proximo.ts para avançar fase (com summary como entregável textual)
|
|
304
343
|
return delegateToProximo(args);
|
|
305
344
|
}
|
|
306
345
|
// === HELPER FUNCTIONS ===
|
|
@@ -529,22 +568,125 @@ function createEmptyManifest(fase, nome) {
|
|
|
529
568
|
timestamp: new Date().toISOString(),
|
|
530
569
|
};
|
|
531
570
|
}
|
|
571
|
+
/**
|
|
572
|
+
* v9.0 Sprint 4: Extrai stack estruturada da arquitetura para o manifest.
|
|
573
|
+
*/
|
|
574
|
+
function extractStackForManifest(arquiteturaContent, faseNome) {
|
|
575
|
+
if (!arquiteturaContent)
|
|
576
|
+
return { framework: '', language: 'TypeScript' };
|
|
577
|
+
const fase = faseNome.toLowerCase();
|
|
578
|
+
const content = arquiteturaContent.toLowerCase();
|
|
579
|
+
const extras = [];
|
|
580
|
+
let framework = '';
|
|
581
|
+
let language = 'TypeScript';
|
|
582
|
+
if (fase.includes('frontend')) {
|
|
583
|
+
if (content.includes('next.js') || content.includes('nextjs'))
|
|
584
|
+
framework = 'Next.js';
|
|
585
|
+
else if (content.includes('react'))
|
|
586
|
+
framework = 'React';
|
|
587
|
+
else if (content.includes('vue'))
|
|
588
|
+
framework = 'Vue.js';
|
|
589
|
+
else if (content.includes('angular'))
|
|
590
|
+
framework = 'Angular';
|
|
591
|
+
if (content.includes('tailwind'))
|
|
592
|
+
extras.push('Tailwind');
|
|
593
|
+
if (content.includes('shadcn'))
|
|
594
|
+
extras.push('shadcn/ui');
|
|
595
|
+
if (content.includes('zustand'))
|
|
596
|
+
extras.push('Zustand');
|
|
597
|
+
if (content.includes('react query') || content.includes('tanstack'))
|
|
598
|
+
extras.push('React Query');
|
|
599
|
+
}
|
|
600
|
+
else if (fase.includes('backend')) {
|
|
601
|
+
if (content.includes('express'))
|
|
602
|
+
framework = 'Express';
|
|
603
|
+
else if (content.includes('fastify'))
|
|
604
|
+
framework = 'Fastify';
|
|
605
|
+
else if (content.includes('nestjs') || content.includes('nest.js'))
|
|
606
|
+
framework = 'NestJS';
|
|
607
|
+
if (content.includes('prisma'))
|
|
608
|
+
extras.push('Prisma');
|
|
609
|
+
if (content.includes('postgresql') || content.includes('postgres'))
|
|
610
|
+
extras.push('PostgreSQL');
|
|
611
|
+
if (content.includes('redis'))
|
|
612
|
+
extras.push('Redis');
|
|
613
|
+
if (content.includes('jwt'))
|
|
614
|
+
extras.push('JWT');
|
|
615
|
+
}
|
|
616
|
+
else if (fase.includes('integra')) {
|
|
617
|
+
if (content.includes('playwright'))
|
|
618
|
+
framework = 'Playwright';
|
|
619
|
+
else if (content.includes('cypress'))
|
|
620
|
+
framework = 'Cypress';
|
|
621
|
+
if (content.includes('docker'))
|
|
622
|
+
extras.push('Docker');
|
|
623
|
+
}
|
|
624
|
+
else if (fase.includes('deploy')) {
|
|
625
|
+
if (content.includes('docker'))
|
|
626
|
+
framework = 'Docker';
|
|
627
|
+
if (content.includes('github actions'))
|
|
628
|
+
extras.push('GitHub Actions');
|
|
629
|
+
if (content.includes('aws'))
|
|
630
|
+
extras.push('AWS');
|
|
631
|
+
}
|
|
632
|
+
if (content.includes('javascript') && !content.includes('typescript'))
|
|
633
|
+
language = 'JavaScript';
|
|
634
|
+
if (content.includes('python'))
|
|
635
|
+
language = 'Python';
|
|
636
|
+
if (content.includes('java') && !content.includes('javascript'))
|
|
637
|
+
language = 'Java';
|
|
638
|
+
return { framework, language, extras: extras.length > 0 ? extras : undefined };
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* v9.0 Sprint 4: Popula manifest.user_stories a partir das tasks do estado.
|
|
642
|
+
* Mapeia tasks com parent_id (stories) para CodeManifestStory.
|
|
643
|
+
*/
|
|
644
|
+
function populateManifestUserStories(manifest, tasks, faseNumero) {
|
|
645
|
+
const phaseTasks = tasks.filter(t => t.phase === faseNumero);
|
|
646
|
+
const stories = phaseTasks.filter(t => t.type === 'story');
|
|
647
|
+
manifest.user_stories = stories.map(story => {
|
|
648
|
+
// Extrair ID da US do título (ex: "US-020: CRUD Produtos")
|
|
649
|
+
const idMatch = story.title.match(/US-\d+/i);
|
|
650
|
+
const id = idMatch ? idMatch[0] : story.id;
|
|
651
|
+
// Verificar status das sub-tasks
|
|
652
|
+
const childTasks = phaseTasks.filter(t => t.parent_id === story.id);
|
|
653
|
+
const allDone = childTasks.length > 0 && childTasks.every(t => t.status === 'done');
|
|
654
|
+
const anyInProgress = childTasks.some(t => t.status === 'in_progress');
|
|
655
|
+
// Coletar arquivos das sub-tasks
|
|
656
|
+
const arquivos = childTasks
|
|
657
|
+
.flatMap(t => t.metadata?.files || [])
|
|
658
|
+
.filter(Boolean);
|
|
659
|
+
return {
|
|
660
|
+
id,
|
|
661
|
+
titulo: story.title.replace(/^US-\d+:\s*/i, ''),
|
|
662
|
+
status: allDone ? 'done' : anyInProgress ? 'in_progress' : 'todo',
|
|
663
|
+
arquivos,
|
|
664
|
+
};
|
|
665
|
+
});
|
|
666
|
+
}
|
|
532
667
|
function generateSummaryMarkdown(manifest, faseInfo, progress) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
${
|
|
547
|
-
|
|
668
|
+
// v9.0 Sprint 4: Stack info
|
|
669
|
+
const stackMd = manifest.stack?.framework
|
|
670
|
+
? `## Stack\n- **Framework:** ${manifest.stack.framework}\n- **Language:** ${manifest.stack.language}${manifest.stack.extras ? `\n- **Extras:** ${manifest.stack.extras.join(', ')}` : ''}\n`
|
|
671
|
+
: '';
|
|
672
|
+
// v9.0 Sprint 4: Tabela rastreável US → arquivos → status
|
|
673
|
+
let traceabilityMd = '';
|
|
674
|
+
if (manifest.user_stories.length > 0) {
|
|
675
|
+
traceabilityMd = `## Rastreabilidade US → Código\n\n| US | Título | Status | Arquivos |\n|----|--------|--------|----------|\n`;
|
|
676
|
+
for (const story of manifest.user_stories) {
|
|
677
|
+
const icon = story.status === 'done' ? '✅' : story.status === 'in_progress' ? '🔄' : '⏳';
|
|
678
|
+
const arquivos = story.arquivos.length > 0
|
|
679
|
+
? story.arquivos.slice(0, 3).map(f => `\`${f}\``).join(', ') + (story.arquivos.length > 3 ? ` (+${story.arquivos.length - 3})` : '')
|
|
680
|
+
: '—';
|
|
681
|
+
traceabilityMd += `| ${story.id} | ${story.titulo.substring(0, 50)} | ${icon} ${story.status} | ${arquivos} |\n`;
|
|
682
|
+
}
|
|
683
|
+
const doneCount = manifest.user_stories.filter(s => s.status === 'done').length;
|
|
684
|
+
traceabilityMd += `\n> **US Concluídas:** ${doneCount}/${manifest.user_stories.length}\n`;
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
traceabilityMd = `## User Stories\n(geradas via TaskDecomposer)\n`;
|
|
688
|
+
}
|
|
689
|
+
return `# ${faseInfo.nome} — Resumo de Implementação\n\n## Progresso\n- **Tasks:** ${progress.done}/${progress.total} (${progress.percentage}%)\n- **Arquivos criados:** ${manifest.arquivos_criados.length}\n\n${stackMd}\n${traceabilityMd}\n## Arquivos Criados\n${manifest.arquivos_criados.map(f => `- \`${f}\``).join('\n') || '(nenhum registrado)'}\n\n## Timestamp\n${manifest.timestamp}\n`;
|
|
548
690
|
}
|
|
549
691
|
function getExpertiseForPhase(faseNome) {
|
|
550
692
|
const fase = faseNome.toLowerCase();
|
|
@@ -559,23 +701,30 @@ function getExpertiseForPhase(faseNome) {
|
|
|
559
701
|
return ['desenvolvimento', 'arquitetura', 'testes'];
|
|
560
702
|
}
|
|
561
703
|
/**
|
|
562
|
-
* Delega para proximo.ts para
|
|
563
|
-
*
|
|
704
|
+
* Delega para proximo.ts para avançar fase.
|
|
705
|
+
*
|
|
706
|
+
* v10.0 FIX: Quando code-validator já aprovou (codeState.status === 'completed'),
|
|
707
|
+
* passa skip_validation=true para pular a re-validação textual redundante
|
|
708
|
+
* em proximo.ts (validateDeliverableForGate). Antes, o code-validator fazia
|
|
709
|
+
* validação por artefatos reais e depois proximo.ts re-validava por keywords,
|
|
710
|
+
* potencialmente contradizendo o score.
|
|
564
711
|
*/
|
|
565
712
|
async function delegateToProximo(args) {
|
|
566
713
|
const { estado, diretorio } = args;
|
|
567
714
|
const codeState = estado.codePhaseState;
|
|
568
715
|
const manifest = codeState?.manifest;
|
|
569
|
-
// Gerar entregável textual a partir do manifest para
|
|
716
|
+
// Gerar entregável textual a partir do manifest (usado para resumo, não validação)
|
|
570
717
|
const entregavelTexto = manifest
|
|
571
718
|
? generateSummaryMarkdown(manifest, { nome: codeState?.faseNome || '' }, getTaskProgress(estado.tasks || [], estado.fase_atual))
|
|
572
719
|
: 'Fase de código concluída. Manifest não gerado.';
|
|
573
|
-
//
|
|
720
|
+
// v10.0: Se code-validator já aprovou, pular validação textual redundante
|
|
721
|
+
const skipValidation = codeState?.status === 'completed';
|
|
574
722
|
const { proximo } = await import("../tools/proximo.js");
|
|
575
723
|
return proximo({
|
|
576
724
|
diretorio,
|
|
577
725
|
estado_json: serializarEstado(estado).content,
|
|
578
726
|
entregavel: entregavelTexto,
|
|
727
|
+
skip_validation: skipValidation,
|
|
579
728
|
});
|
|
580
729
|
}
|
|
581
730
|
//# sourceMappingURL=code-phase-handler.js.map
|