@creative-ia/cortex 1.0.5

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.
Files changed (64) hide show
  1. package/README.md +41 -0
  2. package/dist/config/cloud-proxy.d.ts +15 -0
  3. package/dist/config/cloud-proxy.js +63 -0
  4. package/dist/config/cloudwatch-store.d.ts +13 -0
  5. package/dist/config/cloudwatch-store.js +66 -0
  6. package/dist/config/license.d.ts +29 -0
  7. package/dist/config/license.js +165 -0
  8. package/dist/config/ssm-store.d.ts +2 -0
  9. package/dist/config/ssm-store.js +38 -0
  10. package/dist/config/telemetry.d.ts +17 -0
  11. package/dist/config/telemetry.js +93 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +460 -0
  14. package/dist/knowledge/dynamo-store.d.ts +17 -0
  15. package/dist/knowledge/dynamo-store.js +85 -0
  16. package/dist/knowledge/embeddings.d.ts +2 -0
  17. package/dist/knowledge/embeddings.js +36 -0
  18. package/dist/knowledge/loader.d.ts +8 -0
  19. package/dist/knowledge/loader.js +57 -0
  20. package/dist/lambda-package.zip +0 -0
  21. package/dist/lambda.d.ts +22 -0
  22. package/dist/lambda.js +496 -0
  23. package/dist/package.json +1 -0
  24. package/dist/tools/advance-process.d.ts +7 -0
  25. package/dist/tools/advance-process.js +128 -0
  26. package/dist/tools/analyze-code.d.ts +7 -0
  27. package/dist/tools/analyze-code.js +131 -0
  28. package/dist/tools/analyze-docs.d.ts +8 -0
  29. package/dist/tools/analyze-docs.js +147 -0
  30. package/dist/tools/config-registry.d.ts +3 -0
  31. package/dist/tools/config-registry.js +20 -0
  32. package/dist/tools/create-process.d.ts +6 -0
  33. package/dist/tools/create-process.js +257 -0
  34. package/dist/tools/decompose-epic.d.ts +7 -0
  35. package/dist/tools/decompose-epic.js +603 -0
  36. package/dist/tools/diagrams.d.ts +51 -0
  37. package/dist/tools/diagrams.js +304 -0
  38. package/dist/tools/generate-report.d.ts +9 -0
  39. package/dist/tools/generate-report.js +891 -0
  40. package/dist/tools/generate-wiki.d.ts +10 -0
  41. package/dist/tools/generate-wiki.js +700 -0
  42. package/dist/tools/get-architecture.d.ts +6 -0
  43. package/dist/tools/get-architecture.js +78 -0
  44. package/dist/tools/get-code-standards.d.ts +7 -0
  45. package/dist/tools/get-code-standards.js +52 -0
  46. package/dist/tools/init-process.d.ts +7 -0
  47. package/dist/tools/init-process.js +82 -0
  48. package/dist/tools/knowledge-crud.d.ts +26 -0
  49. package/dist/tools/knowledge-crud.js +142 -0
  50. package/dist/tools/logo-base64.d.ts +1 -0
  51. package/dist/tools/logo-base64.js +1 -0
  52. package/dist/tools/logs-query.d.ts +15 -0
  53. package/dist/tools/logs-query.js +46 -0
  54. package/dist/tools/reverse-engineer.d.ts +13 -0
  55. package/dist/tools/reverse-engineer.js +956 -0
  56. package/dist/tools/semantic-search.d.ts +7 -0
  57. package/dist/tools/semantic-search.js +68 -0
  58. package/dist/tools/update-process.d.ts +17 -0
  59. package/dist/tools/update-process.js +195 -0
  60. package/dist/tools/validate-idea.d.ts +7 -0
  61. package/dist/tools/validate-idea.js +339 -0
  62. package/dist/tools/validate-process.d.ts +6 -0
  63. package/dist/tools/validate-process.js +102 -0
  64. package/package.json +31 -0
