@semacode/cli 0.9.0 → 1.1.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 (46) hide show
  1. package/AGENTS.md +50 -0
  2. package/README.md +24 -3
  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 +501 -0
  7. package/dist/drift.d.ts +15 -0
  8. package/dist/drift.js +496 -5
  9. package/dist/drift.js.map +1 -1
  10. package/dist/importador.d.ts +1 -1
  11. package/dist/importador.js +681 -3
  12. package/dist/importador.js.map +1 -1
  13. package/dist/index.js +1578 -123
  14. package/dist/index.js.map +1 -1
  15. package/dist/projeto.js +49 -1
  16. package/dist/projeto.js.map +1 -1
  17. package/dist/tipos.d.ts +1 -1
  18. package/docs/AGENT_STARTER.md +40 -8
  19. package/docs/como-ensinar-a-sema-para-ia.md +17 -11
  20. package/docs/fluxo-pratico-ia-sema.md +42 -38
  21. package/docs/instalacao-e-primeiro-uso.md +196 -0
  22. package/docs/integracao-com-ia.md +228 -0
  23. package/docs/pagamento-ponta-a-ponta.md +155 -0
  24. package/docs/prompt-base-ia-sema.md +10 -3
  25. package/docs/sintaxe.md +267 -0
  26. package/exemplos/automacao.sema +107 -0
  27. package/exemplos/cadastro_usuario.sema +54 -0
  28. package/exemplos/calculadora.sema +78 -0
  29. package/exemplos/crud_simples.sema +89 -0
  30. package/exemplos/operacao_estrategia.sema +402 -0
  31. package/exemplos/pagamento.sema +222 -0
  32. package/exemplos/pagamento_dominio.sema +35 -0
  33. package/exemplos/testes_embutidos.sema +45 -0
  34. package/exemplos/tratamento_erro.sema +157 -0
  35. package/llms-full.txt +34 -0
  36. package/llms.txt +17 -0
  37. package/node_modules/@sema/gerador-dart/package.json +1 -1
  38. package/node_modules/@sema/gerador-python/dist/index.js +92 -10
  39. package/node_modules/@sema/gerador-python/dist/index.js.map +1 -1
  40. package/node_modules/@sema/gerador-python/package.json +1 -1
  41. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  42. package/node_modules/@sema/nucleo/package.json +1 -1
  43. package/node_modules/@sema/padroes/dist/index.js +47 -1
  44. package/node_modules/@sema/padroes/dist/index.js.map +1 -1
  45. package/node_modules/@sema/padroes/package.json +1 -1
  46. package/package.json +15 -7
package/dist/index.js CHANGED
@@ -12,11 +12,13 @@ import { gerarTypeScript } from "@sema/gerador-typescript";
12
12
  import { carregarConfiguracaoProjeto, carregarProjeto, resolverAlvoPadrao, resolverAlvosVerificacao, resolverEstruturaSaidaPadrao, resolverFrameworkPadrao, resolverSaidaPadrao, } from "./projeto.js";
13
13
  import { importarProjetoLegado, resumoImportacao } from "./importador.js";
14
14
  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.
15
+ 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
16
 
17
17
  Importante:
18
18
  - a Sema se apresenta publicamente como protocolo e funciona tecnicamente como linguagem de intencao
19
- - a Sema e protocolo de governanca semantica, nao gerador magico que deveria fazer tudo
19
+ - a Sema e protocolo de governanca semantica desenhado para IA, nao para ergonomia humana
20
+ - leitura humana e bonus toleravel, nao objetivo de produto
21
+ - a Sema nao e gerador magico que deveria fazer tudo
20
22
  - a Sema modela contratos, estados, fluxos, erros, efeitos, garantias, vinculos e execucao
21
23
  - a Sema gera codigo e scaffolding real para TypeScript, Python e Dart
22
24
  - a Sema usa \`importar\` para bootstrap revisavel, nao para contrato final automatico
@@ -24,7 +26,8 @@ Importante:
24
26
  - a Sema usa \`vinculos\` para ligar contrato a arquivo, simbolo, recurso e superficie real
25
27
  - a Sema usa \`execucao\` para explicitar timeout, retry, compensacao e criticidade
26
28
  - a Sema usa \`drift\` para medir diferenca entre contrato e codigo vivo com score, confianca e lacunas
27
- - a Sema usa \`contexto-ia\` para gerar \`ast.json\`, \`ir.json\`, \`drift.json\` e \`briefing.json\` antes da edicao
29
+ - a Sema usa \`resumo\` e \`prompt-curto\` para IA pequena ou gratuita
30
+ - a Sema usa \`contexto-ia\` para gerar \`ast.json\`, \`ir.json\`, \`drift.json\`, \`briefing.json\` e artefatos compactos antes da edicao
28
31
  - a Sema pode servir de base para interfaces graficas elegantes e coerentes
29
32
  - a Sema nao gera uma interface completa sozinha no estado atual
30
33
  - trate a Sema como cerebro semantico da aplicacao, nao como gerador magico de front-end pronto
@@ -33,6 +36,8 @@ Importante:
33
36
 
34
37
  Regras:
35
38
  - nao invente sintaxe fora da gramatica e dos exemplos oficiais
39
+ - se a IA for pequena, nao tente abrir tudo de uma vez
40
+ - use \`sema resumo\` e \`briefing.min.json\` antes de subir para o pacote completo
36
41
  - trate \`ir --json\` como fonte de verdade semantica
37
42
  - trate \`briefing.json\` como plano de intervencao antes de editar projeto vivo
38
43
  - trate \`diagnosticos --json\` como fonte de correcao
@@ -41,6 +46,8 @@ Regras:
41
46
  - nao cobre da Sema adivinhacao de negocio que nao esta no contrato nem no codigo
42
47
 
43
48
  Comandos essenciais:
49
+ - resumo compacto por capacidade: \`sema resumo <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>]\`
50
+ - prompt curto para IA pequena: \`sema prompt-curto <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>]\`
44
51
  - descoberta do projeto: \`sema inspecionar [arquivo-ou-pasta] --json\`
45
52
  - auditoria do contrato vivo: \`sema drift <arquivo-ou-pasta> [--json]\`
46
53
  - contexto completo do modulo: \`sema contexto-ia <arquivo.sema>\`
@@ -49,16 +56,16 @@ Comandos essenciais:
49
56
  - validacao: \`sema validar <arquivo.sema> --json\`
50
57
  - diagnosticos: \`sema diagnosticos <arquivo.sema> --json\`
51
58
  - formatacao: \`sema formatar <arquivo.sema>\`
52
- - importacao assistida de legado: \`sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> --saida <diretorio>\`
59
+ - 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> <diretorio> --saida <diretorio>\`
53
60
  - geracao de codigo: \`sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>\`
54
61
  - verificacao final: \`sema verificar <arquivo-ou-pasta> [--json]\`
55
62
 
56
63
  Antes de editar:
57
64
  1. leia README, docs de IA e um exemplo oficial parecido
58
- 2. rode \`sema inspecionar\` para descobrir base, codigo vivo e fontes legado
59
- 3. rode \`sema drift\` para medir impls, vinculos, rotas, score e lacunas
60
- 4. rode \`sema contexto-ia\` e leia \`briefing.json\`
61
- 5. consulte AST e IR do modulo alvo
65
+ 2. se a IA for pequena, rode \`sema resumo <arquivo> --micro\` e leia \`briefing.min.json\`
66
+ 3. se a IA aguentar mais, rode \`sema drift\` para medir impls, vinculos, rotas, score e lacunas
67
+ 4. se a tarefa for pesada, rode \`sema contexto-ia\` e leia \`briefing.json\`
68
+ 5. consulte AST e IR do modulo alvo so quando a capacidade realmente aguentar
62
69
 
63
70
  Depois de editar:
64
71
  1. rode \`sema formatar\`
@@ -66,11 +73,12 @@ Depois de editar:
66
73
  3. se houver falha, use \`diagnosticos --json\`
67
74
  4. rode \`sema drift\` de novo quando mexer em codigo vivo
68
75
  5. se a tarefa pedir codigo derivado, rode \`sema compilar\`
69
- 6. feche com \`sema verificar\` ou \`npm run project:check\`
76
+ 6. feche com \`sema verificar <arquivo-ou-pasta> --json\`
70
77
 
71
78
  Priorize sempre:
72
79
  - exemplos oficiais
73
80
  - JSON da CLI
81
+ - o menor artefato que resolva a tarefa da IA atual
74
82
  - score, confianca e lacunas do \`drift\`
75
83
  - \`briefing.json\` como guia de mudanca
76
84
  - consistencia semantica
@@ -88,16 +96,17 @@ Superficies que a IA deve enxergar como first-class:
88
96
 
89
97
  Nao improvise quando faltar contexto.
90
98
  `;
91
- const PROMPT_BASE_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao orientado a contrato, desenhado para facilitar entendimento e operacao por IA.
99
+ const PROMPT_BASE_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao orientado a contrato, desenhado para operacao por IA.
92
100
 
93
- Trate a Sema como camada semantica e linguagem de especificacao executavel. Nao invente sintaxe, palavras-chave ou blocos fora da gramatica e dos exemplos oficiais.
101
+ Trate a Sema como camada semantica e linguagem de especificacao executavel feita para IA, nao para leitura humana confortavel. Nao invente sintaxe, palavras-chave ou blocos fora da gramatica e dos exemplos oficiais.
94
102
 
95
103
  Fontes de verdade, em ordem:
96
104
  1. README do projeto
97
105
  2. gramatica e documentacao de sintaxe da Sema
98
106
  3. especificacao semantica da linguagem
99
107
  4. exemplos oficiais, com prioridade para o vertical de pagamento
100
- 5. AST, IR e diagnosticos exportados pela CLI em JSON
108
+ 5. \`sema resumo\` e \`briefing.min.json\` quando a IA for pequena
109
+ 6. AST, IR e diagnosticos exportados pela CLI em JSON quando a capacidade aguentar
101
110
 
102
111
  Regras de operacao:
103
112
  - preserve o significado semantico
@@ -105,6 +114,7 @@ Regras de operacao:
105
114
  - use diagnosticos estruturados como contrato de correcao
106
115
  - use a IR como fonte de verdade semantica quando houver duvida
107
116
  - nao conclua uma alteracao sem validar e verificar o modulo
117
+ - comece pelo menor artefato semantico que resolva a tarefa
108
118
 
109
119
  Antes de editar \`.sema\`, entenda:
110
120
  - o module alvo
@@ -292,6 +302,8 @@ Nao transforme isso em um \`index.html\` solto.
292
302
  Comandos uteis da CLI para esse fluxo:
293
303
  - \`sema starter-ia\`
294
304
  - \`sema ajuda-ia\`
305
+ - \`sema resumo <arquivo-ou-pasta>\`
306
+ - \`sema prompt-curto <arquivo-ou-pasta>\`
295
307
  - \`sema prompt-ia\`
296
308
  - \`sema prompt-ia-ui\`
297
309
  - \`sema prompt-ia-react\`
@@ -300,40 +312,106 @@ Comandos uteis da CLI para esse fluxo:
300
312
  `;
301
313
  const DIRETORIO_CLI_ATUAL = path.dirname(fileURLToPath(import.meta.url));
302
314
  const VERSAO_CLI = pacoteCli.version;
315
+ const ARQUIVOS_CANONICOS_IA_RAIZ = [
316
+ "llms.txt",
317
+ "SEMA_BRIEF.md",
318
+ "SEMA_INDEX.json",
319
+ "AGENTS.md",
320
+ "README.md",
321
+ "llms-full.txt",
322
+ ];
323
+ const DOCUMENTOS_SUPORTE_IA = [
324
+ "docs/AGENT_STARTER.md",
325
+ "docs/integracao-com-ia.md",
326
+ "docs/fluxo-pratico-ia-sema.md",
327
+ "docs/como-ensinar-a-sema-para-ia.md",
328
+ "docs/sintaxe.md",
329
+ "docs/cli.md",
330
+ ];
303
331
  function obterArgumentos() {
304
332
  const [, , comando, ...resto] = process.argv;
305
333
  return { comando: comando, resto };
306
334
  }
