@semacode/cli 1.3.6 → 1.3.7

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 (98) hide show
  1. package/AGENTS.md +272 -0
  2. package/LICENSE +22 -0
  3. package/README.md +73 -0
  4. package/SEMA_BRIEF.curto.txt +9 -0
  5. package/SEMA_BRIEF.md +49 -0
  6. package/SEMA_BRIEF.micro.txt +7 -0
  7. package/SEMA_INDEX.json +546 -0
  8. package/dist/projeto.js +1 -3
  9. package/dist/projeto.js.map +1 -1
  10. package/dist/typescript-http.js +1 -1
  11. package/dist/typescript-http.js.map +1 -1
  12. package/docs/AGENT_STARTER.md +102 -0
  13. package/docs/como-ensinar-a-sema-para-ia.md +149 -0
  14. package/docs/fluxo-pratico-ia-sema.md +177 -0
  15. package/docs/instalacao-e-primeiro-uso.md +196 -0
  16. package/docs/integracao-com-ia.md +228 -0
  17. package/docs/pagamento-ponta-a-ponta.md +155 -0
  18. package/docs/prompt-base-ia-sema.md +104 -0
  19. package/docs/sintaxe.md +361 -0
  20. package/exemplos/agendamento.sema +106 -0
  21. package/exemplos/assinatura.sema +136 -0
  22. package/exemplos/auditoria.sema +88 -0
  23. package/exemplos/autenticacao.sema +125 -0
  24. package/exemplos/automacao.sema +107 -0
  25. package/exemplos/cadastro_usuario.sema +54 -0
  26. package/exemplos/calculadora.sema +78 -0
  27. package/exemplos/crud_simples.sema +89 -0
  28. package/exemplos/estoque.sema +126 -0
  29. package/exemplos/exportacao.sema +94 -0
  30. package/exemplos/fila.sema +131 -0
  31. package/exemplos/integracao_externa.sema +94 -0
  32. package/exemplos/multi_tenant.sema +140 -0
  33. package/exemplos/notificacao.sema +98 -0
  34. package/exemplos/operacao_estrategia.sema +402 -0
  35. package/exemplos/pagamento.sema +222 -0
  36. package/exemplos/pagamento_dominio.sema +35 -0
  37. package/exemplos/pedido.sema +119 -0
  38. package/exemplos/permissao.sema +121 -0
  39. package/exemplos/relatorio.sema +93 -0
  40. package/exemplos/testes_embutidos.sema +45 -0
  41. package/exemplos/tratamento_erro.sema +157 -0
  42. package/exemplos/upload_arquivo.sema +93 -0
  43. package/exemplos/webhook.sema +96 -0
  44. package/llms-full.txt +34 -0
  45. package/llms.txt +17 -0
  46. package/logo.png +0 -0
  47. package/node_modules/@sema/gerador-css/package.json +3 -10
  48. package/node_modules/@sema/gerador-dart/package.json +3 -10
  49. package/node_modules/@sema/gerador-html/package.json +3 -10
  50. package/node_modules/@sema/gerador-javascript/package.json +3 -10
  51. package/node_modules/@sema/gerador-lua/package.json +3 -10
  52. package/node_modules/@sema/gerador-python/package.json +3 -10
  53. package/node_modules/@sema/gerador-typescript/package.json +3 -10
  54. package/node_modules/@sema/nucleo/package.json +3 -6
  55. package/node_modules/@sema/padroes/package.json +3 -6
  56. package/package.json +33 -21
  57. package/node_modules/@sema/gerador-css/src/index.ts +0 -605
  58. package/node_modules/@sema/gerador-css/tsconfig.json +0 -13
  59. package/node_modules/@sema/gerador-css/tsconfig.tsbuildinfo +0 -1
  60. package/node_modules/@sema/gerador-dart/src/index.ts +0 -52
  61. package/node_modules/@sema/gerador-dart/tsconfig.json +0 -13
  62. package/node_modules/@sema/gerador-dart/tsconfig.tsbuildinfo +0 -1
  63. package/node_modules/@sema/gerador-html/src/index.ts +0 -185
  64. package/node_modules/@sema/gerador-html/tsconfig.json +0 -13
  65. package/node_modules/@sema/gerador-html/tsconfig.tsbuildinfo +0 -1
  66. package/node_modules/@sema/gerador-javascript/src/index.ts +0 -461
  67. package/node_modules/@sema/gerador-javascript/tsconfig.json +0 -13
  68. package/node_modules/@sema/gerador-javascript/tsconfig.tsbuildinfo +0 -1
  69. package/node_modules/@sema/gerador-lua/src/index.d.ts +0 -3
  70. package/node_modules/@sema/gerador-lua/src/index.js.map +0 -1
  71. package/node_modules/@sema/gerador-lua/src/index.ts +0 -359
  72. package/node_modules/@sema/gerador-lua/tsconfig.json +0 -13
  73. package/node_modules/@sema/gerador-lua/tsconfig.tsbuildinfo +0 -1
  74. package/node_modules/@sema/gerador-python/src/index.ts +0 -706
  75. package/node_modules/@sema/gerador-python/tsconfig.json +0 -13
  76. package/node_modules/@sema/gerador-python/tsconfig.tsbuildinfo +0 -1
  77. package/node_modules/@sema/gerador-typescript/src/index.ts +0 -728
  78. package/node_modules/@sema/gerador-typescript/tsconfig.json +0 -13
  79. package/node_modules/@sema/gerador-typescript/tsconfig.tsbuildinfo +0 -1
  80. package/node_modules/@sema/nucleo/src/ast/tipos.ts +0 -191
  81. package/node_modules/@sema/nucleo/src/diagnosticos/index.ts +0 -43
  82. package/node_modules/@sema/nucleo/src/formatador/index.ts +0 -507
  83. package/node_modules/@sema/nucleo/src/index.ts +0 -133
  84. package/node_modules/@sema/nucleo/src/ir/conversor.ts +0 -912
  85. package/node_modules/@sema/nucleo/src/ir/modelos.ts +0 -331
  86. package/node_modules/@sema/nucleo/src/lexer/lexer.ts +0 -166
  87. package/node_modules/@sema/nucleo/src/lexer/tokens.ts +0 -64
  88. package/node_modules/@sema/nucleo/src/parser/gramatica.ebnf +0 -39
  89. package/node_modules/@sema/nucleo/src/parser/parser.ts +0 -790
  90. package/node_modules/@sema/nucleo/src/semantico/analisador.ts +0 -2692
  91. package/node_modules/@sema/nucleo/src/semantico/estruturas.ts +0 -632
  92. package/node_modules/@sema/nucleo/src/semantico/seguranca.ts +0 -362
  93. package/node_modules/@sema/nucleo/src/util/arquivos.ts +0 -28
  94. package/node_modules/@sema/nucleo/tsconfig.json +0 -9
  95. package/node_modules/@sema/nucleo/tsconfig.tsbuildinfo +0 -1
  96. package/node_modules/@sema/padroes/src/index.ts +0 -251
  97. package/node_modules/@sema/padroes/tsconfig.json +0 -9
  98. package/node_modules/@sema/padroes/tsconfig.tsbuildinfo +0 -1
@@ -1,912 +0,0 @@
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
- }