specatlas 0.1.38 → 0.1.40
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/bin.js +347 -67
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -36820,6 +36820,161 @@ function msg(key, language) {
|
|
|
36820
36820
|
return dict[key] ?? key;
|
|
36821
36821
|
}
|
|
36822
36822
|
|
|
36823
|
+
// src/ui.ts
|
|
36824
|
+
var CODIGOS = {
|
|
36825
|
+
rojo: [31, 39],
|
|
36826
|
+
verde: [32, 39],
|
|
36827
|
+
amarillo: [33, 39],
|
|
36828
|
+
azul: [34, 39],
|
|
36829
|
+
morado: [35, 39],
|
|
36830
|
+
cian: [36, 39],
|
|
36831
|
+
gris: [90, 39],
|
|
36832
|
+
negrita: [1, 22],
|
|
36833
|
+
atenuado: [2, 22],
|
|
36834
|
+
subrayado: [4, 24],
|
|
36835
|
+
inverso: [7, 27]
|
|
36836
|
+
};
|
|
36837
|
+
function detectarTema(env = process.env, salida = process.stdout) {
|
|
36838
|
+
const forzado = env["FORCE_COLOR"];
|
|
36839
|
+
const color = forzado !== void 0 && forzado !== "0" ? true : env["NO_COLOR"] !== void 0 || env["TERM"] === "dumb" || salida.isTTY !== true ? false : true;
|
|
36840
|
+
const unicode = env["SPECATLAS_ASCII"] === "1" ? false : process.platform !== "win32" || Boolean(env["WT_SESSION"] || env["TERM_PROGRAM"] || env["ConEmuANSI"] || env["TERM"]);
|
|
36841
|
+
const ancho = Math.max(40, Math.min(salida.columns ?? 100, 120));
|
|
36842
|
+
return { color, unicode, ancho };
|
|
36843
|
+
}
|
|
36844
|
+
function pinta(tema, estilo, texto) {
|
|
36845
|
+
if (!tema.color || texto === "") return texto;
|
|
36846
|
+
const estilos = Array.isArray(estilo) ? estilo : [estilo];
|
|
36847
|
+
return estilos.reduce((acc, uno) => {
|
|
36848
|
+
const [abre, cierra] = CODIGOS[uno];
|
|
36849
|
+
return `\x1B[${abre}m${acc}\x1B[${cierra}m`;
|
|
36850
|
+
}, texto);
|
|
36851
|
+
}
|
|
36852
|
+
var UNICODE = { ok: "\u2713", error: "\u2716", aviso: "\u25B2", info: "\u2139", flecha: "\u2192", punto: "\u25CF", bloqueo: "\u2298", pausa: "\u23F8", lleno: "\u25B0", vacio: "\u25B1", separador: "\xB7" };
|
|
36853
|
+
var ASCII = { ok: "v", error: "x", aviso: "!", info: "i", flecha: "->", punto: "*", bloqueo: "o", pausa: "||", lleno: "#", vacio: "-", separador: "-" };
|
|
36854
|
+
function simbolos(tema) {
|
|
36855
|
+
return tema.unicode ? UNICODE : ASCII;
|
|
36856
|
+
}
|
|
36857
|
+
function anchoVisible(texto) {
|
|
36858
|
+
return texto.replace(/\u001b\[[0-9;]*m/g, "").length;
|
|
36859
|
+
}
|
|
36860
|
+
function rellenar(texto, ancho) {
|
|
36861
|
+
const falta = ancho - anchoVisible(texto);
|
|
36862
|
+
return falta > 0 ? texto + " ".repeat(falta) : texto;
|
|
36863
|
+
}
|
|
36864
|
+
function encabezado(tema, titulo, contexto) {
|
|
36865
|
+
const izquierda = pinta(tema, "negrita", titulo);
|
|
36866
|
+
if (!contexto) return [izquierda, ""];
|
|
36867
|
+
const hueco = tema.ancho - anchoVisible(izquierda) - anchoVisible(contexto);
|
|
36868
|
+
if (hueco < 2) return [izquierda, pinta(tema, "gris", contexto), ""];
|
|
36869
|
+
return [`${izquierda}${" ".repeat(hueco)}${pinta(tema, "gris", contexto)}`, ""];
|
|
36870
|
+
}
|
|
36871
|
+
function barraProgreso(tema, hecho, total, ancho = 8) {
|
|
36872
|
+
const s = simbolos(tema);
|
|
36873
|
+
if (total <= 0) return pinta(tema, "gris", `${s.vacio.repeat(ancho)} 0/0`);
|
|
36874
|
+
const llenos = Math.max(0, Math.min(ancho, Math.round(hecho / total * ancho)));
|
|
36875
|
+
const completo = hecho >= total;
|
|
36876
|
+
const barra = `${s.lleno.repeat(llenos)}${s.vacio.repeat(ancho - llenos)}`;
|
|
36877
|
+
return `${pinta(tema, completo ? "verde" : "azul", barra)} ${hecho}/${total}`;
|
|
36878
|
+
}
|
|
36879
|
+
function marcaSeveridad(tema, severidad) {
|
|
36880
|
+
const s = simbolos(tema);
|
|
36881
|
+
if (severidad === "error") return pinta(tema, "rojo", s.error);
|
|
36882
|
+
if (severidad === "warning") return pinta(tema, "amarillo", s.aviso);
|
|
36883
|
+
return pinta(tema, "azul", s.info);
|
|
36884
|
+
}
|
|
36885
|
+
function formatearDiagnostico(tema, d, rutaRelativa) {
|
|
36886
|
+
const s = simbolos(tema);
|
|
36887
|
+
const ubicacion = rutaRelativa ? pinta(tema, "gris", `${rutaRelativa}${d.line ? `:${d.line}` : ""}`) : "";
|
|
36888
|
+
const codigo = pinta(tema, d.severity === "error" ? ["rojo", "negrita"] : d.severity === "warning" ? ["amarillo", "negrita"] : ["azul", "negrita"], d.code);
|
|
36889
|
+
const cabeza = [` ${marcaSeveridad(tema, d.severity)} ${codigo}`, ubicacion].filter((parte) => parte !== "").join(" ");
|
|
36890
|
+
const lineas = [cabeza, ` ${d.message}`];
|
|
36891
|
+
if (d.suggestion) lineas.push(pinta(tema, "gris", ` ${s.flecha} ${d.suggestion}`));
|
|
36892
|
+
return lineas;
|
|
36893
|
+
}
|
|
36894
|
+
function resumenHallazgos(tema, counts) {
|
|
36895
|
+
const s = simbolos(tema);
|
|
36896
|
+
if (counts.errors === 0 && counts.warnings === 0 && counts.infos === 0) return "";
|
|
36897
|
+
const partes = [];
|
|
36898
|
+
if (counts.errors > 0) partes.push(pinta(tema, "rojo", `${s.error} ${counts.errors} ${counts.errors === 1 ? "error" : "errores"}`));
|
|
36899
|
+
if (counts.warnings > 0) partes.push(pinta(tema, "amarillo", `${s.aviso} ${counts.warnings} ${counts.warnings === 1 ? "aviso" : "avisos"}`));
|
|
36900
|
+
if (counts.infos > 0) partes.push(pinta(tema, "azul", `${s.info} ${counts.infos} ${counts.infos === 1 ? "nota" : "notas"}`));
|
|
36901
|
+
return ` ${partes.join(pinta(tema, "gris", ` ${s.separador} `))}`;
|
|
36902
|
+
}
|
|
36903
|
+
function exito(tema, texto) {
|
|
36904
|
+
return ` ${pinta(tema, "verde", simbolos(tema).ok)} ${texto}`;
|
|
36905
|
+
}
|
|
36906
|
+
function siguienteAccion(tema, comando, descripcion) {
|
|
36907
|
+
const s = simbolos(tema);
|
|
36908
|
+
const lineas = [` ${pinta(tema, "cian", s.flecha)} ${pinta(tema, ["cian", "negrita"], comando)}`];
|
|
36909
|
+
if (descripcion) lineas.push(pinta(tema, "gris", ` ${descripcion}`));
|
|
36910
|
+
return lineas;
|
|
36911
|
+
}
|
|
36912
|
+
function filaAlineada(columnas, separacion = 2) {
|
|
36913
|
+
return columnas.map((columna, indice) => indice === columnas.length - 1 || columna.ancho === void 0 ? columna.texto : rellenar(columna.texto, columna.ancho)).join(" ".repeat(separacion));
|
|
36914
|
+
}
|
|
36915
|
+
function seccion(tema, titulo, detalle) {
|
|
36916
|
+
const cabeza = pinta(tema, ["negrita"], titulo);
|
|
36917
|
+
return detalle ? `${cabeza} ${pinta(tema, "gris", detalle)}` : cabeza;
|
|
36918
|
+
}
|
|
36919
|
+
var MARCA = [
|
|
36920
|
+
[20, 184, 166],
|
|
36921
|
+
[37, 99, 235],
|
|
36922
|
+
[124, 58, 237]
|
|
36923
|
+
];
|
|
36924
|
+
function soportaDegradado(env = process.env) {
|
|
36925
|
+
const colorterm = env["COLORTERM"] ?? "";
|
|
36926
|
+
return colorterm.includes("truecolor") || colorterm.includes("24bit") || env["TERM_PROGRAM"] === "vscode" || Boolean(env["WT_SESSION"]);
|
|
36927
|
+
}
|
|
36928
|
+
function pintaRGB(tema, [r, g, b], texto) {
|
|
36929
|
+
if (!tema.color || texto === "") return texto;
|
|
36930
|
+
return `\x1B[38;2;${r};${g};${b}m${texto}\x1B[39m`;
|
|
36931
|
+
}
|
|
36932
|
+
function mezcla(a, b, t) {
|
|
36933
|
+
return [Math.round(a[0] + (b[0] - a[0]) * t), Math.round(a[1] + (b[1] - a[1]) * t), Math.round(a[2] + (b[2] - a[2]) * t)];
|
|
36934
|
+
}
|
|
36935
|
+
function degradado(tema, texto, paradas = MARCA, env = process.env) {
|
|
36936
|
+
if (!tema.color) return texto;
|
|
36937
|
+
if (!soportaDegradado(env)) return pinta(tema, "cian", texto);
|
|
36938
|
+
const visibles = [...texto];
|
|
36939
|
+
const ultimo = Math.max(1, visibles.length - 1);
|
|
36940
|
+
return visibles.map((caracter, indice) => {
|
|
36941
|
+
if (caracter.trim() === "") return caracter;
|
|
36942
|
+
const posicion = indice / ultimo * (paradas.length - 1);
|
|
36943
|
+
const tramo = Math.min(paradas.length - 2, Math.floor(posicion));
|
|
36944
|
+
return pintaRGB(tema, mezcla(paradas[tramo], paradas[tramo + 1], posicion - tramo), caracter);
|
|
36945
|
+
}).join("");
|
|
36946
|
+
}
|
|
36947
|
+
var LETRAS = {
|
|
36948
|
+
S: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588\u2588\u2588\u2588\u2588", " \u2588", "\u2588\u2588\u2588\u2588\u2588"],
|
|
36949
|
+
P: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 \u2588", "\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588 "],
|
|
36950
|
+
E: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588\u2588\u2588\u2588 ", "\u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
|
|
36951
|
+
C: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588 ", "\u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
|
|
36952
|
+
A: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 \u2588", "\u2588\u2588\u2588\u2588\u2588", "\u2588 \u2588", "\u2588 \u2588"],
|
|
36953
|
+
T: ["\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " \u2588 ", " \u2588 ", " \u2588 "],
|
|
36954
|
+
L: ["\u2588 ", "\u2588 ", "\u2588 ", "\u2588 ", "\u2588\u2588\u2588\u2588\u2588"]
|
|
36955
|
+
};
|
|
36956
|
+
var ALTO_LETRERO = 5;
|
|
36957
|
+
var NOMBRE = "SPECATLAS";
|
|
36958
|
+
var ANCHO_LETRERO = NOMBRE.length * 6 - 1;
|
|
36959
|
+
function letrero(tema) {
|
|
36960
|
+
if (!tema.unicode || tema.ancho < ANCHO_LETRERO + 4) return void 0;
|
|
36961
|
+
const letras = [...NOMBRE].map((letra) => LETRAS[letra]);
|
|
36962
|
+
if (letras.some((letra) => letra === void 0)) return void 0;
|
|
36963
|
+
return Array.from({ length: ALTO_LETRERO }, (_, fila) => letras.map((letra) => letra[fila]).join(" "));
|
|
36964
|
+
}
|
|
36965
|
+
function banner(tema, version, lema = "el proceso se verifica, no se conf\xEDa") {
|
|
36966
|
+
const pie = pinta(tema, "gris", `${version} ${simbolos(tema).separador} ${lema}`);
|
|
36967
|
+
const letras = letrero(tema);
|
|
36968
|
+
if (!letras) return ["", ` ${degradado(tema, "SpecAtlas")}`, ` ${pie}`, ""];
|
|
36969
|
+
return ["", ...letras.map((fila) => ` ${degradado(tema, fila)}`), ` ${pie}`, ""];
|
|
36970
|
+
}
|
|
36971
|
+
function truncar(texto, maximo) {
|
|
36972
|
+
if (maximo <= 1 || anchoVisible(texto) <= maximo) return texto;
|
|
36973
|
+
const corte = texto.slice(0, maximo - 1);
|
|
36974
|
+
const espacio = corte.lastIndexOf(" ");
|
|
36975
|
+
return `${(espacio > maximo * 0.6 ? corte.slice(0, espacio) : corte).trimEnd()}\u2026`;
|
|
36976
|
+
}
|
|
36977
|
+
|
|
36823
36978
|
// src/version.ts
|
|
36824
36979
|
import { readFileSync } from "fs";
|
|
36825
36980
|
import { fileURLToPath } from "url";
|
|
@@ -37665,7 +37820,7 @@ async function runCi(ctx) {
|
|
|
37665
37820
|
}
|
|
37666
37821
|
const gate = await runCiGate({ root, strict, extra });
|
|
37667
37822
|
const diagnostics = [...gate.diagnostics];
|
|
37668
|
-
const lines =
|
|
37823
|
+
const lines = encabezado(detectarTema(), "Comprobaci\xF3n continua", strict ? "modo estricto" : void 0);
|
|
37669
37824
|
let sarifWritten;
|
|
37670
37825
|
if (sarifPath) {
|
|
37671
37826
|
const target = path38.resolve(ctx.cwd, sarifPath);
|
|
@@ -37681,13 +37836,18 @@ async function runCi(ctx) {
|
|
|
37681
37836
|
});
|
|
37682
37837
|
}
|
|
37683
37838
|
}
|
|
37839
|
+
const tema = detectarTema();
|
|
37840
|
+
const s = simbolos(tema);
|
|
37684
37841
|
for (const check of gate.checks) {
|
|
37685
|
-
const
|
|
37686
|
-
|
|
37842
|
+
const marca = check.errors > 0 ? pinta(tema, "rojo", s.error) : check.warnings > 0 ? pinta(tema, "amarillo", s.aviso) : pinta(tema, "verde", s.ok);
|
|
37843
|
+
const detalle = check.errors === 0 && check.warnings === 0 ? pinta(tema, "gris", "sin hallazgos") : [check.errors > 0 ? pinta(tema, "rojo", `${check.errors} ${check.errors === 1 ? "error" : "errores"}`) : "", check.warnings > 0 ? pinta(tema, "amarillo", `${check.warnings} ${check.warnings === 1 ? "aviso" : "avisos"}`) : ""].filter((parte) => parte !== "").join(pinta(tema, "gris", ` ${s.separador} `));
|
|
37844
|
+
lines.push(filaAlineada([{ texto: ` ${marca} ${check.name}`, ancho: 46 }, { texto: detalle }]));
|
|
37687
37845
|
}
|
|
37688
37846
|
lines.push("");
|
|
37689
|
-
lines.push(
|
|
37690
|
-
|
|
37847
|
+
lines.push(
|
|
37848
|
+
gate.failed ? ` ${pinta(tema, ["rojo", "negrita"], `${s.error} BLOQUEADO`)}${pinta(tema, "gris", " \u2014 resuelve los hallazgos antes de continuar")}` : ` ${pinta(tema, ["verde", "negrita"], `${s.ok} TODO EN ORDEN`)}`
|
|
37849
|
+
);
|
|
37850
|
+
if (strict) lines.push(pinta(tema, "gris", " (modo estricto: los avisos tambi\xE9n bloquean)"));
|
|
37691
37851
|
if (sarifPath) {
|
|
37692
37852
|
lines.push(sarifWritten ? `Informe SARIF: ${sarifWritten} (${gate.diagnostics.length} hallazgo(s))` : `Informe SARIF: no se pudo escribir en "${sarifPath}"`);
|
|
37693
37853
|
}
|
|
@@ -38072,7 +38232,7 @@ assumptions: []
|
|
|
38072
38232
|
}
|
|
38073
38233
|
|
|
38074
38234
|
// src/commands/doctor.ts
|
|
38075
|
-
import
|
|
38235
|
+
import "path";
|
|
38076
38236
|
async function runDoctorCommand(ctx) {
|
|
38077
38237
|
const { root, config } = await requireWorkspace(ctx);
|
|
38078
38238
|
const report = await runDoctor(root);
|
|
@@ -38092,17 +38252,10 @@ async function runDoctorCommand(ctx) {
|
|
|
38092
38252
|
const advisory = await upgradeAdvisory(root);
|
|
38093
38253
|
report.findings.push(...advisory.diagnostics);
|
|
38094
38254
|
report.summary = countBySeverity(report.findings);
|
|
38095
|
-
const
|
|
38255
|
+
const tema = detectarTema();
|
|
38256
|
+
const lines = encabezado(tema, msg("doctor.title", ctx.language));
|
|
38096
38257
|
if (report.findings.length === 0) {
|
|
38097
|
-
lines.push("
|
|
38098
|
-
} else {
|
|
38099
|
-
for (const finding of report.findings) {
|
|
38100
|
-
const location = finding.path ? ` ${path44.relative(ctx.cwd, finding.path)}${finding.line ? `:${finding.line}` : ""}` : "";
|
|
38101
|
-
lines.push(` ${finding.severity.toUpperCase()} ${finding.code}${location} \u2014 ${finding.message}`);
|
|
38102
|
-
if (finding.suggestion) lines.push(` \u21B3 ${finding.suggestion}`);
|
|
38103
|
-
}
|
|
38104
|
-
lines.push("");
|
|
38105
|
-
lines.push(`${report.summary.errors} errores, ${report.summary.warnings} avisos, ${report.summary.infos} notas`);
|
|
38258
|
+
lines.push(exito(tema, "El workspace est\xE1 sano."));
|
|
38106
38259
|
}
|
|
38107
38260
|
return {
|
|
38108
38261
|
exitCode: report.summary.errors > 0 ? 1 : 0,
|
|
@@ -38183,27 +38336,72 @@ async function runHash(ctx) {
|
|
|
38183
38336
|
}
|
|
38184
38337
|
|
|
38185
38338
|
// src/commands/help.ts
|
|
38339
|
+
var GRUPOS = [
|
|
38340
|
+
{ titulo: "Empezar", detalle: "poner el flujo en marcha", comandos: ["init", "adopt", "new"] },
|
|
38341
|
+
{ titulo: "El ciclo", detalle: "de lo acordado a la evidencia", comandos: ["approve", "amend", "verify", "review", "archive", "pause", "resume"] },
|
|
38342
|
+
{ titulo: "Saber d\xF3nde est\xE1s", detalle: "qu\xE9 toca y c\xF3mo va", comandos: ["status", "next", "watch", "metrics", "impact", "explain"] },
|
|
38343
|
+
{ titulo: "Comprobar", detalle: "que encaja y que funciona", comandos: ["validate", "trace", "waves", "analyze", "ci", "doctor", "drift", "packs", "contracts", "clarify"] },
|
|
38344
|
+
{ titulo: "Compartir", detalle: "lo que otros van a leer", comandos: ["present", "docs", "mockup", "issue"] },
|
|
38345
|
+
{ titulo: "El proyecto", detalle: "configuraci\xF3n y herramientas", comandos: ["adapters", "profile", "link", "upgrade", "self-update", "hash", "run", "mcp", "version", "help"] }
|
|
38346
|
+
];
|
|
38347
|
+
var TONOS = ["verde", "cian", "azul", "amarillo", "morado", "gris"];
|
|
38348
|
+
function detalleDeComando(tema, nombre) {
|
|
38349
|
+
const spec = CATALOG.find((item) => item.name === nombre);
|
|
38350
|
+
if (!spec) return [];
|
|
38351
|
+
const s = simbolos(tema);
|
|
38352
|
+
return [
|
|
38353
|
+
"",
|
|
38354
|
+
` ${pinta(tema, ["negrita"], `satlas ${spec.name}`)} ${pinta(tema, "gris", spec.description)}`,
|
|
38355
|
+
"",
|
|
38356
|
+
` ${pinta(tema, "cian", s.flecha)} ${pinta(tema, "cian", spec.usage ?? `satlas ${spec.name}`)}`,
|
|
38357
|
+
...spec.flags.length > 0 ? ["", ` ${pinta(tema, "gris", "opciones:")} ${spec.flags.map((flag3) => pinta(tema, "gris", `--${flag3}`)).join(pinta(tema, "gris", " \xB7 "))}`] : [],
|
|
38358
|
+
""
|
|
38359
|
+
];
|
|
38360
|
+
}
|
|
38186
38361
|
async function runHelp(ctx, commandName) {
|
|
38187
38362
|
const language = ctx.language;
|
|
38188
|
-
const
|
|
38189
|
-
|
|
38190
|
-
lines.push("");
|
|
38363
|
+
const tema = detectarTema();
|
|
38364
|
+
const s = simbolos(tema);
|
|
38191
38365
|
if (commandName) {
|
|
38192
|
-
const spec = CATALOG.find((
|
|
38366
|
+
const spec = CATALOG.find((item) => item.name === commandName);
|
|
38193
38367
|
if (!spec) {
|
|
38194
|
-
return {
|
|
38368
|
+
return {
|
|
38369
|
+
exitCode: 2,
|
|
38370
|
+
diagnostics: [{ code: "ATLAS-CLI-001", severity: "error", message: `${msg("cli.unknownCommand", language)}: ${commandName}`, suggestion: "Ejecuta `satlas help` para ver los comandos por grupo" }]
|
|
38371
|
+
};
|
|
38195
38372
|
}
|
|
38196
|
-
|
|
38197
|
-
lines.push(` ${spec.usage ?? `satlas ${spec.name}`}`);
|
|
38198
|
-
return { exitCode: 0, diagnostics: [], text: lines };
|
|
38373
|
+
return { exitCode: 0, diagnostics: [], text: detalleDeComando(tema, commandName) };
|
|
38199
38374
|
}
|
|
38200
|
-
lines
|
|
38375
|
+
const lines = banner(tema, cliVersion());
|
|
38376
|
+
lines.push(filaAlineada([{ texto: ` ${pinta(tema, "gris", "uso")}`, ancho: 8 }, { texto: pinta(tema, "negrita", "satlas <comando> [opciones]") }]));
|
|
38377
|
+
lines.push(filaAlineada([{ texto: ` ${pinta(tema, "gris", "ayuda")}`, ancho: 8 }, { texto: pinta(tema, "gris", "satlas help <comando> \xB7 todos aceptan --json") }]));
|
|
38201
38378
|
lines.push("");
|
|
38202
|
-
|
|
38203
|
-
|
|
38379
|
+
lines.push(` ${pinta(tema, "cian", s.flecha)} ${pinta(tema, ["cian", "negrita"], "satlas next")} ${pinta(tema, "gris", "qu\xE9 toca hacer ahora mismo en este proyecto")}`);
|
|
38380
|
+
lines.push("");
|
|
38381
|
+
const ancho = Math.max(...CATALOG.map((spec) => spec.name.length)) + 2;
|
|
38382
|
+
const anchoDescripcion = Math.max(24, tema.ancho - ancho - 8);
|
|
38383
|
+
GRUPOS.forEach((grupo, indice) => {
|
|
38384
|
+
const disponibles = grupo.comandos.filter((nombre) => CATALOG.some((spec) => spec.name === nombre));
|
|
38385
|
+
if (disponibles.length === 0) return;
|
|
38386
|
+
lines.push(` ${pinta(tema, [TONOS[indice % TONOS.length], "negrita"], grupo.titulo.toUpperCase())} ${pinta(tema, "gris", grupo.detalle)}`);
|
|
38387
|
+
for (const nombre of disponibles) {
|
|
38388
|
+
const spec = CATALOG.find((item) => item.name === nombre);
|
|
38389
|
+
lines.push(filaAlineada([{ texto: ` ${pinta(tema, "negrita", spec.name)}`, ancho: ancho + 4 }, { texto: pinta(tema, "gris", truncar(spec.description, anchoDescripcion)) }]));
|
|
38390
|
+
}
|
|
38391
|
+
lines.push("");
|
|
38392
|
+
});
|
|
38393
|
+
const agrupados = new Set(GRUPOS.flatMap((grupo) => grupo.comandos));
|
|
38394
|
+
const sueltos = CATALOG.filter((spec) => !agrupados.has(spec.name));
|
|
38395
|
+
if (sueltos.length > 0) {
|
|
38396
|
+
lines.push(` ${pinta(tema, ["gris", "negrita"], "OTROS")}`);
|
|
38397
|
+
for (const spec of sueltos) {
|
|
38398
|
+
lines.push(filaAlineada([{ texto: ` ${pinta(tema, "negrita", spec.name)}`, ancho: ancho + 4 }, { texto: pinta(tema, "gris", truncar(spec.description, anchoDescripcion)) }]));
|
|
38399
|
+
}
|
|
38400
|
+
lines.push("");
|
|
38204
38401
|
}
|
|
38402
|
+
lines.push(` ${pinta(tema, "gris", `salida: 0 ${s.separador} 1 hallazgos ${s.separador} 2 uso ${s.separador} 3 E/S`)}`);
|
|
38403
|
+
lines.push(` ${pinta(tema, "gris", "documentaci\xF3n: ")}${degradado(tema, "github.com/AlonsoAM/specatlas")}`);
|
|
38205
38404
|
lines.push("");
|
|
38206
|
-
lines.push("Documentaci\xF3n: ARQUITECTURA.md y PROPUESTA.md en el repositorio.");
|
|
38207
38405
|
return { exitCode: 0, diagnostics: [], text: lines };
|
|
38208
38406
|
}
|
|
38209
38407
|
|
|
@@ -39267,21 +39465,28 @@ async function runNext(ctx) {
|
|
|
39267
39465
|
text: [`\u25B6 ${action.command}`, "", ...outcome.result.text ?? []]
|
|
39268
39466
|
};
|
|
39269
39467
|
}
|
|
39270
|
-
const
|
|
39468
|
+
const tema = detectarTema();
|
|
39469
|
+
const s = simbolos(tema);
|
|
39470
|
+
const lines = encabezado(tema, msg("next.title", ctx.language));
|
|
39271
39471
|
const data = [];
|
|
39272
39472
|
let hasErrors2 = false;
|
|
39273
39473
|
for (const change of targets) {
|
|
39274
39474
|
const evaluation = await evaluateChange(workspace, config, change, approvals);
|
|
39275
39475
|
if (evaluation.blocking > 0) hasErrors2 = true;
|
|
39276
39476
|
const { state, nextAction, blockedBy } = evaluation.state;
|
|
39277
|
-
|
|
39278
|
-
lines.push(
|
|
39279
|
-
|
|
39280
|
-
|
|
39477
|
+
const actor = nextAction.requiresAgent ? pinta(tema, "azul", "con agente") : /^satlas (approve|archive|amend|pause|resume)/.test(nextAction.command) ? pinta(tema, "morado", "humana") : pinta(tema, "verde", "local");
|
|
39478
|
+
lines.push(
|
|
39479
|
+
filaAlineada([
|
|
39480
|
+
{ texto: ` ${pinta(tema, "negrita", change.slug)}`, ancho: 30 },
|
|
39481
|
+
{ texto: pinta(tema, "gris", stateLabel(state)) }
|
|
39482
|
+
])
|
|
39483
|
+
);
|
|
39484
|
+
lines.push(...siguienteAccion(tema, nextAction.command, `${nextAction.description} ${s.separador} ${actor}`));
|
|
39485
|
+
for (const block of blockedBy) lines.push(` ${pinta(tema, "amarillo", s.bloqueo)} ${pinta(tema, "gris", block)}`);
|
|
39281
39486
|
lines.push("");
|
|
39282
39487
|
data.push({ slug: change.slug, state, next: nextAction.command, blockedBy, requiresAgent: nextAction.requiresAgent });
|
|
39283
39488
|
}
|
|
39284
|
-
if (targets.length === 0) lines.push("Sin cambios activos.");
|
|
39489
|
+
if (targets.length === 0) lines.push(pinta(tema, "gris", " Sin cambios activos."));
|
|
39285
39490
|
return { exitCode: hasErrors2 ? 1 : 0, diagnostics: [], data: { changes: data }, text: lines };
|
|
39286
39491
|
}
|
|
39287
39492
|
|
|
@@ -39568,20 +39773,52 @@ async function avisoDeActualizacion(json2, cwd) {
|
|
|
39568
39773
|
}
|
|
39569
39774
|
|
|
39570
39775
|
// src/commands/status.ts
|
|
39776
|
+
var TONO_ESTADO = {
|
|
39777
|
+
draft: "gris",
|
|
39778
|
+
spec_draft: "amarillo",
|
|
39779
|
+
paused: "amarillo",
|
|
39780
|
+
awaiting_mockups: "morado",
|
|
39781
|
+
awaiting_approval: "morado",
|
|
39782
|
+
approved: "azul",
|
|
39783
|
+
planned: "azul",
|
|
39784
|
+
building: "azul",
|
|
39785
|
+
built: "amarillo",
|
|
39786
|
+
verified: "verde",
|
|
39787
|
+
reviewed: "verde",
|
|
39788
|
+
ready: "verde",
|
|
39789
|
+
archived: "gris"
|
|
39790
|
+
};
|
|
39791
|
+
function marcaDeEstado(tema, estado, bloqueado) {
|
|
39792
|
+
const s = simbolos(tema);
|
|
39793
|
+
if (bloqueado) return pinta(tema, "rojo", s.bloqueo);
|
|
39794
|
+
if (estado === "paused") return pinta(tema, "amarillo", s.pausa);
|
|
39795
|
+
if (estado === "ready") return pinta(tema, "verde", s.ok);
|
|
39796
|
+
return pinta(tema, TONO_ESTADO[estado] ?? "azul", s.punto);
|
|
39797
|
+
}
|
|
39571
39798
|
async function runStatus(ctx) {
|
|
39572
39799
|
const { root, workspace, config, approvals } = await requireWorkspace(ctx);
|
|
39573
39800
|
const advisory = await upgradeAdvisory(root);
|
|
39574
|
-
const
|
|
39801
|
+
const tema = detectarTema();
|
|
39802
|
+
const s = simbolos(tema);
|
|
39803
|
+
const fixes = await loadLivingFixes(root);
|
|
39804
|
+
const contexto = [
|
|
39805
|
+
`${workspace.specs.length} ${workspace.specs.length === 1 ? "spec viva" : "specs vivas"}`,
|
|
39806
|
+
`${workspace.changes.length} ${workspace.changes.length === 1 ? "cambio" : "cambios"}`,
|
|
39807
|
+
fixes.length > 0 ? `${fixes.length} ${fixes.length === 1 ? "fix" : "fixes"}` : ""
|
|
39808
|
+
].filter((parte) => parte !== "").join(` ${s.separador} `);
|
|
39809
|
+
const lines = encabezado(tema, msg("status.title", ctx.language), `${config.project.name} ${s.separador} ${contexto}`);
|
|
39575
39810
|
const changes = [];
|
|
39576
39811
|
if (workspace.changes.length === 0) {
|
|
39577
|
-
lines.push("Sin cambios activos. Crea uno con
|
|
39812
|
+
lines.push(pinta(tema, "gris", ` Sin cambios activos. Crea uno con \`satlas new <slug>\`.`));
|
|
39578
39813
|
}
|
|
39579
39814
|
for (const change of workspace.changes) {
|
|
39580
39815
|
const evaluation = await evaluateChange(workspace, config, change, approvals);
|
|
39581
|
-
const { state, progress, nextAction } = evaluation.state;
|
|
39816
|
+
const { state, progress, nextAction, blockedBy } = evaluation.state;
|
|
39817
|
+
const lane = change.meta?.lane ?? config.lanes.default;
|
|
39818
|
+
const bloqueado = blockedBy.length > 0 || evaluation.blocking > 0;
|
|
39582
39819
|
changes.push({
|
|
39583
39820
|
slug: change.slug,
|
|
39584
|
-
lane
|
|
39821
|
+
lane,
|
|
39585
39822
|
domain: change.meta?.domain,
|
|
39586
39823
|
state,
|
|
39587
39824
|
label: stateLabel(state),
|
|
@@ -39590,27 +39827,48 @@ async function runStatus(ctx) {
|
|
|
39590
39827
|
blocking: evaluation.blocking
|
|
39591
39828
|
});
|
|
39592
39829
|
lines.push(
|
|
39593
|
-
|
|
39830
|
+
filaAlineada([
|
|
39831
|
+
{ texto: ` ${marcaDeEstado(tema, state, bloqueado)} ${pinta(tema, "negrita", change.slug)}`, ancho: 30 },
|
|
39832
|
+
{ texto: pinta(tema, TONO_ESTADO[state] ?? "azul", stateLabel(state)), ancho: 22 },
|
|
39833
|
+
{ texto: pinta(tema, "gris", `${change.meta?.domain ?? "\u2014"} ${s.separador} ${lane}`) }
|
|
39834
|
+
])
|
|
39594
39835
|
);
|
|
39595
|
-
|
|
39596
|
-
|
|
39597
|
-
|
|
39598
|
-
|
|
39836
|
+
const medidas = [
|
|
39837
|
+
`${pinta(tema, "gris", "tareas")} ${barraProgreso(tema, progress.tasksDone, progress.tasksTotal)}`,
|
|
39838
|
+
`${pinta(tema, "gris", "evidencia")} ${barraProgreso(tema, progress.scenariosEvidenced, progress.scenariosTotal)}`
|
|
39839
|
+
];
|
|
39840
|
+
lines.push(` ${medidas.join(pinta(tema, "gris", ` ${s.separador} `))}`);
|
|
39841
|
+
for (const bloqueo of blockedBy) lines.push(` ${pinta(tema, "amarillo", s.bloqueo)} ${pinta(tema, "gris", bloqueo)}`);
|
|
39842
|
+
lines.push(...siguienteAccion(tema, nextAction.command, nextAction.description));
|
|
39843
|
+
lines.push("");
|
|
39599
39844
|
}
|
|
39600
|
-
|
|
39601
|
-
|
|
39602
|
-
|
|
39603
|
-
|
|
39845
|
+
if (workspace.specs.length > 0) {
|
|
39846
|
+
lines.push(seccion(tema, msg("status.specs", ctx.language), `${workspace.specs.length}`));
|
|
39847
|
+
const ancho = Math.max(...workspace.specs.map((spec) => spec.domain.length), 8);
|
|
39848
|
+
for (const spec of workspace.specs) {
|
|
39849
|
+
lines.push(
|
|
39850
|
+
filaAlineada([
|
|
39851
|
+
{ texto: ` ${pinta(tema, "morado", s.punto)} ${spec.domain}`, ancho: ancho + 6 },
|
|
39852
|
+
{ texto: pinta(tema, "gris", `${spec.spec.requirements.length} ${spec.spec.requirements.length === 1 ? "requisito" : "requisitos"}`) }
|
|
39853
|
+
])
|
|
39854
|
+
);
|
|
39855
|
+
}
|
|
39856
|
+
lines.push("");
|
|
39604
39857
|
}
|
|
39605
|
-
|
|
39606
|
-
lines.push("");
|
|
39607
|
-
lines.push(`${msg("status.fixes", ctx.language)}: ${fixes.length}`);
|
|
39858
|
+
lines.push(seccion(tema, msg("status.fixes", ctx.language), `${fixes.length}`));
|
|
39608
39859
|
if (fixes.length === 0) {
|
|
39609
|
-
lines.push(" (se llenan al archivar un fix)");
|
|
39860
|
+
lines.push(pinta(tema, "gris", " (se llenan al archivar un fix)"));
|
|
39610
39861
|
} else {
|
|
39611
39862
|
for (const fix of fixes) {
|
|
39612
|
-
const
|
|
39613
|
-
lines.push(
|
|
39863
|
+
const resultado = fix.result === "pass" ? pinta(tema, "verde", fix.result) : pinta(tema, "rojo", fix.result);
|
|
39864
|
+
lines.push(
|
|
39865
|
+
filaAlineada([
|
|
39866
|
+
{ texto: ` ${pinta(tema, "gris", fix.date || "\u2014")}`, ancho: 14 },
|
|
39867
|
+
{ texto: pinta(tema, "gris", fix.domain ?? "\u2014"), ancho: 14 },
|
|
39868
|
+
{ texto: fix.slug, ancho: 28 },
|
|
39869
|
+
{ texto: `${resultado}${fix.source === "archive" ? pinta(tema, "gris", " (hist\xF3rico)") : ""}` }
|
|
39870
|
+
])
|
|
39871
|
+
);
|
|
39614
39872
|
}
|
|
39615
39873
|
}
|
|
39616
39874
|
const diagnostics = [...workspace.diagnostics, ...advisory.diagnostics];
|
|
@@ -39620,7 +39878,7 @@ async function runStatus(ctx) {
|
|
|
39620
39878
|
diagnostics,
|
|
39621
39879
|
data: {
|
|
39622
39880
|
changes,
|
|
39623
|
-
specs: workspace.specs.map((
|
|
39881
|
+
specs: workspace.specs.map((spec) => ({ domain: spec.domain, requirements: spec.spec.requirements.length })),
|
|
39624
39882
|
fixes: fixes.map((fix) => ({
|
|
39625
39883
|
slug: fix.slug,
|
|
39626
39884
|
date: fix.date,
|
|
@@ -39794,8 +40052,10 @@ async function runValidate(ctx) {
|
|
|
39794
40052
|
const slug = flagString(ctx.flags, "change");
|
|
39795
40053
|
const strict = flagBool(ctx.flags, "strict");
|
|
39796
40054
|
const advisory = slug ? void 0 : await upgradeAdvisory(root);
|
|
40055
|
+
const tema = detectarTema();
|
|
40056
|
+
const s = simbolos(tema);
|
|
39797
40057
|
const diagnostics = [];
|
|
39798
|
-
const lines =
|
|
40058
|
+
const lines = encabezado(tema, msg("validate.title", ctx.language), slug ? slug : void 0);
|
|
39799
40059
|
for (const spec of workspace.specs) {
|
|
39800
40060
|
diagnostics.push(...lintSpec(spec.spec, { language: config.spec.language, businessOnly: config.spec.business_only }));
|
|
39801
40061
|
}
|
|
@@ -39811,11 +40071,15 @@ async function runValidate(ctx) {
|
|
|
39811
40071
|
const evaluation = await evaluateChange(workspace, config, change, approvals);
|
|
39812
40072
|
diagnostics.push(...evaluation.lintFindings);
|
|
39813
40073
|
changes.push({ slug: change.slug, blocking: evaluation.blocking, findings: evaluation.lintFindings.length });
|
|
39814
|
-
|
|
39815
|
-
|
|
39816
|
-
|
|
39817
|
-
|
|
39818
|
-
|
|
40074
|
+
const errores = evaluation.lintFindings.filter((finding) => finding.severity === "error").length;
|
|
40075
|
+
const marca = errores > 0 ? pinta(tema, "rojo", s.error) : evaluation.lintFindings.length > 0 ? pinta(tema, "amarillo", s.aviso) : pinta(tema, "verde", s.ok);
|
|
40076
|
+
lines.push(
|
|
40077
|
+
filaAlineada([
|
|
40078
|
+
{ texto: ` ${marca} ${pinta(tema, "negrita", change.slug)}`, ancho: 30 },
|
|
40079
|
+
{ texto: evaluation.lintFindings.length === 0 ? pinta(tema, "gris", "sin hallazgos") : `${evaluation.lintFindings.length} ${msg("summary.findings", ctx.language)}`, ancho: 20 },
|
|
40080
|
+
{ texto: pinta(tema, "gris", path59.relative(ctx.cwd, path59.join(change.dir, "spec.md"))) }
|
|
40081
|
+
])
|
|
40082
|
+
);
|
|
39819
40083
|
}
|
|
39820
40084
|
if (targets.length === 0) lines.push("Sin cambios activos.");
|
|
39821
40085
|
if (advisory && advisory.plan.pending.length > 0) {
|
|
@@ -39823,7 +40087,10 @@ async function runValidate(ctx) {
|
|
|
39823
40087
|
}
|
|
39824
40088
|
const errors = diagnostics.filter((d) => d.severity === "error").length;
|
|
39825
40089
|
const warnings = diagnostics.filter((d) => d.severity === "warning").length;
|
|
39826
|
-
if (errors === 0 && warnings === 0)
|
|
40090
|
+
if (errors === 0 && warnings === 0) {
|
|
40091
|
+
lines.push("");
|
|
40092
|
+
lines.push(exito(tema, msg("validate.ok", ctx.language)));
|
|
40093
|
+
}
|
|
39827
40094
|
return {
|
|
39828
40095
|
exitCode: errors > 0 || strict && warnings > 0 ? 1 : 0,
|
|
39829
40096
|
diagnostics: advisory ? [...diagnostics, ...advisory.diagnostics] : diagnostics,
|
|
@@ -40092,7 +40359,7 @@ var HANDLERS2 = {
|
|
|
40092
40359
|
archive: runArchive,
|
|
40093
40360
|
"self-update": runSelfUpdate,
|
|
40094
40361
|
version: async () => ({ exitCode: 0, data: { version: cliVersion() }, diagnostics: [], text: [`specatlas ${cliVersion()}`] }),
|
|
40095
|
-
help: (ctx) => runHelp(ctx)
|
|
40362
|
+
help: (ctx) => runHelp(ctx, ctx.positionals[0])
|
|
40096
40363
|
};
|
|
40097
40364
|
var COMMANDS = Object.fromEntries(
|
|
40098
40365
|
CATALOG.map((spec) => [spec.name, { description: spec.description, flags: spec.flags, handler: HANDLERS2[spec.name] }])
|
|
@@ -40192,15 +40459,28 @@ function printResult(command, result, json2, language) {
|
|
|
40192
40459
|
`);
|
|
40193
40460
|
return;
|
|
40194
40461
|
}
|
|
40462
|
+
const tema = detectarTema();
|
|
40195
40463
|
const lines = [...result.text ?? []];
|
|
40464
|
+
if (result.diagnostics.length > 0) lines.push("");
|
|
40196
40465
|
for (const d of result.diagnostics) {
|
|
40197
|
-
const
|
|
40198
|
-
lines.push(
|
|
40199
|
-
|
|
40466
|
+
const ruta = d.path ? path62.relative(process.cwd(), d.path) : void 0;
|
|
40467
|
+
lines.push(
|
|
40468
|
+
...formatearDiagnostico(
|
|
40469
|
+
tema,
|
|
40470
|
+
{
|
|
40471
|
+
code: d.code,
|
|
40472
|
+
severity: d.severity,
|
|
40473
|
+
message: d.message,
|
|
40474
|
+
...d.line !== void 0 ? { line: d.line } : {},
|
|
40475
|
+
...d.suggestion !== void 0 ? { suggestion: d.suggestion } : {}
|
|
40476
|
+
},
|
|
40477
|
+
ruta
|
|
40478
|
+
)
|
|
40479
|
+
);
|
|
40200
40480
|
}
|
|
40201
|
-
const counts = countBySeverity(result.diagnostics);
|
|
40202
40481
|
if (result.diagnostics.length > 0) {
|
|
40203
|
-
lines.push(
|
|
40482
|
+
lines.push("");
|
|
40483
|
+
lines.push(resumenHallazgos(tema, countBySeverity(result.diagnostics)));
|
|
40204
40484
|
}
|
|
40205
40485
|
if (lines.length > 0) process.stdout.write(`${lines.join("\n")}
|
|
40206
40486
|
`);
|