@semacode/cli 1.0.0 → 1.2.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 (48) hide show
  1. package/AGENTS.md +50 -0
  2. package/README.md +15 -2
  3. package/SEMA_BRIEF.curto.txt +9 -0
  4. package/SEMA_BRIEF.md +49 -0
  5. package/SEMA_BRIEF.micro.txt +7 -0
  6. package/SEMA_INDEX.json +546 -0
  7. package/dist/drift.d.ts +17 -2
  8. package/dist/drift.js +516 -5
  9. package/dist/drift.js.map +1 -1
  10. package/dist/importador.d.ts +1 -1
  11. package/dist/importador.js +741 -3
  12. package/dist/importador.js.map +1 -1
  13. package/dist/index.js +962 -86
  14. package/dist/index.js.map +1 -1
  15. package/dist/lua-symbols.d.ts +8 -0
  16. package/dist/lua-symbols.js +68 -0
  17. package/dist/lua-symbols.js.map +1 -0
  18. package/dist/projeto.js +56 -2
  19. package/dist/projeto.js.map +1 -1
  20. package/dist/tipos.d.ts +1 -1
  21. package/docs/AGENT_STARTER.md +34 -6
  22. package/docs/instalacao-e-primeiro-uso.md +18 -9
  23. package/llms-full.txt +34 -0
  24. package/llms.txt +17 -0
  25. package/node_modules/@sema/gerador-dart/package.json +1 -1
  26. package/node_modules/@sema/gerador-lua/dist/index.d.ts +3 -0
  27. package/node_modules/@sema/gerador-lua/dist/index.js +360 -0
  28. package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -0
  29. package/node_modules/@sema/gerador-lua/package.json +7 -0
  30. package/node_modules/@sema/gerador-python/dist/index.js +92 -10
  31. package/node_modules/@sema/gerador-python/dist/index.js.map +1 -1
  32. package/node_modules/@sema/gerador-python/package.json +1 -1
  33. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  34. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +1 -1
  35. package/node_modules/@sema/nucleo/dist/ir/conversor.js +4 -0
  36. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  37. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +3 -3
  38. package/node_modules/@sema/nucleo/dist/parser/parser.js +2 -0
  39. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  40. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +2 -2
  41. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +3 -1
  42. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  43. package/node_modules/@sema/nucleo/package.json +1 -1
  44. package/node_modules/@sema/padroes/dist/index.d.ts +2 -1
  45. package/node_modules/@sema/padroes/dist/index.js +64 -1
  46. package/node_modules/@sema/padroes/dist/index.js.map +1 -1
  47. package/node_modules/@sema/padroes/package.json +1 -1
  48. package/package.json +16 -7
package/dist/index.js CHANGED
@@ -7,12 +7,13 @@ import pacoteCli from "../package.json" with { type: "json" };
7
7
  import { compilarCodigo, formatarCodigo, formatarDiagnosticos, lerArquivoTexto, temErros, } from "@sema/nucleo";
8
8
  import { descreverEstruturaModulo } from "@sema/padroes";
9
9
  import { gerarDart } from "@sema/gerador-dart";
10
+ import { gerarLua } from "@sema/gerador-lua";
10
11
  import { gerarPython } from "@sema/gerador-python";
11
12
  import { gerarTypeScript } from "@sema/gerador-typescript";
12
13
  import { carregarConfiguracaoProjeto, carregarProjeto, resolverAlvoPadrao, resolverAlvosVerificacao, resolverEstruturaSaidaPadrao, resolverFrameworkPadrao, resolverSaidaPadrao, } from "./projeto.js";
13
14
  import { importarProjetoLegado, resumoImportacao } from "./importador.js";
14
15
  import { analisarDriftLegado } from "./drift.js";
15
- const STARTER_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao para IA e backend vivo.
16
+ const STARTER_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao para IA sobre software vivo em backend e front consumer.
16
17
 
17
18
  Importante:
18
19
  - a Sema se apresenta publicamente como protocolo e funciona tecnicamente como linguagem de intencao
@@ -20,7 +21,7 @@ Importante:
20
21
  - leitura humana e bonus toleravel, nao objetivo de produto
21
22
  - a Sema nao e gerador magico que deveria fazer tudo
22
23
  - a Sema modela contratos, estados, fluxos, erros, efeitos, garantias, vinculos e execucao
23
- - a Sema gera codigo e scaffolding real para TypeScript, Python e Dart
24
+ - a Sema gera codigo e scaffolding real para TypeScript, Python, Dart e Lua
24
25
  - a Sema usa \`importar\` para bootstrap revisavel, nao para contrato final automatico
25
26
  - a Sema usa \`impl\` para ligar task a simbolo real do runtime
26
27
  - a Sema usa \`vinculos\` para ligar contrato a arquivo, simbolo, recurso e superficie real
@@ -56,8 +57,8 @@ Comandos essenciais:
56
57
  - validacao: \`sema validar <arquivo.sema> --json\`
57
58
  - diagnosticos: \`sema diagnosticos <arquivo.sema> --json\`
58
59
  - formatacao: \`sema formatar <arquivo.sema>\`
59
- - importacao assistida de legado: \`sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> --saida <diretorio>\`
60
- - geracao de codigo: \`sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>\`
60
+ - importacao assistida de legado: \`sema importar <nestjs|fastapi|flask|nextjs|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|firebase|dotnet|java|go|rust|cpp|typescript|python|dart|lua> <diretorio> --saida <diretorio>\`
61
+ - geracao de codigo: \`sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart|lua> --saida <diretorio>\`
61
62
  - verificacao final: \`sema verificar <arquivo-ou-pasta> [--json]\`
62
63
 
63
64
  Antes de editar:
@@ -312,42 +313,106 @@ Comandos uteis da CLI para esse fluxo:
312
313
  `;
313
314
  const DIRETORIO_CLI_ATUAL = path.dirname(fileURLToPath(import.meta.url));
314
315
  const VERSAO_CLI = pacoteCli.version;
316
+ const ARQUIVOS_CANONICOS_IA_RAIZ = [
317
+ "llms.txt",
318
+ "SEMA_BRIEF.md",
319
+ "SEMA_INDEX.json",
320
+ "AGENTS.md",
321
+ "README.md",
322
+ "llms-full.txt",
323
+ ];
324
+ const DOCUMENTOS_SUPORTE_IA = [
325
+ "docs/AGENT_STARTER.md",
326
+ "docs/integracao-com-ia.md",
327
+ "docs/fluxo-pratico-ia-sema.md",
328
+ "docs/como-ensinar-a-sema-para-ia.md",
329
+ "docs/sintaxe.md",
330
+ "docs/cli.md",
331
+ ];
315
332
  function obterArgumentos() {
316
333
  const [, , comando, ...resto] = process.argv;
317
334
  return { comando: comando, resto };
318
335
  }
