@semacode/cli 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
+ import { createRequire } from "node:module";
5
6
  import { fileURLToPath } from "node:url";
6
7
  import pacoteCli from "../package.json" with { type: "json" };
7
8
  import { compilarCodigo, formatarCodigo, formatarDiagnosticos, lerArquivoTexto, temErros, } from "@sema/nucleo";
@@ -15,7 +16,7 @@ import { gerarHtml } from "@sema/gerador-html";
15
16
  import { gerarCss } from "@sema/gerador-css";
16
17
  import { carregarConfiguracaoProjeto, carregarProjeto, resolverAlvoPadrao, resolverAlvosVerificacao, resolverEstruturaSaidaPadrao, resolverFrameworkPadrao, resolverSaidaPadrao, } from "./projeto.js";
17
18
  import { importarProjetoLegado, resumoImportacao } from "./importador.js";
18
- import { analisarDriftLegado } from "./drift.js";
19
+ import { analisarDriftLegado, assistirRenomeacaoSemantica, gerarMapaImpactoSemantico, } from "./drift.js";
19
20
  const STARTER_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao para IA sobre software vivo em backend e front consumer.
20
21
 
21
22
  Importante:
@@ -52,8 +53,10 @@ Regras:
52
53
  Comandos essenciais:
53
54
  - resumo compacto por capacidade: \`sema resumo <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>]\`
54
55
  - prompt curto para IA pequena: \`sema prompt-curto <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>]\`
55
- - descoberta do projeto: \`sema inspecionar [arquivo-ou-pasta] --json\`
56
- - auditoria do contrato vivo: \`sema drift <arquivo-ou-pasta> [--json]\`
56
+ - descoberta do projeto: \`sema inspecionar [arquivo-ou-pasta] --json\`
57
+ - auditoria do contrato vivo: \`sema drift <arquivo-ou-pasta> [--escopo <arquivo|modulo|projeto>] [--json]\`
58
+ - mapa de impacto: \`sema impacto <arquivo-ou-pasta> --alvo <token> [--mudanca <descricao>] [--json]\`
59
+ - renomeacao assistida: \`sema renomear-semantico <arquivo-ou-pasta> --de <nome-atual> --para <nome-novo> [--json]\`
57
60
  - contexto completo do modulo: \`sema contexto-ia <arquivo.sema>\`
58
61
  - estrutura sintatica: \`sema ast <arquivo.sema> --json\`
59
62
  - estrutura semantica: \`sema ir <arquivo.sema> --json\`
@@ -319,6 +322,7 @@ Comandos uteis da CLI para esse fluxo:
319
322
  `;
320
323
  const DIRETORIO_CLI_ATUAL = path.dirname(fileURLToPath(import.meta.url));
321
324
  const VERSAO_CLI = pacoteCli.version;