@@ -0,0 +1,603 @@
1
+ /**
2
+ * Tool: decompose_epic
3
+ * Recebe um EP-XX do markdown de épicos e gera a decomposição completa:
4
+ * EPIC-XXX.md + FEAT-XXX.md[] + US-XXX.md[] + TASK-XXX.md[]
5
+ *
6
+ * Lê o markdown de épicos do processo, parseia o EP solicitado,
7
+ * e gera os artefatos seguindo o padrão do processo 9760b430.
8
+ */
9
+ import { writeFile, mkdir, readFile } from "node:fs/promises";
10
+ import { join } from "node:path";
11
+ import { existsSync } from "node:fs";
12
+ // ============================================================
13
+ // EPIC PARSER — reads EP-XX from epicos markdown
14
+ // ============================================================
15
+ function parseEpicFromMarkdown(content, epicId) {
16
+ const sections = content.split(/\n## /);
17
+ const normalizedId = epicId.replace("EP-", "").padStart(2, "0");
18
+ const prefix = `EP-${normalizedId}`;
19
+ const epicSection = sections.find((s) => s.trim().startsWith(prefix));
20
+ if (!epicSection)
21
+ return null;
22
+ const lines = epicSection.split("\n");
23
+ const titleLine = lines[0] || "";
24
+ const titleMatch = titleLine.match(/EP-\d{2}\s*[—-]\s*(.+)/);
25
+ const title = titleMatch ? titleMatch[1].trim() : titleLine.trim();
26
+ let objective = "";
27
+ let scope = [];
28
+ let criteria = [];
29
+ let dependencies = [];
30
+ let squads = [];
31
+ let size = "M";
32
+ let currentBlock = "";
33
+ for (const line of lines) {
34
+ const trimmed = line.trim();
35
+ if (!trimmed || trimmed === "---")
36
+ continue;
37
+ if (trimmed.startsWith("**Objetivo:**")) {
38
+ objective = trimmed.replace("**Objetivo:**", "").trim();
39
+ currentBlock = "";
40
+ continue;
41
+ }
42
+ if (trimmed.startsWith("**Escopo:**")) {
43
+ currentBlock = "scope";
44
+ continue;
45
+ }
46
+ if (trimmed.startsWith("**Critérios de aceite:**") || trimmed.startsWith("**Criterios de aceite:**")) {
47
+ currentBlock = "criteria";
48
+ continue;
49
+ }
50
+ if (trimmed.match(/^\*\*Depend[eê]ncias:\*\*/)) {
51
+ const val = trimmed.replace(/\*\*Depend[eê]ncias:\*\*/, "").trim();
52
+ if (val && !val.includes("Nenhuma")) {
53
+ dependencies = val.split(",").map((d) => d.trim()).filter(Boolean);
54
+ }
55
+ currentBlock = "";
56
+ continue;
57
+ }
58
+ if (trimmed.startsWith("**Squads:**")) {
59
+ squads = trimmed.replace("**Squads:**", "").trim().split("+").map((s) => s.trim()).filter(Boolean);
60
+ currentBlock = "";
61
+ continue;
62
+ }
63
+ if (trimmed.startsWith("**Estimativa:**")) {
64
+ size = trimmed.includes("L") ? "L" : "M";
65
+ currentBlock = "";
66
+ continue;
67
+ }
68
+ if (trimmed.startsWith("- ") && currentBlock === "scope") {
69
+ scope.push(trimmed.slice(2));
70
+ }
71
+ else if ((trimmed.startsWith("- [ ]") || trimmed.startsWith("- [x]")) && currentBlock === "criteria") {
72
+ criteria.push(trimmed.replace(/^- \[.\]\s*/, ""));
73
+ }
74
+ else if (trimmed.startsWith("- ") && currentBlock === "criteria") {
75
+ criteria.push(trimmed.slice(2));
76
+ }
77
+ }
78
+ return { id: prefix, title, objective, scope, criteria, dependencies, squads, size };
79
+ }
80
+ // ============================================================
81
+ // DECOMPOSITION ENGINE
82
+ // ============================================================
83
+ function decomposeToFeatures(epic, startFeatIdx) {
84
+ const features = [];
85
+ // Group scope items into logical features (2-4 scope items per feature)
86
+ const scopeGroups = [];
87
+ const chunkSize = Math.max(2, Math.ceil(epic.scope.length / Math.ceil(epic.scope.length / 3)));
88
+ for (let i = 0; i < epic.scope.length; i += chunkSize) {
89
+ scopeGroups.push(epic.scope.slice(i, i + chunkSize));
90
+ }
91
+ scopeGroups.forEach((group, idx) => {
92
+ const featNum = (startFeatIdx + idx).toString().padStart(3, "0");
93
+ const featId = `FEAT-${featNum}`;
94
+ const title = inferFeatureTitle(group, epic.title);
95
+ const description = `Implementar ${group.join(", ").toLowerCase()} como parte do épico ${epic.id} (${epic.title}).`;
96
+ // Generate criteria from scope items
97
+ const criteria = group.map((s) => `Funcionalidade "${s}" implementada e testada`);
98
+ features.push({
99
+ id: featId,
100
+ epicId: epic.id,
101
+ title,
102
+ description,
103
+ userStories: [], // filled later
104
+ criteria,
105
+ priority: idx === 0 ? "Alta" : "Media",
106
+ });
107
+ });
108
+ return features;
109
+ }
110
+ function inferFeatureTitle(scopeItems, epicTitle) {
111
+ // Try to find a common theme in the scope items
112
+ const first = scopeItems[0] || epicTitle;
113
+ if (scopeItems.length === 1)
114
+ return first;
115
+ // Use the first item as the main title, simplified
116
+ const simplified = first
117
+ .replace(/\(.*?\)/g, "")
118
+ .replace(/\s+/g, " ")
119
+ .trim();
120
+ return simplified.length > 60 ? simplified.slice(0, 57) + "..." : simplified;
121
+ }
122
+ function decomposeToUserStories(feature, epic, startUsIdx) {
123
+ const stories = [];
124
+ // Each criterion becomes a user story
125
+ feature.criteria.forEach((criterion, idx) => {
126
+ const usNum = (startUsIdx + idx).toString().padStart(3, "0");
127
+ const usId = `US-${usNum}`;
128
+ // Determine persona based on content
129
+ const persona = inferPersona(criterion, epic);
130
+ stories.push({
131
+ id: usId,
132
+ featId: feature.id,
133
+ epicId: epic.id,
134
+ title: criterion.replace(/^Funcionalidade "/, "").replace(/" implementada.*/, ""),
135
+ asA: persona.role,
136
+ iWant: criterion.toLowerCase(),
137
+ soThat: persona.benefit,
138
+ criteria: generateBDDCriteria(criterion),
139
+ tasks: [], // filled later
140
+ });
141
+ });
142
+ return stories;
143
+ }
144
+ function inferPersona(criterion, epic) {
145
+ const lower = criterion.toLowerCase();
146
+ if (lower.includes("api") || lower.includes("integra") || lower.includes("backend"))
147
+ return { role: "desenvolvedor backend", benefit: "a integração funcione de forma confiável" };
148
+ if (lower.includes("tela") || lower.includes("app") || lower.includes("mobile") || lower.includes("web"))
149
+ return { role: "usuário do aplicativo", benefit: "eu possa realizar a operação de forma intuitiva" };
150
+ if (lower.includes("monitor") || lower.includes("log") || lower.includes("alert") || lower.includes("dashboard"))
151
+ return { role: "engenheiro de plataforma", benefit: "eu possa monitorar e diagnosticar problemas rapidamente" };
152
+ if (lower.includes("segur") || lower.includes("certific") || lower.includes("auth"))
153
+ return { role: "engenheiro de segurança", benefit: "a comunicação seja segura e auditável" };
154
+ return { role: "usuário do sistema", benefit: "a funcionalidade atenda aos requisitos de negócio" };
155
+ }
156
+ function generateBDDCriteria(criterion) {
157
+ return [
158
+ `Dado que o sistema está configurado corretamente`,
159
+ `Quando a funcionalidade "${criterion}" é executada`,
160
+ `Então o resultado esperado é obtido sem erros`,
161
+ `E logs de auditoria são gerados`,
162
+ ];
163
+ }
164
+ function decomposeToTasks(story, startTaskIdx) {
165
+ const tasks = [];
166
+ // Dev task
167
+ const devNum = (startTaskIdx).toString().padStart(3, "0");
168
+ tasks.push({
169
+ id: `TASK-${devNum}`,
170
+ usId: story.id,
171
+ featId: story.featId,
172
+ title: `Implementar ${story.title}`,
173
+ type: "dev",
174
+ instructions: [
175
+ `Criar/atualizar módulos conforme especificação da ${story.id}`,
176
+ `Implementar lógica de negócio conforme critérios de aceite`,
177
+ `Integrar com APIs/serviços necessários`,
178
+ `Implementar tratamento de erros e logging estruturado`,
179
+ ],
180
+ files: [],
181
+ estimate: "4h",
182
+ });
183
+ // QA task
184
+ const qaNum = (startTaskIdx + 1).toString().padStart(3, "0");
185
+ tasks.push({
186
+ id: `TASK-${qaNum}`,
187
+ usId: story.id,
188
+ featId: story.featId,
189
+ title: `Testes da ${story.id} — ${story.title}`,
190
+ type: "qa",
191
+ instructions: [
192
+ `Criar testes unitários com cobertura >= 80%`,
193
+ `Criar testes de integração para fluxos principais`,
194
+ `Validar critérios de aceite BDD`,
195
+ `Verificar tratamento de erros e edge cases`,
196
+ ],
197
+ files: [],
198
+ estimate: "3h",
199
+ });
200
+ return tasks;
201
+ }
202
+ // ============================================================
203
+ // MARKDOWN GENERATORS
204
+ // ============================================================
205
+ function generateEpicMd(epic, features, processId) {
206
+ const epicNum = epic.id.replace("EP-", "").padStart(3, "0");
207
+ const now = new Date().toISOString().split("T")[0];
208
+ const featTable = features.map((f) => `| ${f.id} | ${f.title} | ${f.priority} | backlog |`).join("\n");
209
+ const criteriaList = epic.criteria.map((c) => `- [ ] ${c}`).join("\n");
210
+ const scopeList = epic.scope.map((s) => `- ${s}`).join("\n");
211
+ const depsText = epic.dependencies.length > 0 ? epic.dependencies.join(", ") : "Nenhuma (épico fundacional)";
212
+ const squadsText = epic.squads.join(" + ");
213
+ return `# EPIC-${epicNum}: ${epic.title}
214
+
215
+ > Processo: ${processId}
216
+ > Autor: Product Manager
217
+ > Data: ${now}
218
+ > Versao: v1.0.0
219
+
220
+ ---
221
+
222
+ ## Metadata
223
+
224
+ | Campo | Valor |
225
+ |-------|-------|
226
+ | ID | EPIC-${epicNum} |
227
+ | Status | backlog |
228
+ | Prioridade | Alta |
229
+ | Owner | Product Manager |
230
+ | Estimativa | ${epic.size === "L" ? "Grande" : "Médio"} |
231
+ | Processo | ${processId} |
232
+ | Criado em | ${now} |
233
+
234
+ ---
235
+
236
+ ## 1. Objetivo de Negócio (*)
237
+ ${epic.objective}
238
+
239
+ ## 2. Escopo (*)
240
+
241
+ ${scopeList}
242
+
243
+ ## 3. Features (*)
244
+
245
+ | ID | Feature | Prioridade | Status |
246
+ |----|---------|------------|--------|
247
+ ${featTable}
248
+
249
+ ## 4. Dependências
250
+
251
+ ${depsText}
252
+
253
+ ## 5. Squads
254
+
255
+ ${squadsText}
256
+
257
+ ## 6. Critérios de Aceite do Épico (*)
258
+
259
+ ${criteriaList}
260
+
261
+ ---
262
+
263
+ ## Changelog
264
+
265
+ | Versão | Data | Autor | Mudança |
266
+ |--------|------|-------|---------|
267
+ | v1.0.0 | ${now} | Creative IA 50 | Gerado via decompose_epic |
268
+ `;
269
+ }
270
+ function generateFeatureMd(feat, stories, epic, processId) {
271
+ const now = new Date().toISOString().split("T")[0];
272
+ const usTable = stories.map((us) => `| ${us.id} | ${us.title} | 5 | Alta | backlog |`).join("\n");
273
+ const criteriaList = feat.criteria.map((c) => `- [ ] ${c}`).join("\n");
274
+ return `# ${feat.id}: ${feat.title}
275
+
276
+ > Processo: ${processId}
277
+ > Autor: Product Manager
278
+ > Data: ${now}
279
+ > Versao: v1.0.0
280
+
281
+ ---
282
+
283
+ ## Metadata
284
+
285
+ | Campo | Valor |
286
+ |-------|-------|
287
+ | ID | ${feat.id} |
288
+ | Épico | ${epic.id} — ${epic.title} |
289
+ | Status | backlog |
290
+ | Prioridade | ${feat.priority} |
291
+ | Processo | ${processId} |
292
+ | Criado em | ${now} |
293
+
294
+ ---
295
+
296
+ ## 1. Descrição (*)
297
+ ${feat.description}
298
+
299
+ ## 2. User Stories (*)
300
+
301
+ | ID | User Story | Pontos | Prioridade | Status |
302
+ |----|-----------|--------|------------|--------|
303
+ ${usTable}
304
+
305
+ ## 3. Critérios de Aceite da Feature (*)
306
+
307
+ ${criteriaList}
308
+
309
+ ## 4. Dependências
310
+
311
+ | Tipo | Descrição | Status |
312
+ |------|-----------|--------|
313
+ | Épico | ${epic.id} — ${epic.title} | backlog |
314
+
315
+ ---
316
+
317
+ ## Changelog
318
+
319
+ | Versão | Data | Autor | Mudança |
320
+ |--------|------|-------|---------|
321
+ | v1.0.0 | ${now} | Creative IA 50 | Gerado via decompose_epic |
322
+ `;
323
+ }
324
+ function generateUserStoryMd(us, epic, tasks, processId) {
325
+ const now = new Date().toISOString().split("T")[0];
326
+ const taskTable = tasks.map((t) => `| ${t.id} | ${t.title} | ${t.type} | — | ${t.estimate} | backlog |`).join("\n");
327
+ const criteriaText = us.criteria.map((c, i) => {
328
+ if (i === 0)
329
+ return `**Cenário 1: Sucesso**\n- **Dado** ${c}`;
330
+ if (i === 1)
331
+ return `- **Quando** ${c}`;
332
+ if (i === 2)
333
+ return `- **Então** ${c}`;
334
+ return `- **E** ${c}`;
335
+ }).join("\n");
336
+ return `# ${us.id}: ${us.title}
337
+
338
+ > Processo: ${processId}
339
+ > Autor: Tech Lead
340
+ > Data: ${now}
341
+
342
+ ---
343
+
344
+ ## Metadata
345
+
346
+ | Campo | Valor |
347
+ |-------|-------|
348
+ | ID | ${us.id} |
349
+ | Feature | ${us.featId} |
350
+ | Épico | ${epic.id} — ${epic.title} |
351
+ | Status | backlog |
352
+ | Prioridade | Alta |
353
+ | Story Points | 5 |
354
+ | Processo | ${processId} |
355
+
356
+ ---
357
+
358
+ ## 1. User Story (*)
359
+
360
+ **Como** ${us.asA},
361
+ **Quero** ${us.iWant},
362
+ **Para** ${us.soThat}.
363
+
364
+ ## 2. Critérios de Aceite (*)
365
+
366
+ ${criteriaText}
367
+
368
+ ## 3. Tasks (*)
369
+
370
+ | ID | Task | Tipo | Assignee | Estimativa | Status |
371
+ |----|------|------|----------|------------|--------|
372
+ ${taskTable}
373
+
374
+ ## 4. Definição de Ready (DoR)
375
+
376
+ - [ ] Critérios de aceite escritos e revisados
377
+ - [ ] Dependências mapeadas e resolvidas
378
+ - [ ] Tasks decompostas com estimativa
379
+
380
+ ## 5. Definição de Done (DoD)
381
+
382
+ - [ ] Código implementado e revisado (PR aprovado)
383
+ - [ ] Testes unitários passando (cobertura >= 80%)
384
+ - [ ] Critérios de aceite validados
385
+ - [ ] Sem bugs críticos ou bloqueantes
386
+ - [ ] Documentação atualizada
387
+
388
+ ---
389
+
390
+ ## Changelog
391
+
392
+ | Data | Autor | Mudança |
393
+ |------|-------|---------|
394
+ | ${now} | Creative IA 50 | Gerado via decompose_epic |
395
+ `;
396
+ }
397
+ function generateTaskMd(task, processId) {
398
+ const now = new Date().toISOString().split("T")[0];
399
+ const instructionsList = task.instructions.map((i, idx) => `${idx + 1}. ${i}`).join("\n");
400
+ return `# ${task.id}: ${task.title}
401
+
402
+ > Processo: ${processId}
403
+ > Autor: Tech Lead
404
+ > Data: ${now}
405
+
406
+ ---
407
+
408
+ ## Metadata
409
+
410
+ | Campo | Valor |
411
+ |-------|-------|
412
+ | ID | ${task.id} |
413
+ | User Story | ${task.usId} |
414
+ | Feature | ${task.featId} |
415
+ | Tipo | ${task.type} |
416
+ | Status | backlog |
417
+ | Estimativa | ${task.estimate} |
418
+ | Processo | ${processId} |
419
+
420
+ ---
421
+
422
+ ## 1. Objetivo (*)
423
+
424
+ ${task.title}.
425
+
426
+ ## 2. Instruções de Implementação (*)
427
+
428
+ ${instructionsList}
429
+
430
+ ## 3. Critérios de Aceite (*)
431
+
432
+ - [ ] Funcionalidade implementada conforme especificação
433
+ - [ ] Tratamento de erros implementado
434
+ - [ ] Testes passando (cobertura >= 80%)
435
+ - [ ] Sem warnings de lint/build
436
+
437
+ ## 4. Definition of Done (*)
438
+
439
+ - [ ] Código implementado conforme instruções
440
+ - [ ] Code review aprovado
441
+ - [ ] Testes escritos e passando
442
+ - [ ] Documentação atualizada
443
+
444
+ ---
445
+
446
+ ## Changelog
447
+
448
+ | Data | Autor | Mudança |
449
+ |------|-------|---------|
450
+ | ${now} | Creative IA 50 | Gerado via decompose_epic |
451
+ `;
452
+ }
453
+ // ============================================================
454
+ // MAIN FUNCTION — decompose_epic
455
+ // ============================================================
456
+ export async function decomposeEpic(params) {
457
+ const { processId, epicId, processDir } = params;
458
+ // 1. Find and read the epicos markdown
459
+ const possibleFiles = [
460
+ `03-epicos-${processId}.md`,
461
+ `03-epicos.md`,
462
+ ];
463
+ // Also search for any file starting with 03-epicos
464
+ let epicsMdPath = "";
465
+ let epicsMdContent = "";
466
+ for (const f of possibleFiles) {
467
+ const p = join(processDir, f);
468
+ if (existsSync(p)) {
469
+ epicsMdPath = p;
470
+ epicsMdContent = await readFile(p, "utf-8");
471
+ break;
472
+ }
473
+ }
474
+ // Fallback: search for any 03-epicos*.md file
475
+ if (!epicsMdContent) {
476
+ const { readdirSync } = await import("node:fs");
477
+ try {
478
+ const files = readdirSync(processDir);
479
+ const epicFile = files.find((f) => f.startsWith("03-epicos") && f.endsWith(".md"));
480
+ if (epicFile) {
481
+ epicsMdPath = join(processDir, epicFile);
482
+ epicsMdContent = await readFile(epicsMdPath, "utf-8");
483
+ }
484
+ }
485
+ catch { /* ignore */ }
486
+ }
487
+ if (!epicsMdContent) {
488
+ return `Erro: Não encontrei o markdown de épicos no processo ${processId}. Esperado: 03-epicos*.md em ${processDir}`;
489
+ }
490
+ // 2. Parse the requested epic
491
+ const epic = parseEpicFromMarkdown(epicsMdContent, epicId);
492
+ if (!epic) {
493
+ return `Erro: Épico ${epicId} não encontrado no markdown. Épicos disponíveis: ${(epicsMdContent.match(/## EP-\d{2}/g) || []).join(", ")}`;
494
+ }
495
+ // 3. Check existing artifacts to determine starting indices
496
+ const { readdirSync } = await import("node:fs");
497
+ let maxFeat = 0, maxUs = 0, maxTask = 0;
498
+ try {
499
+ const featDir = join(processDir, "features");
500
+ if (existsSync(featDir)) {
501
+ const feats = readdirSync(featDir).filter((f) => f.match(/^FEAT-\d+\.md$/));
502
+ feats.forEach((f) => {
503
+ const num = parseInt(f.replace("FEAT-", "").replace(".md", ""), 10);
504
+ if (num > maxFeat)
505
+ maxFeat = num;
506
+ });
507
+ }
508
+ }
509
+ catch { /* ignore */ }
510
+ try {
511
+ const usDir = join(processDir, "user-stories");
512
+ if (existsSync(usDir)) {
513
+ const uss = readdirSync(usDir).filter((f) => f.match(/^US-\d+\.md$/));
514
+ uss.forEach((f) => {
515
+ const num = parseInt(f.replace("US-", "").replace(".md", ""), 10);
516
+ if (num > maxUs)
517
+ maxUs = num;
518
+ });
519
+ }
520
+ }
521
+ catch { /* ignore */ }
522
+ try {
523
+ const taskDir = join(processDir, "tasks");
524
+ if (existsSync(taskDir)) {
525
+ const tasks = readdirSync(taskDir).filter((f) => f.match(/^TASK-\d+\.md$/));
526
+ tasks.forEach((f) => {
527
+ const num = parseInt(f.replace("TASK-", "").replace(".md", ""), 10);
528
+ if (num > maxTask)
529
+ maxTask = num;
530
+ });
531
+ }
532
+ }
533
+ catch { /* ignore */ }
534
+ // 4. Decompose
535
+ const features = decomposeToFeatures(epic, maxFeat + 1);
536
+ let usIdx = maxUs + 1;
537
+ let taskIdx = maxTask + 1;
538
+ const allStories = [];
539
+ const allTasks = [];
540
+ for (const feat of features) {
541
+ const stories = decomposeToUserStories(feat, epic, usIdx);
542
+ usIdx += stories.length;
543
+ feat.userStories = stories.map((s) => s.id);
544
+ allStories.push({ feature: feat, stories });
545
+ for (const story of stories) {
546
+ const tasks = decomposeToTasks(story, taskIdx);
547
+ taskIdx += tasks.length;
548
+ story.tasks = tasks.map((t) => t.id);
549
+ allTasks.push({ story, tasks });
550
+ }
551
+ }
552
+ // 5. Create directories
553
+ const dirs = ["epics", "features", "user-stories", "tasks"];
554
+ for (const d of dirs) {
555
+ await mkdir(join(processDir, d), { recursive: true });
556
+ }
557
+ // 6. Write files
558
+ const epicNum = epic.id.replace("EP-", "").padStart(3, "0");
559
+ const filesCreated = [];
560
+ // Epic
561
+ const epicPath = join(processDir, "epics", `EPIC-${epicNum}.md`);
562
+ await writeFile(epicPath, generateEpicMd(epic, features, processId), "utf-8");
563
+ filesCreated.push(`epics/EPIC-${epicNum}.md`);
564
+ // Features
565
+ for (const { feature, stories } of allStories) {
566
+ const featPath = join(processDir, "features", `${feature.id}.md`);
567
+ await writeFile(featPath, generateFeatureMd(feature, stories, epic, processId), "utf-8");
568
+ filesCreated.push(`features/${feature.id}.md`);
569
+ }
570
+ // User Stories
571
+ for (const { story, tasks } of allTasks) {
572
+ const usPath = join(processDir, "user-stories", `${story.id}.md`);
573
+ await writeFile(usPath, generateUserStoryMd(story, epic, tasks, processId), "utf-8");
574
+ filesCreated.push(`user-stories/${story.id}.md`);
575
+ }
576
+ // Tasks
577
+ for (const { tasks } of allTasks) {
578
+ for (const task of tasks) {
579
+ const taskPath = join(processDir, "tasks", `${task.id}.md`);
580
+ await writeFile(taskPath, generateTaskMd(task, processId), "utf-8");
581
+ filesCreated.push(`tasks/${task.id}.md`);
582
+ }
583
+ }
584
+ // 7. Summary
585
+ const totalFeats = features.length;
586
+ const totalUs = allStories.reduce((sum, s) => sum + s.stories.length, 0);
587
+ const totalTasks = allTasks.reduce((sum, t) => sum + t.tasks.length, 0);
588
+ const summary = [
589
+ `Decomposição do ${epic.id} — ${epic.title} concluída.`,
590
+ ``,
591
+ `Artefatos gerados:`,
592
+ ` • 1 épico detalhado (EPIC-${epicNum})`,
593
+ ` • ${totalFeats} features (${features.map((f) => f.id).join(", ")})`,
594
+ ` • ${totalUs} user stories`,
595
+ ` • ${totalTasks} tasks`,
596
+ ``,
597
+ `Arquivos criados (${filesCreated.length}):`,
598
+ ...filesCreated.map((f) => ` ${f}`),
599
+ ``,
600
+ `Diretório: ${processDir}`,
601
+ ].join("\n");
602
+ return summary;
603
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Geradores de Diagramas — CSS puro usando classes bd-* do _base-styles.css
3
+ * Gera diagramas visuais de workflow, arquitetura, dominios, riscos, integracoes e benchmark.
4
+ * IP protegido: os templates de diagrama nunca sao expostos ao cliente.
5
+ */
6
+ interface FaseWorkflow {
7
+ name: string;
8
+ status: "concluido" | "ativo" | "pendente";
9
+ subtitle?: string;
10
+ }
11
+ export declare function renderWorkflowDiagram(phases: FaseWorkflow[]): string;
12
+ export declare function renderArchitectureDiagram(): string;
13
+ interface NoDominio {
14
+ name: string;
15
+ type: "core" | "supporting" | "generic";
16
+ squad: string;
17
+ }
18
+ export declare function renderDomainMap(domains: NoDominio[]): string;
19
+ interface ItemRisco {
20
+ name: string;
21
+ probability: "baixa" | "media" | "alta";
22
+ impact: "baixo" | "medio" | "alto";
23
+ category?: string;
24
+ }
25
+ export declare function renderRiskMatrix(risks: ItemRisco[]): string;
26
+ interface NoIntegracao {
27
+ name: string;
28
+ type: "interno" | "externo" | "gateway";
29
+ protocol?: string;
30
+ }
31
+ interface LinkIntegracao {
32
+ from: string;
33
+ to: string;
34
+ label?: string;
35
+ protocol?: string;
36
+ }
37
+ export declare function renderIntegrationFlow(nodes: NoIntegracao[], links: LinkIntegracao[]): string;
38
+ interface Concorrente {
39
+ nome: string;
40
+ tipo: "banco" | "fintech" | "financeira" | "cooperativa" | "nosso";
41
+ indicadores: Record<string, number | string>;
42
+ destaque?: boolean;
43
+ }
44
+ interface DimensaoBenchmark {
45
+ nome: string;
46
+ chave: string;
47
+ unidade?: string;
48
+ maiorMelhor: boolean;
49
+ }
50
+ export declare function renderBenchmarkMercado(concorrentes: Concorrente[], dimensoes: DimensaoBenchmark[], titulo?: string, fontes?: string[]): string;
51
+ export {};