@semacode/cli 1.5.14 → 1.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
2
3
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
3
4
  import path from "node:path";
4
5
  import { spawnSync } from "node:child_process";
5
- import { createRequire } from "node:module";
6
6
  import { fileURLToPath } from "node:url";
7
+ import ts from "typescript";
7
8
  import pacoteCli from "../package.json" with { type: "json" };
8
9
  import { compilarCodigo, formatarCodigo, formatarDiagnosticos, lerArquivoTexto, temErros, } from "@sema/nucleo";
9
10
  import { descreverEstruturaModulo } from "@sema/padroes";
@@ -324,7 +325,6 @@ Comandos uteis da CLI para esse fluxo:
324
325
  `;
325
326
  const DIRETORIO_CLI_ATUAL = path.dirname(fileURLToPath(import.meta.url));
326
327
  const VERSAO_CLI = pacoteCli.version;
327
- const requireRuntimeCli = createRequire(import.meta.url);
328
328
  const ARQUIVOS_CANONICOS_IA_RAIZ = [
329
329
  "llms.txt",
330
330
  "SEMA_BRIEF.md",
@@ -348,16 +348,6 @@ const DOCUMENTOS_SUPORTE_IA = [
348
348
  "docs/rollback.md",
349
349
  "docs/extensao-vscode.md",
350
350
  ];
351
- function resolverImportadorNodeOpcional(especificador) {
352
- try {
353
- return requireRuntimeCli.resolve(especificador);
354
- }
355
- catch {
356
- return undefined;
357
- }
358
- }
359
- const TSX_IMPORTADOR_CLI = resolverImportadorNodeOpcional("tsx");
360
- const TSX_EXECUTOR_CLI = resolverImportadorNodeOpcional("tsx/cli");
361
351
  async function caminhoEhDiretorio(caminhoAlvo) {
362
352
  try {
363
353
  return (await stat(caminhoAlvo)).isDirectory();
@@ -658,11 +648,7 @@ function coletarDependenciasDoctor() {
658
648
  comando: "verificar/typescript",
659
649
  itens: [
660
650
  criarItemDependencia("node", comandoDisponivel("node"), "execucao do runner TypeScript"),
661
- criarItemDependencia("tsx", Boolean(TSX_EXECUTOR_CLI ?? TSX_IMPORTADOR_CLI), TSX_EXECUTOR_CLI
662
- ? `runner resolvido em ${TSX_EXECUTOR_CLI}`
663
- : TSX_IMPORTADOR_CLI
664
- ? `importador resolvido em ${TSX_IMPORTADOR_CLI}`
665
- : "tsx nao foi encontrado junto da CLI"),
651
+ criarItemDependencia("typescript", typeof ts.transpileModule === "function", `transpilador runtime resolvido em typescript ${ts.version}`),
666
652
  ],
667
653
  },
668
654
  {
@@ -712,11 +698,7 @@ function avaliarPreflightVerificacao(configuracoesAlvo) {
712
698
  if (configuracao.alvo === "typescript") {
713
699
  registrar("verificar/typescript", [
714
700
  criarItemDependencia("node", comandoDisponivel("node"), "execucao do runner TypeScript"),
715
- criarItemDependencia("tsx", Boolean(TSX_EXECUTOR_CLI ?? TSX_IMPORTADOR_CLI), TSX_EXECUTOR_CLI
716
- ? `runner resolvido em ${TSX_EXECUTOR_CLI}`
717
- : TSX_IMPORTADOR_CLI
718
- ? `importador resolvido em ${TSX_IMPORTADOR_CLI}`
719
- : "tsx nao foi encontrado junto da CLI"),
701
+ criarItemDependencia("typescript", typeof ts.transpileModule === "function", `transpilador runtime resolvido em typescript ${ts.version}`),
720
702
  ]);
721
703
  continue;
722
704
  }
@@ -1003,6 +985,35 @@ function contarCasosDeTesteGerados(alvo, arquivos) {
1003
985
  }
1004
986
  return (arquivoTeste.conteudo.match(/\bdef test_/g) ?? []).length;
1005
987
  }
988
+ function reescreverImportsTypeScriptGerados(codigo) {
989
+ return codigo
990
+ .replace(/(from\s+["']\.{1,2}\/[^"']+)\.ts(["'])/g, "$1.cjs$2")
991
+ .replace(/(require\(\s*["']\.{1,2}\/[^"']+)\.ts(["']\s*\))/g, "$1.cjs$2");
992
+ }
993
+ function compilarTypeScriptGeradoParaNodeTest(baseSaida, arquivos, arquivoTeste) {
994
+ const pastaRuntime = path.join(baseSaida, ".sema-js-tests");
995
+ rmSync(pastaRuntime, { recursive: true, force: true });
996
+ for (const arquivo of arquivos) {
997
+ if (!arquivo.caminhoRelativo.endsWith(".ts")) {
998
+ continue;
999
+ }
1000
+ const caminhoRelativoJs = arquivo.caminhoRelativo.replace(/\.ts$/i, ".cjs");
1001
+ const destino = path.join(pastaRuntime, caminhoRelativoJs);
1002
+ mkdirSync(path.dirname(destino), { recursive: true });
1003
+ const transpilado = ts.transpileModule(arquivo.conteudo, {
1004
+ fileName: arquivo.caminhoRelativo,
1005
+ compilerOptions: {
1006
+ module: ts.ModuleKind.CommonJS,
1007
+ target: ts.ScriptTarget.ES2022,
1008
+ esModuleInterop: true,
1009
+ sourceMap: false,
1010
+ inlineSourceMap: false,
1011
+ },
1012
+ }).outputText;
1013
+ writeFileSync(destino, reescreverImportsTypeScriptGerados(transpilado), "utf8");
1014
+ }
1015
+ return path.join(pastaRuntime, arquivoTeste.replace(/\.ts$/i, ".cjs"));
1016
+ }
1006
1017
  function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
1007
1018
  const quantidadeTestes = contarCasosDeTesteGerados(alvo, arquivos);
1008
1019
  if (quantidadeTestes === 0) {
@@ -1023,15 +1034,8 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
1023
1034
  }
1024
1035
  return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
1025
1036
  }
1026
- if (!TSX_EXECUTOR_CLI) {
1027
- return {
1028
- codigoSaida: 1,
1029
- quantidadeTestes,
1030
- saidaPadrao: "",
1031
- saidaErro: "Nao foi possivel localizar o runner tsx junto da CLI para executar testes TypeScript.",
1032
- };
1033
- }
1034
- const execucao = spawnSync("node", [TSX_EXECUTOR_CLI, arquivoTeste], {
1037
+ const arquivoTesteJs = compilarTypeScriptGeradoParaNodeTest(baseSaida, arquivos, arquivoTeste);
1038
+ const execucao = spawnSync("node", ["--test", arquivoTesteJs], {
1035
1039
  stdio: silencioso ? "pipe" : "inherit",
1036
1040
  cwd: baseSaida,
1037
1041
  encoding: silencioso ? "utf8" : undefined,
@@ -1353,6 +1357,7 @@ function coletarResumoSemanticoModulo(contexto) {
1353
1357
  ...rotas.map((route) => `${route.metodo ?? "?"} ${route.caminho ?? route.nome}`),
1354
1358
  ]), 8),
1355
1359
  regrasCriticas: limitarLista(regrasCriticas, 8),
1360
+ regrasAuthorAutomaticas: extrairRegrasAuthorAutomaticas(ir),
1356
1361
  efeitos: limitarLista(efeitos, 8),
1357
1362
  erros: limitarLista(erros, 8),
1358
1363
  entidadesAfetadas: limitarLista(entidadesAfetadas, 8),
@@ -1371,6 +1376,19 @@ function coletarResumoSemanticoModulo(contexto) {
1371
1376
  arquivosProvaveisEditar: limitarLista(unicosOrdenados(briefing.arquivosProvaveisEditar ?? briefing.oQueTocar), 8),
1372
1377
  };
1373
1378
  }
1379
+ const NOME_REGRAS_AUTHOR_AUTOMATICAS = "regras_gerais_author";
1380
+ const LINHA_REGRAS_AUTHOR_AUTOMATICAS_COMPACTA = "AUTHOR_RULES_AUTO: regras_gerais_author ativa; aplicar evidencia concreta, causa/consequencia, cena com dupla funcao, exposicao com atrito, subtexto, acao com geografia/dano, final sem slogan, morte com peso estrutural e anti-cliche adaptativa.";
1381
+ function extrairRegrasAuthorAutomaticas(ir) {
1382
+ const regraAutomatica = ir?.author.find((item) => item.tipo === "style_rule" && item.nome === NOME_REGRAS_AUTHOR_AUTOMATICAS);
1383
+ return limitarLista(unicosOrdenados(regraAutomatica?.requisitos ?? []), 20);
1384
+ }
1385
+ function renderizarLinhaRegrasAuthorAutomaticas(ids) {
1386
+ return ids.length > 0 ? LINHA_REGRAS_AUTHOR_AUTOMATICAS_COMPACTA : null;
1387
+ }
1388
+ function renderizarLinhasRegrasAuthorAutomaticas(ids) {
1389
+ const linha = renderizarLinhaRegrasAuthorAutomaticas(ids);
1390
+ return linha ? [linha] : [];
1391
+ }
1374
1392
  function renderizarResumoModuloTexto(resumo, tamanho, modo) {
1375
1393
  const limite = tamanho === "micro" ? 2 : tamanho === "curto" ? 4 : 6;
1376
1394
  const linhas = [
@@ -1378,6 +1396,7 @@ function renderizarResumoModuloTexto(resumo, tamanho, modo) {
1378
1396
  `MODULO: ${resumo.modulo}`,
1379
1397
  `FAZ: ${resumo.faz}`,
1380
1398
  `PERFIL: ${resumo.perfilCompatibilidade}`,
1399
+ ...renderizarLinhasRegrasAuthorAutomaticas(resumo.regrasAuthorAutomaticas),
1381
1400
  `CONSUMER_FRAMEWORK: ${resumo.consumerFramework ?? "nenhum"}`,
1382
1401
  `APP_ROUTES: ${resumirListaTexto(resumo.appRoutes, limite)}`,
1383
1402
  `CONSUMER_SURFACES: ${resumirListaTexto(resumo.consumerSurfaces, limite)}`,
@@ -1402,7 +1421,8 @@ function renderizarResumoModuloTexto(resumo, tamanho, modo) {
1402
1421
  `GERADO_EM: ${resumo.geradoEm}`,
1403
1422
  ];
1404
1423
  if (tamanho === "micro") {
1405
- return `${linhas.slice(0, 12).join("\n")}\n`;
1424
+ const limiteMicro = 12 + (resumo.regrasAuthorAutomaticas.length > 0 ? 1 : 0);
1425
+ return `${linhas.slice(0, limiteMicro).join("\n")}\n`;
1406
1426
  }
1407
1427
  return `${linhas.join("\n")}\n`;
1408
1428
  }
@@ -1429,6 +1449,9 @@ function renderizarResumoModuloMarkdown(resumo, modo, guiaPorCapacidade) {
1429
1449
  `- Entradas chave: ${resumirListaTexto(resumo.entradasChave, 6)}`,
1430
1450
  `- Saidas chave: ${resumirListaTexto(resumo.saidasChave, 6)}`,
1431
1451
  `- Regras criticas: ${resumirListaTexto(resumo.regrasCriticas, 6)}`,
1452
+ ...(resumo.regrasAuthorAutomaticas.length > 0
1453
+ ? [`- Regras Author automaticas: ${resumirListaTexto(resumo.regrasAuthorAutomaticas, 20)}`]
1454
+ : []),
1432
1455
  `- Efeitos: ${resumirListaTexto(resumo.efeitos, 6)}`,
1433
1456
  `- Erros: ${resumirListaTexto(resumo.erros, 6)}`,
1434
1457
  `- Entidades afetadas: ${resumirListaTexto(resumo.entidadesAfetadas, 6)}`,
@@ -1488,6 +1511,7 @@ function criarBriefingMinimo(resumo, modo, tamanho) {
1488
1511
  entradasChave: resumo.entradasChave,
1489
1512
  saidasChave: resumo.saidasChave,
1490
1513
  regrasCriticas: resumo.regrasCriticas,
1514
+ regrasAuthorAutomaticas: resumo.regrasAuthorAutomaticas,
1491
1515
  efeitos: resumo.efeitos,
1492
1516
  erros: resumo.erros,
1493
1517
  arquivosProvaveis: resumo.arquivosProvaveis,
@@ -1528,6 +1552,7 @@ ${resumoTexto}
1528
1552
  }
1529
1553
  function renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade) {
1530
1554
  const entradaCanonica = criarEntradaCanonicaProjeto(guiaPorCapacidade);
1555
+ const regrasAuthorAutomaticas = unicosOrdenados(modulos.flatMap((modulo) => modulo.regrasAuthorAutomaticas));
1531
1556
  const linhas = [
1532
1557
  "# SEMA_BRIEF",
1533
1558
  "",
@@ -1542,6 +1567,9 @@ function renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade) {
1542
1567
  `- IA pequena: ${entradaCanonica.porCapacidade.pequena.join(" -> ")}`,
1543
1568
  `- IA media: ${entradaCanonica.porCapacidade.media.join(" -> ")}`,
1544
1569
  `- IA grande: ${entradaCanonica.porCapacidade.grande.join(" -> ")}`,
1570
+ ...(regrasAuthorAutomaticas.length > 0
1571
+ ? [`- Regras Author automaticas: ${resumirListaTexto(regrasAuthorAutomaticas, 20)}`]
1572
+ : []),
1545
1573
  "",
1546
1574
  "## Guia por capacidade",
1547
1575
  "",
@@ -1864,6 +1892,8 @@ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz
1864
1892
  : path.resolve(baseProjeto, ".tmp", "sema-resumo");
1865
1893
  await mkdir(pastaSaida, { recursive: true });
1866
1894
  const semaBrief = renderizarResumoProjetoMarkdown(geradoEm, modulos, guiaPorCapacidade);
1895
+ const regrasAuthorAutomaticas = unicosOrdenados(modulos.flatMap((modulo) => modulo.regrasAuthorAutomaticas));
1896
+ const linhasRegrasAuthorAutomaticas = renderizarLinhasRegrasAuthorAutomaticas(regrasAuthorAutomaticas);
1867
1897
  const indexJson = {
1868
1898
  comando: "resumo-projeto",
1869
1899
  geradoEm,
@@ -1872,12 +1902,14 @@ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz
1872
1902
  totalModulos: modulos.length,
1873
1903
  entradaCanonica,
1874
1904
  guiaPorCapacidade,
1905
+ regrasAuthorAutomaticas,
1875
1906
  modulos,
1876
1907
  };
1877
1908
  const micro = [
1878
1909
  `PROJETO: ${path.basename(baseProjeto)}`,
1879
1910
  `MODULOS: ${modulos.length}`,
1880
1911
  `ENTRADA_IA: ${entradaCanonica.porCapacidade.pequena.join(" -> ")}`,
1912
+ ...linhasRegrasAuthorAutomaticas,
1881
1913
  `TOP_MODULOS: ${resumirListaTexto(modulos.map((modulo) => modulo.modulo), 3)}`,
1882
1914
  `TOP_RISCOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.riscosPrincipais)), 3)}`,
1883
1915
  `TOP_LACUNAS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.lacunas)), 3)}`,
@@ -1889,6 +1921,7 @@ async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escreverNaRaiz
1889
1921
  `BASE: ${baseProjeto}`,
1890
1922
  `MODULOS: ${modulos.length}`,
1891
1923
  `ENTRADA_IA: ${entradaCanonica.porCapacidade.media.join(" -> ")}`,
1924
+ ...linhasRegrasAuthorAutomaticas,
1892
1925
  `TOP_MODULOS: ${resumirListaTexto(modulos.map((modulo) => modulo.modulo), 6)}`,
1893
1926
  `TOP_RISCOS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.riscosPrincipais)), 6)}`,
1894
1927
  `TOP_LACUNAS: ${resumirListaTexto(unicosOrdenados(modulos.flatMap((modulo) => modulo.lacunas)), 6)}`,
@@ -3402,42 +3435,42 @@ const FLUXO_EDITORIAL_AUTHOR_CLI = [
3402
3435
  const REGRAS_AUTHOR_AUTOMATICAS_CLI = [
3403
3436
  {
3404
3437
  id: "mostrar_por_evidencia",
3405
- nome: "Mostrar Por Evidencia",
3438
+ nome: "Mostrar Por Evidência",
3406
3439
  aplica: "emocao, trauma, revolta e mudanca social precisam aparecer por evidencia concreta em cena",
3407
3440
  evitar: ["moral explicada", "emocao declarada", "simbolo sem uso concreto"],
3408
3441
  preferir: ["objeto alterado", "rotina quebrada", "gesto observavel", "decisao visivel"],
3409
3442
  },
3410
3443
  {
3411
3444
  id: "causa_e_consequencia",
3412
- nome: "Causa E Consequencia",
3445
+ nome: "Causa E Consequência",
3413
3446
  aplica: "acao relevante precisa gerar consequencia proporcional",
3414
3447
  evitar: ["vitoria sem custo", "erro sem punicao", "revelacao sem efeito"],
3415
3448
  preferir: ["custo emocional", "custo fisico", "custo politico", "custo relacional"],
3416
3449
  },
3417
3450
  {
3418
3451
  id: "cena_com_dupla_funcao",
3419
- nome: "Cena Com Dupla Funcao",
3452
+ nome: "Cena Com Dupla Função",
3420
3453
  aplica: "toda cena deve cumprir pelo menos duas funcoes narrativas sem exigir personagem novo",
3421
3454
  evitar: ["cena morta", "deslocamento vazio", "clima sem funcao"],
3422
3455
  preferir: ["avancar trama", "revelar personagem", "plantar pista", "mostrar consequencia"],
3423
3456
  },
3424
3457
  {
3425
3458
  id: "exposicao_com_atrito",
3426
- nome: "Exposicao Com Atrito",
3459
+ nome: "Exposição Com Atrito",
3427
3460
  aplica: "informacao de mundo ou passado deve aparecer em situacao com tensao",
3428
3461
  evitar: ["palestra", "lore sem conflito", "dialogo em que todos ja sabem"],
3429
3462
  preferir: ["discussao", "ameaca", "documento incompleto", "erro operacional"],
3430
3463
  },
3431
3464
  {
3432
3465
  id: "antagonista_com_logica_interna",
3433
- nome: "Antagonista Com Logica Interna",
3466
+ nome: "Antagonista Com Lógica Interna",
3434
3467
  aplica: "antagonistas precisam ter objetivo compreensivel e poder real de afetar a trama",
3435
3468
  evitar: ["malvadeza decorativa", "plano explicado inteiro", "incompetencia conveniente"],
3436
3469
  preferir: ["argumento parcialmente convincente", "vantagem estrutural", "contradicao humana"],
3437
3470
  },
3438
3471
  {
3439
3472
  id: "conflito_sem_solucao_limpa",
3440
- nome: "Conflito Sem Solucao Limpa",
3473
+ nome: "Conflito Sem Solução Limpa",
3441
3474
  aplica: "problemas importantes nao devem ser resolvidos de forma perfeita ou gratuita",
3442
3475
  evitar: ["solucao magica", "perdao instantaneo", "plano sem imprevisto"],
3443
3476
  preferir: ["vitoria parcial", "dilema moral", "perda permanente", "novo problema"],
@@ -3451,28 +3484,28 @@ const REGRAS_AUTHOR_AUTOMATICAS_CLI = [
3451
3484
  },
3452
3485
  {
3453
3486
  id: "misterio_em_escada",
3454
- nome: "Misterio Em Escada",
3487
+ nome: "Mistério Em Escada",
3455
3488
  aplica: "revelacoes devem ser construidas por etapas",
3456
3489
  evitar: ["revelacao sem pista", "segredo tardio", "misterio mantido por falta de conversa"],
3457
3490
  preferir: ["pista", "contradicao", "interpretacao errada", "verdade parcial"],
3458
3491
  },
3459
3492
  {
3460
3493
  id: "dialogo_com_subtexto",
3461
- nome: "Dialogo Com Subtexto",
3494
+ nome: "Diálogo Com Subtexto",
3462
3495
  aplica: "dialogo deve carregar intencao, defesa, disputa ou tensao",
3463
3496
  evitar: ["fala explicativa", "todos com a mesma voz", "frase de efeito no lugar de conflito"],
3464
3497
  preferir: ["resposta indireta", "mentira util", "silencio significativo", "pergunta como ataque"],
3465
3498
  },
3466
3499
  {
3467
3500
  id: "acao_com_geografia_e_dano",
3468
- nome: "Acao Com Geografia E Dano",
3501
+ nome: "Ação Com Geografia E Dano",
3469
3502
  aplica: "acao precisa ter espaco claro, objetivo concreto e consequencia depois",
3470
3503
  evitar: ["correria generica", "tiro para fingir ritmo", "sair ileso sem motivo"],
3471
3504
  preferir: ["mapa mental da cena", "obstaculo crescente", "uso do ambiente", "dano posterior"],
3472
3505
  },
3473
3506
  {
3474
3507
  id: "final_de_capitulo_sem_slogan",
3475
- nome: "Final De Capitulo Sem Slogan",
3508
+ nome: "Final De Capítulo Sem Slogan",
3476
3509
  aplica: "capitulo termina com decisao, imagem, perda, ameaca ou descoberta, nao com moral de trailer",
3477
3510
  evitar: ["frase filosofica", "slogan sobre destino", "resumo da moral da cena"],
3478
3511
  preferir: ["decisao irreversivel", "imagem forte", "perda concreta", "ameaca especifica"],
@@ -3500,7 +3533,7 @@ const REGRAS_AUTHOR_AUTOMATICAS_CLI = [
3500
3533
  },
3501
3534
  {
3502
3535
  id: "anti_cliche_adaptativa",
3503
- nome: "Anti-Cliche Adaptativa",
3536
+ nome: "Anti-Clichê Adaptativa",
3504
3537
  aplica: "estrutura reconhecivel demais deve ser substituida por alternativa especifica",
3505
3538
  evitar: ["nao era sobre X, era sobre Y", "a esperanca renasceu", "o destino cobraria seu preco"],
3506
3539
  preferir: ["acao concreta", "consequencia", "gesto observavel", "pista plantada"],