336
+ function renderizarCaixaAscii(linhas) {
337
+ const largura = Math.max(...linhas.map((linha) => linha.length), 12);
338
+ const borda = `+${"-".repeat(largura + 2)}+`;
339
+ return [
340
+ borda,
341
+ ...linhas.map((linha) => `| ${linha.padEnd(largura, " ")} |`),
342
+ borda,
343
+ ].join("\n");
344
+ }
345
+ function renderizarSecaoAscii(titulo, linhas) {
346
+ return [
347
+ titulo,
348
+ ...linhas.map((linha) => ` ${linha}`),
349
+ ].join("\n");
350
+ }
319
351
  function ajuda() {
320
- return `Sema CLI
321
-
322
- Comandos:
323
- sema --versao
324
- sema --version
325
- sema -v
326
- sema iniciar
327
- sema validar <arquivo-ou-pasta>
328
- sema ast <arquivo.sema>
329
- sema ir <arquivo.sema>
330
- sema compilar <arquivo-ou-pasta> --alvo <python|typescript|dart> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
331
- sema gerar <python|typescript|dart> <arquivo-ou-pasta> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
332
- sema testar <arquivo.sema> --alvo <python|typescript|dart> --saida <diretorio-temporario> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
333
- sema diagnosticos <arquivo.sema> [--json]
334
- sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--json]
335
- sema inspecionar [arquivo-ou-pasta] [--json]
336
- sema drift <arquivo-ou-pasta> [--json]
337
- sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]
338
- sema doctor
339
- sema formatar <arquivo-ou-pasta> [--check] [--json]
340
- sema ajuda-ia
341
- sema starter-ia
342
- sema resumo <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>] [--saida <diretorio>] [--raiz] [--json]
343
- sema prompt-curto <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>] [--json]
344
- sema prompt-ia
345
- sema prompt-ia-ui
346
- sema prompt-ia-react
347
- sema prompt-ia-sema-primeiro
348
- sema exemplos-prompt-ia
349
- sema contexto-ia <arquivo.sema> [--saida <diretorio>] [--json]
350
- `;
352
+ return [
353
+ renderizarCaixaAscii([
354
+ `Sema CLI v${VERSAO_CLI}`,
355
+ "IA-first para contrato, geracao e adocao incremental",
356
+ "novo projeto, edicao guiada e legado sem contrato inicial",
357
+ ]),
358
+ "",
359
+ renderizarSecaoAscii("Fluxos rapidos", [
360
+ "[1] Projeto novo / producao inicial",
361
+ "sema iniciar --template <base|nestjs|fastapi|nextjs-api|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer>",
362
+ "sema validar contratos/<modulo>.sema --json",
363
+ "sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart|lua> --saida <diretorio>",
364
+ "sema verificar <arquivo-ou-pasta> --json",
365
+ "",
366
+ "[2] Editar projeto que ja usa Sema",
367
+ "sema inspecionar . --json",
368
+ "sema resumo <arquivo-ou-pasta> --micro --para mudanca",
369
+ "sema drift <arquivo-ou-pasta> --json",
370
+ "sema contexto-ia <arquivo.sema> --saida ./.tmp/contexto --json",
371
+ "",
372
+ "[3] Adotar Sema em projeto que ainda nao usa",
373
+ "sema importar <fonte> <diretorio> --saida <diretorio> --json",
374
+ "sema formatar <arquivo-ou-pasta>",
375
+ "sema validar <arquivo-ou-pasta> --json",
376
+ "sema drift <arquivo-ou-pasta> --json",
377
+ ]),
378
+ "",
379
+ renderizarSecaoAscii("IA por capacidade", [
380
+ "pequena: sema resumo --micro + briefing.min.json + prompt-curto.txt",
381
+ "media: sema resumo --curto + drift.json + briefing.min.json",
382
+ "grande: sema contexto-ia + briefing.json + ir.json + ast.json",
383
+ ]),
384
+ "",
385
+ renderizarSecaoAscii("Comandos principais", [
386
+ "descoberta: sema inspecionar [arquivo-ou-pasta] [--json]",
387
+ "auditoria: sema drift <arquivo-ou-pasta> [--json]",
388
+ "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|lua> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]",
389
+ "validacao: sema validar <arquivo-ou-pasta> [--json]",
390
+ "diagnostico: sema diagnosticos <arquivo.sema> [--json]",
391
+ "geracao: sema compilar <arquivo-ou-pasta> --alvo <python|typescript|dart|lua> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]",
392
+ "teste local: sema testar <arquivo.sema> --alvo <python|typescript|dart|lua> --saida <diretorio-temporario> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]",
393
+ "verificacao final: sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--json]",
394
+ "formatacao: sema formatar <arquivo-ou-pasta> [--check] [--json]",
395
+ ]),
396
+ "",
397
+ renderizarSecaoAscii("Ajuda IA-first", [
398
+ "sema ajuda-ia",
399
+ "sema starter-ia",
400
+ "sema resumo <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>] [--saida <diretorio>] [--raiz] [--json]",
401
+ "sema prompt-curto <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>] [--json]",
402
+ "sema prompt-ia",
403
+ "sema prompt-ia-ui",
404
+ "sema prompt-ia-react",
405
+ "sema prompt-ia-sema-primeiro",
406
+ "sema exemplos-prompt-ia",
407
+ "sema contexto-ia <arquivo.sema> [--saida <diretorio>] [--json]",
408
+ "sema sync-ai-entrypoints [--json]",
409
+ ]),
410
+ "",
411
+ renderizarSecaoAscii("Operacional", [
412
+ "sema doctor",
413
+ "sema --versao | --version | -v",
414
+ ]),
415
+ ].join("\n");
351
416
  }
