@semacode/cli 0.8.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/README.md +2 -2
  2. package/dist/drift.d.ts +30 -1
  3. package/dist/drift.js +373 -17
  4. package/dist/drift.js.map +1 -1
  5. package/dist/index.js +139 -15
  6. package/dist/index.js.map +1 -1
  7. package/node_modules/@sema/gerador-dart/package.json +1 -1
  8. package/node_modules/@sema/gerador-python/package.json +1 -1
  9. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  10. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +14 -1
  11. package/node_modules/@sema/nucleo/dist/formatador/index.js +131 -22
  12. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
  13. package/node_modules/@sema/nucleo/dist/ir/conversor.js +546 -102
  14. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  15. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +83 -5
  16. package/node_modules/@sema/nucleo/dist/lexer/lexer.js +1 -1
  17. package/node_modules/@sema/nucleo/dist/lexer/lexer.js.map +1 -1
  18. package/node_modules/@sema/nucleo/dist/lexer/tokens.js +10 -0
  19. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
  20. package/node_modules/@sema/nucleo/dist/parser/parser.js +230 -19
  21. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  22. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +6 -1
  23. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +269 -10
  24. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  25. package/node_modules/@sema/nucleo/package.json +1 -1
  26. package/node_modules/@sema/padroes/package.json +1 -1
  27. package/package.json +6 -6
package/README.md CHANGED
@@ -20,7 +20,7 @@ sema --help
20
20
  ## Instalacao via tarball da release
21
21
 
22
22
  ```bash
23
- npm install -g ./sema-cli-0.8.8.tgz
23
+ npm install -g ./sema-cli-0.9.0.tgz
24
24
  ```
25
25
 
26
26
  Ou direto da GitHub Release:
@@ -39,7 +39,7 @@ npx sema --help
39
39
  Ou, se voce estiver testando um tarball local:
40
40
 
41
41
  ```bash
42
- npm install ./sema-cli-0.8.8.tgz
42
+ npm install ./sema-cli-0.9.0.tgz
43
43
  npx sema --help
44
44
  ```
45
45
 
package/dist/drift.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import type { NivelConfiancaSemantica, NivelRiscoSemantico } from "@sema/nucleo";
1
2
  import type { ContextoProjetoCarregado } from "./projeto.js";