325
+ const requireRuntimeCli = createRequire(import.meta.url);
322
326
  const ARQUIVOS_CANONICOS_IA_RAIZ = [
323
327
  "llms.txt",
324
328
  "SEMA_BRIEF.md",
@@ -336,6 +340,16 @@ const DOCUMENTOS_SUPORTE_IA = [
336
340
  "docs/sintaxe.md",
337
341
  "docs/cli.md",
338
342
  ];
343
+ function resolverImportadorNodeOpcional(especificador) {
344
+ try {
345
+ return requireRuntimeCli.resolve(especificador);
346
+ }
347
+ catch {
348
+ return undefined;
349
+ }
350
+ }
351
+ const TSX_IMPORTADOR_CLI = resolverImportadorNodeOpcional("tsx");
352
+ const TSX_EXECUTOR_CLI = resolverImportadorNodeOpcional("tsx/cli");
339
353
  function obterArgumentos() {
340
354
  const [, , comando, ...resto] = process.argv;
341
355
  return { comando: comando, resto };
@@ -373,14 +387,15 @@ function ajuda() {
373
387
  "[2] Editar projeto que ja usa Sema",
374
388
  "sema inspecionar . --json",
375
389
  "sema resumo <arquivo-ou-pasta> --micro --para mudanca",
376
- "sema drift <arquivo-ou-pasta> --json",
390
+ "sema drift <arquivo-ou-pasta> --escopo modulo --json",
391
+ "sema impacto <arquivo-ou-pasta> --alvo <token> --mudanca <descricao> --json",
377
392
  "sema contexto-ia <arquivo.sema> --saida ./.tmp/contexto --json",
378
393
  "",
379
394
  "[3] Adotar Sema em projeto que ainda nao usa",
380
395
  "sema importar <fonte> <diretorio> --saida <diretorio> --json",
381
396
  "sema formatar <arquivo-ou-pasta>",
382
397
  "sema validar <arquivo-ou-pasta> --json",
383
- "sema drift <arquivo-ou-pasta> --json",
398
+ "sema drift <arquivo-ou-pasta> --escopo modulo --json",
384
399
  ]),
385
400
  "",
386
401
  renderizarSecaoAscii("IA por capacidade", [
@@ -391,7 +406,9 @@ function ajuda() {
391
406
  "",
392
407
  renderizarSecaoAscii("Comandos principais", [
393
408
  "descoberta: sema inspecionar [arquivo-ou-pasta] [--json]",
394
- "auditoria: sema drift <arquivo-ou-pasta> [--json]",
409
+ "auditoria: sema drift <arquivo-ou-pasta> [--escopo <arquivo|modulo|projeto>] [--incluir-worktrees] [--incluir-consumidores-laterais] [--json]",
410
+ "impacto: sema impacto <arquivo-ou-pasta> --alvo <token> [--mudanca <descricao>] [--escopo <arquivo|modulo|projeto>] [--json]",
411
+ "renomeacao: sema renomear-semantico <arquivo-ou-pasta> --de <nome-atual> --para <nome-novo> [--escopo <arquivo|modulo|projeto>] [--json]",
395
412
  "importacao: sema importar <nestjs|fastapi|flask|nextjs|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]",
396
413
  "validacao: sema validar <arquivo-ou-pasta> [--json]",
397
414
  "diagnostico: sema diagnosticos <arquivo.sema> [--json]",
@@ -447,10 +464,13 @@ function possuiFlag(args, nome) {
447
464
  const OPCOES_COM_VALOR = new Set([
448
465
  "--template",
449
466
  "--alvo", "-a",
467
+ "--escopo",
450
468
  "--saida", "-s",
451
469
  "--estrutura",
452
470
  "--framework",
453
471
  "--namespace",
472
+ "--mudanca",
473
+ "--de",
454
474
  "--para",
455
475
  ]);
456
476
  const ALIAS_OPCOES = {
@@ -471,6 +491,14 @@ function obterPosicionais(args) {
471
491
  }
472
492
  return posicionais;
473
493
  }
494
+ function resolverOpcoesDriftCli(args) {
495
+ const escopo = obterOpcao(args, "--escopo");
496
+ return {
497
+ escopo: escopo === "arquivo" || escopo === "modulo" || escopo === "projeto" ? escopo : undefined,
498
+ ignorarWorktrees: !possuiFlag(args, "--incluir-worktrees"),
499
+ ignorarConsumidoresLaterais: !possuiFlag(args, "--incluir-consumidores-laterais"),
500
+ };
501
+ }
474
502
  function normalizarTamanhoResumo(args) {
475
503
  const escolhas = [
476
504
  possuiFlag(args, "--micro") ? "micro" : null,
@@ -497,25 +525,172 @@ function comandoDisponivel(comando, argumentos = ["--version"]) {
497
525
  const execucao = spawnSync(comando, argumentos, { stdio: "ignore", shell: process.platform === "win32" });
498
526
  return (execucao.status ?? 1) === 0;
499
527
  }
500
- async function comandoDoctor() {
501
- const checks = [
502
- { nome: "node", ok: comandoDisponivel("node") },
503
- { nome: "npm", ok: comandoDisponivel("npm") },
504
- { nome: "python", ok: comandoDisponivel("python") || comandoDisponivel("py") },
505
- { nome: "dotnet", ok: comandoDisponivel("dotnet") },
506
- { nome: "go", ok: comandoDisponivel("go") },
507
- { nome: "cargo", ok: comandoDisponivel("cargo") },
508
- { nome: "java", ok: comandoDisponivel("java") },
509
- { nome: "code", ok: comandoDisponivel("code", ["--version"]) },
528
+ function resolverExecucaoPython() {
529
+ if (comandoDisponivel("python")) {
530
+ return { comando: "python", argumentosBase: [], rotulo: "python" };
531
+ }
532
+ if (comandoDisponivel("py")) {
533
+ return { comando: "py", argumentosBase: [], rotulo: "py" };
534
+ }
535
+ return undefined;
536
+ }
537
+ function resolverExecucaoPytest() {
538
+ if (comandoDisponivel("pytest")) {
539
+ return { comando: "pytest", argumentosBase: [], rotulo: "pytest" };
540
+ }
541
+ const python = resolverExecucaoPython();
542
+ if (python && comandoDisponivel(python.comando, [...python.argumentosBase, "-m", "pytest", "--version"])) {
543
+ return {
544
+ comando: python.comando,
545
+ argumentosBase: [...python.argumentosBase, "-m", "pytest"],
546
+ rotulo: `${python.rotulo} -m pytest`,
547
+ };
548
+ }
549
+ return undefined;
550
+ }
551
+ function criarItemDependencia(nome, ok, detalhe, obrigatoria = true) {
552
+ return { nome, ok, detalhe, obrigatoria };
553
+ }
554
+ function coletarDependenciasDoctor() {
555
+ const python = resolverExecucaoPython();
556
+ const pytest = resolverExecucaoPytest();
557
+ return [
558
+ {
559
+ comando: "base",
560
+ itens: [
561
+ criarItemDependencia("node", comandoDisponivel("node"), "runtime principal da CLI"),
562
+ criarItemDependencia("npm", comandoDisponivel("npm"), "instalacao, pack e publish"),
563
+ criarItemDependencia("python", Boolean(python), python?.rotulo ? `resolvido via ${python.rotulo}` : "python ou py"),
564
+ criarItemDependencia("dotnet", comandoDisponivel("dotnet"), "ecosistema ASP.NET", false),
565
+ criarItemDependencia("go", comandoDisponivel("go"), "ecosistema Go", false),
566
+ criarItemDependencia("cargo", comandoDisponivel("cargo"), "ecosistema Rust", false),
567
+ criarItemDependencia("java", comandoDisponivel("java"), "ecosistema Java/Spring", false),
568
+ criarItemDependencia("code", comandoDisponivel("code", ["--version"]), "VS Code / extensao", false),
569
+ ],
570
+ },
571
+ {
572
+ comando: "verificar/typescript",
573
+ itens: [
574
+ criarItemDependencia("node", comandoDisponivel("node"), "execucao do runner TypeScript"),
575
+ criarItemDependencia("tsx", Boolean(TSX_EXECUTOR_CLI ?? TSX_IMPORTADOR_CLI), TSX_EXECUTOR_CLI
576
+ ? `runner resolvido em ${TSX_EXECUTOR_CLI}`
577
+ : TSX_IMPORTADOR_CLI
578
+ ? `importador resolvido em ${TSX_IMPORTADOR_CLI}`
579
+ : "tsx nao foi encontrado junto da CLI"),
580
+ ],
581
+ },
582
+ {
583
+ comando: "verificar/javascript",
584
+ itens: [
585
+ criarItemDependencia("node", comandoDisponivel("node"), "node --test"),
586
+ ],
587
+ },
588
+ {
589
+ comando: "verificar/python",
590
+ itens: [
591
+ criarItemDependencia("python", Boolean(python), python?.rotulo ? `resolvido via ${python.rotulo}` : "python ou py"),
592
+ criarItemDependencia("pytest", Boolean(pytest), pytest?.rotulo ? `runner resolvido via ${pytest.rotulo}` : "instale pytest ou exponha python -m pytest"),
593
+ ],
594
+ },
595
+ {
596
+ comando: "verificar/lua",
597
+ itens: [
598
+ criarItemDependencia("lua", comandoDisponivel("lua", ["-v"]), "runner de testes Lua"),
599
+ ],
600
+ },
510
601
  ];
602
+ }
603
+ function avaliarPreflightVerificacao(configuracoesAlvo) {
604
+ const dependencias = [];
605
+ const faltando = [];
606
+ const registrar = (comando, itens) => {
607
+ dependencias.push({ comando, itens });
608
+ for (const item of itens) {
609
+ if (item.obrigatoria && !item.ok) {
610
+ faltando.push({
611
+ comando,
612
+ nome: item.nome,
613
+ detalhe: item.detalhe,
614
+ });
615
+ }
616
+ }
617
+ };
618
+ registrar("base", [
619
+ criarItemDependencia("node", comandoDisponivel("node"), "runtime principal da CLI"),
620
+ criarItemDependencia("npm", comandoDisponivel("npm"), "instalacao e empacotamento"),
621
+ ]);
622
+ for (const configuracao of configuracoesAlvo) {
623
+ if (configuracao.framework !== "base") {
624
+ continue;
625
+ }
626
+ if (configuracao.alvo === "typescript") {
627
+ registrar("verificar/typescript", [
628
+ criarItemDependencia("node", comandoDisponivel("node"), "execucao do runner TypeScript"),
629
+ criarItemDependencia("tsx", Boolean(TSX_EXECUTOR_CLI ?? TSX_IMPORTADOR_CLI), TSX_EXECUTOR_CLI
630
+ ? `runner resolvido em ${TSX_EXECUTOR_CLI}`
631
+ : TSX_IMPORTADOR_CLI
632
+ ? `importador resolvido em ${TSX_IMPORTADOR_CLI}`
633
+ : "tsx nao foi encontrado junto da CLI"),
634
+ ]);
635
+ continue;
636
+ }
637
+ if (configuracao.alvo === "javascript") {
638
+ registrar("verificar/javascript", [
639
+ criarItemDependencia("node", comandoDisponivel("node"), "node --test"),
640
+ ]);
641
+ continue;
642
+ }
643
+ if (configuracao.alvo === "python") {
644
+ const python = resolverExecucaoPython();
645
+ const pytest = resolverExecucaoPytest();
646
+ registrar("verificar/python", [
647
+ criarItemDependencia("python", Boolean(python), python?.rotulo ? `resolvido via ${python.rotulo}` : "python ou py"),
648
+ criarItemDependencia("pytest", Boolean(pytest), pytest?.rotulo ? `runner resolvido via ${pytest.rotulo}` : "instale pytest ou exponha python -m pytest"),
649
+ ]);
650
+ continue;
651
+ }
652
+ if (configuracao.alvo === "lua") {
653
+ registrar("verificar/lua", [
654
+ criarItemDependencia("lua", comandoDisponivel("lua", ["-v"]), "runner de testes Lua"),
655
+ ]);
656
+ }
657
+ }
658
+ return {
659
+ ok: faltando.length === 0,
660
+ dependencias,
661
+ faltando,
662
+ };
663
+ }
664
+ function imprimirDependenciasDoctor(dependencias) {
665
+ for (const dependencia of dependencias) {
666
+ console.log(`\n[${dependencia.comando}]`);
667
+ for (const item of dependencia.itens) {
668
+ const sufixo = item.detalhe ? ` (${item.detalhe})` : "";
669
+ console.log(`- ${item.nome}: ${item.ok ? "ok" : item.obrigatoria ? "faltando" : "ausente"}${sufixo}`);
670
+ }
671
+ }
672
+ }
673
+ function imprimirPreflightVerificacao(preflight) {
674
+ console.error(renderizarCaixaAscii([
675
+ "Preflight de verificacao falhou",
676
+ "a CLI sabe o que falta antes de gerar e testar",
677
+ ]));
678
+ for (const item of preflight.faltando) {
679
+ const detalhe = item.detalhe ? ` (${item.detalhe})` : "";
680
+ console.error(`- ${item.comando}: ${item.nome} faltando${detalhe}`);
681
+ }
682
+ console.error("Rode `sema doctor` para ver as dependencias por comando.");
683
+ }
684
+ async function comandoDoctor() {
685
+ const dependencias = coletarDependenciasDoctor();
511
686
  console.log(renderizarCaixaAscii([
512
687
  "Sema doctor",
513
- "checa a toolchain minima para validar, gerar e operar a CLI",
688
+ "checa a toolchain minima e as dependencias reais por comando",
514
689
  ]));
515
- for (const check of checks) {
516
- console.log(`- ${check.nome}: ${check.ok ? "ok" : "ausente"}`);
517
- }
518
- const obrigatorios = checks.filter((check) => ["node", "npm"].includes(check.nome));
690
+ imprimirDependenciasDoctor(dependencias);
691
+ const obrigatorios = dependencias
692
+ .find((dependencia) => dependencia.comando === "base")
693
+ ?.itens.filter((item) => item.obrigatoria) ?? [];
519
694
  return obrigatorios.every((check) => check.ok) ? 0 : 1;
520
695
  }
521
696
  function validarCompatibilidadeFramework(alvo, framework) {
@@ -754,8 +929,17 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
754
929
  }
755
930
  return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
756
931
  }
757
- const execucao = spawnSync("node", ["--import", "tsx", path.join(baseSaida, arquivoTeste)], {
932
+ if (!TSX_EXECUTOR_CLI) {
933
+ return {
934
+ codigoSaida: 1,
935
+ quantidadeTestes,
936
+ saidaPadrao: "",
937
+ saidaErro: "Nao foi possivel localizar o runner tsx junto da CLI para executar testes TypeScript.",
938
+ };
939
+ }
940
+ const execucao = spawnSync("node", [TSX_EXECUTOR_CLI, arquivoTeste], {
758
941
  stdio: silencioso ? "pipe" : "inherit",
942
+ cwd: baseSaida,
759
943
  encoding: silencioso ? "utf8" : undefined,
760
944
  });
761
945
  return {
@@ -792,6 +976,14 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
792
976
  }
793
977
  return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
794
978
  }
979
+ if (!comandoDisponivel("lua", ["-v"])) {
980
+ return {
981
+ codigoSaida: 1,
982
+ quantidadeTestes,
983
+ saidaPadrao: "",
984
+ saidaErro: "Nao foi possivel localizar o runner lua para executar os testes gerados.",
985
+ };
986
+ }
795
987
  const execucao = spawnSync("lua", [arquivoTeste], {
796
988
  stdio: silencioso ? "pipe" : "inherit",
797
989
  cwd: baseSaida,
@@ -812,10 +1004,20 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
812
1004
  }
813
1005
  return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
814
1006
  }
815
- const execucao = spawnSync("pytest", [arquivoTeste], {
1007
+ const pytest = resolverExecucaoPytest();
1008
+ if (!pytest) {
1009
+ return {
1010
+ codigoSaida: 1,
1011
+ quantidadeTestes,
1012
+ saidaPadrao: "",
1013
+ saidaErro: "Nao foi possivel localizar pytest. Instale pytest ou exponha python -m pytest.",
1014
+ };
1015
+ }
1016
+ const execucao = spawnSync(pytest.comando, [...pytest.argumentosBase, arquivoTeste], {
816
1017
  stdio: silencioso ? "pipe" : "inherit",
817
1018
  cwd: baseSaida,
818
1019
  encoding: silencioso ? "utf8" : undefined,
1020
+ shell: process.platform === "win32" && pytest.comando === "pytest",
819
1021
  });
820
1022
  return {
821
1023
  codigoSaida: execucao.status ?? 1,
@@ -3058,14 +3260,17 @@ async function comandoInspecionar(entrada, emJson, cwd = process.cwd()) {
3058
3260
  }
3059
3261
  return 0;
3060
3262
  }
3061
- async function comandoDrift(entrada, emJson, cwd = process.cwd()) {
3263
+ async function comandoDrift(entrada, args, emJson, cwd = process.cwd()) {
3062
3264
  const contextoProjeto = await carregarProjeto(entrada, cwd);
3063
- const resultado = await analisarDriftLegado(contextoProjeto);
3265
+ const resultado = await analisarDriftLegado(contextoProjeto, resolverOpcoesDriftCli(args));
3064
3266
  if (emJson) {
3065
3267
  console.log(JSON.stringify(resultado, null, 2));
3066
3268
  return resultado.sucesso ? 0 : 1;
3067
3269
  }
3068
3270
  console.log("Drift entre Sema e codigo legado");
3271
+ console.log(`- Escopo aplicado: ${resultado.escopo_aplicado.escopo}`);
3272
+ console.log(`- Ignorar worktrees: ${resultado.escopo_aplicado.ignorarWorktrees ? "sim" : "nao"}`);
3273
+ console.log(`- Ignorar consumidores laterais: ${resultado.escopo_aplicado.ignorarConsumidoresLaterais ? "sim" : "nao"}`);
3069
3274
  console.log(`- Modulos analisados: ${resultado.modulos.length}`);
3070
3275
  console.log(`- Tasks analisadas: ${resultado.tasks.length}`);
3071
3276
  console.log(`- Impl validos: ${resultado.impls_validos.length}`);
@@ -3075,6 +3280,7 @@ async function comandoDrift(entrada, emJson, cwd = process.cwd()) {
3075
3280
  console.log(`- Rotas divergentes: ${resultado.rotas_divergentes.length}`);
3076
3281
  console.log(`- Recursos vivos validos: ${resultado.recursos_validos.length}`);
3077
3282
  console.log(`- Recursos vivos divergentes: ${resultado.recursos_divergentes.length}`);
3283
+ console.log(`- Persistencia real mapeada: ${resultado.persistencia_real.length}`);
3078
3284
  console.log(`- Score medio: ${resultado.resumo_operacional.scoreMedio}`);
3079
3285
  console.log(`- Confianca geral: ${resultado.resumo_operacional.confiancaGeral}`);
3080
3286
  if (resultado.impls_quebrados.length > 0) {
@@ -3101,6 +3307,13 @@ async function comandoDrift(entrada, emJson, cwd = process.cwd()) {
3101
3307
  console.log(` - ${recurso.modulo}.${recurso.task} :: ${recurso.categoria} ${recurso.alvo}`);
3102
3308
  }
3103
3309
  }
3310
+ const persistenciaDivergente = resultado.persistencia_real.filter((item) => item.status !== "materializado");
3311
+ if (persistenciaDivergente.length > 0) {
3312
+ console.log("- Persistencia que pede revisao:");
3313
+ for (const item of persistenciaDivergente.slice(0, 8)) {
3314
+ console.log(` - ${item.modulo}.${item.task} :: ${item.alvo} :: ${item.status} :: categoria=${item.categoriaPersistencia} :: compat=${item.compatibilidade}`);
3315
+ }
3316
+ }
3104
3317
  const semImpl = resultado.tasks.filter((task) => task.semImplementacao);
3105
3318
  if (semImpl.length > 0) {
3106
3319
  console.log("- Tasks sem implementacao vinculada:");
@@ -3137,6 +3350,70 @@ async function comandoDrift(entrada, emJson, cwd = process.cwd()) {
3137
3350
  }
3138
3351
  return resultado.sucesso ? 0 : 1;
3139
3352
  }
3353
+ async function comandoImpacto(entrada, args, emJson, cwd = process.cwd()) {
3354
+ const alvoSemantico = obterOpcao(args, "--alvo");
3355
+ if (!alvoSemantico) {
3356
+ console.error("Uso: sema impacto <arquivo-ou-pasta> --alvo <token-semântico> [--mudanca <descricao>] [--escopo <arquivo|modulo|projeto>] [--incluir-worktrees] [--incluir-consumidores-laterais] [--json]");
3357
+ return 1;
3358
+ }
3359
+ const contextoProjeto = await carregarProjeto(entrada, cwd);
3360
+ const resultado = await gerarMapaImpactoSemantico(contextoProjeto, alvoSemantico, obterOpcao(args, "--mudanca", `avaliar impacto de ${alvoSemantico}`), resolverOpcoesDriftCli(args));
3361
+ if (emJson) {
3362
+ console.log(JSON.stringify(resultado, null, 2));
3363
+ return resultado.sucesso ? 0 : 1;
3364
+ }
3365
+ console.log("Impact map semantico");
3366
+ console.log(`- Escopo: ${resultado.escopo}`);
3367
+ console.log(`- Alvo: ${resultado.alvoSemantico}`);
3368
+ console.log(`- Mudanca: ${resultado.mudancaProposta}`);
3369
+ console.log(`- Arquivos impactados: ${resultado.arquivos.length}`);
3370
+ console.log(`- Tasks afetadas: ${resultado.tasksAfetadas.length}`);
3371
+ console.log(`- Rotas afetadas: ${resultado.routesAfetadas.length}`);
3372
+ console.log(`- Superficies afetadas: ${resultado.superficiesAfetadas.length}`);
3373
+ console.log(`- Persistencia afetada: ${resultado.persistenciaAfetada.length}`);
3374
+ if (resultado.arquivos.length > 0) {
3375
+ console.log("- Arquivos prioritarios:");
3376
+ for (const arquivo of resultado.arquivos.slice(0, 10)) {
3377
+ console.log(` - [${arquivo.prioridade}] ${arquivo.tipo} :: ${arquivo.arquivo}`);
3378
+ }
3379
+ }
3380
+ console.log("- Ordem operacional:");
3381
+ for (const passo of resultado.ordemOperacional) {
3382
+ console.log(` - ${passo}`);
3383
+ }
3384
+ return resultado.sucesso ? 0 : 1;
3385
+ }
3386
+ async function comandoRenomearSemantico(entrada, args, emJson, cwd = process.cwd()) {
3387
+ const nomeAtual = obterOpcao(args, "--de");
3388
+ const nomeNovo = obterOpcao(args, "--para");
3389
+ if (!nomeAtual || !nomeNovo) {
3390
+ console.error("Uso: sema renomear-semantico <arquivo-ou-pasta> --de <nome-atual> --para <nome-novo> [--escopo <arquivo|modulo|projeto>] [--incluir-worktrees] [--incluir-consumidores-laterais] [--json]");
3391
+ return 1;
3392
+ }
3393
+ const contextoProjeto = await carregarProjeto(entrada, cwd);
3394
+ const resultado = await assistirRenomeacaoSemantica(contextoProjeto, nomeAtual, nomeNovo, resolverOpcoesDriftCli(args));
3395
+ if (emJson) {
3396
+ console.log(JSON.stringify(resultado, null, 2));
3397
+ return resultado.sucesso ? 0 : 1;
3398
+ }
3399
+ console.log("Renomeacao semantica assistida");
3400
+ console.log(`- Escopo: ${resultado.escopo}`);
3401
+ console.log(`- De: ${resultado.de}`);
3402
+ console.log(`- Para: ${resultado.para}`);
3403
+ console.log(`- Arquivos afetados: ${resultado.arquivos.length}`);
3404
+ console.log(`- Sugestoes: ${resultado.sugestoes.length}`);
3405
+ if (resultado.sugestoes.length > 0) {
3406
+ console.log("- Primeiras sugestoes:");
3407
+ for (const sugestao of resultado.sugestoes.slice(0, 12)) {
3408
+ console.log(` - ${sugestao.arquivo}:${sugestao.linha} :: ${sugestao.atual} -> ${sugestao.sugerido}`);
3409
+ }
3410
+ }
3411
+ console.log("- Ordem operacional:");
3412
+ for (const passo of resultado.ordemOperacional) {
3413
+ console.log(` - ${passo}`);
3414
+ }
3415
+ return resultado.sucesso ? 0 : 1;
3416
+ }
3140
3417
  async function comandoImportar(fonte, diretorio, saida, namespaceBase, emJson) {
3141
3418
  const resultado = await importarProjetoLegado(fonte, diretorio, namespaceBase);
3142
3419
  const resumo = resumoImportacao(resultado);
@@ -3666,6 +3943,11 @@ async function comandoVerificar(entrada, baseSaida, cwd = process.cwd()) {
3666
3943
  console.error(incompatibilidade.incompatibilidade);
3667
3944
  return 1;
3668
3945
  }
3946
+ const preflight = avaliarPreflightVerificacao(configuracoesAlvo);
3947
+ if (!preflight.ok) {
3948
+ imprimirPreflightVerificacao(preflight);
3949
+ return 1;
3950
+ }
3669
3951
  const resumos = [];
3670
3952
  for (const modulo of modulos) {
3671
3953
  const ir = garantirIr(modulo.resultado, modulo.caminho);
@@ -3733,6 +4015,18 @@ async function comandoVerificarJson(entrada, baseSaida, cwd = process.cwd()) {
3733
4015
  }, null, 2));
3734
4016
  return 1;
3735
4017
  }
4018
+ const preflight = avaliarPreflightVerificacao(configuracoesAlvo);
4019
+ if (!preflight.ok) {
4020
+ console.log(JSON.stringify({
4021
+ comando: "verificar",
4022
+ sucesso: false,
4023
+ erro: "Dependencias obrigatorias ausentes para executar a verificacao.",
4024
+ preflight,
4025
+ modulos: [],
4026
+ totais: { modulos: 0, alvos: 0, arquivos: 0, testes: 0 },
4027
+ }, null, 2));
4028
+ return 1;
4029
+ }
3736
4030
  const resumos = [];
3737
4031
  let codigoSaida = 0;
3738
4032
  for (const modulo of modulos) {
@@ -3855,7 +4149,13 @@ async function principal() {
3855
4149
  codigoSaida = await comandoInspecionar(posicionais[0], possuiFlag(resto, "--json"), cwd);
3856
4150
  break;
3857
4151
  case "drift":
3858
- codigoSaida = await comandoDrift(posicionais[0], possuiFlag(resto, "--json"), cwd);
4152
+ codigoSaida = await comandoDrift(posicionais[0], resto, possuiFlag(resto, "--json"), cwd);
4153
+ break;
4154
+ case "impacto":
4155
+ codigoSaida = await comandoImpacto(posicionais[0], resto, possuiFlag(resto, "--json"), cwd);
4156
+ break;
4157
+ case "renomear-semantico":
4158
+ codigoSaida = await comandoRenomearSemantico(posicionais[0], resto, possuiFlag(resto, "--json"), cwd);
3859
4159
  break;
3860
4160
  case "importar":
3861
4161
  {