@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.
- package/AGENTS.md +50 -0
- package/README.md +15 -2
- package/SEMA_BRIEF.curto.txt +9 -0
- package/SEMA_BRIEF.md +49 -0
- package/SEMA_BRIEF.micro.txt +7 -0
- package/SEMA_INDEX.json +546 -0
- package/dist/drift.d.ts +17 -2
- package/dist/drift.js +516 -5
- package/dist/drift.js.map +1 -1
- package/dist/importador.d.ts +1 -1
- package/dist/importador.js +741 -3
- package/dist/importador.js.map +1 -1
- package/dist/index.js +962 -86
- package/dist/index.js.map +1 -1
- package/dist/lua-symbols.d.ts +8 -0
- package/dist/lua-symbols.js +68 -0
- package/dist/lua-symbols.js.map +1 -0
- package/dist/projeto.js +56 -2
- package/dist/projeto.js.map +1 -1
- package/dist/tipos.d.ts +1 -1
- package/docs/AGENT_STARTER.md +34 -6
- package/docs/instalacao-e-primeiro-uso.md +18 -9
- package/llms-full.txt +34 -0
- package/llms.txt +17 -0
- package/node_modules/@sema/gerador-dart/package.json +1 -1
- package/node_modules/@sema/gerador-lua/dist/index.d.ts +3 -0
- package/node_modules/@sema/gerador-lua/dist/index.js +360 -0
- package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -0
- package/node_modules/@sema/gerador-lua/package.json +7 -0
- package/node_modules/@sema/gerador-python/dist/index.js +92 -10
- package/node_modules/@sema/gerador-python/dist/index.js.map +1 -1
- package/node_modules/@sema/gerador-python/package.json +1 -1
- package/node_modules/@sema/gerador-typescript/package.json +1 -1
- package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +1 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.js +4 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +3 -3
- package/node_modules/@sema/nucleo/dist/parser/parser.js +2 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +2 -2
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js +3 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
- package/node_modules/@sema/nucleo/package.json +1 -1
- package/node_modules/@sema/padroes/dist/index.d.ts +2 -1
- package/node_modules/@sema/padroes/dist/index.js +64 -1
- package/node_modules/@sema/padroes/dist/index.js.map +1 -1
- package/node_modules/@sema/padroes/package.json +1 -1
- 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
|
|
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
|
|
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
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
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("
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
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("
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
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
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
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("
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
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
|
-
|
|
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;
|