2
3
  export interface DiagnosticoDrift {
3
- tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente";
4
+ tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado";
4
5
  modulo: string;
5
6
  task?: string;
6
7
  route?: string;
@@ -49,9 +50,26 @@ interface ResumoTaskDrift {
49
50
  implsValidos: number;
50
51
  implsQuebrados: number;
51
52
  semImplementacao: boolean;
53
+ scoreSemantico: number;
54
+ confiancaVinculo: NivelConfiancaSemantica;
55
+ riscoOperacional: NivelRiscoSemantico;
56
+ lacunas: string[];
52
57
  arquivosReferenciados: string[];
58
+ arquivosProvaveisEditar: string[];
53
59
  simbolosReferenciados: string[];
54
60
  candidatosImpl: SimboloCandidatoDrift[];
61
+ checksSugeridos: string[];
62
+ }
63
+ interface RegistroVinculoDrift {
64
+ modulo: string;
65
+ donoTipo: "modulo" | "task" | "flow" | "route" | "superficie";
66
+ dono: string;
67
+ tipo: string;
68
+ valor: string;
69
+ arquivo?: string;
70
+ simbolo?: string;
71
+ status: "resolvido" | "parcial" | "nao_encontrado";
72
+ confianca: NivelConfiancaSemantica;
55
73
  }
56
74
  export interface ResultadoDrift {
57
75
  comando: "drift";
@@ -65,9 +83,20 @@ export interface ResultadoDrift {
65
83
  tasks: ResumoTaskDrift[];
66
84
  impls_validos: RegistroImplDrift[];
67
85
  impls_quebrados: RegistroImplDrift[];
86
+ vinculos_validos: RegistroVinculoDrift[];
87
+ vinculos_quebrados: RegistroVinculoDrift[];
68
88
  rotas_divergentes: RegistroRotaDivergente[];
69
89
  recursos_validos: RegistroRecursoDrift[];
70
90
  recursos_divergentes: RegistroRecursoDrift[];
91
+ resumo_operacional: {
92
+ scoreMedio: number;
93
+ confiancaGeral: NivelConfiancaSemantica;
94
+ riscosPrincipais: string[];
95
+ oQueTocar: string[];
96
+ oQueValidar: string[];
97
+ oQueEstaFrouxo: string[];
98
+ oQueFoiInferido: string[];
99
+ };
71
100
  diagnosticos: DiagnosticoDrift[];
72
101
  }
73
102
  export declare function analisarDriftLegado(contexto: ContextoProjetoCarregado): Promise<ResultadoDrift>;
package/dist/drift.js CHANGED
@@ -25,6 +25,178 @@ const DIRETORIOS_IGNORADOS = new Set([
25
25
  ".tmp",
26
26
  "generated",
27
27
  ]);
28
+ function normalizarFragmentoArquivo(valor) {
29
+ return valor.replace(/\\/g, "/").replace(/^\.?\//, "").trim().toLowerCase();
30
+ }
31
+ function escolherArquivoPorVinculo(arquivos, valor) {
32
+ const normalizado = normalizarFragmentoArquivo(valor);
33
+ const exato = arquivos.find((arquivo) => normalizarFragmentoArquivo(arquivo) === normalizado);
34
+ if (exato) {
35
+ return { arquivo: exato, confianca: "alta", status: "resolvido" };
36
+ }
37
+ const porSufixo = arquivos.find((arquivo) => normalizarFragmentoArquivo(arquivo).endsWith(normalizado));
38
+ if (porSufixo) {
39
+ return { arquivo: porSufixo, confianca: "media", status: "parcial" };
40
+ }
41
+ return { confianca: "baixa", status: "nao_encontrado" };
42
+ }
43
+ function escolherSimboloPorVinculo(simbolos, mapaImpl, valor) {
44
+ const exato = mapaImpl.get(valor);
45
+ if (exato) {
46
+ return { simbolo: exato, confianca: "alta", status: "resolvido" };
47
+ }
48
+ const ultimoSegmento = valor.split(".").at(-1)?.toLowerCase();
49
+ const aproximado = simbolos.find((simbolo) => simbolo.caminho.toLowerCase() === valor.toLowerCase()
50
+ || simbolo.simbolo.toLowerCase() === ultimoSegmento
51
+ || simbolo.caminho.toLowerCase().endsWith(`.${ultimoSegmento}`));
52
+ if (aproximado) {
53
+ return { simbolo: aproximado, confianca: "media", status: "parcial" };
54
+ }
55
+ return { confianca: "baixa", status: "nao_encontrado" };
56
+ }
57
+ function resolverArquivoOuSimboloAncora(vinculos, simbolos, mapaImpl, arquivos) {
58
+ for (const vinculo of vinculos) {
59
+ if (vinculo.simbolo) {
60
+ const resolucaoSimbolo = escolherSimboloPorVinculo(simbolos, mapaImpl, vinculo.simbolo);
61
+ if (resolucaoSimbolo.status !== "nao_encontrado") {
62
+ return {
63
+ arquivo: resolucaoSimbolo.simbolo?.arquivo,
64
+ simbolo: resolucaoSimbolo.simbolo?.simbolo,
65
+ confianca: resolucaoSimbolo.confianca,
66
+ };
67
+ }
68
+ }
69
+ if (vinculo.arquivo) {
70
+ const resolucaoArquivo = escolherArquivoPorVinculo(arquivos, vinculo.arquivo);
71
+ if (resolucaoArquivo.status !== "nao_encontrado") {
72
+ return {
73
+ arquivo: resolucaoArquivo.arquivo,
74
+ confianca: resolucaoArquivo.confianca,
75
+ };
76
+ }
77
+ }
78
+ }
79
+ return undefined;
80
+ }
81
+ function encontrarAncoraSuperficie(ir, superficie, simbolos, mapaImpl, arquivos) {
82
+ const ancoraDireta = resolverArquivoOuSimboloAncora(superficie.vinculos, simbolos, mapaImpl, arquivos);
83
+ if (ancoraDireta) {
84
+ return ancoraDireta;
85
+ }
86
+ for (const impl of superficie.implementacoesExternas) {
87
+ const resolvido = mapaImpl.get(impl.caminho);
88
+ if (resolvido) {
89
+ return {
90
+ arquivo: resolvido.arquivo,
91
+ simbolo: resolvido.simbolo,
92
+ confianca: "alta",
93
+ };
94
+ }
95
+ }
96
+ if (!superficie.task) {
97
+ return undefined;
98
+ }
99
+ const taskAssociada = ir.tasks.find((task) => task.nome === superficie.task);
100
+ if (!taskAssociada) {
101
+ return undefined;
102
+ }
103
+ const ancoraTask = resolverArquivoOuSimboloAncora(taskAssociada.vinculos, simbolos, mapaImpl, arquivos);
104
+ if (ancoraTask) {
105
+ return ancoraTask;
106
+ }
107
+ for (const impl of taskAssociada.implementacoesExternas) {
108
+ const resolvido = mapaImpl.get(impl.caminho);
109
+ if (resolvido) {
110
+ return {
111
+ arquivo: resolvido.arquivo,
112
+ simbolo: resolvido.simbolo,
113
+ confianca: "alta",
114
+ };
115
+ }
116
+ }
117
+ return undefined;
118
+ }
119
+ function calcularRiscoOperacional(task) {
120
+ if (task.execucao.criticidadeOperacional === "alta"
121
+ || task.execucao.criticidadeOperacional === "critica"
122
+ || task.efeitosEstruturados.some((efeito) => efeito.categoria === "persistencia" || efeito.criticidade === "critica")) {
123
+ return "alto";
124
+ }
125
+ if (task.efeitosEstruturados.length > 0 || task.vinculos.length > 0 || task.errosDetalhados.length > 0) {
126
+ return "medio";
127
+ }
128
+ return "baixo";
129
+ }
130
+ function calcularConfiancaTask(task, implsValidos, implsQuebrados, vinculosValidos, vinculosQuebrados) {
131
+ if ((implsValidos > 0 || vinculosValidos > 0) && implsQuebrados === 0 && vinculosQuebrados === 0) {
132
+ return "alta";
133
+ }
134
+ if (implsValidos > 0 || vinculosValidos > 0 || task.implementacoesExternas.length > 0 || task.vinculos.length > 0) {
135
+ return "media";
136
+ }
137
+ return "baixa";
138
+ }
139
+ function calcularScoreTask(task, implsValidos, implsQuebrados, vinculosValidos, vinculosQuebrados, semImplementacao) {
140
+ let score = 45;
141
+ if (!semImplementacao && task.implementacoesExternas.length > 0) {
142
+ score += 15;
143
+ }
144
+ score += Math.min(implsValidos * 10, 20);
145
+ score -= Math.min(implsQuebrados * 20, 30);
146
+ score += Math.min(vinculosValidos * 5, 15);
147
+ score -= Math.min(vinculosQuebrados * 10, 20);
148
+ if (task.guarantees.length > 0) {
149
+ score += 5;
150
+ }
151
+ if (task.execucao.explicita) {
152
+ score += 5;
153
+ }
154
+ return Math.max(0, Math.min(100, score));
155
+ }
156
+ function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQuebrados) {
157
+ const lacunas = [];
158
+ if (semImplementacao) {
159
+ lacunas.push("sem_impl");
160
+ }
161
+ if (implsQuebrados > 0) {
162
+ lacunas.push("impl_quebrado");
163
+ }
164
+ if (task.vinculos.length === 0) {
165
+ lacunas.push("sem_vinculos");
166
+ }
167
+ if (vinculosQuebrados > 0) {
168
+ lacunas.push("vinculo_quebrado");
169
+ }
170
+ if (!task.execucao.explicita) {
171
+ lacunas.push("execucao_implicita");
172
+ }
173
+ return lacunas;
174
+ }
175
+ function resumirOperacional(resultado) {
176
+ const scoreMedio = resultado.tasks.length > 0
177
+ ? Math.round(resultado.tasks.reduce((total, task) => total + task.scoreSemantico, 0) / resultado.tasks.length)
178
+ : 0;
179
+ const confiancaGeral = scoreMedio >= 80 ? "alta" : scoreMedio >= 55 ? "media" : "baixa";
180
+ const riscosPrincipais = [...new Set(resultado.tasks.filter((task) => task.riscoOperacional !== "baixo").map((task) => `${task.task}:${task.riscoOperacional}`))];
181
+ const oQueTocar = [...new Set(resultado.tasks.flatMap((task) => task.arquivosProvaveisEditar))].slice(0, 20);
182
+ const oQueValidar = [...new Set(resultado.tasks.flatMap((task) => task.checksSugeridos))];
183
+ const oQueEstaFrouxo = [...new Set(resultado.tasks.flatMap((task) => task.lacunas))];
184
+ const oQueFoiInferido = [
185
+ ...new Set([
186
+ ...resultado.impls_quebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.caminho) ?? []),
187
+ ...resultado.vinculos_quebrados.filter((vinculo) => vinculo.status === "parcial").map((vinculo) => `${vinculo.dono}:${vinculo.valor}`),
188
+ ]),
189
+ ];
190
+ return {
191
+ scoreMedio,
192
+ confiancaGeral,
193
+ riscosPrincipais,
194
+ oQueTocar,
195
+ oQueValidar,
196
+ oQueEstaFrouxo,
197
+ oQueFoiInferido,
198
+ };
199
+ }
28
200
  function paraIdentificadorModulo(valor) {
29
201
  return valor
30
202
  .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
@@ -174,10 +346,10 @@ async function indexarTypeScript(diretorios) {
174
346
  });
