@semacode/cli 1.3.2 → 1.3.6

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 (96) hide show
  1. package/dist/index.js +33 -27
  2. package/dist/index.js.map +1 -1
  3. package/node_modules/@sema/gerador-css/package.json +10 -3
  4. package/node_modules/@sema/gerador-css/src/index.ts +605 -0
  5. package/node_modules/@sema/gerador-css/tsconfig.json +13 -0
  6. package/node_modules/@sema/gerador-css/tsconfig.tsbuildinfo +1 -0
  7. package/node_modules/@sema/gerador-dart/package.json +10 -3
  8. package/node_modules/@sema/gerador-dart/src/index.ts +52 -0
  9. package/node_modules/@sema/gerador-dart/tsconfig.json +13 -0
  10. package/node_modules/@sema/gerador-dart/tsconfig.tsbuildinfo +1 -0
  11. package/node_modules/@sema/gerador-html/package.json +10 -3
  12. package/node_modules/@sema/gerador-html/src/index.ts +185 -0
  13. package/node_modules/@sema/gerador-html/tsconfig.json +13 -0
  14. package/node_modules/@sema/gerador-html/tsconfig.tsbuildinfo +1 -0
  15. package/node_modules/@sema/gerador-javascript/package.json +10 -3
  16. package/node_modules/@sema/gerador-javascript/src/index.ts +461 -0
  17. package/node_modules/@sema/gerador-javascript/tsconfig.json +13 -0
  18. package/node_modules/@sema/gerador-javascript/tsconfig.tsbuildinfo +1 -0
  19. package/node_modules/@sema/gerador-lua/package.json +10 -3
  20. package/node_modules/@sema/gerador-lua/src/index.d.ts +3 -0
  21. package/node_modules/@sema/gerador-lua/src/index.js.map +1 -0
  22. package/node_modules/@sema/gerador-lua/src/index.ts +359 -0
  23. package/node_modules/@sema/gerador-lua/tsconfig.json +13 -0
  24. package/node_modules/@sema/gerador-lua/tsconfig.tsbuildinfo +1 -0
  25. package/node_modules/@sema/gerador-python/package.json +10 -3
  26. package/node_modules/@sema/gerador-python/src/index.ts +706 -0
  27. package/node_modules/@sema/gerador-python/tsconfig.json +13 -0
  28. package/node_modules/@sema/gerador-python/tsconfig.tsbuildinfo +1 -0
  29. package/node_modules/@sema/gerador-typescript/package.json +10 -3
  30. package/node_modules/@sema/gerador-typescript/src/index.ts +728 -0
  31. package/node_modules/@sema/gerador-typescript/tsconfig.json +13 -0
  32. package/node_modules/@sema/gerador-typescript/tsconfig.tsbuildinfo +1 -0
  33. package/node_modules/@sema/nucleo/package.json +6 -3
  34. package/node_modules/@sema/nucleo/src/ast/tipos.ts +191 -0
  35. package/node_modules/@sema/nucleo/src/diagnosticos/index.ts +43 -0
  36. package/node_modules/@sema/nucleo/src/formatador/index.ts +507 -0
  37. package/node_modules/@sema/nucleo/src/index.ts +133 -0
  38. package/node_modules/@sema/nucleo/src/ir/conversor.ts +912 -0
  39. package/node_modules/@sema/nucleo/src/ir/modelos.ts +331 -0
  40. package/node_modules/@sema/nucleo/src/lexer/lexer.ts +166 -0
  41. package/node_modules/@sema/nucleo/src/lexer/tokens.ts +64 -0
  42. package/node_modules/@sema/nucleo/src/parser/gramatica.ebnf +39 -0
  43. package/node_modules/@sema/nucleo/src/parser/parser.ts +790 -0
  44. package/node_modules/@sema/nucleo/src/semantico/analisador.ts +2692 -0
  45. package/node_modules/@sema/nucleo/src/semantico/estruturas.ts +632 -0
  46. package/node_modules/@sema/nucleo/src/semantico/seguranca.ts +362 -0
  47. package/node_modules/@sema/nucleo/src/util/arquivos.ts +28 -0
  48. package/node_modules/@sema/nucleo/tsconfig.json +9 -0
  49. package/node_modules/@sema/nucleo/tsconfig.tsbuildinfo +1 -0
  50. package/node_modules/@sema/padroes/package.json +6 -3
  51. package/node_modules/@sema/padroes/src/index.ts +251 -0
  52. package/node_modules/@sema/padroes/tsconfig.json +9 -0
  53. package/node_modules/@sema/padroes/tsconfig.tsbuildinfo +1 -0
  54. package/package.json +21 -33
  55. package/AGENTS.md +0 -272
  56. package/LICENSE +0 -22
  57. package/README.md +0 -73
  58. package/SEMA_BRIEF.curto.txt +0 -9
  59. package/SEMA_BRIEF.md +0 -49
  60. package/SEMA_BRIEF.micro.txt +0 -7
  61. package/SEMA_INDEX.json +0 -546
  62. package/docs/AGENT_STARTER.md +0 -102
  63. package/docs/como-ensinar-a-sema-para-ia.md +0 -149
  64. package/docs/fluxo-pratico-ia-sema.md +0 -177
  65. package/docs/instalacao-e-primeiro-uso.md +0 -196
  66. package/docs/integracao-com-ia.md +0 -228
  67. package/docs/pagamento-ponta-a-ponta.md +0 -155
  68. package/docs/prompt-base-ia-sema.md +0 -104
  69. package/docs/sintaxe.md +0 -361
  70. package/exemplos/agendamento.sema +0 -106
  71. package/exemplos/assinatura.sema +0 -136
  72. package/exemplos/auditoria.sema +0 -88
  73. package/exemplos/autenticacao.sema +0 -125
  74. package/exemplos/automacao.sema +0 -107
  75. package/exemplos/cadastro_usuario.sema +0 -54
  76. package/exemplos/calculadora.sema +0 -78
  77. package/exemplos/crud_simples.sema +0 -89
  78. package/exemplos/estoque.sema +0 -126
  79. package/exemplos/exportacao.sema +0 -94
  80. package/exemplos/fila.sema +0 -131
  81. package/exemplos/integracao_externa.sema +0 -94
  82. package/exemplos/multi_tenant.sema +0 -140
  83. package/exemplos/notificacao.sema +0 -98
  84. package/exemplos/operacao_estrategia.sema +0 -402
  85. package/exemplos/pagamento.sema +0 -222
  86. package/exemplos/pagamento_dominio.sema +0 -35
  87. package/exemplos/pedido.sema +0 -119
  88. package/exemplos/permissao.sema +0 -121
  89. package/exemplos/relatorio.sema +0 -93
  90. package/exemplos/testes_embutidos.sema +0 -45
  91. package/exemplos/tratamento_erro.sema +0 -157
  92. package/exemplos/upload_arquivo.sema +0 -93
  93. package/exemplos/webhook.sema +0 -96
  94. package/llms-full.txt +0 -34
  95. package/llms.txt +0 -17
  96. package/logo.png +0 -0