335
+ function renderizarCaixaAscii(linhas) {
336
+ const largura = Math.max(...linhas.map((linha) => linha.length), 12);
337
+ const borda = `+${"-".repeat(largura + 2)}+`;
338
+ return [
339
+ borda,
340
+ ...linhas.map((linha) => `| ${linha.padEnd(largura, " ")} |`),
341
+ borda,
342
+ ].join("\n");
343
+ }
344
+ function renderizarSecaoAscii(titulo, linhas) {
345
+ return [
346
+ titulo,
347
+ ...linhas.map((linha) => ` ${linha}`),
348
+ ].join("\n");
349
+ }
307
350
  function ajuda() {
308
- return `Sema CLI
309
-
310
- Comandos:
311
- sema --versao
312
- sema --version
313
- sema -v
314
- sema iniciar
315
- sema validar <arquivo-ou-pasta>
316
- sema ast <arquivo.sema>
317
- sema ir <arquivo.sema>
318
- sema compilar <arquivo-ou-pasta> --alvo <python|typescript|dart> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
319
- sema gerar <python|typescript|dart> <arquivo-ou-pasta> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
320
- sema testar <arquivo.sema> --alvo <python|typescript|dart> --saida <diretorio-temporario> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
321
- sema diagnosticos <arquivo.sema> [--json]
322
- sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--json]
323
- sema inspecionar [arquivo-ou-pasta] [--json]
324
- sema drift <arquivo-ou-pasta> [--json]
325
- sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]
326
- sema doctor
327
- sema formatar <arquivo-ou-pasta> [--check] [--json]
328
- sema ajuda-ia
329
- sema starter-ia
330
- sema prompt-ia
331
- sema prompt-ia-ui
332
- sema prompt-ia-react
333
- sema prompt-ia-sema-primeiro
334
- sema exemplos-prompt-ia
335
- sema contexto-ia <arquivo.sema> [--saida <diretorio>] [--json]
336
- `;
351
+ return [
352
+ renderizarCaixaAscii([
353
+ `Sema CLI v${VERSAO_CLI}`,
354
+ "IA-first para contrato, geracao e adocao incremental",
355
+ "novo projeto, edicao guiada e legado sem contrato inicial",
356
+ ]),
357
+ "",
358
+ renderizarSecaoAscii("Fluxos rapidos", [
359
+ "[1] Projeto novo / producao inicial",
360
+ "sema iniciar --template <base|nestjs|fastapi|nextjs-api|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer>",
361
+ "sema validar contratos/<modulo>.sema --json",
362
+ "sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>",
363
+ "sema verificar <arquivo-ou-pasta> --json",
364
+ "",
365
+ "[2] Editar projeto que ja usa Sema",
366
+ "sema inspecionar . --json",
367
+ "sema resumo <arquivo-ou-pasta> --micro --para mudanca",
368
+ "sema drift <arquivo-ou-pasta> --json",
369
+ "sema contexto-ia <arquivo.sema> --saida ./.tmp/contexto --json",
370
+ "",
371
+ "[3] Adotar Sema em projeto que ainda nao usa",
372
+ "sema importar <fonte> <diretorio> --saida <diretorio> --json",
373
+ "sema formatar <arquivo-ou-pasta>",
374
+ "sema validar <arquivo-ou-pasta> --json",
375
+ "sema drift <arquivo-ou-pasta> --json",
376
+ ]),
377
+ "",
378
+ renderizarSecaoAscii("IA por capacidade", [
379
+ "pequena: sema resumo --micro + briefing.min.json + prompt-curto.txt",
380
+ "media: sema resumo --curto + drift.json + briefing.min.json",
381
+ "grande: sema contexto-ia + briefing.json + ir.json + ast.json",
382
+ ]),
383
+ "",
384
+ renderizarSecaoAscii("Comandos principais", [
385
+ "descoberta: sema inspecionar [arquivo-ou-pasta] [--json]",
386
+ "auditoria: sema drift <arquivo-ou-pasta> [--json]",
387
+ "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]",
388
+ "validacao: sema validar <arquivo-ou-pasta> [--json]",
389
+ "diagnostico: sema diagnosticos <arquivo.sema> [--json]",
390
+ "geracao: sema compilar <arquivo-ou-pasta> --alvo <python|typescript|dart> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]",
391
+ "teste local: sema testar <arquivo.sema> --alvo <python|typescript|dart> --saida <diretorio-temporario> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]",
392
+ "verificacao final: sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--json]",
393
+ "formatacao: sema formatar <arquivo-ou-pasta> [--check] [--json]",
394
+ ]),
395
+ "",
396
+ renderizarSecaoAscii("Ajuda IA-first", [
397
+ "sema ajuda-ia",
398
+ "sema starter-ia",
399
+ "sema resumo <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>] [--saida <diretorio>] [--raiz] [--json]",
400
+ "sema prompt-curto <arquivo-ou-pasta> [--micro|--curto|--medio] [--para <resumo|onboarding|review|mudanca|bug|arquitetura>] [--json]",
401
+ "sema prompt-ia",
402
+ "sema prompt-ia-ui",
403
+ "sema prompt-ia-react",
404
+ "sema prompt-ia-sema-primeiro",
405
+ "sema exemplos-prompt-ia",
406
+ "sema contexto-ia <arquivo.sema> [--saida <diretorio>] [--json]",
407
+ "sema sync-ai-entrypoints [--json]",
408
+ ]),
409
+ "",
410
+ renderizarSecaoAscii("Operacional", [
411
+ "sema doctor",
412
+ "sema --versao | --version | -v",
413
+ ]),
414
+ ].join("\n");
337
415
  }
