@semacode/cli 1.5.0 → 1.5.2
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/README.md +1 -1
- package/dist/drift.d.ts +8 -4
- package/dist/drift.js +332 -38
- package/dist/drift.js.map +1 -1
- package/dist/index.js +221 -18
- package/dist/index.js.map +1 -1
- package/docs/cli.md +1 -1
- package/docs/persistencia-vendor-first.md +1 -1
- package/node_modules/@sema/gerador-css/package.json +1 -1
- package/node_modules/@sema/gerador-dart/package.json +1 -1
- package/node_modules/@sema/gerador-html/package.json +1 -1
- package/node_modules/@sema/gerador-javascript/package.json +1 -1
- package/node_modules/@sema/gerador-lua/package.json +1 -1
- package/node_modules/@sema/gerador-python/dist/index.js +23 -5
- 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/parser/parser.js +17 -1
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
- package/node_modules/@sema/nucleo/package.json +1 -1
- package/node_modules/@sema/padroes/package.json +1 -1
- package/package.json +11 -10
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import pacoteCli from "../package.json" with { type: "json" };
|
|
7
8
|
import { compilarCodigo, formatarCodigo, formatarDiagnosticos, lerArquivoTexto, temErros, } from "@sema/nucleo";
|
|
@@ -321,6 +322,7 @@ Comandos uteis da CLI para esse fluxo:
|
|
|
321
322
|
`;
|
|
322
323
|
const DIRETORIO_CLI_ATUAL = path.dirname(fileURLToPath(import.meta.url));
|
|
323
324
|
const VERSAO_CLI = pacoteCli.version;
|
|
325
|
+
const requireRuntimeCli = createRequire(import.meta.url);
|
|
324
326
|
const ARQUIVOS_CANONICOS_IA_RAIZ = [
|
|
325
327
|
"llms.txt",
|
|
326
328
|
"SEMA_BRIEF.md",
|
|
@@ -338,6 +340,16 @@ const DOCUMENTOS_SUPORTE_IA = [
|
|
|
338
340
|
"docs/sintaxe.md",
|
|
339
341
|
"docs/cli.md",
|
|
340
342
|
];
|
|
343
|
+
function resolverImportadorNodeOpcional(especificador) {
|
|
344
|
+
try {
|
|
345
|
+
return requireRuntimeCli.resolve(especificador);
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const TSX_IMPORTADOR_CLI = resolverImportadorNodeOpcional("tsx");
|
|
352
|
+
const TSX_EXECUTOR_CLI = resolverImportadorNodeOpcional("tsx/cli");
|
|
341
353
|
function obterArgumentos() {
|
|
342
354
|
const [, , comando, ...resto] = process.argv;
|
|
343
355
|
return { comando: comando, resto };
|
|
@@ -513,25 +525,172 @@ function comandoDisponivel(comando, argumentos = ["--version"]) {
|
|
|
513
525
|
const execucao = spawnSync(comando, argumentos, { stdio: "ignore", shell: process.platform === "win32" });
|
|
514
526
|
return (execucao.status ?? 1) === 0;
|
|
515
527
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
{
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
{
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
528
|
+
function resolverExecucaoPython() {
|
|
529
|
+
if (comandoDisponivel("python")) {
|
|
530
|
+
return { comando: "python", argumentosBase: [], rotulo: "python" };
|
|
531
|
+
}
|
|
532
|
+
if (comandoDisponivel("py")) {
|
|
533
|
+
return { comando: "py", argumentosBase: [], rotulo: "py" };
|
|
534
|
+
}
|
|
535
|
+
return undefined;
|
|
536
|
+
}
|
|
537
|
+
function resolverExecucaoPytest() {
|
|
538
|
+
if (comandoDisponivel("pytest")) {
|
|
539
|
+
return { comando: "pytest", argumentosBase: [], rotulo: "pytest" };
|
|
540
|
+
}
|
|
541
|
+
const python = resolverExecucaoPython();
|
|
542
|
+
if (python && comandoDisponivel(python.comando, [...python.argumentosBase, "-m", "pytest", "--version"])) {
|
|
543
|
+
return {
|
|
544
|
+
comando: python.comando,
|
|
545
|
+
argumentosBase: [...python.argumentosBase, "-m", "pytest"],
|
|
546
|
+
rotulo: `${python.rotulo} -m pytest`,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
return undefined;
|
|
550
|
+
}
|
|
551
|
+
function criarItemDependencia(nome, ok, detalhe, obrigatoria = true) {
|
|
552
|
+
return { nome, ok, detalhe, obrigatoria };
|
|
553
|
+
}
|
|
554
|
+
function coletarDependenciasDoctor() {
|
|
555
|
+
const python = resolverExecucaoPython();
|
|
556
|
+
const pytest = resolverExecucaoPytest();
|
|
557
|
+
return [
|
|
558
|
+
{
|
|
559
|
+
comando: "base",
|
|
560
|
+
itens: [
|
|
561
|
+
criarItemDependencia("node", comandoDisponivel("node"), "runtime principal da CLI"),
|
|
562
|
+
criarItemDependencia("npm", comandoDisponivel("npm"), "instalacao, pack e publish"),
|
|
563
|
+
criarItemDependencia("python", Boolean(python), python?.rotulo ? `resolvido via ${python.rotulo}` : "python ou py"),
|
|
564
|
+
criarItemDependencia("dotnet", comandoDisponivel("dotnet"), "ecosistema ASP.NET", false),
|
|
565
|
+
criarItemDependencia("go", comandoDisponivel("go"), "ecosistema Go", false),
|
|
566
|
+
criarItemDependencia("cargo", comandoDisponivel("cargo"), "ecosistema Rust", false),
|
|
567
|
+
criarItemDependencia("java", comandoDisponivel("java"), "ecosistema Java/Spring", false),
|
|
568
|
+
criarItemDependencia("code", comandoDisponivel("code", ["--version"]), "VS Code / extensao", false),
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
comando: "verificar/typescript",
|
|
573
|
+
itens: [
|
|
574
|
+
criarItemDependencia("node", comandoDisponivel("node"), "execucao do runner TypeScript"),
|
|
575
|
+
criarItemDependencia("tsx", Boolean(TSX_EXECUTOR_CLI ?? TSX_IMPORTADOR_CLI), TSX_EXECUTOR_CLI
|
|
576
|
+
? `runner resolvido em ${TSX_EXECUTOR_CLI}`
|
|
577
|
+
: TSX_IMPORTADOR_CLI
|
|
578
|
+
? `importador resolvido em ${TSX_IMPORTADOR_CLI}`
|
|
579
|
+
: "tsx nao foi encontrado junto da CLI"),
|
|
580
|
+
],
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
comando: "verificar/javascript",
|
|
584
|
+
itens: [
|
|
585
|
+
criarItemDependencia("node", comandoDisponivel("node"), "node --test"),
|
|
586
|
+
],
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
comando: "verificar/python",
|
|
590
|
+
itens: [
|
|
591
|
+
criarItemDependencia("python", Boolean(python), python?.rotulo ? `resolvido via ${python.rotulo}` : "python ou py"),
|
|
592
|
+
criarItemDependencia("pytest", Boolean(pytest), pytest?.rotulo ? `runner resolvido via ${pytest.rotulo}` : "instale pytest ou exponha python -m pytest"),
|
|
593
|
+
],
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
comando: "verificar/lua",
|
|
597
|
+
itens: [
|
|
598
|
+
criarItemDependencia("lua", comandoDisponivel("lua", ["-v"]), "runner de testes Lua"),
|
|
599
|
+
],
|
|
600
|
+
},
|
|
526
601
|
];
|
|
602
|
+
}
|
|
603
|
+
function avaliarPreflightVerificacao(configuracoesAlvo) {
|
|
604
|
+
const dependencias = [];
|
|
605
|
+
const faltando = [];
|
|
606
|
+
const registrar = (comando, itens) => {
|
|
607
|
+
dependencias.push({ comando, itens });
|
|
608
|
+
for (const item of itens) {
|
|
609
|
+
if (item.obrigatoria && !item.ok) {
|
|
610
|
+
faltando.push({
|
|
611
|
+
comando,
|
|
612
|
+
nome: item.nome,
|
|
613
|
+
detalhe: item.detalhe,
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
registrar("base", [
|
|
619
|
+
criarItemDependencia("node", comandoDisponivel("node"), "runtime principal da CLI"),
|
|
620
|
+
criarItemDependencia("npm", comandoDisponivel("npm"), "instalacao e empacotamento"),
|
|
621
|
+
]);
|
|
622
|
+
for (const configuracao of configuracoesAlvo) {
|
|
623
|
+
if (configuracao.framework !== "base") {
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
if (configuracao.alvo === "typescript") {
|
|
627
|
+
registrar("verificar/typescript", [
|
|
628
|
+
criarItemDependencia("node", comandoDisponivel("node"), "execucao do runner TypeScript"),
|
|
629
|
+
criarItemDependencia("tsx", Boolean(TSX_EXECUTOR_CLI ?? TSX_IMPORTADOR_CLI), TSX_EXECUTOR_CLI
|
|
630
|
+
? `runner resolvido em ${TSX_EXECUTOR_CLI}`
|
|
631
|
+
: TSX_IMPORTADOR_CLI
|
|
632
|
+
? `importador resolvido em ${TSX_IMPORTADOR_CLI}`
|
|
633
|
+
: "tsx nao foi encontrado junto da CLI"),
|
|
634
|
+
]);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
if (configuracao.alvo === "javascript") {
|
|
638
|
+
registrar("verificar/javascript", [
|
|
639
|
+
criarItemDependencia("node", comandoDisponivel("node"), "node --test"),
|
|
640
|
+
]);
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (configuracao.alvo === "python") {
|
|
644
|
+
const python = resolverExecucaoPython();
|
|
645
|
+
const pytest = resolverExecucaoPytest();
|
|
646
|
+
registrar("verificar/python", [
|
|
647
|
+
criarItemDependencia("python", Boolean(python), python?.rotulo ? `resolvido via ${python.rotulo}` : "python ou py"),
|
|
648
|
+
criarItemDependencia("pytest", Boolean(pytest), pytest?.rotulo ? `runner resolvido via ${pytest.rotulo}` : "instale pytest ou exponha python -m pytest"),
|
|
649
|
+
]);
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
if (configuracao.alvo === "lua") {
|
|
653
|
+
registrar("verificar/lua", [
|
|
654
|
+
criarItemDependencia("lua", comandoDisponivel("lua", ["-v"]), "runner de testes Lua"),
|
|
655
|
+
]);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return {
|
|
659
|
+
ok: faltando.length === 0,
|
|
660
|
+
dependencias,
|
|
661
|
+
faltando,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function imprimirDependenciasDoctor(dependencias) {
|
|
665
|
+
for (const dependencia of dependencias) {
|
|
666
|
+
console.log(`\n[${dependencia.comando}]`);
|
|
667
|
+
for (const item of dependencia.itens) {
|
|
668
|
+
const sufixo = item.detalhe ? ` (${item.detalhe})` : "";
|
|
669
|
+
console.log(`- ${item.nome}: ${item.ok ? "ok" : item.obrigatoria ? "faltando" : "ausente"}${sufixo}`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
function imprimirPreflightVerificacao(preflight) {
|
|
674
|
+
console.error(renderizarCaixaAscii([
|
|
675
|
+
"Preflight de verificacao falhou",
|
|
676
|
+
"a CLI sabe o que falta antes de gerar e testar",
|
|
677
|
+
]));
|
|
678
|
+
for (const item of preflight.faltando) {
|
|
679
|
+
const detalhe = item.detalhe ? ` (${item.detalhe})` : "";
|
|
680
|
+
console.error(`- ${item.comando}: ${item.nome} faltando${detalhe}`);
|
|
681
|
+
}
|
|
682
|
+
console.error("Rode `sema doctor` para ver as dependencias por comando.");
|
|
683
|
+
}
|
|
684
|
+
async function comandoDoctor() {
|
|
685
|
+
const dependencias = coletarDependenciasDoctor();
|
|
527
686
|
console.log(renderizarCaixaAscii([
|
|
528
687
|
"Sema doctor",
|
|
529
|
-
"checa a toolchain minima
|
|
688
|
+
"checa a toolchain minima e as dependencias reais por comando",
|
|
530
689
|
]));
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
690
|
+
imprimirDependenciasDoctor(dependencias);
|
|
691
|
+
const obrigatorios = dependencias
|
|
692
|
+
.find((dependencia) => dependencia.comando === "base")
|
|
693
|
+
?.itens.filter((item) => item.obrigatoria) ?? [];
|
|
535
694
|
return obrigatorios.every((check) => check.ok) ? 0 : 1;
|
|
536
695
|
}
|
|
537
696
|
function validarCompatibilidadeFramework(alvo, framework) {
|
|
@@ -770,8 +929,17 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
|
|
|
770
929
|
}
|
|
771
930
|
return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
|
|
772
931
|
}
|
|
773
|
-
|
|
932
|
+
if (!TSX_EXECUTOR_CLI) {
|
|
933
|
+
return {
|
|
934
|
+
codigoSaida: 1,
|
|
935
|
+
quantidadeTestes,
|
|
936
|
+
saidaPadrao: "",
|
|
937
|
+
saidaErro: "Nao foi possivel localizar o runner tsx junto da CLI para executar testes TypeScript.",
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
const execucao = spawnSync("node", [TSX_EXECUTOR_CLI, arquivoTeste], {
|
|
774
941
|
stdio: silencioso ? "pipe" : "inherit",
|
|
942
|
+
cwd: baseSaida,
|
|
775
943
|
encoding: silencioso ? "utf8" : undefined,
|
|
776
944
|
});
|
|
777
945
|
return {
|
|
@@ -808,6 +976,14 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
|
|
|
808
976
|
}
|
|
809
977
|
return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
|
|
810
978
|
}
|
|
979
|
+
if (!comandoDisponivel("lua", ["-v"])) {
|
|
980
|
+
return {
|
|
981
|
+
codigoSaida: 1,
|
|
982
|
+
quantidadeTestes,
|
|
983
|
+
saidaPadrao: "",
|
|
984
|
+
saidaErro: "Nao foi possivel localizar o runner lua para executar os testes gerados.",
|
|
985
|
+
};
|
|
986
|
+
}
|
|
811
987
|
const execucao = spawnSync("lua", [arquivoTeste], {
|
|
812
988
|
stdio: silencioso ? "pipe" : "inherit",
|
|
813
989
|
cwd: baseSaida,
|
|
@@ -828,10 +1004,20 @@ function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
|
|
|
828
1004
|
}
|
|
829
1005
|
return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
|
|
830
1006
|
}
|
|
831
|
-
const
|
|
1007
|
+
const pytest = resolverExecucaoPytest();
|
|
1008
|
+
if (!pytest) {
|
|
1009
|
+
return {
|
|
1010
|
+
codigoSaida: 1,
|
|
1011
|
+
quantidadeTestes,
|
|
1012
|
+
saidaPadrao: "",
|
|
1013
|
+
saidaErro: "Nao foi possivel localizar pytest. Instale pytest ou exponha python -m pytest.",
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
const execucao = spawnSync(pytest.comando, [...pytest.argumentosBase, arquivoTeste], {
|
|
832
1017
|
stdio: silencioso ? "pipe" : "inherit",
|
|
833
1018
|
cwd: baseSaida,
|
|
834
1019
|
encoding: silencioso ? "utf8" : undefined,
|
|
1020
|
+
shell: process.platform === "win32" && pytest.comando === "pytest",
|
|
835
1021
|
});
|
|
836
1022
|
return {
|
|
837
1023
|
codigoSaida: execucao.status ?? 1,
|
|
@@ -3125,7 +3311,7 @@ async function comandoDrift(entrada, args, emJson, cwd = process.cwd()) {
|
|
|
3125
3311
|
if (persistenciaDivergente.length > 0) {
|
|
3126
3312
|
console.log("- Persistencia que pede revisao:");
|
|
3127
3313
|
for (const item of persistenciaDivergente.slice(0, 8)) {
|
|
3128
|
-
console.log(` - ${item.modulo}.${item.task} :: ${item.alvo} :: ${item.status} :: compat=${item.compatibilidade}`);
|
|
3314
|
+
console.log(` - ${item.modulo}.${item.task} :: ${item.alvo} :: ${item.status} :: categoria=${item.categoriaPersistencia} :: compat=${item.compatibilidade}`);
|
|
3129
3315
|
}
|
|
3130
3316
|
}
|
|
3131
3317
|
const semImpl = resultado.tasks.filter((task) => task.semImplementacao);
|
|
@@ -3757,6 +3943,11 @@ async function comandoVerificar(entrada, baseSaida, cwd = process.cwd()) {
|
|
|
3757
3943
|
console.error(incompatibilidade.incompatibilidade);
|
|
3758
3944
|
return 1;
|
|
3759
3945
|
}
|
|
3946
|
+
const preflight = avaliarPreflightVerificacao(configuracoesAlvo);
|
|
3947
|
+
if (!preflight.ok) {
|
|
3948
|
+
imprimirPreflightVerificacao(preflight);
|
|
3949
|
+
return 1;
|
|
3950
|
+
}
|
|
3760
3951
|
const resumos = [];
|
|
3761
3952
|
for (const modulo of modulos) {
|
|
3762
3953
|
const ir = garantirIr(modulo.resultado, modulo.caminho);
|
|
@@ -3824,6 +4015,18 @@ async function comandoVerificarJson(entrada, baseSaida, cwd = process.cwd()) {
|
|
|
3824
4015
|
}, null, 2));
|
|
3825
4016
|
return 1;
|
|
3826
4017
|
}
|
|
4018
|
+
const preflight = avaliarPreflightVerificacao(configuracoesAlvo);
|
|
4019
|
+
if (!preflight.ok) {
|
|
4020
|
+
console.log(JSON.stringify({
|
|
4021
|
+
comando: "verificar",
|
|
4022
|
+
sucesso: false,
|
|
4023
|
+
erro: "Dependencias obrigatorias ausentes para executar a verificacao.",
|
|
4024
|
+
preflight,
|
|
4025
|
+
modulos: [],
|
|
4026
|
+
totais: { modulos: 0, alvos: 0, arquivos: 0, testes: 0 },
|
|
4027
|
+
}, null, 2));
|
|
4028
|
+
return 1;
|
|
4029
|
+
}
|
|
3827
4030
|
const resumos = [];
|
|
3828
4031
|
let codigoSaida = 0;
|
|
3829
4032
|
for (const modulo of modulos) {
|