352
417
  async function carregarModulos(entrada, cwd = process.cwd()) {
353
418
  return (await carregarProjeto(entrada, cwd)).modulosSelecionados;
@@ -419,18 +484,32 @@ function comandoDisponivel(comando, argumentos = ["--version"]) {
419
484
  const execucao = spawnSync(comando, argumentos, { stdio: "ignore", shell: process.platform === "win32" });
420
485
  return (execucao.status ?? 1) === 0;
421
486
  }
487
+ function resolverComandoLua() {
488
+ if (comandoDisponivel("lua", ["-v"])) {
489
+ return "lua";
490
+ }
491
+ if (comandoDisponivel("luajit", ["-v"])) {
492
+ return "luajit";
493
+ }
494
+ return undefined;
495
+ }
422
496
  async function comandoDoctor() {
497
+ const comandoLua = resolverComandoLua();
423
498
  const checks = [
424
499
  { nome: "node", ok: comandoDisponivel("node") },
425
500
  { nome: "npm", ok: comandoDisponivel("npm") },
426
501
  { nome: "python", ok: comandoDisponivel("python") || comandoDisponivel("py") },
502
+ { nome: "lua", ok: comandoLua !== undefined },
427
503
  { nome: "dotnet", ok: comandoDisponivel("dotnet") },
428
504
  { nome: "go", ok: comandoDisponivel("go") },
429
505
  { nome: "cargo", ok: comandoDisponivel("cargo") },
430
506
  { nome: "java", ok: comandoDisponivel("java") },
431
507
  { nome: "code", ok: comandoDisponivel("code", ["--version"]) },
432
508
  ];
433
- console.log("Sema doctor");
509
+ console.log(renderizarCaixaAscii([
510
+ "Sema doctor",
511
+ "checa a toolchain minima para validar, gerar e operar a CLI",
512
+ ]));
434
513
  for (const check of checks) {
435
514
  console.log(`- ${check.nome}: ${check.ok ? "ok" : "ausente"}`);
436
515
  }
@@ -447,8 +526,8 @@ function validarCompatibilidadeFramework(alvo, framework) {
447
526
  if (framework === "fastapi" && alvo !== "python") {
448
527
  return `Framework "${framework}" so pode ser usado com o alvo python.`;
449
528
  }
450
- if (alvo === "dart") {
451
- return `Framework "${framework}" nao e suportado para o alvo dart.`;
529
+ if (alvo === "dart" || alvo === "lua") {
530
+ return `Framework "${framework}" nao e suportado para o alvo ${alvo}.`;
452
531
  }
453
532
  return undefined;
454
533
  }
@@ -471,6 +550,18 @@ function normalizarFonteImportacao(valor) {
471
550
  if (valor === "next") {
472
551
  return "nextjs";
473
552
  }
553
+ if (valor === "next-consumer" || valor === "nextjs-consumer") {
554
+ return "nextjs-consumer";
555
+ }
556
+ if (valor === "react-vite" || valor === "react-vite-consumer" || valor === "react-consumer") {
557
+ return "react-vite-consumer";
558
+ }
559
+ if (valor === "angular" || valor === "angular-consumer") {
560
+ return "angular-consumer";
561
+ }
562
+ if (valor === "flutter" || valor === "flutter-consumer") {
563
+ return "flutter-consumer";
564
+ }
474
565
  if (valor === "fb") {
475
566
  return "firebase";
476
567
  }
@@ -486,6 +577,9 @@ function normalizarFonteImportacao(valor) {
486
577
  if (valor === "rust" || valor === "rs") {
487
578
  return "rust";
488
579
  }
580
+ if (valor === "lua" || valor === "luajit") {
581
+ return "lua";
582
+ }
489
583
  if (valor === "cpp" || valor === "cxx" || valor === "cc" || valor === "c++") {
490
584
  return "cpp";
491
585
  }
@@ -493,6 +587,10 @@ function normalizarFonteImportacao(valor) {
493
587
  || valor === "fastapi"
494
588
  || valor === "flask"
495
589
  || valor === "nextjs"
590
+ || valor === "nextjs-consumer"
591
+ || valor === "react-vite-consumer"
592
+ || valor === "angular-consumer"
593
+ || valor === "flutter-consumer"
496
594
  || valor === "firebase"
497
595
  || valor === "dotnet"
498
596
  || valor === "java"
@@ -501,7 +599,8 @@ function normalizarFonteImportacao(valor) {
501
599
  || valor === "cpp"
502
600
  || valor === "typescript"
503
601
  || valor === "python"
504
- || valor === "dart") {
602
+ || valor === "dart"
603
+ || valor === "lua") {
505
604
  return valor;
506
605
  }
507
606
  return undefined;
@@ -510,6 +609,10 @@ function normalizarTemplateIniciar(valor) {
510
609
  if (valor === "nestjs"
511
610
  || valor === "fastapi"
512
611
  || valor === "nextjs-api"
612
+ || valor === "nextjs-consumer"
613
+ || valor === "react-vite-consumer"
614
+ || valor === "angular-consumer"
615
+ || valor === "flutter-consumer"
513
616
  || valor === "node-firebase-worker"
514
617
  || valor === "aspnet-api"
515
618
  || valor === "springboot-api"
@@ -533,6 +636,9 @@ function gerarArquivosPorAlvo(ir, alvo, framework) {
533
636
  if (alvo === "dart") {
534
637
  return gerarDart(ir);
535
638
  }
639
+ if (alvo === "lua") {
640
+ return gerarLua(ir);
641
+ }
536
642
  return gerarTypeScript(ir, { framework });
537
643
  }
538
644
  function aplicarEstruturaSaida(arquivos, ir, estrutura) {
@@ -564,6 +670,12 @@ function aplicarEstruturaSaida(arquivos, ir, estrutura) {
564
670
  else if (basename === `${nomeBaseAntigo}.dart`) {
565
671
  novoBasename = `${nomeArquivo}.dart`;
566
672
  }
673
+ else if (basename === `${nomeBaseAntigo}.lua`) {
674
+ novoBasename = `${nomeArquivo}.lua`;
675
+ }
676
+ else if (basename === `test_${nomeBaseAntigo}.lua`) {
677
+ novoBasename = `test_${nomeArquivo}.lua`;
678
+ }
567
679
  return {
568
680
  caminhoRelativo: pastaModulo ? path.join(pastaModulo, novoBasename) : novoBasename,
569
681
  conteudo,
@@ -581,6 +693,13 @@ function contarCasosDeTesteGerados(alvo, arquivos) {
581
693
  }
582
694
  return (arquivoTeste.conteudo.match(/\btest\(/g) ?? []).length;
583
695
  }
696
+ if (alvo === "lua") {
697
+ const arquivoTeste = arquivos.find((item) => path.basename(item.caminhoRelativo).startsWith("test_") && item.caminhoRelativo.endsWith(".lua"));
698
+ if (!arquivoTeste) {
699
+ return 0;
700
+ }
701
+ return (arquivoTeste.conteudo.match(/\blocal function test_/g) ?? []).length;
702
+ }
584
703
  const arquivoTeste = arquivos.find((item) => path.basename(item.caminhoRelativo).startsWith("test_"));
585
704
  if (!arquivoTeste) {
586
705
  return 0;
@@ -591,7 +710,8 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
591
710
  const quantidadeTestes = contarCasosDeTesteGerados(alvo, arquivos);
592
711
  if (quantidadeTestes === 0) {
593
712
  if (!silencioso) {
594
- console.log(`Nenhum teste ${alvo === "typescript" ? "TypeScript" : "Python"} foi gerado.`);
713
+ const rotulo = alvo === "typescript" ? "TypeScript" : alvo === "python" ? "Python" : alvo === "dart" ? "Dart" : "Lua";
714
+ console.log(`Nenhum teste ${rotulo} foi gerado.`);
595
715
  }
596
716
  return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
597
717
  }
@@ -614,6 +734,36 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
614
734
  saidaErro: typeof execucao.stderr === "string" ? execucao.stderr : "",
615
735
  };
616
736
  }
737
+ if (alvo === "lua") {
738
+ const arquivoTeste = arquivos.find((item) => path.basename(item.caminhoRelativo).startsWith("test_") && item.caminhoRelativo.endsWith(".lua"))?.caminhoRelativo;
739
+ if (!arquivoTeste) {
740
+ if (!silencioso) {
741
+ console.log("Nenhum teste Lua foi gerado.");
742
+ }
743
+ return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
744
+ }
745
+ const comandoLua = resolverComandoLua();
746
+ if (!comandoLua) {
747
+ return {
748
+ codigoSaida: 1,
749
+ quantidadeTestes,
750
+ saidaPadrao: "",
751
+ saidaErro: "Interpretador Lua nao encontrado. Instale `lua` ou `luajit` para rodar testes gerados.",
752
+ };
753
+ }
754
+ const execucao = spawnSync(comandoLua, [arquivoTeste], {
755
+ stdio: silencioso ? "pipe" : "inherit",
756
+ cwd: baseSaida,
757
+ encoding: silencioso ? "utf8" : undefined,
758
+ shell: process.platform === "win32",
759
+ });
760
+ return {
761
+ codigoSaida: execucao.status ?? 1,
762
+ quantidadeTestes,
763
+ saidaPadrao: typeof execucao.stdout === "string" ? execucao.stdout : "",
764
+ saidaErro: typeof execucao.stderr === "string" ? execucao.stderr : "",
765
+ };
766
+ }
617
767
  const arquivoTeste = arquivos.find((item) => path.basename(item.caminhoRelativo).startsWith("test_"))?.caminhoRelativo;
618
768
  if (!arquivoTeste) {
619
769
  if (!silencioso) {
@@ -692,6 +842,7 @@ function renderizarCabecalhoDocsIa(descoberta) {
692
842
  const linhas = [
693
843
  "Modo IA-first da instalacao atual",
694
844
  "- Use `sema` como interface publica principal.",
845
+ "- A Sema entra em projeto novo, projeto ja semantizado e adocao incremental em legado sem contrato inicial.",
695
846
  "- Nao assuma monorepo, `node pacotes/cli/dist/index.js`, `npm run project:check` ou uma pasta `exemplos` externa ao projeto atual.",
696
847
  "- Se a IA tiver contexto curto, comece por `sema resumo` e `sema prompt-curto`.",
697
848
  "- Se a IA aguentar mais contexto, suba para `sema drift --json` e `sema contexto-ia`.",
@@ -847,6 +998,11 @@ function coletarResumoSemanticoModulo(contexto) {
847
998
  inferido: limitarLista(unicosOrdenados(briefing.oQueFoiInferido), 6),
848
999
  checksSugeridos: limitarLista(unicosOrdenados(briefing.oQueValidar), 6),
849
1000
  testesMinimos: limitarLista(unicosOrdenados(briefing.testesMinimos), 6),
1001
+ consumerFramework: briefing.consumerFramework ?? drift.drift.consumerFramework ?? null,
1002
+ appRoutes: limitarLista(unicosOrdenados(briefing.appRoutes ?? drift.drift.appRoutes ?? []), 8),
1003
+ consumerSurfaces: limitarLista(unicosOrdenados(briefing.consumerSurfaces ?? []), 8),
1004
+ consumerBridges: limitarLista(unicosOrdenados(briefing.consumerBridges ?? []), 8),
1005
+ arquivosProvaveisEditar: limitarLista(unicosOrdenados(briefing.arquivosProvaveisEditar ?? briefing.oQueTocar), 8),
850
1006
  };
851
1007
  }
852
1008
  function renderizarResumoModuloTexto(resumo, tamanho, modo) {
@@ -856,6 +1012,10 @@ function renderizarResumoModuloTexto(resumo, tamanho, modo) {
856
1012
  `MODULO: ${resumo.modulo}`,
857
1013
  `FAZ: ${resumo.faz}`,
858
1014
  `PERFIL: ${resumo.perfilCompatibilidade}`,
1015
+ `CONSUMER_FRAMEWORK: ${resumo.consumerFramework ?? "nenhum"}`,
1016
+ `APP_ROUTES: ${resumirListaTexto(resumo.appRoutes, limite)}`,
1017
+ `CONSUMER_SURFACES: ${resumirListaTexto(resumo.consumerSurfaces, limite)}`,
1018
+ `CONSUMER_BRIDGES: ${resumirListaTexto(resumo.consumerBridges, limite)}`,
859
1019
  `PUBLICO: ${resumirListaTexto(resumo.superficiesPublicas, limite)}`,
860
1020
  `TAREFAS: ${resumirListaTexto(resumo.tarefasPrincipais, limite)}`,
861
1021
  `ENTRADAS: ${resumirListaTexto(resumo.entradasChave, limite)}`,
@@ -906,6 +1066,17 @@ function renderizarResumoModuloMarkdown(resumo, modo, guiaPorCapacidade) {
906
1066
  `- Erros: ${resumirListaTexto(resumo.erros, 6)}`,
907
1067
  `- Entidades afetadas: ${resumirListaTexto(resumo.entidadesAfetadas, 6)}`,
908
1068
  "",
1069
+ ...(resumo.consumerFramework
1070
+ ? [
1071
+ "## Consumer IA-first",
1072
+ "",
1073
+ `- Framework consumer: ${resumo.consumerFramework}`,
1074
+ `- Rotas de app: ${resumirListaTexto(resumo.appRoutes, 6)}`,
1075
+ `- Superficies consumer: ${resumirListaTexto(resumo.consumerSurfaces, 6)}`,
1076
+ `- Bridges consumer: ${resumirListaTexto(resumo.consumerBridges, 6)}`,
1077
+ "",
1078
+ ]
1079
+ : []),
909
1080
  "## Intervencao segura",
910
1081
  "",
911
1082
  `- Arquivos provaveis: ${resumirListaTexto(resumo.arquivosProvaveis, 6)}`,
@@ -953,12 +1124,17 @@ function criarBriefingMinimo(resumo, modo, tamanho) {
953
1124
  efeitos: resumo.efeitos,
954
1125
  erros: resumo.erros,
955
1126
  arquivosProvaveis: resumo.arquivosProvaveis,
1127
+ arquivosProvaveisEditar: resumo.arquivosProvaveisEditar,
956
1128
  simbolosRelacionados: resumo.simbolosRelacionados,
957
1129
  riscosPrincipais: resumo.riscosPrincipais,
958
1130
  lacunas: resumo.lacunas,
959
1131
  inferido: resumo.inferido,
960
1132
  checksSugeridos: resumo.checksSugeridos,
961
1133
  testesMinimos: resumo.testesMinimos,
1134
+ consumerFramework: resumo.consumerFramework,
1135
+ appRoutes: resumo.appRoutes,
1136
+ consumerSurfaces: resumo.consumerSurfaces,
1137
+ consumerBridges: resumo.consumerBridges,
962
1138
  };
963
1139
  }
964
1140
  function criarPromptCurtoModulo(resumo, modo, tamanho, capacidade) {
@@ -975,13 +1151,15 @@ Regras:
975
1151
  - preserve a intencao do contrato
976
1152
  - use este resumo como fonte compacta inicial
977
1153
  - se a tarefa pedir mais contexto, suba para \`briefing.min.json\`, \`drift.json\` e depois \`ir.json\`
978
- - nao saia editando backend vivo sem olhar risco, lacuna e checks sugeridos
1154
+ - nao saia editando software vivo sem olhar risco, lacuna e checks sugeridos
1155
+ ${resumo.consumerFramework ? "- se for tarefa visual consumer, priorize `appRoutes`, `consumerSurfaces` e `consumerBridges` antes de abrir arquivos aleatorios" : ""}
979
1156
 
980
1157
  Contexto compacto:
981
1158
  ${resumoTexto}
982
1159
  `;
983
1160
  }
984
1161
  function renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade) {
1162
+ const entradaCanonica = criarEntradaCanonicaProjeto(guiaPorCapacidade);
985
1163
  const linhas = [
986
1164
  "# SEMA_BRIEF",
987
1165
  "",
@@ -990,6 +1168,13 @@ function renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade) {
990
1168
  `- Gerado em: \`${geradoEm}\``,
991
1169
  `- Modulos: \`${modulos.length}\``,
992
1170
  "",
1171
+ "## Entrada canonica para IA",
1172
+ "",
1173
+ `- Ordem minima: ${entradaCanonica.ordemLeitura.join(" -> ")}`,
1174
+ `- IA pequena: ${entradaCanonica.porCapacidade.pequena.join(" -> ")}`,
1175
+ `- IA media: ${entradaCanonica.porCapacidade.media.join(" -> ")}`,
1176
+ `- IA grande: ${entradaCanonica.porCapacidade.grande.join(" -> ")}`,
1177
+ "",
993
1178
  "## Guia por capacidade",
994
1179
  "",
995
1180
  ];
@@ -1011,6 +1196,19 @@ function renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade) {
1011
1196
  }
1012
1197
  return `${linhas.join("\n").trim()}\n`;
1013
1198
  }
1199
+ function criarEntradaCanonicaProjeto(guiaPorCapacidade) {
1200
+ return {
1201
+ descricao: "Entrada canonica do repositorio para IA. O repo nao e human-first; a IA deve começar por esses artefatos antes de abrir codigo cru.",
1202
+ ordemLeitura: [...ARQUIVOS_CANONICOS_IA_RAIZ],
1203
+ porCapacidade: {
1204
+ pequena: ["llms.txt", "SEMA_BRIEF.micro.txt", "SEMA_INDEX.json", "AGENTS.md"],
1205
+ media: ["llms.txt", "SEMA_BRIEF.curto.txt", "SEMA_INDEX.json", "AGENTS.md", "README.md"],
1206
+ grande: ["llms-full.txt", "SEMA_BRIEF.md", "SEMA_INDEX.json", "AGENTS.md", "README.md"],
1207
+ },
1208
+ docsSuporte: [...DOCUMENTOS_SUPORTE_IA],
1209
+ guiaPorCapacidade,
1210
+ };
1211
+ }
1014
1212
  function falharContextoIa(mensagem) {
1015
1213
  throw new Error(mensagem);
1016
1214
  }
@@ -1044,6 +1242,41 @@ function resumirDriftPorModulo(modulo, caminho, resultadoDrift) {
1044
1242
  const recursosDivergentes = modulo
1045
1243
  ? resultadoDrift.recursos_divergentes.filter((recurso) => recurso.modulo === modulo)
1046
1244
  : [];
1245
+ const vinculosModulo = modulo
1246
+ ? [
1247
+ ...resultadoDrift.vinculos_validos.filter((vinculo) => vinculo.modulo === modulo),
1248
+ ...resultadoDrift.vinculos_quebrados.filter((vinculo) => vinculo.modulo === modulo),
1249
+ ]
1250
+ : [];
1251
+ const rotasConsumerModulo = new Set(vinculosModulo
1252
+ .filter((vinculo) => vinculo.tipo === "superficie")
1253
+ .map((vinculo) => vinculo.valor));
1254
+ const arquivosRelacionados = [...new Set([
1255
+ ...tasks.flatMap((task) => task.arquivosReferenciados),
1256
+ ...tasks.flatMap((task) => task.arquivosProvaveisEditar),
1257
+ ...implsValidos.map((impl) => impl.arquivo).filter((item) => Boolean(item)),
1258
+ ...implsQuebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.arquivo) ?? []),
1259
+ ...vinculosValidos.map((vinculo) => vinculo.arquivo).filter((item) => Boolean(item)),
1260
+ ...recursosValidos.map((recurso) => recurso.arquivo).filter(Boolean),
1261
+ ...recursosDivergentes.map((recurso) => recurso.arquivo).filter(Boolean),
1262
+ ])].sort((a, b) => a.localeCompare(b, "pt-BR"));
1263
+ const consumerSurfaces = resultadoDrift.consumerSurfaces
1264
+ .filter((surface) => arquivosRelacionados.includes(surface.arquivo)
1265
+ || rotasConsumerModulo.has(surface.rota))
1266
+ .map((surface) => `${surface.tipoArquivo}:${surface.rota} -> ${surface.arquivo}`)
1267
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1268
+ const consumerBridges = resultadoDrift.consumerBridges
1269
+ .filter((bridge) => arquivosRelacionados.includes(bridge.arquivo))
1270
+ .map((bridge) => bridge.caminho)
1271
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1272
+ const appRoutes = [...new Set(resultadoDrift.consumerSurfaces
1273
+ .filter((surface) => arquivosRelacionados.includes(surface.arquivo)
1274
+ || rotasConsumerModulo.has(surface.rota))
1275
+ .map((surface) => surface.rota))]
1276
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1277
+ const consumerFramework = appRoutes.length > 0 || consumerBridges.length > 0
1278
+ ? resultadoDrift.consumerFramework
1279
+ : null;
1047
1280
  return {
1048
1281
  caminho,
1049
1282
  modulo,
@@ -1060,15 +1293,12 @@ function resumirDriftPorModulo(modulo, caminho, resultadoDrift) {
1060
1293
  : tasks.some((task) => task.confiancaVinculo === "media")
1061
1294
  ? "media"
1062
1295
  : "baixa",
1063
- arquivosRelacionados: [...new Set([
1064
- ...tasks.flatMap((task) => task.arquivosReferenciados),
1065
- ...tasks.flatMap((task) => task.arquivosProvaveisEditar),
1066
- ...implsValidos.map((impl) => impl.arquivo).filter((item) => Boolean(item)),
1067
- ...implsQuebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.arquivo) ?? []),
1068
- ...vinculosValidos.map((vinculo) => vinculo.arquivo).filter((item) => Boolean(item)),
1069
- ...recursosValidos.map((recurso) => recurso.arquivo).filter(Boolean),
1070
- ...recursosDivergentes.map((recurso) => recurso.arquivo).filter(Boolean),
1071
- ])].sort((a, b) => a.localeCompare(b, "pt-BR")),
1296
+ arquivosRelacionados,
1297
+ arquivosProvaveisEditar: arquivosRelacionados,
1298
+ consumerFramework,
1299
+ appRoutes,
1300
+ consumerSurfaces,
1301
+ consumerBridges,
1072
1302
  checksSugeridos: [...new Set(tasks.flatMap((task) => task.checksSugeridos))],
1073
1303
  lacunas: [...new Set(tasks.flatMap((task) => task.lacunas))],
1074
1304
  tasks,
@@ -1090,6 +1320,7 @@ function criarBriefingAgente(arquivo, modulo, ir, resumoDrift, resultadoDrift) {
1090
1320
  ...(ir?.resumoAgente.riscos ?? []),
1091
1321
  ])],
1092
1322
  oQueTocar: resumoDrift.arquivosRelacionados,
1323
+ arquivosProvaveisEditar: resumoDrift.arquivosProvaveisEditar,
1093
1324
  oQueValidar: [...new Set([
1094
1325
  ...resumoDrift.checksSugeridos,
1095
1326
  ...resultadoDrift.resumo_operacional.oQueValidar,
@@ -1117,6 +1348,10 @@ function criarBriefingAgente(arquivo, modulo, ir, resumoDrift, resultadoDrift) {
1117
1348
  ...(ir?.routes.map((route) => `${route.metodo ?? "?"} ${route.caminho ?? route.nome}`) ?? []),
1118
1349
  ...(ir?.superficies.map((superficie) => `${superficie.tipo}:${superficie.nome}`) ?? []),
1119
1350
  ],
1351
+ consumerFramework: resumoDrift.consumerFramework,
1352
+ appRoutes: resumoDrift.appRoutes,
1353
+ consumerSurfaces: resumoDrift.consumerSurfaces,
1354
+ consumerBridges: resumoDrift.consumerBridges,
1120
1355
  testesMinimos: [
1121
1356
  "sema validar <arquivo> --json",
1122
1357
  "sema drift <arquivo> --json",
@@ -1216,6 +1451,7 @@ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz
1216
1451
  const contextoProjeto = await carregarProjeto(entrada, process.cwd());
1217
1452
  const geradoEm = new Date().toISOString();
1218
1453
  const guiaPorCapacidade = criarGuiaCapacidadeIa();
1454
+ const entradaCanonica = criarEntradaCanonicaProjeto(guiaPorCapacidade);
1219
1455
  const resultadoDrift = await analisarDriftLegado(contextoProjeto);
1220
1456
  const modulos = contextoProjeto.modulosSelecionados.map((item) => {
1221
1457
  const modulo = item.resultado.modulo?.nome ?? path.basename(item.caminho, ".sema");
@@ -1251,12 +1487,14 @@ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz
1251
1487
  cliVersao: VERSAO_CLI,
1252
1488
  baseProjeto,
1253
1489
  totalModulos: modulos.length,
1490
+ entradaCanonica,
1254
1491
  guiaPorCapacidade,
1255
1492
  modulos,
1256
1493
  };
1257
1494
  const micro = [
1258
1495
  `PROJETO: ${path.basename(baseProjeto)}`,
1259
1496
  `MODULOS: ${modulos.length}`,
1497
+ `ENTRADA_IA: ${entradaCanonica.porCapacidade.pequena.join(" -> ")}`,
1260
1498
  `TOP_MODULOS: ${resumirListaTexto(modulos.map((modulo) => modulo.modulo), 3)}`,
1261
1499
  `TOP_RISCOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.riscosPrincipais)), 3)}`,
1262
1500
  `TOP_LACUNAS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.lacunas)), 3)}`,
@@ -1267,6 +1505,7 @@ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz
1267
1505
  `PROJETO: ${path.basename(baseProjeto)}`,
1268
1506
  `BASE: ${baseProjeto}`,
1269
1507
  `MODULOS: ${modulos.length}`,
1508
+ `ENTRADA_IA: ${entradaCanonica.porCapacidade.media.join(" -> ")}`,
1270
1509
  `TOP_MODULOS: ${resumirListaTexto(modulos.map((modulo) => modulo.modulo), 6)}`,
1271
1510
  `TOP_RISCOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.riscosPrincipais)), 6)}`,
1272
1511
  `TOP_LACUNAS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.lacunas)), 6)}`,
@@ -1548,6 +1787,596 @@ async function comandoIniciar(cwd, template) {
1548
1787
  - Contratos em \`contratos/\`
1549
1788
  - Handlers App Router em \`src/app/api/\`
1550
1789
  - Rota de exemplo validada por \`drift\`
1790
+ `,
1791
+ },
1792
+ ];
1793
+ }
1794
+ else if (template === "nextjs-consumer") {
1795
+ arquivos = [
1796
+ {
1797
+ caminhoRelativo: "sema.config.json",
1798
+ conteudo: `{
1799
+ "origens": ["./contratos"],
1800
+ "saida": "./generated",
1801
+ "alvos": ["typescript"],
1802
+ "alvoPadrao": "typescript",
1803
+ "estruturaSaida": "modulos",
1804
+ "framework": "base",
1805
+ "modoEstrito": true,
1806
+ "diretoriosCodigo": ["./src"],
1807
+ "fontesLegado": ["nextjs-consumer", "typescript"],
1808
+ "diretoriosSaidaPorAlvo": {
1809
+ "typescript": "./generated/typescript"
1810
+ },
1811
+ "convencoesGeracaoPorProjeto": "base"
1812
+ }
1813
+ `,
1814
+ },
1815
+ {
1816
+ caminhoRelativo: "contratos/showroom_consumer.sema",
1817
+ conteudo: `module showroom.consumer {
1818
+ task fetch_showroom_ranking {
1819
+ input {
1820
+ }
1821
+ output {
1822
+ ranking: Json
1823
+ }
1824
+ impl {
1825
+ ts: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1826
+ }
1827
+ vinculos {
1828
+ arquivo: "src/lib/sema_consumer_bridge.ts"
1829
+ simbolo: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1830
+ superficie: "/ranking"
1831
+ arquivo: "src/app/ranking/page.tsx"
1832
+ arquivo: "src/app/ranking/loading.tsx"
1833
+ arquivo: "src/app/ranking/error.tsx"
1834
+ }
1835
+ guarantees {
1836
+ ranking existe
1837
+ }
1838
+ }
1839
+ }
1840
+ `,
1841
+ },
1842
+ {
1843
+ caminhoRelativo: "src/lib/sema_consumer_bridge.ts",
1844
+ conteudo: `export async function semaFetchShowroomRanking() {
1845
+ return {
1846
+ ranking: [
1847
+ { clube: "Tigres do Norte", pontos: 33 },
1848
+ { clube: "Porto Azul", pontos: 31 },
1849
+ { clube: "Galo de Ouro", pontos: 28 },
1850
+ ],
1851
+ };
1852
+ }
1853
+ `,
1854
+ },
1855
+ {
1856
+ caminhoRelativo: "src/app/ranking/page.tsx",
1857
+ conteudo: `import { semaFetchShowroomRanking } from "../../lib/sema_consumer_bridge";
1858
+
1859
+ export default async function RankingPage() {
1860
+ const { ranking } = await semaFetchShowroomRanking();
1861
+
1862
+ return (
1863
+ <main>
1864
+ <h1>Ranking showroom</h1>
1865
+ <ul>
1866
+ {ranking.map((item) => (
1867
+ <li key={item.clube}>
1868
+ {item.clube} - {item.pontos} pts
1869
+ </li>
1870
+ ))}
1871
+ </ul>
1872
+ </main>
1873
+ );
1874
+ }
1875
+ `,
1876
+ },
1877
+ {
1878
+ caminhoRelativo: "src/app/ranking/loading.tsx",
1879
+ conteudo: `export default function Loading() {
1880
+ return <p>Carregando ranking...</p>;
1881
+ }
1882
+ `,
1883
+ },
1884
+ {
1885
+ caminhoRelativo: "src/app/ranking/error.tsx",
1886
+ conteudo: `"use client";
1887
+
1888
+ export default function Error({
1889
+ error,
1890
+ reset,
1891
+ }: {
1892
+ error: Error;
1893
+ reset: () => void;
1894
+ }) {
1895
+ return (
1896
+ <main>
1897
+ <h1>Falha ao carregar ranking</h1>
1898
+ <p>{error.message}</p>
1899
+ <button type="button" onClick={reset}>Tentar novamente</button>
1900
+ </main>
1901
+ );
1902
+ }
1903
+ `,
1904
+ },
1905
+ {
1906
+ caminhoRelativo: "README.md",
1907
+ conteudo: `# Starter Next.js Consumer + Sema
1908
+
1909
+ - Contratos em \`contratos/\`
1910
+ - Bridge consumer canonico em \`src/lib/sema_consumer_bridge.ts\`
1911
+ - Superficies App Router em \`src/app/\`
1912
+ - O slice oficial desta fase e \`consumer bridge + App Router surfaces\`
1913
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual drift
1914
+ `,
1915
+ },
1916
+ ];
1917
+ }
1918
+ else if (template === "react-vite-consumer") {
1919
+ arquivos = [
1920
+ {
1921
+ caminhoRelativo: "sema.config.json",
1922
+ conteudo: `{
1923
+ "origens": ["./contratos"],
1924
+ "saida": "./generated",
1925
+ "alvos": ["typescript"],
1926
+ "alvoPadrao": "typescript",
1927
+ "estruturaSaida": "modulos",
1928
+ "framework": "base",
1929
+ "modoEstrito": true,
1930
+ "diretoriosCodigo": ["./src"],
1931
+ "fontesLegado": ["react-vite-consumer", "typescript"],
1932
+ "diretoriosSaidaPorAlvo": {
1933
+ "typescript": "./generated/typescript"
1934
+ },
1935
+ "convencoesGeracaoPorProjeto": "base"
1936
+ }
1937
+ `,
1938
+ },
1939
+ {
1940
+ caminhoRelativo: "contratos/showroom_consumer.sema",
1941
+ conteudo: `module showroom.consumer {
1942
+ task fetch_showroom_ranking {
1943
+ input {
1944
+ }
1945
+ output {
1946
+ ranking: Json
1947
+ }
1948
+ impl {
1949
+ ts: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1950
+ }
1951
+ vinculos {
1952
+ arquivo: "src/lib/sema_consumer_bridge.ts"
1953
+ simbolo: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1954
+ superficie: "/ranking"
1955
+ arquivo: "src/router.tsx"
1956
+ arquivo: "src/pages/ranking.tsx"
1957
+ }
1958
+ guarantees {
1959
+ ranking existe
1960
+ }
1961
+ }
1962
+ }
1963
+ `,
1964
+ },
1965
+ {
1966
+ caminhoRelativo: "src/lib/sema_consumer_bridge.ts",
1967
+ conteudo: `export async function semaFetchShowroomRanking() {
1968
+ return {
1969
+ ranking: [
1970
+ { clube: "Tigres do Norte", pontos: 33 },
1971
+ { clube: "Porto Azul", pontos: 31 },
1972
+ { clube: "Galo de Ouro", pontos: 28 },
1973
+ ],
1974
+ };
1975
+ }
1976
+ `,
1977
+ },
1978
+ {
1979
+ caminhoRelativo: "src/pages/ranking.tsx",
1980
+ conteudo: `import { useEffect, useState } from "react";
1981
+ import { semaFetchShowroomRanking } from "../lib/sema_consumer_bridge";
1982
+
1983
+ export function RankingPage() {
1984
+ const [ranking, setRanking] = useState<Array<{ clube: string; pontos: number }>>([]);
1985
+
1986
+ useEffect(() => {
1987
+ void semaFetchShowroomRanking().then((payload) => setRanking(payload.ranking ?? []));
1988
+ }, []);
1989
+
1990
+ return (
1991
+ <main>
1992
+ <h1>Ranking showroom</h1>
1993
+ <ul>
1994
+ {ranking.map((item) => (
1995
+ <li key={item.clube}>
1996
+ {item.clube} - {item.pontos} pts
1997
+ </li>
1998
+ ))}
1999
+ </ul>
2000
+ </main>
2001
+ );
2002
+ }
2003
+ `,
2004
+ },
2005
+ {
2006
+ caminhoRelativo: "src/router.tsx",
2007
+ conteudo: `import { createBrowserRouter } from "react-router-dom";
2008
+ import { RankingPage } from "./pages/ranking";
2009
+
2010
+ export const appRouter = createBrowserRouter([
2011
+ {
2012
+ path: "/ranking",
2013
+ Component: RankingPage,
2014
+ },
2015
+ ]);
2016
+ `,
2017
+ },
2018
+ {
2019
+ caminhoRelativo: "src/App.tsx",
2020
+ conteudo: `import { RouterProvider } from "react-router-dom";
2021
+ import { appRouter } from "./router";
2022
+
2023
+ export default function App() {
2024
+ return <RouterProvider router={appRouter} />;
2025
+ }
2026
+ `,
2027
+ },
2028
+ {
2029
+ caminhoRelativo: "src/main.tsx",
2030
+ conteudo: `import React from "react";
2031
+ import ReactDOM from "react-dom/client";
2032
+ import App from "./App";
2033
+
2034
+ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
2035
+ <React.StrictMode>
2036
+ <App />
2037
+ </React.StrictMode>,
2038
+ );
2039
+ `,
2040
+ },
2041
+ {
2042
+ caminhoRelativo: "README.md",
2043
+ conteudo: `# Starter React Vite Consumer + Sema
2044
+
2045
+ - Contratos em \`contratos/\`
2046
+ - Bridge consumer canonico em \`src/lib/sema_consumer_bridge.ts\`
2047
+ - Rotas explicitas em \`src/router.tsx\`
2048
+ - Superficies consumer em \`src/pages/\`
2049
+ - O slice oficial desta fase e \`consumer bridge + react-router surfaces\`
2050
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual drift
2051
+ `,
2052
+ },
2053
+ ];
2054
+ }
2055
+ else if (template === "angular-consumer") {
2056
+ arquivos = [
2057
+ {
2058
+ caminhoRelativo: "sema.config.json",
2059
+ conteudo: `{
2060
+ "origens": ["./contratos"],
2061
+ "saida": "./generated",
2062
+ "alvos": ["typescript"],
2063
+ "alvoPadrao": "typescript",
2064
+ "estruturaSaida": "modulos",
2065
+ "framework": "base",
2066
+ "modoEstrito": true,
2067
+ "diretoriosCodigo": ["./src"],
2068
+ "fontesLegado": ["angular-consumer", "typescript"],
2069
+ "diretoriosSaidaPorAlvo": {
2070
+ "typescript": "./generated/typescript"
2071
+ },
2072
+ "convencoesGeracaoPorProjeto": "base"
2073
+ }
2074
+ `,
2075
+ },
2076
+ {
2077
+ caminhoRelativo: "contratos/showroom_consumer.sema",
2078
+ conteudo: `module showroom.consumer {
2079
+ task fetch_showroom_ranking {
2080
+ input {
2081
+ }
2082
+ output {
2083
+ ranking: Json
2084
+ }
2085
+ impl {
2086
+ ts: src.app.sema_consumer_bridge.semaFetchShowroomRanking
2087
+ }
2088
+ vinculos {
2089
+ arquivo: "src/app/sema_consumer_bridge.ts"
2090
+ simbolo: src.app.sema_consumer_bridge.semaFetchShowroomRanking
2091
+ superficie: "/ranking"
2092
+ arquivo: "src/app/app.routes.ts"
2093
+ arquivo: "src/app/features/ranking/ranking.routes.ts"
2094
+ arquivo: "src/app/features/ranking/ranking-page.component.ts"
2095
+ }
2096
+ guarantees {
2097
+ ranking existe
2098
+ }
2099
+ }
2100
+ }
2101
+ `,
2102
+ },
2103
+ {
2104
+ caminhoRelativo: "src/app/sema_consumer_bridge.ts",
2105
+ conteudo: `export async function semaFetchShowroomRanking() {
2106
+ return {
2107
+ ranking: [
2108
+ { clube: "Tigres do Norte", pontos: 33 },
2109
+ { clube: "Porto Azul", pontos: 31 },
2110
+ { clube: "Galo de Ouro", pontos: 28 },
2111
+ ],
2112
+ };
2113
+ }
2114
+ `,
2115
+ },
2116
+ {
2117
+ caminhoRelativo: "src/app/app.routes.ts",
2118
+ conteudo: `import { Routes } from "@angular/router";
2119
+
2120
+ export const routes: Routes = [
2121
+ {
2122
+ path: "ranking",
2123
+ loadChildren: () => import("./features/ranking/ranking.routes").then((m) => m.RANKING_ROUTES),
2124
+ },
2125
+ ];
2126
+ `,
2127
+ },
2128
+ {
2129
+ caminhoRelativo: "src/app/features/ranking/ranking.routes.ts",
2130
+ conteudo: `import { Routes } from "@angular/router";
2131
+
2132
+ export const RANKING_ROUTES: Routes = [
2133
+ {
2134
+ path: "",
2135
+ loadComponent: () => import("./ranking-page.component").then((m) => m.RankingPageComponent),
2136
+ },
2137
+ ];
2138
+ `,
2139
+ },
2140
+ {
2141
+ caminhoRelativo: "src/app/features/ranking/ranking-page.component.ts",
2142
+ conteudo: `import { Component, OnInit } from "@angular/core";
2143
+ import { CommonModule } from "@angular/common";
2144
+ import { semaFetchShowroomRanking } from "../../sema_consumer_bridge";
2145
+
2146
+ @Component({
2147
+ selector: "app-ranking-page",
2148
+ standalone: true,
2149
+ imports: [CommonModule],
2150
+ template: \`
2151
+ <main>
2152
+ <h1>Ranking showroom</h1>
2153
+ <ul>
2154
+ <li *ngFor="let item of ranking">
2155
+ {{ item.clube }} - {{ item.pontos }} pts
2156
+ </li>
2157
+ </ul>
2158
+ </main>
2159
+ \`,
2160
+ })
2161
+ export class RankingPageComponent implements OnInit {
2162
+ ranking: Array<{ clube: string; pontos: number }> = [];
2163
+
2164
+ async ngOnInit() {
2165
+ const payload = await semaFetchShowroomRanking();
2166
+ this.ranking = payload.ranking ?? [];
2167
+ }
2168
+ }
2169
+ `,
2170
+ },
2171
+ {
2172
+ caminhoRelativo: "src/app/app.component.ts",
2173
+ conteudo: `import { Component } from "@angular/core";
2174
+ import { RouterOutlet } from "@angular/router";
2175
+
2176
+ @Component({
2177
+ selector: "app-root",
2178
+ standalone: true,
2179
+ imports: [RouterOutlet],
2180
+ template: "<router-outlet />",
2181
+ })
2182
+ export class AppComponent {}
2183
+ `,
2184
+ },
2185
+ {
2186
+ caminhoRelativo: "src/main.ts",
2187
+ conteudo: `import { bootstrapApplication } from "@angular/platform-browser";
2188
+ import { provideRouter } from "@angular/router";
2189
+ import { AppComponent } from "./app/app.component";
2190
+ import { routes } from "./app/app.routes";
2191
+
2192
+ void bootstrapApplication(AppComponent, {
2193
+ providers: [provideRouter(routes)],
2194
+ });
2195
+ `,
2196
+ },
2197
+ {
2198
+ caminhoRelativo: "README.md",
2199
+ conteudo: `# Starter Angular Consumer + Sema
2200
+
2201
+ - Contratos em \`contratos/\`
2202
+ - Bridge consumer canonico em \`src/app/sema_consumer_bridge.ts\`
2203
+ - Rotas lazy em \`src/app/app.routes.ts\`
2204
+ - Feature folders em \`src/app/features/\`
2205
+ - O slice oficial desta fase e \`consumer bridge + route config surfaces\`
2206
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual drift
2207
+ `,
2208
+ },
2209
+ ];
2210
+ }
2211
+ else if (template === "flutter-consumer") {
2212
+ arquivos = [
2213
+ {
2214
+ caminhoRelativo: "sema.config.json",
2215
+ conteudo: `{
2216
+ "origens": ["./contratos"],
2217
+ "saida": "./generated",
2218
+ "alvos": ["dart"],
2219
+ "alvoPadrao": "dart",
2220
+ "estruturaSaida": "modulos",
2221
+ "framework": "base",
2222
+ "modoEstrito": true,
2223
+ "diretoriosCodigo": ["./lib"],
2224
+ "fontesLegado": ["flutter-consumer", "dart"],
2225
+ "diretoriosSaidaPorAlvo": {
2226
+ "dart": "./generated/dart"
2227
+ },
2228
+ "convencoesGeracaoPorProjeto": "base"
2229
+ }
2230
+ `,
2231
+ },
2232
+ {
2233
+ caminhoRelativo: "pubspec.yaml",
2234
+ conteudo: `name: sema_flutter_consumer
2235
+ description: Starter Flutter consumer IA-first com Sema
2236
+ publish_to: "none"
2237
+
2238
+ environment:
2239
+ sdk: ">=3.3.0 <4.0.0"
2240
+
2241
+ dependencies:
2242
+ flutter:
2243
+ sdk: flutter
2244
+ go_router: ^14.0.0
2245
+ `,
2246
+ },
2247
+ {
2248
+ caminhoRelativo: "contratos/showroom_consumer.sema",
2249
+ conteudo: `module showroom.consumer {
2250
+ task fetch_showroom_ranking {
2251
+ input {
2252
+ }
2253
+ output {
2254
+ resultado: Json
2255
+ }
2256
+ impl {
2257
+ dart: lib.sema_consumer_bridge.semaFetchShowroomRanking
2258
+ }
2259
+ vinculos {
2260
+ arquivo: "lib/sema_consumer_bridge.dart"
2261
+ simbolo: lib.sema_consumer_bridge.semaFetchShowroomRanking
2262
+ superficie: "/ranking"
2263
+ arquivo: "lib/router.dart"
2264
+ arquivo: "lib/screens/ranking_screen.dart"
2265
+ }
2266
+ guarantees {
2267
+ resultado existe
2268
+ }
2269
+ }
2270
+ }
2271
+ `,
2272
+ },
2273
+ {
2274
+ caminhoRelativo: "lib/sema_consumer_bridge.dart",
2275
+ conteudo: `Future<Map<String, dynamic>> semaFetchShowroomRanking() async {
2276
+ return {
2277
+ "ranking": [
2278
+ {"clube": "Tigres do Norte", "pontos": 33},
2279
+ {"clube": "Porto Azul", "pontos": 31},
2280
+ {"clube": "Galo de Ouro", "pontos": 28},
2281
+ ],
2282
+ };
2283
+ }
2284
+ `,
2285
+ },
2286
+ {
2287
+ caminhoRelativo: "lib/router.dart",
2288
+ conteudo: `import "package:go_router/go_router.dart";
2289
+ import "package:flutter/widgets.dart";
2290
+ import "screens/ranking_screen.dart";
2291
+
2292
+ final appRouter = GoRouter(
2293
+ routes: [
2294
+ GoRoute(
2295
+ path: "/ranking",
2296
+ builder: (BuildContext context, GoRouterState state) => const RankingScreen(),
2297
+ ),
2298
+ ],
2299
+ );
2300
+ `,
2301
+ },
2302
+ {
2303
+ caminhoRelativo: "lib/screens/ranking_screen.dart",
2304
+ conteudo: `import "package:flutter/widgets.dart";
2305
+ import "../sema_consumer_bridge.dart";
2306
+
2307
+ class RankingScreen extends StatefulWidget {
2308
+ const RankingScreen({super.key});
2309
+
2310
+ @override
2311
+ State<RankingScreen> createState() => _RankingScreenState();
2312
+ }
2313
+
2314
+ class _RankingScreenState extends State<RankingScreen> {
2315
+ List<Map<String, dynamic>> ranking = const [];
2316
+
2317
+ @override
2318
+ void initState() {
2319
+ super.initState();
2320
+ semaFetchShowroomRanking().then((payload) {
2321
+ final itens = (payload["ranking"] as List<dynamic>? ?? const [])
2322
+ .whereType<Map<String, dynamic>>()
2323
+ .toList();
2324
+ if (!mounted) return;
2325
+ setState(() {
2326
+ ranking = itens;
2327
+ });
2328
+ });
2329
+ }
2330
+
2331
+ @override
2332
+ Widget build(BuildContext context) {
2333
+ return ListView(
2334
+ children: [
2335
+ const Padding(
2336
+ padding: EdgeInsets.all(16),
2337
+ child: Text("Ranking showroom"),
2338
+ ),
2339
+ ...ranking.map((item) => Padding(
2340
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
2341
+ child: Text("\${item["clube"]} - \${item["pontos"]} pts"),
2342
+ )),
2343
+ ],
2344
+ );
2345
+ }
2346
+ }
2347
+ `,
2348
+ },
2349
+ {
2350
+ caminhoRelativo: "lib/main.dart",
2351
+ conteudo: `import "package:flutter/material.dart";
2352
+ import "router.dart";
2353
+
2354
+ void main() {
2355
+ runApp(const ShowroomApp());
2356
+ }
2357
+
2358
+ class ShowroomApp extends StatelessWidget {
2359
+ const ShowroomApp({super.key});
2360
+
2361
+ @override
2362
+ Widget build(BuildContext context) {
2363
+ return MaterialApp.router(
2364
+ routerConfig: appRouter,
2365
+ );
2366
+ }
2367
+ }
2368
+ `,
2369
+ },
2370
+ {
2371
+ caminhoRelativo: "README.md",
2372
+ conteudo: `# Starter Flutter Consumer + Sema
2373
+
2374
+ - Contratos em \`contratos/\`
2375
+ - Bridge consumer canonico em \`lib/sema_consumer_bridge.dart\`
2376
+ - Rotas consumer em \`lib/router.dart\`
2377
+ - Superficies consumer em \`lib/screens/\`
2378
+ - O slice oficial desta fase e \`consumer bridge + router/screen surfaces\`
2379
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual diff
1551
2380
  `,
1552
2381
  },
1553
2382
  ];
@@ -2106,6 +2935,10 @@ async function comandoInspecionar(entrada, emJson, cwd = process.cwd()) {
2106
2935
  modoAdocao: contextoProjeto.modoAdocao,
2107
2936
  scoreDrift: resultadoDrift.resumo_operacional.scoreMedio,
2108
2937
  confiancaGeral: resultadoDrift.resumo_operacional.confiancaGeral,
2938
+ consumerFramework: resultadoDrift.consumerFramework,
2939
+ appRoutes: resultadoDrift.appRoutes,
2940
+ consumerSurfaces: resultadoDrift.consumerSurfaces,
2941
+ consumerBridges: resultadoDrift.consumerBridges,
2109
2942
  },
2110
2943
  projeto: {
2111
2944
  arquivos: contextoProjeto.arquivosProjeto,
@@ -2440,49 +3273,80 @@ async function comandoStarterIa() {
2440
3273
  console.log(STARTER_IA);
2441
3274
  return 0;
2442
3275
  }
3276
+ async function comandoSyncAiEntrypoints(emJson) {
3277
+ const resumoProjeto = await gerarResumoProjetoIa(process.cwd(), undefined, true);
3278
+ const indexJson = JSON.parse(await readFile(path.join(resumoProjeto.pastaSaida, "SEMA_INDEX.json"), "utf8"));
3279
+ const artefatos = [...new Set([
3280
+ ...ARQUIVOS_CANONICOS_IA_RAIZ,
3281
+ ...resumoProjeto.artefatos,
3282
+ ])];
3283
+ if (emJson) {
3284
+ console.log(JSON.stringify({
3285
+ comando: "sync-ai-entrypoints",
3286
+ sucesso: true,
3287
+ baseProjeto: resumoProjeto.baseProjeto,
3288
+ pastaSaida: resumoProjeto.pastaSaida,
3289
+ artefatos,
3290
+ entradaCanonica: indexJson.entradaCanonica,
3291
+ }, null, 2));
3292
+ return 0;
3293
+ }
3294
+ console.log("Entrypoints IA-first sincronizados");
3295
+ console.log("");
3296
+ console.log(`Base do projeto: ${resumoProjeto.baseProjeto}`);
3297
+ console.log(`Ordem canonica: ${indexJson.entradaCanonica.ordemLeitura.join(" -> ")}`);
3298
+ console.log(`IA pequena: ${indexJson.entradaCanonica.porCapacidade.pequena.join(" -> ")}`);
3299
+ console.log(`IA media: ${indexJson.entradaCanonica.porCapacidade.media.join(" -> ")}`);
3300
+ console.log(`IA grande: ${indexJson.entradaCanonica.porCapacidade.grande.join(" -> ")}`);
3301
+ return 0;
3302
+ }
2443
3303
  async function comandoAjudaIa() {
2444
3304
  const descoberta = await descobrirDocsIa();
2445
3305
  console.log("Ajuda de IA da Sema");
2446
3306
  console.log("");
3307
+ console.log(renderizarCaixaAscii([
3308
+ "IA-first para greenfield, edicao guiada e legado sem contrato inicial",
3309
+ "use o menor artefato semantico que resolva a tarefa",
3310
+ ]));
3311
+ console.log("");
2447
3312
  console.log(renderizarCabecalhoDocsIa(descoberta));
2448
3313
  console.log("");
2449
- console.log("O que a Sema faz de verdade");
2450
- console.log("- Foi feita para IA operar melhor; leitura humana e consequencia, nao centro de produto.");
2451
- console.log("- Governa contrato, intencao, erro, efeito, garantia, fluxo, vinculos e execucao.");
2452
- console.log("- Usa `importar` para bootstrap revisavel de legado.");
2453
- console.log("- Usa `impl` para ligar contrato a simbolos reais.");
2454
- console.log("- Usa `vinculos` para ligar contrato a arquivo, simbolo, recurso e superficie real.");
2455
- console.log("- Usa `execucao` para explicitar timeout, retry, compensacao e criticidade.");
2456
- console.log("- Usa `drift` para medir divergencia entre contrato e codigo vivo com score, confianca e lacunas.");
2457
- console.log("- Usa `resumo` e `prompt-curto` para IA pequena ou gratuita.");
2458
- console.log("- Usa `contexto-ia` para preparar AST, IR, diagnosticos, drift, `briefing.json` e artefatos compactos antes da edicao.");
3314
+ console.log(renderizarSecaoAscii("Tres jeitos de usar a Sema", [
3315
+ "[1] Producao inicial: modele, valide, compile e verifique antes de subir codigo derivado.",
3316
+ "[2] Edicao em projeto com Sema: inspecione, leia resumo, rode drift e gere contexto antes de editar codigo vivo.",
3317
+ "[3] Projeto sem Sema ainda: importe, revise o rascunho, formate, valide e use drift como juiz da adocao incremental.",
3318
+ ]));
2459
3319
  console.log("");
2460
- console.log("O que a Sema nao promete");
2461
- console.log("- Nao escreve contrato final sozinho.");
2462
- console.log("- Nao substitui decisao arquitetural.");
2463
- console.log("- Nao adivinha regra de negocio que o codigo nao explicita.");
3320
+ console.log(renderizarSecaoAscii("Capacidade de IA", [
3321
+ "pequena: `sema resumo --micro`, `briefing.min.json`, `prompt-curto.txt`",
3322
+ "media: `sema resumo --curto`, `drift.json`, `briefing.min.json`",
3323
+ "grande: `sema contexto-ia`, `briefing.json`, `ir.json`, `ast.json`",
3324
+ ]));
2464
3325
  console.log("");
2465
- console.log("Fluxo recomendado");
2466
- console.log("- Use `sema starter-ia` para um texto curto de onboarding.");
2467
- console.log("- Use `sema resumo <arquivo> --micro --para onboarding` para IA pequena.");
2468
- console.log("- Use `sema prompt-curto <arquivo> --curto --para mudanca` para colar contexto em modelo gratuito.");
2469
- console.log("- Use `sema prompt-ia` para o prompt-base geral.");
2470
- console.log("- Use `sema prompt-ia-ui` para tarefas visuais com Sema + UI.");
2471
- console.log("- Use `sema prompt-ia-react` para projeto com Sema + React + TypeScript.");
2472
- console.log("- Use `sema prompt-ia-sema-primeiro` para forcar modelagem semantica antes da implementacao.");
2473
- console.log("- Use `sema exemplos-prompt-ia` para pegar modelos prontos de prompt.");
2474
- console.log("- Use `sema inspecionar` para descobrir base, codigo vivo e fontes legado.");
2475
- console.log("- Use `sema drift` para medir impls, vinculos, rotas, score e lacunas.");
2476
- console.log("- Use `sema contexto-ia <arquivo.sema>` para gerar AST, IR, drift, `briefing.json` e `briefing.min.json` do modulo alvo.");
2477
- console.log("- Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>` quando a tarefa pedir codigo derivado.");
3326
+ console.log(renderizarSecaoAscii("Fluxo recomendado", [
3327
+ "Use `sema starter-ia` para um texto curto de onboarding.",
3328
+ "Use `sema sync-ai-entrypoints` para regenerar `SEMA_BRIEF.*` e `SEMA_INDEX.json` na raiz.",
3329
+ "Use `sema resumo <arquivo> --micro --para onboarding` para IA pequena.",
3330
+ "Use `sema prompt-curto <arquivo> --curto --para mudanca` para colar contexto em modelo gratuito.",
3331
+ "Use `sema prompt-ia`, `sema prompt-ia-ui`, `sema prompt-ia-react` e `sema prompt-ia-sema-primeiro` conforme a tarefa.",
3332
+ "Use `sema exemplos-prompt-ia` para pegar modelos prontos de prompt.",
3333
+ "Use `sema inspecionar` para descobrir base, codigo vivo e fontes legado.",
3334
+ "Use `sema drift` para medir impls, vinculos, rotas, score e lacunas.",
3335
+ "Use `sema contexto-ia <arquivo.sema>` para gerar AST, IR, drift, `briefing.json` e `briefing.min.json`.",
3336
+ "Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart|lua> --saida <diretorio>` quando a tarefa pedir codigo derivado.",
3337
+ ]));
2478
3338
  console.log("");
2479
- console.log("Regra pratica");
2480
- console.log("- Se voce quer testar a Sema de verdade, nao peca so HTML solto.");
2481
- console.log("- Peca `.sema` + arquitetura + React + TypeScript, ou use o modo `Sema primeiro`.");
2482
- console.log("- Se o projeto ja existe, trate `importar` como rascunho e `drift` como juiz.");
2483
- console.log("- IA pequena comeca no menor artefato que resolve a tarefa; nao enfie `ast.json` inteiro nela de bobeira.");
2484
- console.log("- Antes de editar backend vivo, leia `briefing.min.json` ou `briefing.json` em vez de sair cavando arquivo na fe.");
2485
- console.log("- Trate `route`, `worker`, `evento`, `fila`, `cron`, `webhook`, `cache`, `storage` e `policy` como superficies de primeira classe.");
3339
+ console.log(renderizarSecaoAscii("Regras praticas", [
3340
+ "Foi feita para IA operar melhor; leitura humana e consequencia, nao centro de produto.",
3341
+ "Governa contrato, intencao, erro, efeito, garantia, fluxo, vinculos e execucao.",
3342
+ "Nao escreve contrato final sozinho nem substitui decisao arquitetural.",
3343
+ "Se voce quer testar a Sema de verdade, nao peca so HTML solto.",
3344
+ "Peca `.sema` + arquitetura + React + TypeScript, ou use o modo `Sema primeiro`.",
3345
+ "Se o projeto ja existe, trate `importar` como rascunho e `drift` como juiz.",
3346
+ "IA pequena comeca no menor artefato que resolve a tarefa; nao enfie `ast.json` inteiro nela de bobeira.",
3347
+ "Antes de editar software vivo, leia `briefing.min.json` ou `briefing.json` em vez de sair cavando arquivo na fe.",
3348
+ "Trate `route`, `worker`, `evento`, `fila`, `cron`, `webhook`, `cache`, `storage` e `policy` como superficies de primeira classe.",
3349
+ ]));
2486
3350
  return 0;
2487
3351
  }
2488
3352
  async function comandoPromptIa() {
@@ -2697,7 +3561,16 @@ async function comandoTestar(arquivo, alvo, saida, estrutura, framework) {
2697
3561
  console.log(`Scaffold ${framework} gerado em ${saida}. A execucao automatica de testes continua focada no framework base da Sema.`);
2698
3562
  return 0;
2699
3563
  }
2700
- return executarTestesGerados(alvo, saida, arquivos).codigoSaida;
3564
+ const execucao = executarTestesGerados(alvo, saida, arquivos);
3565
+ if (execucao.codigoSaida !== 0) {
3566
+ if (execucao.saidaPadrao) {
3567
+ console.log(execucao.saidaPadrao);
3568
+ }
3569
+ if (execucao.saidaErro) {
3570
+ console.error(execucao.saidaErro);
3571
+ }
3572
+ }
3573
+ return execucao.codigoSaida;
2701
3574
  }
2702
3575
  function imprimirResumoVerificacao(resumos) {
2703
3576
  console.log("\nResumo da verificacao:");
@@ -2897,7 +3770,7 @@ async function principal() {
2897
3770
  {
2898
3771
  const fonte = normalizarFonteImportacao(posicionais[0]);
2899
3772
  if (!fonte || !posicionais[1]) {
2900
- console.error("Uso: sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
3773
+ console.error("Uso: sema importar <nestjs|fastapi|flask|nextjs|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|firebase|dotnet|java|go|rust|cpp|typescript|python|dart|lua> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
2901
3774
  codigoSaida = 1;
2902
3775
  break;
2903
3776
  }
@@ -2916,6 +3789,9 @@ async function principal() {
2916
3789
  case "starter-ia":
2917
3790
  codigoSaida = await comandoStarterIa();
2918
3791
  break;
3792
+ case "sync-ai-entrypoints":
3793
+ codigoSaida = await comandoSyncAiEntrypoints(possuiFlag(resto, "--json"));
3794
+ break;
2919
3795
  case "resumo":
2920
3796
  codigoSaida = await comandoResumo(posicionais[0], resto, possuiFlag(resto, "--json"));
2921
3797
  break;