338
416
  async function carregarModulos(entrada, cwd = process.cwd()) {
339
417
  return (await carregarProjeto(entrada, cwd)).modulosSelecionados;
@@ -356,18 +434,51 @@ function obterOpcao(args, nome, padrao) {
356
434
  function possuiFlag(args, nome) {
357
435
  return args.includes(nome);
358
436
  }
437
+ const OPCOES_COM_VALOR = new Set([
438
+ "--template",
439
+ "--alvo",
440
+ "--saida",
441
+ "--estrutura",
442
+ "--framework",
443
+ "--namespace",
444
+ "--para",
445
+ ]);
359
446
  function obterPosicionais(args) {
360
447
  const posicionais = [];
361
448
  for (let indice = 0; indice < args.length; indice += 1) {
362
449
  const atual = args[indice];
363
450
  if (atual.startsWith("--")) {
364
- indice += 1;
451
+ if (OPCOES_COM_VALOR.has(atual)) {
452
+ indice += 1;
453
+ }
365
454
  continue;
366
455
  }
367
456
  posicionais.push(atual);
368
457
  }
369
458
  return posicionais;
370
459
  }
460
+ function normalizarTamanhoResumo(args) {
461
+ const escolhas = [
462
+ possuiFlag(args, "--micro") ? "micro" : null,
463
+ possuiFlag(args, "--curto") ? "curto" : null,
464
+ possuiFlag(args, "--medio") ? "medio" : null,
465
+ ].filter((item) => item !== null);
466
+ if (escolhas.length > 1) {
467
+ throw new Error("Use apenas uma entre as flags --micro, --curto ou --medio.");
468
+ }
469
+ return escolhas[0] ?? "curto";
470
+ }
471
+ function normalizarModoResumo(valor) {
472
+ if (valor === "resumo"
473
+ || valor === "onboarding"
474
+ || valor === "review"
475
+ || valor === "mudanca"
476
+ || valor === "bug"
477
+ || valor === "arquitetura") {
478
+ return valor;
479
+ }
480
+ return "resumo";
481
+ }
371
482
  function comandoDisponivel(comando, argumentos = ["--version"]) {
372
483
  const execucao = spawnSync(comando, argumentos, { stdio: "ignore", shell: process.platform === "win32" });
373
484
  return (execucao.status ?? 1) === 0;
@@ -383,7 +494,10 @@ async function comandoDoctor() {
383
494
  { nome: "java", ok: comandoDisponivel("java") },
384
495
  { nome: "code", ok: comandoDisponivel("code", ["--version"]) },
385
496
  ];
386
- console.log("Sema doctor");
497
+ console.log(renderizarCaixaAscii([
498
+ "Sema doctor",
499
+ "checa a toolchain minima para validar, gerar e operar a CLI",
500
+ ]));
387
501
  for (const check of checks) {
388
502
  console.log(`- ${check.nome}: ${check.ok ? "ok" : "ausente"}`);
389
503
  }
@@ -424,6 +538,18 @@ function normalizarFonteImportacao(valor) {
424
538
  if (valor === "next") {
425
539
  return "nextjs";
426
540
  }
541
+ if (valor === "next-consumer" || valor === "nextjs-consumer") {
542
+ return "nextjs-consumer";
543
+ }
544
+ if (valor === "react-vite" || valor === "react-vite-consumer" || valor === "react-consumer") {
545
+ return "react-vite-consumer";
546
+ }
547
+ if (valor === "angular" || valor === "angular-consumer") {
548
+ return "angular-consumer";
549
+ }
550
+ if (valor === "flutter" || valor === "flutter-consumer") {
551
+ return "flutter-consumer";
552
+ }
427
553
  if (valor === "fb") {
428
554
  return "firebase";
429
555
  }
@@ -446,6 +572,10 @@ function normalizarFonteImportacao(valor) {
446
572
  || valor === "fastapi"
447
573
  || valor === "flask"
448
574
  || valor === "nextjs"
575
+ || valor === "nextjs-consumer"
576
+ || valor === "react-vite-consumer"
577
+ || valor === "angular-consumer"
578
+ || valor === "flutter-consumer"
449
579
  || valor === "firebase"
450
580
  || valor === "dotnet"
451
581
  || valor === "java"
@@ -463,6 +593,10 @@ function normalizarTemplateIniciar(valor) {
463
593
  if (valor === "nestjs"
464
594
  || valor === "fastapi"
465
595
  || valor === "nextjs-api"
596
+ || valor === "nextjs-consumer"
597
+ || valor === "react-vite-consumer"
598
+ || valor === "angular-consumer"
599
+ || valor === "flutter-consumer"
466
600
  || valor === "node-firebase-worker"
467
601
  || valor === "aspnet-api"
468
602
  || valor === "springboot-api"
@@ -641,23 +775,377 @@ async function descobrirDocsIa() {
641
775
  };
642
776
  }
643
777
  function renderizarCabecalhoDocsIa(descoberta) {
778
+ const documentos = descoberta.documentos.map((documento) => `\`${documento.nome}\``);
644
779
  const linhas = [
645
- "Informacoes da instalacao atual",
646
- `- Origem da instalacao: ${descoberta.origemInstalacao}`,
647
- `- Base detectada: ${descoberta.baseDetectada ?? "nao encontrada"}`,
780
+ "Modo IA-first da instalacao atual",
781
+ "- Use `sema` como interface publica principal.",
782
+ "- A Sema entra em projeto novo, projeto ja semantizado e adocao incremental em legado sem contrato inicial.",
783
+ "- Nao assuma monorepo, `node pacotes/cli/dist/index.js`, `npm run project:check` ou uma pasta `exemplos` externa ao projeto atual.",
784
+ "- Se a IA tiver contexto curto, comece por `sema resumo` e `sema prompt-curto`.",
785
+ "- Se a IA aguentar mais contexto, suba para `sema drift --json` e `sema contexto-ia`.",
786
+ "- So leia `ast.json` e `ir.json` completos quando a capacidade da IA realmente aguentar esse volume.",
648
787
  ];
649
- if (descoberta.documentos.length > 0) {
650
- linhas.push("- Documentos locais encontrados:");
651
- for (const documento of descoberta.documentos) {
652
- linhas.push(` - ${documento.nome}: ${documento.caminho}`);
653
- }
788
+ if (documentos.length > 0) {
789
+ linhas.push(`- Documentos locais empacotados: ${documentos.join(", ")}.`);
654
790
  }
655
791
  else {
656
- linhas.push("- Documentos locais encontrados: nenhum");
657
- linhas.push(" - Esta instalacao da CLI nao conseguiu localizar a pasta docs ao redor do pacote atual.");
792
+ linhas.push("- Documentos locais empacotados: nenhum extra detectado. Siga a CLI, o contrato atual e os artefatos JSON.");
658
793
  }
659
794
  return linhas.join("\n");
660
795
  }
796
+ function unicos(itens) {
797
+ return [...new Set(itens)];
798
+ }
799
+ function unicosOrdenados(itens) {
800
+ return unicos(itens).sort((a, b) => a.localeCompare(b, "pt-BR"));
801
+ }
802
+ function limitarLista(itens, limite) {
803
+ return itens.slice(0, limite);
804
+ }
805
+ function resumirListaTexto(itens, limite, padrao = "nenhum") {
806
+ if (itens.length === 0) {
807
+ return padrao;
808
+ }
809
+ const visiveis = itens.slice(0, limite);
810
+ const restante = itens.length - visiveis.length;
811
+ return restante > 0 ? `${visiveis.join(", ")} (+${restante})` : visiveis.join(", ");
812
+ }
813
+ function normalizarIdentificadorResumo(valor) {
814
+ return valor.replace(/[._]/g, " ").replace(/\s+/g, " ").trim();
815
+ }
816
+ function resumirCamposTask(task, campo, limiteCampos) {
817
+ const campos = (task[campo] ?? []).map((item) => item.nome).slice(0, limiteCampos);
818
+ if (campos.length === 0) {
819
+ return `${task.nome}(-)`;
820
+ }
821
+ return `${task.nome}(${campos.join(", ")})`;
822
+ }
823
+ function formatarEfeitoSemanticoResumido(efeito) {
824
+ if (efeito.textoOriginal) {
825
+ return efeito.textoOriginal;
826
+ }
827
+ const partes = [`${efeito.categoria} ${efeito.alvo}`];
828
+ if (efeito.criticidade) {
829
+ partes.push(`criticidade=${efeito.criticidade}`);
830
+ }
831
+ if (efeito.detalhe) {
832
+ partes.push(efeito.detalhe);
833
+ }
834
+ return partes.join(" ");
835
+ }
836
+ function calcularRiscoOperacionalResumo(resumoDrift) {
837
+ if (resumoDrift.tasks.some((task) => task.riscoOperacional === "alto")) {
838
+ return "alto";
839
+ }
840
+ if (resumoDrift.tasks.some((task) => task.riscoOperacional === "medio")) {
841
+ return "medio";
842
+ }
843
+ return "baixo";
844
+ }
845
+ function descreverFazModulo(ir, modulo) {
846
+ if (!ir) {
847
+ return `governa o modulo ${normalizarIdentificadorResumo(modulo)}`;
848
+ }
849
+ const partes = [];
850
+ if (ir.routes.length > 0) {
851
+ partes.push(`${ir.routes.length} rota(s)`);
852
+ }
853
+ if (ir.superficies.length > 0) {
854
+ partes.push(`${ir.superficies.length} superficie(s)`);
855
+ }
856
+ if (ir.tasks.length > 0) {
857
+ partes.push(`${ir.tasks.length} task(s)`);
858
+ }
859
+ const foco = ir.routes[0]?.nome ?? ir.superficies[0]?.nome ?? ir.tasks[0]?.nome ?? modulo;
860
+ return partes.length > 0
861
+ ? `governa ${partes.join(", ")} com foco em ${normalizarIdentificadorResumo(foco)}`
862
+ : `governa o modulo ${normalizarIdentificadorResumo(modulo)}`;
863
+ }
864
+ function criarGuiaCapacidadeIa() {
865
+ return {
866
+ pequena: {
867
+ descricao: "IA gratuita ou com contexto curto. Leia so o cartao semantico e o briefing minimo.",
868
+ artefatos: ["resumo.micro.txt", "briefing.min.json", "prompt-curto.txt"],
869
+ ordemLeitura: ["resumo.micro.txt", "briefing.min.json", "resumo.curto.txt"],
870
+ evitar: ["ast.json", "ir.json", "diagnosticos.json"],
871
+ },
872
+ media: {
873
+ descricao: "IA com contexto medio. Aguenta resumo expandido, briefing minimo e drift.",
874
+ artefatos: ["resumo.curto.txt", "briefing.min.json", "drift.json", "prompt-curto.txt"],
875
+ ordemLeitura: ["resumo.curto.txt", "briefing.min.json", "drift.json", "resumo.md"],
876
+ evitar: ["ast.json"],
877
+ },
878
+ grande: {
879
+ descricao: "IA com contexto grande ou tool use. Pode consumir o pacote completo.",
880
+ artefatos: ["README.md", "resumo.md", "briefing.json", "drift.json", "ir.json", "ast.json"],
881
+ ordemLeitura: ["README.md", "resumo.md", "briefing.json", "drift.json", "ir.json", "ast.json"],
882
+ evitar: [],
883
+ },
884
+ };
885
+ }
886
+ function coletarResumoSemanticoModulo(contexto) {
887
+ const { arquivo, modulo, geradoEm, ir, briefing, drift } = contexto;
888
+ const tarefas = ir?.tasks ?? [];
889
+ const rotas = ir?.routes ?? [];
890
+ const superficies = ir?.superficies ?? [];
891
+ const regrasCriticas = unicosOrdenados([
892
+ ...tarefas.flatMap((task) => task.rules),
893
+ ...tarefas.flatMap((task) => task.guarantees),
894
+ ]);
895
+ const efeitos = unicosOrdenados([
896
+ ...tarefas.flatMap((task) => task.effects),
897
+ ...rotas.flatMap((route) => route.efeitosPublicos.map((efeito) => formatarEfeitoSemanticoResumido(efeito))),
898
+ ...superficies.flatMap((superficie) => superficie.effects.map((efeito) => formatarEfeitoSemanticoResumido(efeito))),
899
+ ]);
900
+ const erros = unicosOrdenados([
901
+ ...tarefas.flatMap((task) => Object.keys(task.errors)),
902
+ ...tarefas.flatMap((task) => task.errosDetalhados.map((erro) => erro.codigo)),
903
+ ...rotas.flatMap((route) => route.errosPublicos.map((erro) => erro.codigo)),
904
+ ]);
905
+ const entidadesAfetadas = unicosOrdenados([
906
+ ...(ir?.resumoAgente.entidadesAfetadas ?? []),
907
+ ...tarefas.flatMap((task) => task.resumoAgente.entidadesAfetadas),
908
+ ...rotas.flatMap((route) => route.resumoAgente.entidadesAfetadas),
909
+ ...superficies.flatMap((superficie) => superficie.resumoAgente.entidadesAfetadas),
910
+ ]);
911
+ return {
912
+ geradoEm,
913
+ arquivo,
914
+ modulo,
915
+ perfilCompatibilidade: ir?.perfilCompatibilidade ?? briefing.perfilCompatibilidade,
916
+ scoreSemantico: briefing.scoreSemantico,
917
+ confiancaGeral: briefing.confiancaGeral,
918
+ riscoOperacional: calcularRiscoOperacionalResumo(drift.resumo),
919
+ faz: descreverFazModulo(ir, modulo),
920
+ tarefasPrincipais: limitarLista(tarefas.map((task) => task.nome), 6),
921
+ entradasChave: limitarLista(tarefas.map((task) => resumirCamposTask(task, "input", 4)), 4),
922
+ saidasChave: limitarLista(tarefas.map((task) => resumirCamposTask(task, "output", 4)), 4),
923
+ superficiesPublicas: limitarLista(unicosOrdenados([
924
+ ...briefing.superficiesImpactadas,
925
+ ...rotas.map((route) => `${route.metodo ?? "?"} ${route.caminho ?? route.nome}`),
926
+ ]), 8),
927
+ regrasCriticas: limitarLista(regrasCriticas, 8),
928
+ efeitos: limitarLista(efeitos, 8),
929
+ erros: limitarLista(erros, 8),
930
+ entidadesAfetadas: limitarLista(entidadesAfetadas, 8),
931
+ arquivosProvaveis: limitarLista(unicosOrdenados(briefing.oQueTocar), 8),
932
+ simbolosRelacionados: limitarLista(unicosOrdenados(briefing.simbolosRelacionados), 8),
933
+ riscosPrincipais: limitarLista(unicosOrdenados(briefing.riscosPrincipais), 6),
934
+ lacunas: limitarLista(unicosOrdenados(briefing.oQueEstaFrouxo), 6),
935
+ inferido: limitarLista(unicosOrdenados(briefing.oQueFoiInferido), 6),
936
+ checksSugeridos: limitarLista(unicosOrdenados(briefing.oQueValidar), 6),
937
+ testesMinimos: limitarLista(unicosOrdenados(briefing.testesMinimos), 6),
938
+ consumerFramework: briefing.consumerFramework ?? drift.drift.consumerFramework ?? null,
939
+ appRoutes: limitarLista(unicosOrdenados(briefing.appRoutes ?? drift.drift.appRoutes ?? []), 8),
940
+ consumerSurfaces: limitarLista(unicosOrdenados(briefing.consumerSurfaces ?? []), 8),
941
+ consumerBridges: limitarLista(unicosOrdenados(briefing.consumerBridges ?? []), 8),
942
+ arquivosProvaveisEditar: limitarLista(unicosOrdenados(briefing.arquivosProvaveisEditar ?? briefing.oQueTocar), 8),
943
+ };
944
+ }
945
+ function renderizarResumoModuloTexto(resumo, tamanho, modo) {
946
+ const limite = tamanho === "micro" ? 2 : tamanho === "curto" ? 4 : 6;
947
+ const linhas = [
948
+ `MODO: ${modo}`,
949
+ `MODULO: ${resumo.modulo}`,
950
+ `FAZ: ${resumo.faz}`,
951
+ `PERFIL: ${resumo.perfilCompatibilidade}`,
952
+ `CONSUMER_FRAMEWORK: ${resumo.consumerFramework ?? "nenhum"}`,
953
+ `APP_ROUTES: ${resumirListaTexto(resumo.appRoutes, limite)}`,
954
+ `CONSUMER_SURFACES: ${resumirListaTexto(resumo.consumerSurfaces, limite)}`,
955
+ `CONSUMER_BRIDGES: ${resumirListaTexto(resumo.consumerBridges, limite)}`,
956
+ `PUBLICO: ${resumirListaTexto(resumo.superficiesPublicas, limite)}`,
957
+ `TAREFAS: ${resumirListaTexto(resumo.tarefasPrincipais, limite)}`,
958
+ `ENTRADAS: ${resumirListaTexto(resumo.entradasChave, limite)}`,
959
+ `SAIDAS: ${resumirListaTexto(resumo.saidasChave, limite)}`,
960
+ `REGRAS: ${resumirListaTexto(resumo.regrasCriticas, limite)}`,
961
+ `EFEITOS: ${resumirListaTexto(resumo.efeitos, limite)}`,
962
+ `ERROS: ${resumirListaTexto(resumo.erros, limite)}`,
963
+ `TOCAR: ${resumirListaTexto(resumo.arquivosProvaveis, limite)}`,
964
+ `VALIDAR: ${resumirListaTexto(resumo.checksSugeridos, limite)}`,
965
+ `TESTES: ${resumirListaTexto(resumo.testesMinimos, limite)}`,
966
+ `RISCOS: ${resumirListaTexto(resumo.riscosPrincipais, limite)}`,
967
+ `LACUNAS: ${resumirListaTexto(resumo.lacunas, limite)}`,
968
+ `INFERIDO: ${resumirListaTexto(resumo.inferido, limite)}`,
969
+ `CONFIANCA: ${resumo.confiancaGeral}`,
970
+ `RISCO_OPERACIONAL: ${resumo.riscoOperacional}`,
971
+ `SCORE: ${resumo.scoreSemantico}`,
972
+ `GERADO_EM: ${resumo.geradoEm}`,
973
+ ];
974
+ if (tamanho === "micro") {
975
+ return `${linhas.slice(0, 12).join("\n")}\n`;
976
+ }
977
+ return `${linhas.join("\n")}\n`;
978
+ }
979
+ function renderizarResumoModuloMarkdown(resumo, modo, guiaPorCapacidade) {
980
+ const linhas = [
981
+ `# Resumo Sema para ${resumo.modulo}`,
982
+ "",
983
+ `- Modo: \`${modo}\``,
984
+ `- Gerado em: \`${resumo.geradoEm}\``,
985
+ `- Arquivo: \`${resumo.arquivo}\``,
986
+ `- Perfil: \`${resumo.perfilCompatibilidade}\``,
987
+ `- Score: \`${resumo.scoreSemantico}\``,
988
+ `- Confianca: \`${resumo.confiancaGeral}\``,
989
+ `- Risco operacional: \`${resumo.riscoOperacional}\``,
990
+ "",
991
+ "## O que este modulo faz",
992
+ "",
993
+ `- ${resumo.faz}`,
994
+ `- Superficies publicas: ${resumirListaTexto(resumo.superficiesPublicas, 8)}`,
995
+ `- Tarefas principais: ${resumirListaTexto(resumo.tarefasPrincipais, 8)}`,
996
+ "",
997
+ "## Contrato util para IA",
998
+ "",
999
+ `- Entradas chave: ${resumirListaTexto(resumo.entradasChave, 6)}`,
1000
+ `- Saidas chave: ${resumirListaTexto(resumo.saidasChave, 6)}`,
1001
+ `- Regras criticas: ${resumirListaTexto(resumo.regrasCriticas, 6)}`,
1002
+ `- Efeitos: ${resumirListaTexto(resumo.efeitos, 6)}`,
1003
+ `- Erros: ${resumirListaTexto(resumo.erros, 6)}`,
1004
+ `- Entidades afetadas: ${resumirListaTexto(resumo.entidadesAfetadas, 6)}`,
1005
+ "",
1006
+ ...(resumo.consumerFramework
1007
+ ? [
1008
+ "## Consumer IA-first",
1009
+ "",
1010
+ `- Framework consumer: ${resumo.consumerFramework}`,
1011
+ `- Rotas de app: ${resumirListaTexto(resumo.appRoutes, 6)}`,
1012
+ `- Superficies consumer: ${resumirListaTexto(resumo.consumerSurfaces, 6)}`,
1013
+ `- Bridges consumer: ${resumirListaTexto(resumo.consumerBridges, 6)}`,
1014
+ "",
1015
+ ]
1016
+ : []),
1017
+ "## Intervencao segura",
1018
+ "",
1019
+ `- Arquivos provaveis: ${resumirListaTexto(resumo.arquivosProvaveis, 6)}`,
1020
+ `- Simbolos relacionados: ${resumirListaTexto(resumo.simbolosRelacionados, 6)}`,
1021
+ `- Riscos principais: ${resumirListaTexto(resumo.riscosPrincipais, 6)}`,
1022
+ `- Lacunas: ${resumirListaTexto(resumo.lacunas, 6)}`,
1023
+ `- O que foi inferido: ${resumirListaTexto(resumo.inferido, 6)}`,
1024
+ `- Checks sugeridos: ${resumirListaTexto(resumo.checksSugeridos, 6)}`,
1025
+ `- Testes minimos: ${resumirListaTexto(resumo.testesMinimos, 6)}`,
1026
+ "",
1027
+ "## Guia por capacidade de IA",
1028
+ "",
1029
+ ];
1030
+ for (const capacidade of ["pequena", "media", "grande"]) {
1031
+ const guia = guiaPorCapacidade[capacidade];
1032
+ linhas.push(`### ${capacidade}`);
1033
+ linhas.push("");
1034
+ linhas.push(`- ${guia.descricao}`);
1035
+ linhas.push(`- Artefatos: ${guia.artefatos.map((item) => `\`${item}\``).join(", ")}`);
1036
+ linhas.push(`- Ordem de leitura: ${guia.ordemLeitura.map((item) => `\`${item}\``).join(" -> ")}`);
1037
+ linhas.push(`- Evitar: ${guia.evitar.length > 0 ? guia.evitar.map((item) => `\`${item}\``).join(", ") : "nada obrigatorio"}`);
1038
+ linhas.push("");
1039
+ }
1040
+ return `${linhas.join("\n").trim()}\n`;
1041
+ }
1042
+ function criarBriefingMinimo(resumo, modo, tamanho) {
1043
+ return {
1044
+ comando: "briefing-minimo",
1045
+ geradoEm: resumo.geradoEm,
1046
+ cliVersao: VERSAO_CLI,
1047
+ modo,
1048
+ tamanho,
1049
+ arquivo: resumo.arquivo,
1050
+ modulo: resumo.modulo,
1051
+ perfilCompatibilidade: resumo.perfilCompatibilidade,
1052
+ scoreSemantico: resumo.scoreSemantico,
1053
+ confiancaGeral: resumo.confiancaGeral,
1054
+ riscoOperacional: resumo.riscoOperacional,
1055
+ faz: resumo.faz,
1056
+ publico: resumo.superficiesPublicas,
1057
+ tarefasPrincipais: resumo.tarefasPrincipais,
1058
+ entradasChave: resumo.entradasChave,
1059
+ saidasChave: resumo.saidasChave,
1060
+ regrasCriticas: resumo.regrasCriticas,
1061
+ efeitos: resumo.efeitos,
1062
+ erros: resumo.erros,
1063
+ arquivosProvaveis: resumo.arquivosProvaveis,
1064
+ arquivosProvaveisEditar: resumo.arquivosProvaveisEditar,
1065
+ simbolosRelacionados: resumo.simbolosRelacionados,
1066
+ riscosPrincipais: resumo.riscosPrincipais,
1067
+ lacunas: resumo.lacunas,
1068
+ inferido: resumo.inferido,
1069
+ checksSugeridos: resumo.checksSugeridos,
1070
+ testesMinimos: resumo.testesMinimos,
1071
+ consumerFramework: resumo.consumerFramework,
1072
+ appRoutes: resumo.appRoutes,
1073
+ consumerSurfaces: resumo.consumerSurfaces,
1074
+ consumerBridges: resumo.consumerBridges,
1075
+ };
1076
+ }
1077
+ function criarPromptCurtoModulo(resumo, modo, tamanho, capacidade) {
1078
+ const resumoTexto = renderizarResumoModuloTexto(resumo, tamanho, modo).trim();
1079
+ return `Voce esta operando Sema em modo IA-first.
1080
+
1081
+ Esta linguagem nao foi desenhada para agradar humano; ela existe para reduzir ambiguidade para IA.
1082
+
1083
+ Capacidade alvo: ${capacidade}
1084
+ Modo da tarefa: ${modo}
1085
+
1086
+ Regras:
1087
+ - nao invente sintaxe nem bloco fora da gramatica oficial
1088
+ - preserve a intencao do contrato
1089
+ - use este resumo como fonte compacta inicial
1090
+ - se a tarefa pedir mais contexto, suba para \`briefing.min.json\`, \`drift.json\` e depois \`ir.json\`
1091
+ - nao saia editando software vivo sem olhar risco, lacuna e checks sugeridos
1092
+ ${resumo.consumerFramework ? "- se for tarefa visual consumer, priorize `appRoutes`, `consumerSurfaces` e `consumerBridges` antes de abrir arquivos aleatorios" : ""}
1093
+
1094
+ Contexto compacto:
1095
+ ${resumoTexto}
1096
+ `;
1097
+ }
1098
+ function renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade) {
1099
+ const entradaCanonica = criarEntradaCanonicaProjeto(guiaPorCapacidade);
1100
+ const linhas = [
1101
+ "# SEMA_BRIEF",
1102
+ "",
1103
+ "Sema e IA-first. Este arquivo existe para IA achar o ponto de entrada do projeto sem ter que catar o repo inteiro feito barata tonta.",
1104
+ "",
1105
+ `- Gerado em: \`${geradoEm}\``,
1106
+ `- Modulos: \`${modulos.length}\``,
1107
+ "",
1108
+ "## Entrada canonica para IA",
1109
+ "",
1110
+ `- Ordem minima: ${entradaCanonica.ordemLeitura.join(" -> ")}`,
1111
+ `- IA pequena: ${entradaCanonica.porCapacidade.pequena.join(" -> ")}`,
1112
+ `- IA media: ${entradaCanonica.porCapacidade.media.join(" -> ")}`,
1113
+ `- IA grande: ${entradaCanonica.porCapacidade.grande.join(" -> ")}`,
1114
+ "",
1115
+ "## Guia por capacidade",
1116
+ "",
1117
+ ];
1118
+ for (const capacidade of ["pequena", "media", "grande"]) {
1119
+ const guia = guiaPorCapacidade[capacidade];
1120
+ linhas.push(`- ${capacidade}: ${guia.descricao} Artefatos: ${guia.artefatos.join(", ")}.`);
1121
+ }
1122
+ linhas.push("");
1123
+ linhas.push("## Modulos");
1124
+ linhas.push("");
1125
+ for (const modulo of modulos) {
1126
+ linhas.push(`### ${modulo.modulo}`);
1127
+ linhas.push(`- Faz: ${modulo.faz}`);
1128
+ linhas.push(`- Publico: ${resumirListaTexto(modulo.superficiesPublicas, 4)}`);
1129
+ linhas.push(`- Tocar: ${resumirListaTexto(modulo.arquivosProvaveis, 4)}`);
1130
+ linhas.push(`- Score: ${modulo.scoreSemantico} | Confianca: ${modulo.confiancaGeral} | Risco: ${modulo.riscoOperacional}`);
1131
+ linhas.push(`- Lacunas: ${resumirListaTexto(modulo.lacunas, 4)}`);
1132
+ linhas.push("");
1133
+ }
1134
+ return `${linhas.join("\n").trim()}\n`;
1135
+ }
1136
+ function criarEntradaCanonicaProjeto(guiaPorCapacidade) {
1137
+ return {
1138
+ 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.",
1139
+ ordemLeitura: [...ARQUIVOS_CANONICOS_IA_RAIZ],
1140
+ porCapacidade: {
1141
+ pequena: ["llms.txt", "SEMA_BRIEF.micro.txt", "SEMA_INDEX.json", "AGENTS.md"],
1142
+ media: ["llms.txt", "SEMA_BRIEF.curto.txt", "SEMA_INDEX.json", "AGENTS.md", "README.md"],
1143
+ grande: ["llms-full.txt", "SEMA_BRIEF.md", "SEMA_INDEX.json", "AGENTS.md", "README.md"],
1144
+ },
1145
+ docsSuporte: [...DOCUMENTOS_SUPORTE_IA],
1146
+ guiaPorCapacidade,
1147
+ };
1148
+ }
661
1149
  function falharContextoIa(mensagem) {
662
1150
  throw new Error(mensagem);
663
1151
  }
@@ -691,6 +1179,41 @@ function resumirDriftPorModulo(modulo, caminho, resultadoDrift) {
691
1179
  const recursosDivergentes = modulo
692
1180
  ? resultadoDrift.recursos_divergentes.filter((recurso) => recurso.modulo === modulo)
693
1181
  : [];
1182
+ const vinculosModulo = modulo
1183
+ ? [
1184
+ ...resultadoDrift.vinculos_validos.filter((vinculo) => vinculo.modulo === modulo),
1185
+ ...resultadoDrift.vinculos_quebrados.filter((vinculo) => vinculo.modulo === modulo),
1186
+ ]
1187
+ : [];
1188
+ const rotasConsumerModulo = new Set(vinculosModulo
1189
+ .filter((vinculo) => vinculo.tipo === "superficie")
1190
+ .map((vinculo) => vinculo.valor));
1191
+ const arquivosRelacionados = [...new Set([
1192
+ ...tasks.flatMap((task) => task.arquivosReferenciados),
1193
+ ...tasks.flatMap((task) => task.arquivosProvaveisEditar),
1194
+ ...implsValidos.map((impl) => impl.arquivo).filter((item) => Boolean(item)),
1195
+ ...implsQuebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.arquivo) ?? []),
1196
+ ...vinculosValidos.map((vinculo) => vinculo.arquivo).filter((item) => Boolean(item)),
1197
+ ...recursosValidos.map((recurso) => recurso.arquivo).filter(Boolean),
1198
+ ...recursosDivergentes.map((recurso) => recurso.arquivo).filter(Boolean),
1199
+ ])].sort((a, b) => a.localeCompare(b, "pt-BR"));
1200
+ const consumerSurfaces = resultadoDrift.consumerSurfaces
1201
+ .filter((surface) => arquivosRelacionados.includes(surface.arquivo)
1202
+ || rotasConsumerModulo.has(surface.rota))
1203
+ .map((surface) => `${surface.tipoArquivo}:${surface.rota} -> ${surface.arquivo}`)
1204
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1205
+ const consumerBridges = resultadoDrift.consumerBridges
1206
+ .filter((bridge) => arquivosRelacionados.includes(bridge.arquivo))
1207
+ .map((bridge) => bridge.caminho)
1208
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1209
+ const appRoutes = [...new Set(resultadoDrift.consumerSurfaces
1210
+ .filter((surface) => arquivosRelacionados.includes(surface.arquivo)
1211
+ || rotasConsumerModulo.has(surface.rota))
1212
+ .map((surface) => surface.rota))]
1213
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1214
+ const consumerFramework = appRoutes.length > 0 || consumerBridges.length > 0
1215
+ ? resultadoDrift.consumerFramework
1216
+ : null;
694
1217
  return {
695
1218
  caminho,
696
1219
  modulo,
@@ -707,15 +1230,12 @@ function resumirDriftPorModulo(modulo, caminho, resultadoDrift) {
707
1230
  : tasks.some((task) => task.confiancaVinculo === "media")
708
1231
  ? "media"
709
1232
  : "baixa",
710
- arquivosRelacionados: [...new Set([
711
- ...tasks.flatMap((task) => task.arquivosReferenciados),
712
- ...tasks.flatMap((task) => task.arquivosProvaveisEditar),
713
- ...implsValidos.map((impl) => impl.arquivo).filter((item) => Boolean(item)),
714
- ...implsQuebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.arquivo) ?? []),
715
- ...vinculosValidos.map((vinculo) => vinculo.arquivo).filter((item) => Boolean(item)),
716
- ...recursosValidos.map((recurso) => recurso.arquivo).filter(Boolean),
717
- ...recursosDivergentes.map((recurso) => recurso.arquivo).filter(Boolean),
718
- ])].sort((a, b) => a.localeCompare(b, "pt-BR")),
1233
+ arquivosRelacionados,
1234
+ arquivosProvaveisEditar: arquivosRelacionados,
1235
+ consumerFramework,
1236
+ appRoutes,
1237
+ consumerSurfaces,
1238
+ consumerBridges,
719
1239
  checksSugeridos: [...new Set(tasks.flatMap((task) => task.checksSugeridos))],
720
1240
  lacunas: [...new Set(tasks.flatMap((task) => task.lacunas))],
721
1241
  tasks,
@@ -737,6 +1257,7 @@ function criarBriefingAgente(arquivo, modulo, ir, resumoDrift, resultadoDrift) {
737
1257
  ...(ir?.resumoAgente.riscos ?? []),
738
1258
  ])],
739
1259
  oQueTocar: resumoDrift.arquivosRelacionados,
1260
+ arquivosProvaveisEditar: resumoDrift.arquivosProvaveisEditar,
740
1261
  oQueValidar: [...new Set([
741
1262
  ...resumoDrift.checksSugeridos,
742
1263
  ...resultadoDrift.resumo_operacional.oQueValidar,
@@ -764,20 +1285,20 @@ function criarBriefingAgente(arquivo, modulo, ir, resumoDrift, resultadoDrift) {
764
1285
  ...(ir?.routes.map((route) => `${route.metodo ?? "?"} ${route.caminho ?? route.nome}`) ?? []),
765
1286
  ...(ir?.superficies.map((superficie) => `${superficie.tipo}:${superficie.nome}`) ?? []),
766
1287
  ],
1288
+ consumerFramework: resumoDrift.consumerFramework,
1289
+ appRoutes: resumoDrift.appRoutes,
1290
+ consumerSurfaces: resumoDrift.consumerSurfaces,
1291
+ consumerBridges: resumoDrift.consumerBridges,
767
1292
  testesMinimos: [
768
1293
  "sema validar <arquivo> --json",
769
1294
  "sema drift <arquivo> --json",
770
- "sema verificar exemplos --json",
1295
+ "sema verificar <arquivo-ou-pasta> --json",
771
1296
  ],
772
1297
  };
773
1298
  }
774
- async function gerarContextoIa(arquivoEntrada, pastaSaidaOpcional) {
1299
+ async function carregarContextoModuloIa(arquivoEntrada) {
775
1300
  const arquivo = path.resolve(arquivoEntrada);
776
1301
  garantirArquivoSema(arquivo);
777
- const pastaBase = pastaSaidaOpcional
778
- ? path.resolve(pastaSaidaOpcional)
779
- : path.resolve(process.cwd(), ".tmp", "contexto-ia", path.basename(arquivo, ".sema"));
780
- await mkdir(pastaBase, { recursive: true });
781
1302
  const contextoProjeto = await carregarProjeto(arquivo, process.cwd());
782
1303
  const resultadoModulo = contextoProjeto.modulosSelecionados.find((item) => path.resolve(item.caminho) === arquivo)?.resultado;
783
1304
  if (!resultadoModulo) {
@@ -785,6 +1306,7 @@ async function gerarContextoIa(arquivoEntrada, pastaSaidaOpcional) {
785
1306
  }
786
1307
  const sucesso = !temErros(resultadoModulo.diagnosticos);
787
1308
  const modulo = resultadoModulo.modulo?.nome ?? path.basename(arquivo, ".sema");
1309
+ const geradoEm = new Date().toISOString();
788
1310
  const resultadoDrift = await analisarDriftLegado(contextoProjeto);
789
1311
  const drift = {
790
1312
  comando: "drift",
@@ -829,21 +1351,146 @@ async function gerarContextoIa(arquivoEntrada, pastaSaidaOpcional) {
829
1351
  ir: resultadoModulo.ir ?? null,
830
1352
  };
831
1353
  const briefing = criarBriefingAgente(arquivo, modulo, resultadoModulo.ir ?? null, drift.resumo, resultadoDrift);
832
- await writeFile(path.join(pastaBase, "validar.json"), `${JSON.stringify(validar, null, 2)}\n`, "utf8");
833
- await writeFile(path.join(pastaBase, "diagnosticos.json"), `${JSON.stringify(diagnosticos, null, 2)}\n`, "utf8");
834
- await writeFile(path.join(pastaBase, "ast.json"), `${JSON.stringify(ast, null, 2)}\n`, "utf8");
835
- await writeFile(path.join(pastaBase, "ir.json"), `${JSON.stringify(ir, null, 2)}\n`, "utf8");
836
- await writeFile(path.join(pastaBase, "drift.json"), `${JSON.stringify(drift, null, 2)}\n`, "utf8");
837
- await writeFile(path.join(pastaBase, "briefing.json"), `${JSON.stringify(briefing, null, 2)}\n`, "utf8");
838
- const resumo = `# Contexto de IA para ${modulo}
839
-
840
- - Arquivo alvo: \`${arquivo}\`
841
- - Modulo: \`${modulo}\`
842
- - Sucesso em validar: \`${sucesso}\`
843
- - Quantidade de diagnosticos: \`${resultadoModulo.diagnosticos.length}\`
1354
+ return {
1355
+ arquivo,
1356
+ modulo,
1357
+ sucesso,
1358
+ geradoEm,
1359
+ diagnosticos: resultadoModulo.diagnosticos,
1360
+ ir: resultadoModulo.ir ?? null,
1361
+ validar,
1362
+ diagnosticosJson: diagnosticos,
1363
+ ast,
1364
+ irJson: ir,
1365
+ drift,
1366
+ briefing,
1367
+ };
1368
+ }
1369
+ async function gerarArquivosResumoModuloIa(contexto, pastaBase) {
1370
+ const guiaPorCapacidade = criarGuiaCapacidadeIa();
1371
+ const resumoSemantico = coletarResumoSemanticoModulo(contexto);
1372
+ const resumoMicro = renderizarResumoModuloTexto(resumoSemantico, "micro", "resumo");
1373
+ const resumoCurto = renderizarResumoModuloTexto(resumoSemantico, "curto", "resumo");
1374
+ const resumoMarkdown = renderizarResumoModuloMarkdown(resumoSemantico, "resumo", guiaPorCapacidade);
1375
+ const briefingMinimo = criarBriefingMinimo(resumoSemantico, "resumo", "curto");
1376
+ const promptCurto = criarPromptCurtoModulo(resumoSemantico, "mudanca", "curto", "pequena");
1377
+ await writeFile(path.join(pastaBase, "resumo.micro.txt"), resumoMicro, "utf8");
1378
+ await writeFile(path.join(pastaBase, "resumo.curto.txt"), resumoCurto, "utf8");
1379
+ await writeFile(path.join(pastaBase, "resumo.md"), resumoMarkdown, "utf8");
1380
+ await writeFile(path.join(pastaBase, "briefing.min.json"), `${JSON.stringify(briefingMinimo, null, 2)}\n`, "utf8");
1381
+ await writeFile(path.join(pastaBase, "prompt-curto.txt"), promptCurto, "utf8");
1382
+ return {
1383
+ artefatosCompactos: ["resumo.micro.txt", "resumo.curto.txt", "resumo.md", "briefing.min.json", "prompt-curto.txt"],
1384
+ guiaPorCapacidade,
1385
+ };
1386
+ }
1387
+ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz = false) {
1388
+ const contextoProjeto = await carregarProjeto(entrada, process.cwd());
1389
+ const geradoEm = new Date().toISOString();
1390
+ const guiaPorCapacidade = criarGuiaCapacidadeIa();
1391
+ const entradaCanonica = criarEntradaCanonicaProjeto(guiaPorCapacidade);
1392
+ const resultadoDrift = await analisarDriftLegado(contextoProjeto);
1393
+ const modulos = contextoProjeto.modulosSelecionados.map((item) => {
1394
+ const modulo = item.resultado.modulo?.nome ?? path.basename(item.caminho, ".sema");
1395
+ const driftResumo = resumirDriftPorModulo(modulo, item.caminho, resultadoDrift);
1396
+ const briefing = criarBriefingAgente(item.caminho, modulo, item.resultado.ir ?? null, driftResumo, resultadoDrift);
1397
+ return coletarResumoSemanticoModulo({
1398
+ arquivo: item.caminho,
1399
+ modulo,
1400
+ geradoEm,
1401
+ ir: item.resultado.ir ?? null,
1402
+ briefing,
1403
+ drift: {
1404
+ comando: "drift",
1405
+ caminho: item.caminho,
1406
+ modulo,
1407
+ sucesso: resultadoDrift.sucesso,
1408
+ resumo: driftResumo,
1409
+ drift: resultadoDrift,
1410
+ },
1411
+ });
1412
+ });
1413
+ const baseProjeto = contextoProjeto.baseProjeto;
1414
+ const pastaSaida = escreverNaRaiz
1415
+ ? baseProjeto
1416
+ : pastaSaidaOpcional
1417
+ ? path.resolve(pastaSaidaOpcional)
1418
+ : path.resolve(baseProjeto, ".tmp", "sema-resumo");
1419
+ await mkdir(pastaSaida, { recursive: true });
1420
+ const semaBrief = renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade);
1421
+ const indexJson = {
1422
+ comando: "resumo-projeto",
1423
+ geradoEm,
1424
+ cliVersao: VERSAO_CLI,
1425
+ baseProjeto,
1426
+ totalModulos: modulos.length,
1427
+ entradaCanonica,
1428
+ guiaPorCapacidade,
1429
+ modulos,
1430
+ };
1431
+ const micro = [
1432
+ `PROJETO: ${path.basename(baseProjeto)}`,
1433
+ `MODULOS: ${modulos.length}`,
1434
+ `ENTRADA_IA: ${entradaCanonica.porCapacidade.pequena.join(" -> ")}`,
1435
+ `TOP_MODULOS: ${resumirListaTexto(modulos.map((modulo) => modulo.modulo), 3)}`,
1436
+ `TOP_RISCOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.riscosPrincipais)), 3)}`,
1437
+ `TOP_LACUNAS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.lacunas)), 3)}`,
1438
+ `GERADO_EM: ${geradoEm}`,
1439
+ "",
1440
+ ].join("\n");
1441
+ const curto = [
1442
+ `PROJETO: ${path.basename(baseProjeto)}`,
1443
+ `BASE: ${baseProjeto}`,
1444
+ `MODULOS: ${modulos.length}`,
1445
+ `ENTRADA_IA: ${entradaCanonica.porCapacidade.media.join(" -> ")}`,
1446
+ `TOP_MODULOS: ${resumirListaTexto(modulos.map((modulo) => modulo.modulo), 6)}`,
1447
+ `TOP_RISCOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.riscosPrincipais)), 6)}`,
1448
+ `TOP_LACUNAS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.lacunas)), 6)}`,
1449
+ `TOP_ARQUIVOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.arquivosProvaveis)), 6)}`,
1450
+ `GERADO_EM: ${geradoEm}`,
1451
+ "",
1452
+ ].join("\n");
1453
+ await writeFile(path.join(pastaSaida, "SEMA_BRIEF.md"), semaBrief, "utf8");
1454
+ await writeFile(path.join(pastaSaida, "SEMA_BRIEF.micro.txt"), micro, "utf8");
1455
+ await writeFile(path.join(pastaSaida, "SEMA_BRIEF.curto.txt"), curto, "utf8");
1456
+ await writeFile(path.join(pastaSaida, "SEMA_INDEX.json"), `${JSON.stringify(indexJson, null, 2)}\n`, "utf8");
1457
+ return {
1458
+ geradoEm,
1459
+ baseProjeto,
1460
+ pastaSaida,
1461
+ artefatos: ["SEMA_BRIEF.md", "SEMA_BRIEF.micro.txt", "SEMA_BRIEF.curto.txt", "SEMA_INDEX.json"],
1462
+ modulos,
1463
+ guiaPorCapacidade,
1464
+ };
1465
+ }
1466
+ async function gerarContextoIa(arquivoEntrada, pastaSaidaOpcional) {
1467
+ const contexto = await carregarContextoModuloIa(arquivoEntrada);
1468
+ const pastaBase = pastaSaidaOpcional
1469
+ ? path.resolve(pastaSaidaOpcional)
1470
+ : path.resolve(process.cwd(), ".tmp", "contexto-ia", path.basename(contexto.arquivo, ".sema"));
1471
+ await mkdir(pastaBase, { recursive: true });
1472
+ await writeFile(path.join(pastaBase, "validar.json"), `${JSON.stringify(contexto.validar, null, 2)}\n`, "utf8");
1473
+ await writeFile(path.join(pastaBase, "diagnosticos.json"), `${JSON.stringify(contexto.diagnosticosJson, null, 2)}\n`, "utf8");
1474
+ await writeFile(path.join(pastaBase, "ast.json"), `${JSON.stringify(contexto.ast, null, 2)}\n`, "utf8");
1475
+ await writeFile(path.join(pastaBase, "ir.json"), `${JSON.stringify(contexto.irJson, null, 2)}\n`, "utf8");
1476
+ await writeFile(path.join(pastaBase, "drift.json"), `${JSON.stringify(contexto.drift, null, 2)}\n`, "utf8");
1477
+ await writeFile(path.join(pastaBase, "briefing.json"), `${JSON.stringify(contexto.briefing, null, 2)}\n`, "utf8");
1478
+ const resumoGerado = await gerarArquivosResumoModuloIa(contexto, pastaBase);
1479
+ const resumo = `# Contexto de IA para ${contexto.modulo}
1480
+
1481
+ - Arquivo alvo: \`${contexto.arquivo}\`
1482
+ - Modulo: \`${contexto.modulo}\`
1483
+ - Sucesso em validar: \`${contexto.sucesso}\`
1484
+ - Quantidade de diagnosticos: \`${contexto.diagnosticos.length}\`
1485
+ - Gerado em: \`${contexto.geradoEm}\`
844
1486
 
845
1487
  ## Arquivos gerados neste pacote
846
1488
 
1489
+ - \`resumo.micro.txt\`
1490
+ - \`resumo.curto.txt\`
1491
+ - \`resumo.md\`
1492
+ - \`briefing.min.json\`
1493
+ - \`prompt-curto.txt\`
847
1494
  - \`validar.json\`
848
1495
  - \`diagnosticos.json\`
849
1496
  - \`ast.json\`
@@ -853,28 +1500,61 @@ async function gerarContextoIa(arquivoEntrada, pastaSaidaOpcional) {
853
1500
 
854
1501
  ## Fluxo recomendado para o agente
855
1502
 
856
- 1. Ler \`ast.json\` para entender a forma escrita.
857
- 2. Ler \`ir.json\` para entender a forma semantica resolvida.
858
- 3. Ler \`drift.json\` para ver quais arquivos e simbolos vivos sustentam a implementacao.
859
- 4. Ler \`briefing.json\` para saber o que tocar, o que validar e o que esta frouxo.
860
- 5. Ler \`diagnosticos.json\` se houver falha ou aviso relevante.
861
- 6. Editar o arquivo \`.sema\`.
862
- 7. Rodar \`sema formatar "${arquivo}"\`.
863
- 8. Rodar \`sema validar "${arquivo}" --json\`.
864
- 9. Fechar com \`sema verificar exemplos --json --saida ./.tmp/verificacao-ia\` ou \`npm run project:check\`.
1503
+ ### IA pequena ou gratuita
1504
+
1505
+ 1. Ler \`resumo.micro.txt\`.
1506
+ 2. Ler \`briefing.min.json\`.
1507
+ 3. Se ainda couber contexto, ler \`resumo.curto.txt\`.
1508
+
1509
+ ### IA media
1510
+
1511
+ 1. Ler \`resumo.curto.txt\`.
1512
+ 2. Ler \`briefing.min.json\`.
1513
+ 3. Ler \`drift.json\`.
1514
+ 4. Se precisar, subir para \`resumo.md\`.
1515
+
1516
+ ### IA grande ou com tool use
1517
+
1518
+ 1. Ler \`README.md\`.
1519
+ 2. Ler \`resumo.md\`.
1520
+ 3. Ler \`briefing.json\`.
1521
+ 4. Ler \`drift.json\`.
1522
+ 5. So depois abrir \`ir.json\` e \`ast.json\`.
1523
+
1524
+ ## Fechamento
1525
+
1526
+ 1. Editar o arquivo \`.sema\`.
1527
+ 2. Rodar \`sema formatar "${contexto.arquivo}"\`.
1528
+ 3. Rodar \`sema validar "${contexto.arquivo}" --json\`.
1529
+ 4. Rodar \`sema drift "${contexto.arquivo}" --json\`.
1530
+ 5. Fechar com \`sema verificar <arquivo-ou-pasta> --json --saida ./.tmp/verificacao-ia\`.
865
1531
 
866
1532
  ## Textos base para onboarding do agente
867
1533
 
868
1534
  - \`sema starter-ia\`
1535
+ - \`sema resumo "${contexto.arquivo}" --micro --para onboarding\`
1536
+ - \`sema prompt-curto "${contexto.arquivo}" --para mudanca\`
869
1537
  - \`sema prompt-ia\`
870
1538
  `;