@@ -0,0 +1,912 @@
1
+ import type { BlocoCasoTesteAst, BlocoGenericoAst, CampoAst, ModuloAst } from "../ast/tipos.js";
2
+ import type { Diagnostico } from "../diagnosticos/index.js";
3
+ import type { ContextoSemantico, ErroSemanticoTask } from "../semantico/analisador.js";
4
+ import {
5
+ contratoDadosTemSensivel,
6
+ extrairContratoAudit,
7
+ extrairContratoAuth,
8
+ extrairContratoAuthz,
9
+ extrairContratoDados,
10
+ extrairContratoForbidden,
11
+ extrairContratoSegredos,
12
+ efeitoEhPrivilegiado,
13
+ } from "../semantico/seguranca.js";
14
+ import { parsearEfeitoSemantico, parsearEtapaFlow, parsearExpressaoSemantica, parsearTransicaoEstado } from "../semantico/estruturas.js";
15
+ import type {
16
+ IrBlocoDeclarativo,
17
+ IrCampo,
18
+ IrCasoTeste,
19
+ IrAudit,
20
+ IrAuth,
21
+ IrAuthz,
22
+ IrDados,
23
+ IrEntity,
24
+ IrErroOperacional,
25
+ IrExecucao,
26
+ IrForbidden,
27
+ IrFlow,
28
+ IrImplementacaoTask,
29
+ IrModulo,
30
+ IrResumoAgente,
31
+ IrRoute,
32
+ IrRoutePublica,
33
+ IrSegredos,
34
+ IrState,
35
+ IrSuperficie,
36
+ IrTask,
37
+ IrType,
38
+ IrVinculo,
39
+ NivelConfiancaSemantica,
40
+ NivelRiscoSemantico,
41
+ PerfilCompatibilidade,
42
+ TipoSuperficieIr,
43
+ } from "./modelos.js";
44
+
45
+ const TIPOS_PRIMITIVOS = new Set([
46
+ "Texto",
47
+ "Numero",
48
+ "Inteiro",
49
+ "Decimal",
50
+ "Booleano",
51
+ "Data",
52
+ "DataHora",
53
+ "Id",
54
+ "Email",
55
+ "Url",
56
+ "Json",
57
+ "Vazio",
58
+ ]);
59
+
60
+ function encontrarSubBloco(bloco: BlocoGenericoAst, palavraChave: string): BlocoGenericoAst | undefined {
61
+ return bloco.blocos.find((subbloco): subbloco is BlocoGenericoAst => subbloco.tipo === "bloco_generico" && subbloco.palavraChave === palavraChave);
62
+ }
63
+
64
+ function localizarCampo(bloco: BlocoGenericoAst | undefined, ...nomes: string[]): CampoAst | undefined {
65
+ return bloco?.campos.find((campo) => nomes.includes(campo.nome));
66
+ }
67
+
68
+ function valorCampoCompleto(campo?: CampoAst): string | undefined {
69
+ if (!campo) {
70
+ return undefined;
71
+ }
72
+ return [campo.valor, ...campo.modificadores].join(" ").trim() || undefined;
73
+ }
74
+
75
+ function normalizarTipoDeclarado(tipo: string): string {
76
+ return tipo
77
+ .replace(/\s*([<>\[\](),|?])\s*/g, "$1")
78
+ .replace(/\s+/g, "")
79
+ .trim();
80
+ }
81
+
82
+ function dividirNoNivelRaiz(texto: string, separador: string): string[] {
83
+ const partes: string[] = [];
84
+ let profundidadeAngular = 0;
85
+ let profundidadeColchete = 0;
86
+ let inicio = 0;
87
+
88
+ for (let indice = 0; indice < texto.length; indice += 1) {
89
+ const caractere = texto[indice]!;
90
+ if (caractere === "<") {
91
+ profundidadeAngular += 1;
92
+ continue;
93
+ }
94
+ if (caractere === ">") {
95
+ profundidadeAngular = Math.max(0, profundidadeAngular - 1);
96
+ continue;
97
+ }
98
+ if (caractere === "[") {
99
+ profundidadeColchete += 1;
100
+ continue;
101
+ }
102
+ if (caractere === "]") {
103
+ profundidadeColchete = Math.max(0, profundidadeColchete - 1);
104
+ continue;
105
+ }
106
+ if (profundidadeAngular === 0 && profundidadeColchete === 0 && texto.startsWith(separador, indice)) {
107
+ partes.push(texto.slice(inicio, indice));
108
+ inicio = indice + separador.length;
109
+ indice += separador.length - 1;
110
+ }
111
+ }
112
+
113
+ partes.push(texto.slice(inicio));
114
+ return partes.map((parte) => parte.trim()).filter(Boolean);
115
+ }
116
+
117
+ function analisarCampoTipo(tipo: string, modificadores: string[]): Omit<IrCampo, "nome"> {
118
+ const tipoOriginal = normalizarTipoDeclarado(tipo);
119
+ const modificadoresNormalizados = modificadores.map((item) => item.trim()).filter(Boolean);
120
+ const refinamentos = modificadoresNormalizados.filter((item) => !["required", "optional", "opcional"].includes(item));
121
+ const opcionalPorModificador = modificadoresNormalizados.includes("optional") || modificadoresNormalizados.includes("opcional");
122
+
123
+ let tipoBase = tipoOriginal;
124
+ let cardinalidade: IrCampo["cardinalidade"] = "unitario";
125
+ let tiposAlternativos: string[] = [];
126
+ let tipoItem: string | undefined;
127
+ let chaveMapa: string | undefined;
128
+ let valorMapa: string | undefined;
129
+ let opcional = opcionalPorModificador;
130
+
131
+ if (tipoBase.endsWith("?")) {
132
+ opcional = true;
133
+ tipoBase = tipoBase.slice(0, -1);
134
+ }
135
+
136
+ if (/^Opcional<.+>$/.test(tipoBase)) {
137
+ opcional = true;
138
+ tipoBase = tipoBase.slice("Opcional<".length, -1);
139
+ }
140
+
141
+ const uniao = dividirNoNivelRaiz(tipoBase, "|");
142
+ if (uniao.length > 1) {
143
+ cardinalidade = "uniao";
144
+ tiposAlternativos = uniao.map(normalizarTipoDeclarado);
145
+ tipoBase = tiposAlternativos[0] ?? tipoBase;
146
+ } else if (/^Lista<.+>$/.test(tipoBase)) {
147
+ cardinalidade = "lista";
148
+ tipoItem = tipoBase.slice("Lista<".length, -1).trim();
149
+ tipoBase = tipoItem;
150
+ } else if (/^Mapa<.+>$/.test(tipoBase)) {
151
+ cardinalidade = "mapa";
152
+ const partesMapa = dividirNoNivelRaiz(tipoBase.slice("Mapa<".length, -1), ",");
153
+ chaveMapa = partesMapa[0];
154
+ valorMapa = partesMapa[1];
155
+ tipoBase = valorMapa ?? tipoBase;
156
+ }
157
+
158
+ return {
159
+ tipo: tipoOriginal,
160
+ modificadores: modificadoresNormalizados,
161
+ tipoOriginal,
162
+ tipoBase,
163
+ cardinalidade,
164
+ opcional,
165
+ tiposAlternativos,
166
+ tipoItem,
167
+ chaveMapa,
168
+ valorMapa,
169
+ refinamentos,
170
+ };
171
+ }
172
+
173
+ function converterCampo(campo: CampoAst): IrCampo {
174
+ return {
175
+ nome: campo.nome,
176
+ ...analisarCampoTipo(campo.valor, campo.modificadores),
177
+ };
178
+ }
179
+
180
+ function converterCampos(bloco?: BlocoGenericoAst): IrCampo[] {
181
+ if (!bloco) {
182
+ return [];
183
+ }
184
+ return bloco.campos.map(converterCampo);
185
+ }
186
+
187
+ function converterBloco(bloco?: BlocoGenericoAst): IrBlocoDeclarativo {
188
+ return {
189
+ campos: converterCampos(bloco),
190
+ linhas: bloco?.linhas.map((linha) => linha.conteudo) ?? [],
191
+ blocos: (bloco?.blocos ?? [])
192
+ .filter((subbloco): subbloco is BlocoGenericoAst => subbloco.tipo === "bloco_generico")
193
+ .map((subbloco) => ({
194
+ nome: subbloco.nome ?? subbloco.palavraChave,
195
+ conteudo: converterBloco(subbloco),
196
+ })),
197
+ };
198
+ }
199
+
200
+ function converterCaso(caso: BlocoCasoTesteAst): IrCasoTeste {
201
+ return {
202
+ nome: caso.nome,
203
+ given: converterBloco(caso.given),
204
+ when: caso.when ? converterBloco(caso.when) : undefined,
205
+ expect: converterBloco(caso.expect),
206
+ error: caso.error ? converterBloco(caso.error) : undefined,
207
+ };
208
+ }
209
+
210
+ function converterImplementacoes(bloco?: BlocoGenericoAst): IrImplementacaoTask[] {
211
+ const implementacoes: IrImplementacaoTask[] = [];
212
+ for (const campo of bloco?.campos ?? []) {
213
+ const origem = campo.nome.toLowerCase();
214
+ if (origem === "ts" || origem === "typescript") {
215
+ implementacoes.push({ origem: "ts", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
216
+ continue;
217
+ }
218
+ if (origem === "py" || origem === "python") {
219
+ implementacoes.push({ origem: "py", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
220
+ continue;
221
+ }
222
+ if (origem === "dart") {
223
+ implementacoes.push({ origem: "dart", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
224
+ continue;
225
+ }
226
+ if (origem === "cs" || origem === "csharp" || origem === "dotnet") {
227
+ implementacoes.push({ origem: "cs", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
228
+ continue;
229
+ }
230
+ if (origem === "java") {
231
+ implementacoes.push({ origem: "java", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
232
+ continue;
233
+ }
234
+ if (origem === "go" || origem === "golang") {
235
+ implementacoes.push({ origem: "go", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
236
+ continue;
237
+ }
238
+ if (origem === "rust" || origem === "rs") {
239
+ implementacoes.push({ origem: "rust", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
240
+ continue;
241
+ }
242
+ if (origem === "cpp" || origem === "cxx" || origem === "cc" || origem === "c++") {
243
+ implementacoes.push({ origem: "cpp", caminho: campo.valor, resolucaoImpl: campo.valor, statusImpl: "nao_verificado" });
244
+ }
245
+ }
246
+ return implementacoes;
247
+ }
248
+
249
+ function converterVinculos(bloco?: BlocoGenericoAst): IrVinculo[] {
250
+ if (!bloco) {
251
+ return [];
252
+ }
253
+
254
+ const campos = bloco.campos.map((campo) => {
255
+ const valor = valorCampoCompleto(campo) ?? "";
256
+ return {
257
+ tipo: campo.nome,
258
+ valor,
259
+ arquivo: campo.nome === "arquivo" ? valor : undefined,
260
+ simbolo: campo.nome === "simbolo" ? valor : undefined,
261
+ recurso: ["recurso", "tabela", "fila", "cache", "storage"].includes(campo.nome) ? valor : undefined,
262
+ superficie: ["superficie", "rota", "worker", "cron", "webhook", "evento", "policy", "fila", "cache", "storage"].includes(campo.nome) ? valor : undefined,
263
+ statusResolucao: "nao_verificado" as const,
264
+ };
265
+ });
266
+
267
+ const linhas = bloco.linhas.map((linha) => {
268
+ const [tipo, ...resto] = linha.conteudo.split(/\s+/);
269
+ const valor = resto.join(" ").trim();
270
+ return {
271
+ tipo: tipo ?? "desconhecido",
272
+ valor,
273
+ statusResolucao: "nao_verificado" as const,
274
+ };
275
+ }).filter((item) => item.valor);
276
+
277
+ const subblocos = bloco.blocos
278
+ .filter((item): item is BlocoGenericoAst => item.tipo === "bloco_generico")
279
+ .map((item) => ({
280
+ tipo: item.palavraChave === "desconhecido" ? (item.nome ?? "desconhecido") : item.palavraChave,
281
+ valor: item.nome ?? item.palavraChave,
282
+ arquivo: valorCampoCompleto(localizarCampo(item, "arquivo")),
283
+ simbolo: valorCampoCompleto(localizarCampo(item, "simbolo")),
284
+ recurso: valorCampoCompleto(localizarCampo(item, "recurso", "tabela", "fila", "cache", "storage")),
285
+ superficie: valorCampoCompleto(localizarCampo(item, "superficie", "rota", "worker", "cron", "webhook", "evento")),
286
+ statusResolucao: "nao_verificado" as const,
287
+ }));
288
+
289
+ return [...campos, ...linhas, ...subblocos];
290
+ }
291
+
292
+ function converterExecucao(bloco?: BlocoGenericoAst): IrExecucao {
293
+ const idempotencia = valorCampoCompleto(localizarCampo(bloco, "idempotencia"));
294
+ const criticidadeOperacional = valorCampoCompleto(localizarCampo(bloco, "criticidade_operacional"));
295
+
296
+ return {
297
+ idempotencia: idempotencia === "verdadeiro" || idempotencia === "true",
298
+ timeout: valorCampoCompleto(localizarCampo(bloco, "timeout")) ?? "padrao",
299
+ retry: valorCampoCompleto(localizarCampo(bloco, "retry")) ?? "nenhum",
300
+ compensacao: valorCampoCompleto(localizarCampo(bloco, "compensacao")) ?? "nenhuma",
301
+ criticidadeOperacional: (
302
+ criticidadeOperacional === "baixa"
303
+ || criticidadeOperacional === "alta"
304
+ || criticidadeOperacional === "critica"
305
+ ) ? criticidadeOperacional : "media",
306
+ explicita: Boolean(bloco),
307
+ };
308
+ }
309
+
310
+ function converterAuth(bloco?: BlocoGenericoAst): IrAuth {
311
+ return extrairContratoAuth(bloco);
312
+ }
313
+
314
+ function converterAuthz(bloco?: BlocoGenericoAst): IrAuthz {
315
+ return extrairContratoAuthz(bloco);
316
+ }
317
+
318
+ function converterDados(bloco?: BlocoGenericoAst): IrDados {
319
+ return extrairContratoDados(bloco);
320
+ }
321
+
322
+ function converterAudit(bloco?: BlocoGenericoAst): IrAudit {
323
+ return extrairContratoAudit(bloco);
324
+ }
325
+
326
+ function converterSegredos(bloco?: BlocoGenericoAst): IrSegredos {
327
+ return extrairContratoSegredos(bloco);
328
+ }
329
+
330
+ function converterForbidden(bloco?: BlocoGenericoAst): IrForbidden {
331
+ return extrairContratoForbidden(bloco);
332
+ }
333
+
334
+ function converterErrosTask(bloco?: BlocoGenericoAst, fallback?: ErroSemanticoTask[]): IrErroOperacional[] {
335
+ const erros = new Map<string, IrErroOperacional>();
336
+
337
+ for (const campo of bloco?.campos ?? []) {
338
+ erros.set(campo.nome, {
339
+ codigo: campo.nome,
340
+ mensagem: valorCampoCompleto(campo) ?? "",
341
+ });
342
+ }
343
+
344
+ for (const subbloco of bloco?.blocos ?? []) {
345
+ if (subbloco.tipo !== "bloco_generico") {
346
+ continue;
347
+ }
348
+ const codigo = subbloco.nome ?? subbloco.palavraChave;
349
+ if (!codigo || codigo === "desconhecido") {
350
+ continue;
351
+ }
352
+ erros.set(codigo, {
353
+ codigo,
354
+ mensagem: valorCampoCompleto(localizarCampo(subbloco, "mensagem")) ?? `Erro estruturado "${codigo}".`,
355
+ categoria: valorCampoCompleto(localizarCampo(subbloco, "categoria")),
356
+ recuperabilidade: valorCampoCompleto(localizarCampo(subbloco, "recuperabilidade")),
357
+ acaoChamador: valorCampoCompleto(localizarCampo(subbloco, "acao_chamador")),
358
+ impactaEstado: valorCampoCompleto(localizarCampo(subbloco, "impacta_estado")) === "verdadeiro",
359
+ requerCompensacao: valorCampoCompleto(localizarCampo(subbloco, "requer_compensacao")) === "verdadeiro",
360
+ });
361
+ }
362
+
363
+ for (const erro of fallback ?? []) {
364
+ if (!erros.has(erro.codigo)) {
365
+ erros.set(erro.codigo, {
366
+ codigo: erro.codigo,
367
+ mensagem: erro.mensagem,
368
+ categoria: erro.categoria,
369
+ recuperabilidade: erro.recuperabilidade,
370
+ acaoChamador: erro.acaoChamador,
371
+ impactaEstado: erro.impactaEstado,
372
+ requerCompensacao: erro.requerCompensacao,
373
+ });
374
+ }
375
+ }
376
+
377
+ return [...erros.values()];
378
+ }
379
+
380
+ function extrairPerfil(bloco?: BlocoGenericoAst, padrao: PerfilCompatibilidade = "interno"): PerfilCompatibilidade {
381
+ const perfil = valorCampoCompleto(localizarCampo(bloco, "perfil", "compatibilidade"))?.toLowerCase();
382
+ if (
383
+ perfil === "publico"
384
+ || perfil === "interno"
385
+ || perfil === "experimental"
386
+ || perfil === "legado"
387
+ || perfil === "deprecado"
388
+ ) {
389
+ return perfil;
390
+ }
391
+ return padrao;
392
+ }
393
+
394
+ function tipoNaoPrimitivo(campo: IrCampo): string | undefined {
395
+ if (!TIPOS_PRIMITIVOS.has(campo.tipoBase)) {
396
+ return campo.tipoBase;
397
+ }
398
+ if (campo.tipoItem && !TIPOS_PRIMITIVOS.has(campo.tipoItem)) {
399
+ return campo.tipoItem;
400
+ }
401
+ if (campo.valorMapa && !TIPOS_PRIMITIVOS.has(campo.valorMapa)) {
402
+ return campo.valorMapa;
403
+ }
404
+ return undefined;
405
+ }
406
+
407
+ function deduplicarTexto(valores: string[]): string[] {
408
+ return [...new Set(valores.filter(Boolean))].sort((a, b) => a.localeCompare(b, "pt-BR"));
409
+ }
410
+
411
+ function resumirAgente(params: {
412
+ input?: IrCampo[];
413
+ output?: IrCampo[];
414
+ efeitos?: Array<{ categoria: string; alvo: string; criticidade?: string }>;
415
+ vinculos?: IrVinculo[];
416
+ execucao?: IrExecucao;
417
+ auth?: IrAuth;
418
+ authz?: IrAuthz;
419
+ dados?: IrDados;
420
+ audit?: IrAudit;
421
+ segredos?: IrSegredos;
422
+ forbidden?: IrForbidden;
423
+ superficiePublica?: string;
424
+ }): IrResumoAgente {
425
+ const entidadesAfetadas = deduplicarTexto([
426
+ ...(params.input ?? []).map(tipoNaoPrimitivo).filter((item): item is string => Boolean(item)),
427
+ ...(params.output ?? []).map(tipoNaoPrimitivo).filter((item): item is string => Boolean(item)),
428
+ ...(params.efeitos ?? []).map((efeito) => efeito.alvo),
429
+ ]);
430
+
431
+ const mutacoesPrevistas = deduplicarTexto(
432
+ (params.efeitos ?? []).map((efeito) => `${efeito.categoria}:${efeito.alvo}`),
433
+ );
434
+
435
+ const riscos = new Set<string>();
436
+ if ((params.efeitos ?? []).some((efeito) => efeito.categoria === "persistencia")) {
437
+ riscos.add("altera_persistencia");
438
+ }
439
+ if ((params.efeitos ?? []).some((efeito) => efeitoEhPrivilegiado(efeito))) {
440
+ riscos.add("efeito_privilegiado");
441
+ }
442
+ if ((params.efeitos ?? []).some((efeito) => efeito.criticidade === "alta" || efeito.criticidade === "critica")) {
443
+ riscos.add("efeito_critico");
444
+ }
445
+ if (params.execucao?.criticidadeOperacional === "alta" || params.execucao?.criticidadeOperacional === "critica") {
446
+ riscos.add("execucao_critica");
447
+ }
448
+ if (contratoDadosTemSensivel(params.dados)) {
449
+ riscos.add("dados_sensiveis");
450
+ }
451
+ if (params.segredos?.itens.length) {
452
+ riscos.add("segredo_operacional");
453
+ }
454
+ if ((params.vinculos ?? []).length === 0) {
455
+ riscos.add("vinculo_fraco");
456
+ }
457
+
458
+ const checks = new Set<string>();
459
+ checks.add("rodar sema validar --json");
460
+ if ((params.output ?? []).length > 0) {
461
+ checks.add("verificar guarantees");
462
+ }
463
+ if ((params.vinculos ?? []).length > 0) {
464
+ checks.add("rodar sema drift --json");
465
+ }
466
+ if (params.auth?.explicita || params.authz?.explicita) {
467
+ checks.add("revisar auth e authz");
468
+ }
469
+ if (params.dados?.explicita) {
470
+ checks.add("validar classificacao de dados");
471
+ }
472
+ if (params.audit?.explicita) {
473
+ checks.add("validar trilha de auditoria");
474
+ }
475
+ if (params.forbidden?.explicita) {
476
+ checks.add("confirmar proibicoes operacionais");
477
+ }
478
+ if (params.superficiePublica) {
479
+ checks.add("validar superficie publica impactada");
480
+ }
481
+
482
+ return {
483
+ riscos: [...riscos],
484
+ checks: [...checks],
485
+ entidadesAfetadas,
486
+ superficiesPublicas: params.superficiePublica ? [params.superficiePublica] : [],
487
+ mutacoesPrevistas,
488
+ };
489
+ }
490
+
491
+ function recomporCaminho(campo?: CampoAst): string | undefined {
492
+ const valor = valorCampoCompleto(campo);
493
+ return valor?.replace(/\s*\/\s*/g, "/").trim();
494
+ }
495
+
496
+ function ehUseInterop(
497
+ use: ModuloAst["uses"][number],
498
+ ): use is ModuloAst["uses"][number] & { origem: "ts" | "py" | "dart" | "cs" | "java" | "go" | "rust" | "cpp" } {
499
+ return use.origem !== "sema";
500
+ }
501
+
502
+ function converterErroPublico(erro: IrErroOperacional, origemTask?: string) {
503
+ return {
504
+ nome: erro.codigo,
505
+ codigo: erro.codigo,
506
+ mensagem: erro.mensagem,
507
+ categoria: erro.categoria,
508
+ recuperabilidade: erro.recuperabilidade,
509
+ acaoChamador: erro.acaoChamador,
510
+ impactaEstado: erro.impactaEstado,
511
+ requerCompensacao: erro.requerCompensacao,
512
+ origemTask,
513
+ };
514
+ }
515
+
516
+ function calcularConfiancaPublica(route: IrRoute): NivelConfiancaSemantica {
517
+ if (route.task && route.vinculos.length > 0) {
518
+ return "alta";
519
+ }
520
+ if (route.task || route.vinculos.length > 0) {
521
+ return "media";
522
+ }
523
+ return "baixa";
524
+ }
525
+
526
+ function calcularRiscoPublico(route: IrRoute): NivelRiscoSemantico {
527
+ if (
528
+ !route.auth.explicita
529
+ || contratoDadosTemSensivel(route.dados)
530
+ || route.efeitosPublicos.some((efeito) => efeitoEhPrivilegiado(efeito) || efeito.categoria === "persistencia" || efeito.criticidade === "critica")
531
+ ) {
532
+ return "alto";
533
+ }
534
+ if (route.efeitosPublicos.length > 0 || route.errosPublicos.length > 0) {
535
+ return "medio";
536
+ }
537
+ return "baixo";
538
+ }
539
+
540
+ function converterSuperficie(
541
+ tipo: TipoSuperficieIr,
542
+ superficie: BlocoGenericoAst,
543
+ ): IrSuperficie {
544
+ const input = converterCampos(encontrarSubBloco(superficie, "input"));
545
+ const output = converterCampos(encontrarSubBloco(superficie, "output"));
546
+ const effects = (encontrarSubBloco(superficie, "effects")?.linhas ?? [])
547
+ .map((linha) => parsearEfeitoSemantico(linha.conteudo))
548
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha));
549
+ const vinculos = converterVinculos(encontrarSubBloco(superficie, "vinculos"));
550
+ const execucao = converterExecucao(encontrarSubBloco(superficie, "execucao"));
551
+ const auth = converterAuth(encontrarSubBloco(superficie, "auth"));
552
+ const authz = converterAuthz(encontrarSubBloco(superficie, "authz"));
553
+ const dados = converterDados(encontrarSubBloco(superficie, "dados"));
554
+ const audit = converterAudit(encontrarSubBloco(superficie, "audit"));
555
+ const segredos = converterSegredos(encontrarSubBloco(superficie, "segredos"));
556
+ const forbidden = converterForbidden(encontrarSubBloco(superficie, "forbidden"));
557
+ const task = valorCampoCompleto(localizarCampo(superficie, "task", "tarefa"));
558
+ const perfilCompatibilidade = extrairPerfil(superficie, tipo === "webhook" ? "publico" : "interno");
559
+ const resumoAgente = resumirAgente({
560
+ input,
561
+ output,
562
+ efeitos: effects,
563
+ vinculos,
564
+ execucao,
565
+ auth,
566
+ authz,
567
+ dados,
568
+ audit,
569
+ segredos,
570
+ forbidden,
571
+ superficiePublica: perfilCompatibilidade === "publico" ? `${tipo}:${superficie.nome ?? tipo}` : undefined,
572
+ });
573
+
574
+ return {
575
+ tipo,
576
+ nome: superficie.nome ?? tipo,
577
+ campos: converterCampos(superficie),
578
+ linhas: superficie.linhas.map((linha) => linha.conteudo),
579
+ task: task || undefined,
580
+ input,
581
+ output,
582
+ effects,
583
+ implementacoesExternas: converterImplementacoes(encontrarSubBloco(superficie, "impl")),
584
+ vinculos,
585
+ execucao,
586
+ auth,
587
+ authz,
588
+ dados,
589
+ audit,
590
+ segredos,
591
+ forbidden,
592
+ perfilCompatibilidade,
593
+ resumoAgente,
594
+ };
595
+ }
596
+
597
+ export function converterParaIr(modulo: ModuloAst, diagnosticos: Diagnostico[], contexto?: ContextoSemantico): IrModulo {
598
+ const perfilModulo = extrairPerfil(modulo.vinculos, modulo.routes.length > 0 || modulo.webhooks.length > 0 ? "publico" : "interno");
599
+
600
+ const types: IrType[] = modulo.types.map((type) => ({
601
+ nome: type.nome,
602
+ definicao: converterBloco(encontrarSubBloco(type.corpo, "fields") ?? type.corpo),
603
+ invariantes: (encontrarSubBloco(type.corpo, "invariants")?.linhas ?? [])
604
+ .map((linha) => parsearExpressaoSemantica(linha.conteudo))
605
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
606
+ }));
607
+
608
+ const entities: IrEntity[] = modulo.entities.map((entity) => ({
609
+ nome: entity.nome,
610
+ campos: converterCampos(encontrarSubBloco(entity.corpo, "fields")),
611
+ invariantes: (encontrarSubBloco(entity.corpo, "invariants")?.linhas ?? [])
612
+ .map((linha) => parsearExpressaoSemantica(linha.conteudo))
613
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
614
+ }));
615
+
616
+ const tarefasSemanticas = contexto?.tarefasDetalhadas ?? new Map();
617
+ const tasks: IrTask[] = modulo.tasks.map((task) => {
618
+ const input = converterCampos(task.input);
619
+ const output = converterCampos(task.output);
620
+ const effects = (task.effects?.linhas ?? [])
621
+ .map((linha) => parsearEfeitoSemantico(linha.conteudo))
622
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha));
623
+ const vinculos = converterVinculos(task.vinculos);
624
+ const execucao = converterExecucao(task.execucao);
625
+ const auth = converterAuth(encontrarSubBloco(task.corpo, "auth"));
626
+ const authz = converterAuthz(encontrarSubBloco(task.corpo, "authz"));
627
+ const dados = converterDados(encontrarSubBloco(task.corpo, "dados"));
628
+ const audit = converterAudit(encontrarSubBloco(task.corpo, "audit"));
629
+ const segredos = converterSegredos(encontrarSubBloco(task.corpo, "segredos"));
630
+ const forbidden = converterForbidden(encontrarSubBloco(task.corpo, "forbidden"));
631
+ const errosDetalhados = converterErrosTask(task.error, tarefasSemanticas.get(task.nome)?.errors);
632
+ const perfilCompatibilidade = extrairPerfil(task.corpo, "interno");
633
+ const resumoAgente = resumirAgente({
634
+ input,
635
+ output,
636
+ efeitos: effects,
637
+ vinculos,
638
+ execucao,
639
+ auth,
640
+ authz,
641
+ dados,
642
+ audit,
643
+ segredos,
644
+ forbidden,
645
+ });
646
+
647
+ return {
648
+ nome: task.nome,
649
+ input,
650
+ output,
651
+ rules: task.rules?.linhas.map((linha) => linha.conteudo) ?? [],
652
+ regrasEstruturadas: (task.rules?.linhas ?? [])
653
+ .map((linha) => parsearExpressaoSemantica(linha.conteudo))
654
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
655
+ effects: task.effects?.linhas.map((linha) => linha.conteudo) ?? [],
656
+ efeitosEstruturados: effects,
657
+ implementacoesExternas: converterImplementacoes(task.impl),
658
+ vinculos,
659
+ execucao,
660
+ auth,
661
+ authz,
662
+ dados,
663
+ audit,
664
+ segredos,
665
+ forbidden,
666
+ guarantees: task.guarantees?.linhas.map((linha) => linha.conteudo) ?? [],
667
+ garantiasEstruturadas: (task.guarantees?.linhas ?? [])
668
+ .map((linha) => parsearExpressaoSemantica(linha.conteudo))
669
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
670
+ errors: Object.fromEntries(errosDetalhados.map((erro) => [erro.codigo, erro.mensagem])),
671
+ errosDetalhados,
672
+ perfilCompatibilidade,
673
+ stateContract: task.state ? {
674
+ nomeEstado: task.state.nome ?? task.state.campos.find((campo) => campo.nome === "state" || campo.nome === "estado")?.valor,
675
+ campos: converterCampos(task.state),
676
+ linhas: task.state.linhas.map((linha) => linha.conteudo),
677
+ transicoes: (encontrarSubBloco(task.state, "transitions")?.linhas ?? task.state.linhas)
678
+ .map((linha) => parsearTransicaoEstado(linha.conteudo))
679
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
680
+ } : undefined,
681
+ resumoAgente,
682
+ tests: (task.tests?.blocos.filter((bloco): bloco is BlocoCasoTesteAst => bloco.tipo === "caso_teste") ?? []).map(converterCaso),
683
+ };
684
+ });
685
+
686
+ const tarefasPorNome = new Map(tasks.map((task) => [task.nome, task] as const));
687
+
688
+ const flows: IrFlow[] = modulo.flows.map((flow) => {
689
+ const campos = converterCampos(flow.corpo);
690
+ const effects = (encontrarSubBloco(flow.corpo, "effects")?.linhas ?? [])
691
+ .map((linha) => parsearEfeitoSemantico(linha.conteudo))
692
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha));
693
+ const vinculos = converterVinculos(flow.vinculos);
694
+ const perfilCompatibilidade = extrairPerfil(flow.corpo, "interno");
695
+ return {
696
+ nome: flow.nome,
697
+ campos,
698
+ linhas: flow.corpo.linhas.map((linha) => linha.conteudo),
699
+ tasksReferenciadas: flow.corpo.campos
700
+ .filter((campo) => campo.nome === "task" || campo.nome === "tarefa")
701
+ .map((campo) => campo.valor),
702
+ etapasEstruturadas: flow.corpo.linhas
703
+ .map((linha) => parsearEtapaFlow(linha.conteudo))
704
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
705
+ effects: (encontrarSubBloco(flow.corpo, "effects")?.linhas ?? []).map((linha) => linha.conteudo),
706
+ efeitosEstruturados: effects,
707
+ vinculos,
708
+ perfilCompatibilidade,
709
+ resumoAgente: resumirAgente({
710
+ input: campos,
711
+ efeitos: effects,
712
+ vinculos,
713
+ }),
714
+ };
715
+ });
716
+
717
+ const routes: IrRoute[] = modulo.routes.map((route) => ({
718
+ nome: route.nome,
719
+ campos: converterCampos(route.corpo),
720
+ linhas: route.corpo.linhas.map((linha) => linha.conteudo),
721
+ metodo: route.corpo.campos.find((campo) => campo.nome === "metodo")?.valor,
722
+ caminho: recomporCaminho(route.corpo.campos.find((campo) => campo.nome === "caminho")),
723
+ task: route.corpo.campos.find((campo) => campo.nome === "task" || campo.nome === "tarefa")?.valor,
724
+ inputPublico: [],
725
+ outputPublico: [],
726
+ errosPublicos: [],
727
+ efeitosPublicos: [],
728
+ vinculos: converterVinculos(route.vinculos),
729
+ auth: converterAuth(encontrarSubBloco(route.corpo, "auth")),
730
+ authz: converterAuthz(encontrarSubBloco(route.corpo, "authz")),
731
+ dados: converterDados(encontrarSubBloco(route.corpo, "dados")),
732
+ audit: converterAudit(encontrarSubBloco(route.corpo, "audit")),
733
+ segredos: converterSegredos(encontrarSubBloco(route.corpo, "segredos")),
734
+ forbidden: converterForbidden(encontrarSubBloco(route.corpo, "forbidden")),
735
+ perfilCompatibilidade: extrairPerfil(route.corpo, "publico"),
736
+ garantiasPublicasMinimas: [],
737
+ resumoAgente: {
738
+ riscos: [],
739
+ checks: [],
740
+ entidadesAfetadas: [],
741
+ superficiesPublicas: [],
742
+ mutacoesPrevistas: [],
743
+ },
744
+ publico: {
745
+ metodo: undefined,
746
+ caminho: undefined,
747
+ task: undefined,
748
+ input: [],
749
+ output: [],
750
+ errors: [],
751
+ effects: [],
752
+ garantiasMinimas: [],
753
+ },
754
+ })).map((route) => {
755
+ const routeAst = modulo.routes.find((item) => item.nome === route.nome)!;
756
+ const tarefaAssociada = route.task ? tarefasPorNome.get(route.task) : undefined;
757
+ const tarefaSemantica = route.task ? tarefasSemanticas.get(route.task) : undefined;
758
+ const inputPublicoDeclarado = converterCampos(encontrarSubBloco(routeAst.corpo, "input"));
759
+ const outputPublicoDeclarado = converterCampos(encontrarSubBloco(routeAst.corpo, "output"));
760
+ const errosDeclarados = converterErrosTask(encontrarSubBloco(routeAst.corpo, "error"), tarefaSemantica?.errors);
761
+ const efeitosPublicosDeclarados = (encontrarSubBloco(routeAst.corpo, "effects")?.linhas ?? [])
762
+ .map((linha) => parsearEfeitoSemantico(linha.conteudo))
763
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha));
764
+ const inputPublicoResolvido = inputPublicoDeclarado.length > 0
765
+ ? inputPublicoDeclarado
766
+ : (tarefaAssociada?.input ?? tarefaSemantica?.input?.map((campo: { nome: string; tipo: string; modificadores: string[] }) => ({
767
+ nome: campo.nome,
768
+ tipo: campo.tipo,
769
+ modificadores: campo.modificadores,
770
+ tipoOriginal: campo.tipo,
771
+ tipoBase: campo.tipo,
772
+ cardinalidade: "unitario" as const,
773
+ opcional: false,
774
+ tiposAlternativos: [],
775
+ refinamentos: [],
776
+ })) ?? []);
777
+ const outputPublicoResolvido = outputPublicoDeclarado.length > 0
778
+ ? outputPublicoDeclarado
779
+ : (tarefaAssociada?.output ?? tarefaSemantica?.output?.map((campo: { nome: string; tipo: string; modificadores: string[] }) => ({
780
+ nome: campo.nome,
781
+ tipo: campo.tipo,
782
+ modificadores: campo.modificadores,
783
+ tipoOriginal: campo.tipo,
784
+ tipoBase: campo.tipo,
785
+ cardinalidade: "unitario" as const,
786
+ opcional: false,
787
+ tiposAlternativos: [],
788
+ refinamentos: [],
789
+ })) ?? []);
790
+ const errosPublicosResolvidos = errosDeclarados.length > 0
791
+ ? errosDeclarados.map((erro) => converterErroPublico(erro, route.task))
792
+ : (tarefaAssociada?.errosDetalhados ?? (tarefaSemantica?.errors ?? []).map((erro: { codigo: string; mensagem: string }) => ({ codigo: erro.codigo, mensagem: erro.mensagem }))).map((erro: IrErroOperacional) =>
793
+ converterErroPublico(erro, route.task));
794
+ const garantiasPublicasMinimas = (tarefaAssociada?.guarantees ?? tarefaSemantica?.guarantees ?? []).filter((garantia: string) => {
795
+ const referencia = garantia.trim().split(/\s+/)[0] ?? "";
796
+ return outputPublicoResolvido.some((campo: IrCampo) => campo.nome === referencia || garantia.includes(`${campo.nome}.`));
797
+ });
798
+
799
+ const routeResolvida: IrRoute = {
800
+ ...route,
801
+ inputPublico: inputPublicoResolvido,
802
+ outputPublico: outputPublicoResolvido,
803
+ errosPublicos: errosPublicosResolvidos,
804
+ efeitosPublicos: efeitosPublicosDeclarados,
805
+ garantiasPublicasMinimas,
806
+ resumoAgente: resumirAgente({
807
+ input: inputPublicoResolvido,
808
+ output: outputPublicoResolvido,
809
+ efeitos: efeitosPublicosDeclarados,
810
+ vinculos: route.vinculos,
811
+ auth: route.auth,
812
+ authz: route.authz,
813
+ dados: route.dados,
814
+ audit: route.audit,
815
+ segredos: route.segredos,
816
+ forbidden: route.forbidden,
817
+ superficiePublica: `${route.metodo ?? "?"} ${route.caminho ?? "?"}`,
818
+ }),
819
+ publico: {
820
+ metodo: route.metodo,
821
+ caminho: route.caminho,
822
+ task: route.task,
823
+ input: inputPublicoResolvido,
824
+ output: outputPublicoResolvido,
825
+ errors: errosPublicosResolvidos,
826
+ effects: efeitosPublicosDeclarados,
827
+ garantiasMinimas: garantiasPublicasMinimas,
828
+ confiancaContrato: "media",
829
+ riscoRegressao: "medio",
830
+ divergenciasPublicas: [],
831
+ },
832
+ };
833
+
834
+ routeResolvida.publico.confiancaContrato = calcularConfiancaPublica(routeResolvida);
835
+ routeResolvida.publico.riscoRegressao = calcularRiscoPublico(routeResolvida);
836
+ return routeResolvida;
837
+ });
838
+
839
+ const superficies: IrSuperficie[] = [
840
+ ...modulo.workers.map((item) => converterSuperficie("worker", item)),
841
+ ...modulo.eventos.map((item) => converterSuperficie("evento", item)),
842
+ ...modulo.filas.map((item) => converterSuperficie("fila", item)),
843
+ ...modulo.crons.map((item) => converterSuperficie("cron", item)),
844
+ ...modulo.webhooks.map((item) => converterSuperficie("webhook", item)),
845
+ ...modulo.caches.map((item) => converterSuperficie("cache", item)),
846
+ ...modulo.storages.map((item) => converterSuperficie("storage", item)),
847
+ ...modulo.policies.map((item) => converterSuperficie("policy", item)),
848
+ ];
849
+
850
+ const states: IrState[] = modulo.states.map((state) => ({
851
+ nome: state.nome,
852
+ campos: converterCampos(encontrarSubBloco(state.corpo, "fields") ?? state.corpo),
853
+ linhas: state.corpo.linhas.map((linha) => linha.conteudo),
854
+ invariantes: (encontrarSubBloco(state.corpo, "invariants")?.linhas ?? [])
855
+ .map((linha) => parsearExpressaoSemantica(linha.conteudo))
856
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
857
+ transicoes: (encontrarSubBloco(state.corpo, "transitions")?.linhas ?? [])
858
+ .map((linha) => parsearTransicaoEstado(linha.conteudo))
859
+ .filter((linha): linha is NonNullable<typeof linha> => Boolean(linha)),
860
+ }));
861
+
862
+ const resumoAgenteModulo = resumirAgente({
863
+ input: [],
864
+ output: [],
865
+ efeitos: [
866
+ ...tasks.flatMap((task) => task.efeitosEstruturados),
867
+ ...routes.flatMap((route) => route.efeitosPublicos),
868
+ ...superficies.flatMap((superficie) => superficie.effects),
869
+ ],
870
+ vinculos: [
871
+ ...converterVinculos(modulo.vinculos),
872
+ ...tasks.flatMap((task) => task.vinculos),
873
+ ...routes.flatMap((route) => route.vinculos),
874
+ ...superficies.flatMap((superficie) => superficie.vinculos),
875
+ ],
876
+ });
877
+
878
+ return {
879
+ nome: modulo.nome,
880
+ uses: contexto?.modulosImportados.length
881
+ ? [...contexto.modulosImportados]
882
+ : modulo.uses.filter((use) => use.origem === "sema").map((use) => use.caminho),
883
+ imports: modulo.uses.map((use) => ({
884
+ origem: use.origem,
885
+ caminho: use.caminho,
886
+ externo: use.origem !== "sema",
887
+ })),
888
+ interoperabilidades: contexto?.interoperabilidades.map((interop) => ({ ...interop })) ?? modulo.uses
889
+ .filter(ehUseInterop)
890
+ .map((use) => ({ origem: use.origem, caminho: use.caminho })),
891
+ vinculos: converterVinculos(modulo.vinculos),
892
+ perfilCompatibilidade: perfilModulo,
893
+ types,
894
+ entities,
895
+ enums: modulo.enums.map((enumeracao) => ({ nome: enumeracao.nome, valores: enumeracao.valores })),
896
+ tasks,
897
+ flows,
898
+ routes,
899
+ superficies,
900
+ states,
901
+ resumoAgente: {
902
+ ...resumoAgenteModulo,
903
+ superficiesPublicas: deduplicarTexto([
904
+ ...routes.map((route) => `${route.metodo ?? "?"} ${route.caminho ?? route.nome}`),
905
+ ...superficies
906
+ .filter((superficie) => superficie.perfilCompatibilidade === "publico")
907
+ .map((superficie) => `${superficie.tipo}:${superficie.nome}`),
908
+ ]),
909
+ },
910
+ diagnosticos,
911
+ };
912
+ }