175
347
  }
176
348
  for (const node of sourceFile.statements) {
177
- if (ts.isFunctionDeclaration(node) && node.name && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
349
+ if (ts.isFunctionDeclaration(node) && node.name) {
178
350
  registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, node.name.text);
179
351
  }
180
- if (ts.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
352
+ if (ts.isVariableStatement(node)) {
181
353
  for (const declaracao of node.declarationList.declarations) {
182
354
  if (!ts.isIdentifier(declaracao.name) || !declaracao.initializer) {
183
355
  continue;
@@ -196,21 +368,19 @@ async function indexarTypeScript(diretorios) {
196
368
  if (!ts.isMethodDeclaration(member) || !member.name) {
197
369
  continue;
198
370
  }
199
- if (member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword)) {
200
- continue;
201
- }
202
371
  const nomeMetodo = member.name.getText(sourceFile);
203
372
  if (nomeMetodo === "constructor") {
204
373
  continue;
205
374
  }
206
375
  registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, nomeMetodo, node.name.text);
376
+ const metodoEhInterno = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword);
207
377
  for (const baseSimbolica of basesSimbolicas) {
208
378
  const caminhoMetodoDireto = `${baseSimbolica}.${nomeMetodo}`;
209
379
  if (!simbolos.has(caminhoMetodoDireto)) {
210
380
  simbolos.set(caminhoMetodoDireto, { origem: "ts", caminho: caminhoMetodoDireto, arquivo, simbolo: nomeMetodo });
211
381
  }
212
382
  }
213
- if (controllerDecorator) {
383
+ if (controllerDecorator && !metodoEhInterno) {
214
384
  const httpDecorator = lerDecorator(member, ["Get", "Post", "Put", "Patch", "Delete"]);
215
385
  if (httpDecorator) {
216
386
  rotas.push({
@@ -483,7 +653,7 @@ function normalizarCaminhoRota(caminho) {
483
653
  if (!caminho) {
484
654
  return "/";
485
655
  }
486
- const limpo = normalizarCaminhoFlask(caminho.trim());
656
+ const limpo = normalizarCaminhoFlask(caminho.trim().replace(/\s*\/\s*/g, "/"));
487
657
  const comBarra = limpo.startsWith("/") ? limpo : `/${limpo}`;
488
658
  const normalizado = comBarra.replace(/\/+/g, "/");
489
659
  return normalizado.endsWith("/") && normalizado !== "/" ? normalizado.slice(0, -1) : normalizado;
@@ -680,6 +850,15 @@ function extrairRecursosEsperados(task) {
680
850
  alvo: efeito.alvo,
681
851
  }));
682
852
  }
853
+ function coletarVinculosIr(ir) {
854
+ return [
855
+ ...ir.vinculos.map((vinculo) => ({ donoTipo: "modulo", dono: ir.nome, vinculo })),
856
+ ...ir.tasks.flatMap((task) => task.vinculos.map((vinculo) => ({ donoTipo: "task", dono: task.nome, vinculo }))),
857
+ ...ir.flows.flatMap((flow) => flow.vinculos.map((vinculo) => ({ donoTipo: "flow", dono: flow.nome, vinculo }))),
858
+ ...ir.routes.flatMap((route) => route.vinculos.map((vinculo) => ({ donoTipo: "route", dono: route.nome, vinculo }))),
859
+ ...ir.superficies.flatMap((superficie) => superficie.vinculos.map((vinculo) => ({ donoTipo: "superficie", dono: `${superficie.tipo}:${superficie.nome}`, vinculo }))),
860
+ ];
861
+ }
683
862
  export async function analisarDriftLegado(contexto) {
684
863
  const indexTs = await indexarTypeScript(contexto.diretoriosCodigo);
685
864
  const indexPy = await indexarPython(contexto.diretoriosCodigo);
@@ -710,19 +889,38 @@ export async function analisarDriftLegado(contexto) {
710
889
  ...indexCpp.map((item) => [item.caminho, item]),
711
890
  ]);
712
891
  const mapaRecursos = new Map(indexTs.recursos.map((item) => [item.nome, item]));
892
+ const todasRotasIndexadas = [
893
+ ...indexTs.rotas,
894
+ ...indexPy.rotas,
895
+ ...indexDotnet.rotas,
896
+ ...indexJava.rotas,
897
+ ...indexGo.rotas,
898
+ ...indexRust.rotas,
899
+ ];
900
+ const todosArquivosConhecidos = [...new Set([
901
+ ...todosSimbolos.map((item) => item.arquivo),
902
+ ...todasRotasIndexadas.map((item) => item.arquivo),
903
+ ...indexTs.recursos.map((item) => item.arquivo),
904
+ ])].sort((a, b) => a.localeCompare(b, "pt-BR"));
713
905
  const implsValidos = [];
714
906
  const implsQuebrados = [];
907
+ const vinculosValidos = [];
908
+ const vinculosQuebrados = [];
715
909
  const rotasDivergentes = [];
716
910
  const recursosValidos = [];
717
911
  const recursosDivergentes = [];
718
912
  const diagnosticos = [];
719
913
  const tasksResumo = [];
914
+ const taskPorChave = new Map();
915
+ const resumoVinculosPorTask = new Map();
720
916
  for (const item of contexto.modulosSelecionados) {
721
917
  const ir = item.resultado.ir;
722
918
  if (!ir) {
723
919
  continue;
724
920
  }
921
+ const superficiesPorChave = new Map(ir.superficies.map((superficie) => [`${superficie.tipo}:${superficie.nome}`, superficie]));
725
922
  for (const task of ir.tasks) {
923
+ taskPorChave.set(`${ir.nome}:${task.nome}`, task);
726
924
  let validos = 0;
727
925
  let quebrados = 0;
728
926
  const arquivosReferenciados = new Set();
@@ -779,9 +977,15 @@ export async function analisarDriftLegado(contexto) {
779
977
  implsValidos: validos,
780
978
  implsQuebrados: quebrados,
781
979
  semImplementacao: task.implementacoesExternas.length === 0,
980
+ scoreSemantico: 0,
981
+ confiancaVinculo: "baixa",
982
+ riscoOperacional: "baixo",
983
+ lacunas: [],
782
984
  arquivosReferenciados: [...arquivosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
985
+ arquivosProvaveisEditar: [],
783
986
  simbolosReferenciados: [...simbolosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
784
987
  candidatosImpl: ordenarCandidatos([...candidatosTask.values()]).slice(0, 5),
988
+ checksSugeridos: [],
785
989
  });
786
990
  for (const recursoEsperado of extrairRecursosEsperados(task)) {
787
991
  const resolvido = mapaRecursos.get(recursoEsperado.alvo);
@@ -821,22 +1025,33 @@ export async function analisarDriftLegado(contexto) {
821
1025
  effects: [],
822
1026
  efeitosEstruturados: [],
823
1027
  implementacoesExternas: [],
1028
+ vinculos: [],
1029
+ execucao: {
1030
+ idempotencia: false,
1031
+ timeout: "padrao",
1032
+ retry: "nenhum",
1033
+ compensacao: "nenhuma",
1034
+ criticidadeOperacional: "media",
1035
+ explicita: false,
1036
+ },
824
1037
  guarantees: [],
825
1038
  garantiasEstruturadas: [],
826
1039
  errors: {},
1040
+ errosDetalhados: [],
1041
+ perfilCompatibilidade: "interno",
1042
+ resumoAgente: {
1043
+ riscos: [],
1044
+ checks: [],
1045
+ entidadesAfetadas: [],
1046
+ superficiesPublicas: [],
1047
+ mutacoesPrevistas: [],
1048
+ },
827
1049
  tests: [],
828
1050
  }, contexto.fontesLegado);
829
1051
  if (!esperadas.length || !route.metodo || !route.caminho) {
830
1052
  continue;
831
1053
  }
832
- const encontradas = [
833
- ...indexTs.rotas,
834
- ...indexPy.rotas,
835
- ...indexDotnet.rotas,
836
- ...indexJava.rotas,
837
- ...indexGo.rotas,
838
- ...indexRust.rotas,
839
- ].filter((rotaResolvida) => esperadas.includes(rotaResolvida.origem));
1054
+ const encontradas = todasRotasIndexadas.filter((rotaResolvida) => esperadas.includes(rotaResolvida.origem));
840
1055
  const combina = encontradas.some((rotaResolvida) => rotaResolvida.metodo === route.metodo
841
1056
  && normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(route.caminho));
842
1057
  if (!combina) {
@@ -856,10 +1071,135 @@ export async function analisarDriftLegado(contexto) {
856
1071
  });
857
1072
  }
858
1073
  }
1074
+ for (const itemVinculo of coletarVinculosIr(ir)) {
1075
+ const registro = {
1076
+ modulo: ir.nome,
1077
+ donoTipo: itemVinculo.donoTipo,
1078
+ dono: itemVinculo.dono,
1079
+ tipo: itemVinculo.vinculo.tipo,
1080
+ valor: itemVinculo.vinculo.valor,
1081
+ status: "nao_encontrado",
1082
+ confianca: "baixa",
1083
+ };
1084
+ const arquivoDeclarado = itemVinculo.vinculo.arquivo ?? (itemVinculo.vinculo.tipo === "arquivo" ? itemVinculo.vinculo.valor : undefined);
1085
+ const simboloDeclarado = itemVinculo.vinculo.simbolo ?? (itemVinculo.vinculo.tipo === "simbolo" ? itemVinculo.vinculo.valor : undefined);
1086
+ const recursoDeclarado = itemVinculo.vinculo.recurso ?? (["recurso", "tabela", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
1087
+ const superficieDeclarada = itemVinculo.vinculo.superficie ?? (["superficie", "rota", "worker", "cron", "webhook", "evento", "policy", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
1088
+ if (simboloDeclarado) {
1089
+ const resolucaoSimbolo = escolherSimboloPorVinculo(todosSimbolos, mapaImpl, simboloDeclarado);
1090
+ registro.status = resolucaoSimbolo.status;
1091
+ registro.confianca = resolucaoSimbolo.confianca;
1092
+ registro.arquivo = resolucaoSimbolo.simbolo?.arquivo;
1093
+ registro.simbolo = resolucaoSimbolo.simbolo?.simbolo;
1094
+ }
1095
+ else if (arquivoDeclarado) {
1096
+ const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, arquivoDeclarado);
1097
+ registro.status = resolucaoArquivo.status;
1098
+ registro.confianca = resolucaoArquivo.confianca;
1099
+ registro.arquivo = resolucaoArquivo.arquivo;
1100
+ }
1101
+ else if (recursoDeclarado) {
1102
+ const recurso = mapaRecursos.get(recursoDeclarado);
1103
+ if (recurso) {
1104
+ registro.status = "resolvido";
1105
+ registro.confianca = "alta";
1106
+ registro.arquivo = recurso.arquivo;
1107
+ }
1108
+ }
1109
+ else if (superficieDeclarada) {
1110
+ const rota = todasRotasIndexadas.find((rotaResolvida) => normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(superficieDeclarada));
1111
+ if (rota) {
1112
+ registro.status = "resolvido";
1113
+ registro.confianca = "alta";
1114
+ registro.arquivo = rota.arquivo;
1115
+ registro.simbolo = rota.simbolo;
1116
+ }
1117
+ else {
1118
+ const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, superficieDeclarada);
1119
+ registro.status = resolucaoArquivo.status;
1120
+ registro.confianca = resolucaoArquivo.confianca;
1121
+ registro.arquivo = resolucaoArquivo.arquivo;
1122
+ }
1123
+ }
1124
+ else {
1125
+ const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, itemVinculo.vinculo.valor);
1126
+ registro.status = resolucaoArquivo.status;
1127
+ registro.confianca = resolucaoArquivo.confianca;
1128
+ registro.arquivo = resolucaoArquivo.arquivo;
1129
+ }
1130
+ if (registro.status === "nao_encontrado" && itemVinculo.donoTipo === "superficie") {
1131
+ const superficie = superficiesPorChave.get(itemVinculo.dono);
1132
+ const ancora = superficie
1133
+ ? encontrarAncoraSuperficie(ir, superficie, todosSimbolos, mapaImpl, todosArquivosConhecidos)
1134
+ : undefined;
1135
+ if (ancora) {
1136
+ registro.status = "parcial";
1137
+ registro.confianca = ancora.confianca === "alta" ? "media" : ancora.confianca;
1138
+ registro.arquivo = registro.arquivo ?? ancora.arquivo;
1139
+ registro.simbolo = registro.simbolo ?? ancora.simbolo;
1140
+ }
1141
+ }
1142
+ if (registro.status === "nao_encontrado") {
1143
+ vinculosQuebrados.push(registro);
1144
+ diagnosticos.push({
1145
+ tipo: "vinculo_quebrado",
1146
+ modulo: ir.nome,
1147
+ mensagem: `Vinculo ${registro.tipo}="${registro.valor}" de ${registro.donoTipo} "${registro.dono}" nao foi resolvido no codigo vivo.`,
1148
+ ...(itemVinculo.donoTipo === "task" ? { task: itemVinculo.dono } : itemVinculo.donoTipo === "route" ? { route: itemVinculo.dono } : {}),
1149
+ });
1150
+ }
1151
+ else {
1152
+ vinculosValidos.push(registro);
1153
+ }
1154
+ if (itemVinculo.donoTipo === "task") {
1155
+ const chaveTask = `${ir.nome}:${itemVinculo.dono}`;
1156
+ const resumo = resumoVinculosPorTask.get(chaveTask) ?? {
1157
+ validos: 0,
1158
+ quebrados: 0,
1159
+ arquivos: new Set(),
1160
+ };
1161
+ if (registro.status === "nao_encontrado") {
1162
+ resumo.quebrados += 1;
1163
+ }
1164
+ else {
1165
+ resumo.validos += 1;
1166
+ }
1167
+ if (registro.arquivo) {
1168
+ resumo.arquivos.add(registro.arquivo);
1169
+ }
1170
+ resumoVinculosPorTask.set(chaveTask, resumo);
1171
+ }
1172
+ }
859
1173
  }
860
- return {
1174
+ for (const resumo of tasksResumo) {
1175
+ const chaveTask = `${resumo.modulo}:${resumo.task}`;
1176
+ const task = taskPorChave.get(chaveTask);
1177
+ const resumoVinculos = resumoVinculosPorTask.get(chaveTask) ?? {
1178
+ validos: 0,
1179
+ quebrados: 0,
1180
+ arquivos: new Set(),
1181
+ };
1182
+ if (!task) {
1183
+ continue;
1184
+ }
1185
+ resumo.confiancaVinculo = calcularConfiancaTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados);
1186
+ resumo.riscoOperacional = calcularRiscoOperacional(task);
1187
+ resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados);
1188
+ resumo.scoreSemantico = calcularScoreTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados, resumo.semImplementacao);
1189
+ resumo.arquivosProvaveisEditar = [...new Set([
1190
+ ...resumo.arquivosReferenciados,
1191
+ ...resumo.candidatosImpl.map((candidato) => candidato.arquivo),
1192
+ ...resumoVinculos.arquivos,
1193
+ ])].sort((a, b) => a.localeCompare(b, "pt-BR"));
1194
+ resumo.checksSugeridos = [...new Set([
1195
+ ...task.resumoAgente.checks,
1196
+ resumo.riscoOperacional !== "baixo" ? "revisar efeitos operacionais" : "",
1197
+ resumo.lacunas.includes("vinculo_quebrado") ? "corrigir vinculos rastreaveis" : "",
1198
+ ].filter(Boolean))];
1199
+ }
1200
+ const payloadBase = {
861
1201
  comando: "drift",
862
- sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0,
1202
+ sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0 && vinculosQuebrados.length === 0,
863
1203
  modulos: contexto.modulosSelecionados.map((item) => ({
864
1204
  caminho: item.caminho,
865
1205
  modulo: item.resultado.ir?.nome ?? item.resultado.modulo?.nome ?? null,
@@ -869,10 +1209,26 @@ export async function analisarDriftLegado(contexto) {
869
1209
  tasks: tasksResumo,
870
1210
  impls_validos: implsValidos,
871
1211
  impls_quebrados: implsQuebrados,
1212
+ vinculos_validos: vinculosValidos,
1213
+ vinculos_quebrados: vinculosQuebrados,
872
1214
  rotas_divergentes: rotasDivergentes,
873
1215
  recursos_validos: recursosValidos,
874
1216
  recursos_divergentes: recursosDivergentes,
875
1217
  diagnosticos,
1218
+ resumo_operacional: {
1219
+ scoreMedio: 0,
1220
+ confiancaGeral: "baixa",
1221
+ riscosPrincipais: [],
1222
+ oQueTocar: [],
1223
+ oQueValidar: [],
1224
+ oQueEstaFrouxo: [],
1225
+ oQueFoiInferido: [],
1226
+ },
1227
+ };
1228
+ const resumoOperacional = resumirOperacional(payloadBase);
1229
+ return {
1230
+ ...payloadBase,
1231
+ resumo_operacional: resumoOperacional,
876
1232
  };
877
1233
  }
878
1234
  //# sourceMappingURL=drift.js.map