871
1539
  await writeFile(path.join(pastaBase, "README.md"), resumo, "utf8");
872
1540
  return {
873
- sucesso: true,
874
- arquivo,
875
- modulo,
1541
+ sucesso: contexto.sucesso,
1542
+ arquivo: contexto.arquivo,
1543
+ modulo: contexto.modulo,
876
1544
  pastaSaida: pastaBase,
877
- artefatos: ["validar.json", "diagnosticos.json", "ast.json", "ir.json", "drift.json", "briefing.json", "README.md"],
1545
+ artefatos: [
1546
+ "validar.json",
1547
+ "diagnosticos.json",
1548
+ "ast.json",
1549
+ "ir.json",
1550
+ "drift.json",
1551
+ "briefing.json",
1552
+ "README.md",
1553
+ ...resumoGerado.artefatosCompactos,
1554
+ ],
1555
+ artefatosCompactos: resumoGerado.artefatosCompactos,
1556
+ geradoEm: contexto.geradoEm,
1557
+ guiaPorCapacidade: resumoGerado.guiaPorCapacidade,
878
1558
  };
879
1559
  }
880
1560
  async function comandoIniciar(cwd, template) {
@@ -1044,6 +1724,596 @@ async function comandoIniciar(cwd, template) {
1044
1724
  - Contratos em \`contratos/\`
1045
1725
  - Handlers App Router em \`src/app/api/\`
1046
1726
  - Rota de exemplo validada por \`drift\`
1727
+ `,
1728
+ },
1729
+ ];
1730
+ }
1731
+ else if (template === "nextjs-consumer") {
1732
+ arquivos = [
1733
+ {
1734
+ caminhoRelativo: "sema.config.json",
1735
+ conteudo: `{
1736
+ "origens": ["./contratos"],
1737
+ "saida": "./generated",
1738
+ "alvos": ["typescript"],
1739
+ "alvoPadrao": "typescript",
1740
+ "estruturaSaida": "modulos",
1741
+ "framework": "base",
1742
+ "modoEstrito": true,
1743
+ "diretoriosCodigo": ["./src"],
1744
+ "fontesLegado": ["nextjs-consumer", "typescript"],
1745
+ "diretoriosSaidaPorAlvo": {
1746
+ "typescript": "./generated/typescript"
1747
+ },
1748
+ "convencoesGeracaoPorProjeto": "base"
1749
+ }
1750
+ `,
1751
+ },
1752
+ {
1753
+ caminhoRelativo: "contratos/showroom_consumer.sema",
1754
+ conteudo: `module showroom.consumer {
1755
+ task fetch_showroom_ranking {
1756
+ input {
1757
+ }
1758
+ output {
1759
+ ranking: Json
1760
+ }
1761
+ impl {
1762
+ ts: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1763
+ }
1764
+ vinculos {
1765
+ arquivo: "src/lib/sema_consumer_bridge.ts"
1766
+ simbolo: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1767
+ superficie: "/ranking"
1768
+ arquivo: "src/app/ranking/page.tsx"
1769
+ arquivo: "src/app/ranking/loading.tsx"
1770
+ arquivo: "src/app/ranking/error.tsx"
1771
+ }
1772
+ guarantees {
1773
+ ranking existe
1774
+ }
1775
+ }
1776
+ }
1777
+ `,
1778
+ },
1779
+ {
1780
+ caminhoRelativo: "src/lib/sema_consumer_bridge.ts",
1781
+ conteudo: `export async function semaFetchShowroomRanking() {
1782
+ return {
1783
+ ranking: [
1784
+ { clube: "Tigres do Norte", pontos: 33 },
1785
+ { clube: "Porto Azul", pontos: 31 },
1786
+ { clube: "Galo de Ouro", pontos: 28 },
1787
+ ],
1788
+ };
1789
+ }
1790
+ `,
1791
+ },
1792
+ {
1793
+ caminhoRelativo: "src/app/ranking/page.tsx",
1794
+ conteudo: `import { semaFetchShowroomRanking } from "../../lib/sema_consumer_bridge";
1795
+
1796
+ export default async function RankingPage() {
1797
+ const { ranking } = await semaFetchShowroomRanking();
1798
+
1799
+ return (
1800
+ <main>
1801
+ <h1>Ranking showroom</h1>
1802
+ <ul>
1803
+ {ranking.map((item) => (
1804
+ <li key={item.clube}>
1805
+ {item.clube} - {item.pontos} pts
1806
+ </li>
1807
+ ))}
1808
+ </ul>
1809
+ </main>
1810
+ );
1811
+ }
1812
+ `,
1813
+ },
1814
+ {
1815
+ caminhoRelativo: "src/app/ranking/loading.tsx",
1816
+ conteudo: `export default function Loading() {
1817
+ return <p>Carregando ranking...</p>;
1818
+ }
1819
+ `,
1820
+ },
1821
+ {
1822
+ caminhoRelativo: "src/app/ranking/error.tsx",
1823
+ conteudo: `"use client";
1824
+
1825
+ export default function Error({
1826
+ error,
1827
+ reset,
1828
+ }: {
1829
+ error: Error;
1830
+ reset: () => void;
1831
+ }) {
1832
+ return (
1833
+ <main>
1834
+ <h1>Falha ao carregar ranking</h1>
1835
+ <p>{error.message}</p>
1836
+ <button type="button" onClick={reset}>Tentar novamente</button>
1837
+ </main>
1838
+ );
1839
+ }
1840
+ `,
1841
+ },
1842
+ {
1843
+ caminhoRelativo: "README.md",
1844
+ conteudo: `# Starter Next.js Consumer + Sema
1845
+
1846
+ - Contratos em \`contratos/\`
1847
+ - Bridge consumer canonico em \`src/lib/sema_consumer_bridge.ts\`
1848
+ - Superficies App Router em \`src/app/\`
1849
+ - O slice oficial desta fase e \`consumer bridge + App Router surfaces\`
1850
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual drift
1851
+ `,
1852
+ },
1853
+ ];
1854
+ }
1855
+ else if (template === "react-vite-consumer") {
1856
+ arquivos = [
1857
+ {
1858
+ caminhoRelativo: "sema.config.json",
1859
+ conteudo: `{
1860
+ "origens": ["./contratos"],
1861
+ "saida": "./generated",
1862
+ "alvos": ["typescript"],
1863
+ "alvoPadrao": "typescript",
1864
+ "estruturaSaida": "modulos",
1865
+ "framework": "base",
1866
+ "modoEstrito": true,
1867
+ "diretoriosCodigo": ["./src"],
1868
+ "fontesLegado": ["react-vite-consumer", "typescript"],
1869
+ "diretoriosSaidaPorAlvo": {
1870
+ "typescript": "./generated/typescript"
1871
+ },
1872
+ "convencoesGeracaoPorProjeto": "base"
1873
+ }
1874
+ `,
1875
+ },
1876
+ {
1877
+ caminhoRelativo: "contratos/showroom_consumer.sema",
1878
+ conteudo: `module showroom.consumer {
1879
+ task fetch_showroom_ranking {
1880
+ input {
1881
+ }
1882
+ output {
1883
+ ranking: Json
1884
+ }
1885
+ impl {
1886
+ ts: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1887
+ }
1888
+ vinculos {
1889
+ arquivo: "src/lib/sema_consumer_bridge.ts"
1890
+ simbolo: src.lib.sema_consumer_bridge.semaFetchShowroomRanking
1891
+ superficie: "/ranking"
1892
+ arquivo: "src/router.tsx"
1893
+ arquivo: "src/pages/ranking.tsx"
1894
+ }
1895
+ guarantees {
1896
+ ranking existe
1897
+ }
1898
+ }
1899
+ }
1900
+ `,
1901
+ },
1902
+ {
1903
+ caminhoRelativo: "src/lib/sema_consumer_bridge.ts",
1904
+ conteudo: `export async function semaFetchShowroomRanking() {
1905
+ return {
1906
+ ranking: [
1907
+ { clube: "Tigres do Norte", pontos: 33 },
1908
+ { clube: "Porto Azul", pontos: 31 },
1909
+ { clube: "Galo de Ouro", pontos: 28 },
1910
+ ],
1911
+ };
1912
+ }
1913
+ `,
1914
+ },
1915
+ {
1916
+ caminhoRelativo: "src/pages/ranking.tsx",
1917
+ conteudo: `import { useEffect, useState } from "react";
1918
+ import { semaFetchShowroomRanking } from "../lib/sema_consumer_bridge";
1919
+
1920
+ export function RankingPage() {
1921
+ const [ranking, setRanking] = useState<Array<{ clube: string; pontos: number }>>([]);
1922
+
1923
+ useEffect(() => {
1924
+ void semaFetchShowroomRanking().then((payload) => setRanking(payload.ranking ?? []));
1925
+ }, []);
1926
+
1927
+ return (
1928
+ <main>
1929
+ <h1>Ranking showroom</h1>
1930
+ <ul>
1931
+ {ranking.map((item) => (
1932
+ <li key={item.clube}>
1933
+ {item.clube} - {item.pontos} pts
1934
+ </li>
1935
+ ))}
1936
+ </ul>
1937
+ </main>
1938
+ );
1939
+ }
1940
+ `,
1941
+ },
1942
+ {
1943
+ caminhoRelativo: "src/router.tsx",
1944
+ conteudo: `import { createBrowserRouter } from "react-router-dom";
1945
+ import { RankingPage } from "./pages/ranking";
1946
+
1947
+ export const appRouter = createBrowserRouter([
1948
+ {
1949
+ path: "/ranking",
1950
+ Component: RankingPage,
1951
+ },
1952
+ ]);
1953
+ `,
1954
+ },
1955
+ {
1956
+ caminhoRelativo: "src/App.tsx",
1957
+ conteudo: `import { RouterProvider } from "react-router-dom";
1958
+ import { appRouter } from "./router";
1959
+
1960
+ export default function App() {
1961
+ return <RouterProvider router={appRouter} />;
1962
+ }
1963
+ `,
1964
+ },
1965
+ {
1966
+ caminhoRelativo: "src/main.tsx",
1967
+ conteudo: `import React from "react";
1968
+ import ReactDOM from "react-dom/client";
1969
+ import App from "./App";
1970
+
1971
+ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
1972
+ <React.StrictMode>
1973
+ <App />
1974
+ </React.StrictMode>,
1975
+ );
1976
+ `,
1977
+ },
1978
+ {
1979
+ caminhoRelativo: "README.md",
1980
+ conteudo: `# Starter React Vite Consumer + Sema
1981
+
1982
+ - Contratos em \`contratos/\`
1983
+ - Bridge consumer canonico em \`src/lib/sema_consumer_bridge.ts\`
1984
+ - Rotas explicitas em \`src/router.tsx\`
1985
+ - Superficies consumer em \`src/pages/\`
1986
+ - O slice oficial desta fase e \`consumer bridge + react-router surfaces\`
1987
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual drift
1988
+ `,
1989
+ },
1990
+ ];
1991
+ }
1992
+ else if (template === "angular-consumer") {
1993
+ arquivos = [
1994
+ {
1995
+ caminhoRelativo: "sema.config.json",
1996
+ conteudo: `{
1997
+ "origens": ["./contratos"],
1998
+ "saida": "./generated",
1999
+ "alvos": ["typescript"],
2000
+ "alvoPadrao": "typescript",
2001
+ "estruturaSaida": "modulos",
2002
+ "framework": "base",
2003
+ "modoEstrito": true,
2004
+ "diretoriosCodigo": ["./src"],
2005
+ "fontesLegado": ["angular-consumer", "typescript"],
2006
+ "diretoriosSaidaPorAlvo": {
2007
+ "typescript": "./generated/typescript"
2008
+ },
2009
+ "convencoesGeracaoPorProjeto": "base"
2010
+ }
2011
+ `,
2012
+ },
2013
+ {
2014
+ caminhoRelativo: "contratos/showroom_consumer.sema",
2015
+ conteudo: `module showroom.consumer {
2016
+ task fetch_showroom_ranking {
2017
+ input {
2018
+ }
2019
+ output {
2020
+ ranking: Json
2021
+ }
2022
+ impl {
2023
+ ts: src.app.sema_consumer_bridge.semaFetchShowroomRanking
2024
+ }
2025
+ vinculos {
2026
+ arquivo: "src/app/sema_consumer_bridge.ts"
2027
+ simbolo: src.app.sema_consumer_bridge.semaFetchShowroomRanking
2028
+ superficie: "/ranking"
2029
+ arquivo: "src/app/app.routes.ts"
2030
+ arquivo: "src/app/features/ranking/ranking.routes.ts"
2031
+ arquivo: "src/app/features/ranking/ranking-page.component.ts"
2032
+ }
2033
+ guarantees {
2034
+ ranking existe
2035
+ }
2036
+ }
2037
+ }
2038
+ `,
2039
+ },
2040
+ {
2041
+ caminhoRelativo: "src/app/sema_consumer_bridge.ts",
2042
+ conteudo: `export async function semaFetchShowroomRanking() {
2043
+ return {
2044
+ ranking: [
2045
+ { clube: "Tigres do Norte", pontos: 33 },
2046
+ { clube: "Porto Azul", pontos: 31 },
2047
+ { clube: "Galo de Ouro", pontos: 28 },
2048
+ ],
2049
+ };
2050
+ }
2051
+ `,
2052
+ },
2053
+ {
2054
+ caminhoRelativo: "src/app/app.routes.ts",
2055
+ conteudo: `import { Routes } from "@angular/router";
2056
+
2057
+ export const routes: Routes = [
2058
+ {
2059
+ path: "ranking",
2060
+ loadChildren: () => import("./features/ranking/ranking.routes").then((m) => m.RANKING_ROUTES),
2061
+ },
2062
+ ];
2063
+ `,
2064
+ },
2065
+ {
2066
+ caminhoRelativo: "src/app/features/ranking/ranking.routes.ts",
2067
+ conteudo: `import { Routes } from "@angular/router";
2068
+
2069
+ export const RANKING_ROUTES: Routes = [
2070
+ {
2071
+ path: "",
2072
+ loadComponent: () => import("./ranking-page.component").then((m) => m.RankingPageComponent),
2073
+ },
2074
+ ];
2075
+ `,
2076
+ },
2077
+ {
2078
+ caminhoRelativo: "src/app/features/ranking/ranking-page.component.ts",
2079
+ conteudo: `import { Component, OnInit } from "@angular/core";
2080
+ import { CommonModule } from "@angular/common";
2081
+ import { semaFetchShowroomRanking } from "../../sema_consumer_bridge";
2082
+
2083
+ @Component({
2084
+ selector: "app-ranking-page",
2085
+ standalone: true,
2086
+ imports: [CommonModule],
2087
+ template: \`
2088
+ <main>
2089
+ <h1>Ranking showroom</h1>
2090
+ <ul>
2091
+ <li *ngFor="let item of ranking">
2092
+ {{ item.clube }} - {{ item.pontos }} pts
2093
+ </li>
2094
+ </ul>
2095
+ </main>
2096
+ \`,
2097
+ })
2098
+ export class RankingPageComponent implements OnInit {
2099
+ ranking: Array<{ clube: string; pontos: number }> = [];
2100
+
2101
+ async ngOnInit() {
2102
+ const payload = await semaFetchShowroomRanking();
2103
+ this.ranking = payload.ranking ?? [];
2104
+ }
2105
+ }
2106
+ `,
2107
+ },
2108
+ {
2109
+ caminhoRelativo: "src/app/app.component.ts",
2110
+ conteudo: `import { Component } from "@angular/core";
2111
+ import { RouterOutlet } from "@angular/router";
2112
+
2113
+ @Component({
2114
+ selector: "app-root",
2115
+ standalone: true,
2116
+ imports: [RouterOutlet],
2117
+ template: "<router-outlet />",
2118
+ })
2119
+ export class AppComponent {}
2120
+ `,
2121
+ },
2122
+ {
2123
+ caminhoRelativo: "src/main.ts",
2124
+ conteudo: `import { bootstrapApplication } from "@angular/platform-browser";
2125
+ import { provideRouter } from "@angular/router";
2126
+ import { AppComponent } from "./app/app.component";
2127
+ import { routes } from "./app/app.routes";
2128
+
2129
+ void bootstrapApplication(AppComponent, {
2130
+ providers: [provideRouter(routes)],
2131
+ });
2132
+ `,
2133
+ },
2134
+ {
2135
+ caminhoRelativo: "README.md",
2136
+ conteudo: `# Starter Angular Consumer + Sema
2137
+
2138
+ - Contratos em \`contratos/\`
2139
+ - Bridge consumer canonico em \`src/app/sema_consumer_bridge.ts\`
2140
+ - Rotas lazy em \`src/app/app.routes.ts\`
2141
+ - Feature folders em \`src/app/features/\`
2142
+ - O slice oficial desta fase e \`consumer bridge + route config surfaces\`
2143
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual drift
2144
+ `,
2145
+ },
2146
+ ];
2147
+ }
2148
+ else if (template === "flutter-consumer") {
2149
+ arquivos = [
2150
+ {
2151
+ caminhoRelativo: "sema.config.json",
2152
+ conteudo: `{
2153
+ "origens": ["./contratos"],
2154
+ "saida": "./generated",
2155
+ "alvos": ["dart"],
2156
+ "alvoPadrao": "dart",
2157
+ "estruturaSaida": "modulos",
2158
+ "framework": "base",
2159
+ "modoEstrito": true,
2160
+ "diretoriosCodigo": ["./lib"],
2161
+ "fontesLegado": ["flutter-consumer", "dart"],
2162
+ "diretoriosSaidaPorAlvo": {
2163
+ "dart": "./generated/dart"
2164
+ },
2165
+ "convencoesGeracaoPorProjeto": "base"
2166
+ }
2167
+ `,
2168
+ },
2169
+ {
2170
+ caminhoRelativo: "pubspec.yaml",
2171
+ conteudo: `name: sema_flutter_consumer
2172
+ description: Starter Flutter consumer IA-first com Sema
2173
+ publish_to: "none"
2174
+
2175
+ environment:
2176
+ sdk: ">=3.3.0 <4.0.0"
2177
+
2178
+ dependencies:
2179
+ flutter:
2180
+ sdk: flutter
2181
+ go_router: ^14.0.0
2182
+ `,
2183
+ },
2184
+ {
2185
+ caminhoRelativo: "contratos/showroom_consumer.sema",
2186
+ conteudo: `module showroom.consumer {
2187
+ task fetch_showroom_ranking {
2188
+ input {
2189
+ }
2190
+ output {
2191
+ resultado: Json
2192
+ }
2193
+ impl {
2194
+ dart: lib.sema_consumer_bridge.semaFetchShowroomRanking
2195
+ }
2196
+ vinculos {
2197
+ arquivo: "lib/sema_consumer_bridge.dart"
2198
+ simbolo: lib.sema_consumer_bridge.semaFetchShowroomRanking
2199
+ superficie: "/ranking"
2200
+ arquivo: "lib/router.dart"
2201
+ arquivo: "lib/screens/ranking_screen.dart"
2202
+ }
2203
+ guarantees {
2204
+ resultado existe
2205
+ }
2206
+ }
2207
+ }
2208
+ `,
2209
+ },
2210
+ {
2211
+ caminhoRelativo: "lib/sema_consumer_bridge.dart",
2212
+ conteudo: `Future<Map<String, dynamic>> semaFetchShowroomRanking() async {
2213
+ return {
2214
+ "ranking": [
2215
+ {"clube": "Tigres do Norte", "pontos": 33},
2216
+ {"clube": "Porto Azul", "pontos": 31},
2217
+ {"clube": "Galo de Ouro", "pontos": 28},
2218
+ ],
2219
+ };
2220
+ }
2221
+ `,
2222
+ },
2223
+ {
2224
+ caminhoRelativo: "lib/router.dart",
2225
+ conteudo: `import "package:go_router/go_router.dart";
2226
+ import "package:flutter/widgets.dart";
2227
+ import "screens/ranking_screen.dart";
2228
+
2229
+ final appRouter = GoRouter(
2230
+ routes: [
2231
+ GoRoute(
2232
+ path: "/ranking",
2233
+ builder: (BuildContext context, GoRouterState state) => const RankingScreen(),
2234
+ ),
2235
+ ],
2236
+ );
2237
+ `,
2238
+ },
2239
+ {
2240
+ caminhoRelativo: "lib/screens/ranking_screen.dart",
2241
+ conteudo: `import "package:flutter/widgets.dart";
2242
+ import "../sema_consumer_bridge.dart";
2243
+
2244
+ class RankingScreen extends StatefulWidget {
2245
+ const RankingScreen({super.key});
2246
+
2247
+ @override
2248
+ State<RankingScreen> createState() => _RankingScreenState();
2249
+ }
2250
+
2251
+ class _RankingScreenState extends State<RankingScreen> {
2252
+ List<Map<String, dynamic>> ranking = const [];
2253
+
2254
+ @override
2255
+ void initState() {
2256
+ super.initState();
2257
+ semaFetchShowroomRanking().then((payload) {
2258
+ final itens = (payload["ranking"] as List<dynamic>? ?? const [])
2259
+ .whereType<Map<String, dynamic>>()
2260
+ .toList();
2261
+ if (!mounted) return;
2262
+ setState(() {
2263
+ ranking = itens;
2264
+ });
2265
+ });
2266
+ }
2267
+
2268
+ @override
2269
+ Widget build(BuildContext context) {
2270
+ return ListView(
2271
+ children: [
2272
+ const Padding(
2273
+ padding: EdgeInsets.all(16),
2274
+ child: Text("Ranking showroom"),
2275
+ ),
2276
+ ...ranking.map((item) => Padding(
2277
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
2278
+ child: Text("\${item["clube"]} - \${item["pontos"]} pts"),
2279
+ )),
2280
+ ],
2281
+ );
2282
+ }
2283
+ }
2284
+ `,
2285
+ },
2286
+ {
2287
+ caminhoRelativo: "lib/main.dart",
2288
+ conteudo: `import "package:flutter/material.dart";
2289
+ import "router.dart";
2290
+
2291
+ void main() {
2292
+ runApp(const ShowroomApp());
2293
+ }
2294
+
2295
+ class ShowroomApp extends StatelessWidget {
2296
+ const ShowroomApp({super.key});
2297
+
2298
+ @override
2299
+ Widget build(BuildContext context) {
2300
+ return MaterialApp.router(
2301
+ routerConfig: appRouter,
2302
+ );
2303
+ }
2304
+ }
2305
+ `,
2306
+ },
2307
+ {
2308
+ caminhoRelativo: "README.md",
2309
+ conteudo: `# Starter Flutter Consumer + Sema
2310
+
2311
+ - Contratos em \`contratos/\`
2312
+ - Bridge consumer canonico em \`lib/sema_consumer_bridge.dart\`
2313
+ - Rotas consumer em \`lib/router.dart\`
2314
+ - Superficies consumer em \`lib/screens/\`
2315
+ - O slice oficial desta fase e \`consumer bridge + router/screen surfaces\`
2316
+ - \`drift\` valida \`impl\`, \`vinculos\`, bridge e superficies, sem prometer visual diff
1047
2317
  `,
1048
2318
  },
1049
2319
  ];
@@ -1602,6 +2872,10 @@ async function comandoInspecionar(entrada, emJson, cwd = process.cwd()) {
1602
2872
  modoAdocao: contextoProjeto.modoAdocao,
1603
2873
  scoreDrift: resultadoDrift.resumo_operacional.scoreMedio,
1604
2874
  confiancaGeral: resultadoDrift.resumo_operacional.confiancaGeral,
2875
+ consumerFramework: resultadoDrift.consumerFramework,
2876
+ appRoutes: resultadoDrift.appRoutes,
2877
+ consumerSurfaces: resultadoDrift.consumerSurfaces,
2878
+ consumerBridges: resultadoDrift.consumerBridges,
1605
2879
  },
1606
2880
  projeto: {
1607
2881
  arquivos: contextoProjeto.arquivosProjeto,
@@ -1936,44 +3210,80 @@ async function comandoStarterIa() {
1936
3210
  console.log(STARTER_IA);
1937
3211
  return 0;
1938
3212
  }
3213
+ async function comandoSyncAiEntrypoints(emJson) {
3214
+ const resumoProjeto = await gerarResumoProjetoIa(process.cwd(), undefined, true);
3215
+ const indexJson = JSON.parse(await readFile(path.join(resumoProjeto.pastaSaida, "SEMA_INDEX.json"), "utf8"));
3216
+ const artefatos = [...new Set([
3217
+ ...ARQUIVOS_CANONICOS_IA_RAIZ,
3218
+ ...resumoProjeto.artefatos,
3219
+ ])];
3220
+ if (emJson) {
3221
+ console.log(JSON.stringify({
3222
+ comando: "sync-ai-entrypoints",
3223
+ sucesso: true,
3224
+ baseProjeto: resumoProjeto.baseProjeto,
3225
+ pastaSaida: resumoProjeto.pastaSaida,
3226
+ artefatos,
3227
+ entradaCanonica: indexJson.entradaCanonica,
3228
+ }, null, 2));
3229
+ return 0;
3230
+ }
3231
+ console.log("Entrypoints IA-first sincronizados");
3232
+ console.log("");
3233
+ console.log(`Base do projeto: ${resumoProjeto.baseProjeto}`);
3234
+ console.log(`Ordem canonica: ${indexJson.entradaCanonica.ordemLeitura.join(" -> ")}`);
3235
+ console.log(`IA pequena: ${indexJson.entradaCanonica.porCapacidade.pequena.join(" -> ")}`);
3236
+ console.log(`IA media: ${indexJson.entradaCanonica.porCapacidade.media.join(" -> ")}`);
3237
+ console.log(`IA grande: ${indexJson.entradaCanonica.porCapacidade.grande.join(" -> ")}`);
3238
+ return 0;
3239
+ }
1939
3240
  async function comandoAjudaIa() {
1940
3241
  const descoberta = await descobrirDocsIa();
1941
3242
  console.log("Ajuda de IA da Sema");
1942
3243
  console.log("");
3244
+ console.log(renderizarCaixaAscii([
3245
+ "IA-first para greenfield, edicao guiada e legado sem contrato inicial",
3246
+ "use o menor artefato semantico que resolva a tarefa",
3247
+ ]));
3248
+ console.log("");
1943
3249
  console.log(renderizarCabecalhoDocsIa(descoberta));
1944
3250
  console.log("");
1945
- console.log("O que a Sema faz de verdade");
1946
- console.log("- Governa contrato, intencao, erro, efeito, garantia, fluxo, vinculos e execucao.");
1947
- console.log("- Usa `importar` para bootstrap revisavel de legado.");
1948
- console.log("- Usa `impl` para ligar contrato a simbolos reais.");
1949
- console.log("- Usa `vinculos` para ligar contrato a arquivo, simbolo, recurso e superficie real.");
1950
- console.log("- Usa `execucao` para explicitar timeout, retry, compensacao e criticidade.");
1951
- console.log("- Usa `drift` para medir divergencia entre contrato e codigo vivo com score, confianca e lacunas.");
1952
- console.log("- Usa `contexto-ia` para preparar AST, IR, diagnosticos, drift e `briefing.json` antes da edicao.");
3251
+ console.log(renderizarSecaoAscii("Tres jeitos de usar a Sema", [
3252
+ "[1] Producao inicial: modele, valide, compile e verifique antes de subir codigo derivado.",
3253
+ "[2] Edicao em projeto com Sema: inspecione, leia resumo, rode drift e gere contexto antes de editar codigo vivo.",
3254
+ "[3] Projeto sem Sema ainda: importe, revise o rascunho, formate, valide e use drift como juiz da adocao incremental.",
3255
+ ]));
1953
3256
  console.log("");
1954
- console.log("O que a Sema nao promete");
1955
- console.log("- Nao escreve contrato final sozinho.");
1956
- console.log("- Nao substitui decisao arquitetural.");
1957
- console.log("- Nao adivinha regra de negocio que o codigo nao explicita.");
3257
+ console.log(renderizarSecaoAscii("Capacidade de IA", [
3258
+ "pequena: `sema resumo --micro`, `briefing.min.json`, `prompt-curto.txt`",
3259
+ "media: `sema resumo --curto`, `drift.json`, `briefing.min.json`",
3260
+ "grande: `sema contexto-ia`, `briefing.json`, `ir.json`, `ast.json`",
3261
+ ]));
1958
3262
  console.log("");
1959
- console.log("Fluxo recomendado");
1960
- console.log("- Use `sema starter-ia` para um texto curto de onboarding.");
1961
- console.log("- Use `sema prompt-ia` para o prompt-base geral.");
1962
- console.log("- Use `sema prompt-ia-ui` para tarefas visuais com Sema + UI.");
1963
- console.log("- Use `sema prompt-ia-react` para projeto com Sema + React + TypeScript.");
1964
- console.log("- Use `sema prompt-ia-sema-primeiro` para forcar modelagem semantica antes da implementacao.");
1965
- console.log("- Use `sema exemplos-prompt-ia` para pegar modelos prontos de prompt.");
1966
- console.log("- Use `sema inspecionar` para descobrir base, codigo vivo e fontes legado.");
1967
- console.log("- Use `sema drift` para medir impls, vinculos, rotas, score e lacunas.");
1968
- console.log("- Use `sema contexto-ia <arquivo.sema>` para gerar AST, IR, drift e `briefing.json` do modulo alvo.");
1969
- console.log("- Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>` quando a tarefa pedir codigo derivado.");
3263
+ console.log(renderizarSecaoAscii("Fluxo recomendado", [
3264
+ "Use `sema starter-ia` para um texto curto de onboarding.",
3265
+ "Use `sema sync-ai-entrypoints` para regenerar `SEMA_BRIEF.*` e `SEMA_INDEX.json` na raiz.",
3266
+ "Use `sema resumo <arquivo> --micro --para onboarding` para IA pequena.",
3267
+ "Use `sema prompt-curto <arquivo> --curto --para mudanca` para colar contexto em modelo gratuito.",
3268
+ "Use `sema prompt-ia`, `sema prompt-ia-ui`, `sema prompt-ia-react` e `sema prompt-ia-sema-primeiro` conforme a tarefa.",
3269
+ "Use `sema exemplos-prompt-ia` para pegar modelos prontos de prompt.",
3270
+ "Use `sema inspecionar` para descobrir base, codigo vivo e fontes legado.",
3271
+ "Use `sema drift` para medir impls, vinculos, rotas, score e lacunas.",
3272
+ "Use `sema contexto-ia <arquivo.sema>` para gerar AST, IR, drift, `briefing.json` e `briefing.min.json`.",
3273
+ "Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>` quando a tarefa pedir codigo derivado.",
3274
+ ]));
1970
3275
  console.log("");
1971
- console.log("Regra pratica");
1972
- console.log("- Se voce quer testar a Sema de verdade, nao peca so HTML solto.");
1973
- console.log("- Peca `.sema` + arquitetura + React + TypeScript, ou use o modo `Sema primeiro`.");
1974
- console.log("- Se o projeto ja existe, trate `importar` como rascunho e `drift` como juiz.");
1975
- console.log("- Antes de editar backend vivo, leia `briefing.json` em vez de sair cavando arquivo na fe.");
1976
- console.log("- Trate `route`, `worker`, `evento`, `fila`, `cron`, `webhook`, `cache`, `storage` e `policy` como superficies de primeira classe.");
3276
+ console.log(renderizarSecaoAscii("Regras praticas", [
3277
+ "Foi feita para IA operar melhor; leitura humana e consequencia, nao centro de produto.",
3278
+ "Governa contrato, intencao, erro, efeito, garantia, fluxo, vinculos e execucao.",
3279
+ "Nao escreve contrato final sozinho nem substitui decisao arquitetural.",
3280
+ "Se voce quer testar a Sema de verdade, nao peca so HTML solto.",
3281
+ "Peca `.sema` + arquitetura + React + TypeScript, ou use o modo `Sema primeiro`.",
3282
+ "Se o projeto ja existe, trate `importar` como rascunho e `drift` como juiz.",
3283
+ "IA pequena comeca no menor artefato que resolve a tarefa; nao enfie `ast.json` inteiro nela de bobeira.",
3284
+ "Antes de editar software vivo, leia `briefing.min.json` ou `briefing.json` em vez de sair cavando arquivo na fe.",
3285
+ "Trate `route`, `worker`, `evento`, `fila`, `cron`, `webhook`, `cache`, `storage` e `policy` como superficies de primeira classe.",
3286
+ ]));
1977
3287
  return 0;
1978
3288
  }
1979
3289
  async function comandoPromptIa() {
@@ -2021,6 +3331,142 @@ async function comandoExemplosPromptIa() {
2021
3331
  console.log(EXEMPLOS_PROMPT_IA);
2022
3332
  return 0;
2023
3333
  }
3334
+ async function comandoResumo(entrada, args, emJson) {
3335
+ const tamanho = normalizarTamanhoResumo(args);
3336
+ const modo = normalizarModoResumo(obterOpcao(args, "--para"));
3337
+ const pastaSaida = obterOpcao(args, "--saida");
3338
+ const escreverNaRaiz = possuiFlag(args, "--raiz");
3339
+ const alvo = entrada ? path.resolve(process.cwd(), entrada) : process.cwd();
3340
+ if (entrada && entrada.toLowerCase().endsWith(".sema")) {
3341
+ const contexto = await carregarContextoModuloIa(alvo);
3342
+ const resumoSemantico = coletarResumoSemanticoModulo(contexto);
3343
+ const guiaPorCapacidade = criarGuiaCapacidadeIa();
3344
+ const texto = tamanho === "medio"
3345
+ ? renderizarResumoModuloMarkdown(resumoSemantico, modo, guiaPorCapacidade)
3346
+ : renderizarResumoModuloTexto(resumoSemantico, tamanho, modo);
3347
+ let pastaResumo;
3348
+ let artefatosCompactos = [];
3349
+ if (pastaSaida) {
3350
+ pastaResumo = path.resolve(pastaSaida);
3351
+ await mkdir(pastaResumo, { recursive: true });
3352
+ const gerado = await gerarArquivosResumoModuloIa(contexto, pastaResumo);
3353
+ artefatosCompactos = gerado.artefatosCompactos;
3354
+ }
3355
+ if (emJson) {
3356
+ console.log(JSON.stringify({
3357
+ comando: "resumo",
3358
+ modo,
3359
+ tamanho,
3360
+ geradoEm: contexto.geradoEm,
3361
+ arquivo: contexto.arquivo,
3362
+ modulo: contexto.modulo,
3363
+ pastaSaida: pastaResumo ?? null,
3364
+ artefatosCompactos,
3365
+ guiaPorCapacidade,
3366
+ resumo: resumoSemantico,
3367
+ texto,
3368
+ }, null, 2));
3369
+ return 0;
3370
+ }
3371
+ if (pastaResumo) {
3372
+ console.log(`Resumo IA-first gerado em ${pastaResumo}`);
3373
+ console.log("");
3374
+ }
3375
+ console.log(texto);
3376
+ return 0;
3377
+ }
3378
+ const resumoProjeto = await gerarResumoProjetoIa(alvo, pastaSaida, escreverNaRaiz);
3379
+ const arquivoResumo = tamanho === "micro"
3380
+ ? "SEMA_BRIEF.micro.txt"
3381
+ : tamanho === "curto"
3382
+ ? "SEMA_BRIEF.curto.txt"
3383
+ : "SEMA_BRIEF.md";
3384
+ const texto = await readFile(path.join(resumoProjeto.pastaSaida, arquivoResumo), "utf8");
3385
+ if (emJson) {
3386
+ console.log(JSON.stringify({
3387
+ comando: "resumo",
3388
+ modo,
3389
+ tamanho,
3390
+ geradoEm: resumoProjeto.geradoEm,
3391
+ baseProjeto: resumoProjeto.baseProjeto,
3392
+ pastaSaida: resumoProjeto.pastaSaida,
3393
+ artefatos: resumoProjeto.artefatos,
3394
+ guiaPorCapacidade: resumoProjeto.guiaPorCapacidade,
3395
+ modulos: resumoProjeto.modulos,
3396
+ texto,
3397
+ }, null, 2));
3398
+ return 0;
3399
+ }
3400
+ console.log(`Resumo IA-first do projeto gerado em ${resumoProjeto.pastaSaida}`);
3401
+ console.log("");
3402
+ console.log(texto);
3403
+ return 0;
3404
+ }
3405
+ async function comandoPromptCurto(entrada, args, emJson) {
3406
+ const tamanho = normalizarTamanhoResumo(args);
3407
+ const modo = normalizarModoResumo(obterOpcao(args, "--para"));
3408
+ const alvo = entrada ? path.resolve(process.cwd(), entrada) : process.cwd();
3409
+ if (entrada && entrada.toLowerCase().endsWith(".sema")) {
3410
+ const contexto = await carregarContextoModuloIa(alvo);
3411
+ const resumoSemantico = coletarResumoSemanticoModulo(contexto);
3412
+ const capacidade = tamanho === "micro" ? "pequena" : tamanho === "curto" ? "media" : "grande";
3413
+ const prompt = criarPromptCurtoModulo(resumoSemantico, modo, tamanho, capacidade);
3414
+ if (emJson) {
3415
+ console.log(JSON.stringify({
3416
+ comando: "prompt-curto",
3417
+ modo,
3418
+ tamanho,
3419
+ capacidade,
3420
+ geradoEm: contexto.geradoEm,
3421
+ arquivo: contexto.arquivo,
3422
+ modulo: contexto.modulo,
3423
+ prompt,
3424
+ }, null, 2));
3425
+ return 0;
3426
+ }
3427
+ console.log(prompt);
3428
+ return 0;
3429
+ }
3430
+ const resumoProjeto = await gerarResumoProjetoIa(alvo);
3431
+ const arquivoResumo = tamanho === "micro"
3432
+ ? "SEMA_BRIEF.micro.txt"
3433
+ : tamanho === "curto"
3434
+ ? "SEMA_BRIEF.curto.txt"
3435
+ : "SEMA_BRIEF.md";
3436
+ const contextoProjeto = await readFile(path.join(resumoProjeto.pastaSaida, arquivoResumo), "utf8");
3437
+ const capacidade = tamanho === "micro" ? "pequena" : tamanho === "curto" ? "media" : "grande";
3438
+ const prompt = `Voce esta operando Sema em modo IA-first.
3439
+
3440
+ Isto nao e material feito para humano; e contexto comprimido para IA.
3441
+
3442
+ Capacidade alvo: ${capacidade}
3443
+ Modo da tarefa: ${modo}
3444
+
3445
+ Regras:
3446
+ - comece pelo resumo compacto abaixo
3447
+ - se a tarefa pedir mais contexto, abra \`SEMA_INDEX.json\`
3448
+ - nao tente ler o repo inteiro se o resumo ja disser onde tocar
3449
+ - preserve contrato, risco, lacuna e checks sugeridos
3450
+
3451
+ Contexto do projeto:
3452
+ ${contextoProjeto.trim()}
3453
+ `;
3454
+ if (emJson) {
3455
+ console.log(JSON.stringify({
3456
+ comando: "prompt-curto",
3457
+ modo,
3458
+ tamanho,
3459
+ capacidade,
3460
+ geradoEm: resumoProjeto.geradoEm,
3461
+ baseProjeto: resumoProjeto.baseProjeto,
3462
+ pastaSaida: resumoProjeto.pastaSaida,
3463
+ prompt,
3464
+ }, null, 2));
3465
+ return 0;
3466
+ }
3467
+ console.log(prompt);
3468
+ return 0;
3469
+ }
2024
3470
  async function comandoContextoIa(arquivo, pastaSaida, emJson) {
2025
3471
  const resultado = await gerarContextoIa(arquivo, pastaSaida);
2026
3472
  if (emJson) {
@@ -2252,7 +3698,7 @@ async function principal() {
2252
3698
  {
2253
3699
  const fonte = normalizarFonteImportacao(posicionais[0]);
2254
3700
  if (!fonte || !posicionais[1]) {
2255
- console.error("Uso: sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
3701
+ 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> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
2256
3702
  codigoSaida = 1;
2257
3703
  break;
2258
3704
  }
@@ -2271,6 +3717,15 @@ async function principal() {
2271
3717
  case "starter-ia":
2272
3718
  codigoSaida = await comandoStarterIa();
2273
3719
  break;
3720
+ case "sync-ai-entrypoints":
3721
+ codigoSaida = await comandoSyncAiEntrypoints(possuiFlag(resto, "--json"));
3722
+ break;
3723
+ case "resumo":
3724
+ codigoSaida = await comandoResumo(posicionais[0], resto, possuiFlag(resto, "--json"));
3725
+ break;
3726
+ case "prompt-curto":
3727
+ codigoSaida = await comandoPromptCurto(posicionais[0], resto, possuiFlag(resto, "--json"));
3728
+ break;
2274
3729
  case "prompt-ia":
2275
3730
  codigoSaida = await comandoPromptIa();
2276
3731
  break;