sabia 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/sabia.mjs +36 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sabia",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Instala, atualiza e desinstala o Sabiá e os toolkits dele no Kiro e no opencode, com um inventário em ~/.sabia/, e explica a rota dos fluxos (sabia rota).",
5
5
  "type": "module",
6
6
  "bin": {
package/sabia.mjs CHANGED
@@ -362,7 +362,7 @@ function mostrarDiferencas(dif) {
362
362
  }
363
363
 
364
364
  export async function instalar(opcoes = {}) {
365
- ctx.log(BANNER + "\n");
365
+ if (process.stdout.isTTY) ctx.log(BANNER + "\n");
366
366
  const inv = lerInventario();
367
367
  const novo = baixarFramework(opcoes);
368
368
  fs.rmSync(sabia("framework"), { recursive: true, force: true });
@@ -664,7 +664,10 @@ export function listarToolkits(opcoes = {}) {
664
664
  l[0] = `↳ ${l[0]}`;
665
665
  linhas.splice(i < 0 ? linhas.length : i + 1, 0, l);
666
666
  }
667
- ctx.log(colunas([["TOOLKIT", "AUTOR", "NO ÍNDICE", "INSTALADO", "NESTE PROJETO", "DESCRIÇÃO"], ...linhas]));
667
+ // no terminal, a descrição é cortada na largura da tela; em pipe ou arquivo, sai inteira
668
+ const largura = process.stdout.columns;
669
+ const corta = (s) => { const c = [...s]; return !largura || c.length <= largura ? s : c.slice(0, largura - 1).join("") + "…"; };
670
+ ctx.log(colunas([["TOOLKIT", "AUTOR", "NO ÍNDICE", "INSTALADO", "NESTE PROJETO", "DESCRIÇÃO"], ...linhas]).split("\n").map(corta).join("\n"));
668
671
  return linhas;
669
672
  }
670
673
 
@@ -883,9 +886,9 @@ export function rotaMapa(opcoes = {}) {
883
886
 
884
887
  // ---------- linha de comando ----------
885
888
 
886
- const AJUDA = `${BANNER}
889
+ const AJUDA = `sabia ${VERSAO} — instala o Sabiá e os toolkits no Kiro e no opencode
887
890
 
888
- sabia ${VERSAO} — instala o Sabiá e os toolkits no Kiro e no opencode
891
+ sabia (sem comando, no terminal) modo interativo: o banner uma vez e um prompt para vários comandos
889
892
 
890
893
  sabia instalar [--alvo kiro,opencode] [--versao X] [--fonte <pasta|url-git>[@ref]]
891
894
  sabia atualizar [--versao X] [--fonte <pasta|url-git>[@ref]]
@@ -921,10 +924,35 @@ export function lerArgs(argv) {
921
924
  return { posicionais, opcoes };
922
925
  }
923
926
 
924
- export async function main(argv = process.argv.slice(2)) {
927
+ /** `sabia` sem comando, no terminal: o banner uma vez e um prompt; cada linha é um comando, até "sair". */
928
+ export async function interativo(entrada) {
929
+ ctx.log(BANNER + "\n\nDigite um comando (ex.: toolkits listar), ajuda ou sair.\n");
930
+ const rl = entrada ? null : readline.createInterface({ input: process.stdin, output: process.stdout });
931
+ const antes = ctx.perguntar;
932
+ // as confirmações dos comandos usam o mesmo prompt: dois readline no mesmo stdin brigam pela linha
933
+ if (rl) ctx.perguntar = async (texto, padrao) => { const r = (await rl.question(`${texto} `)).trim(); return r === "" ? padrao : r; };
934
+ const linhas = entrada ?? (async function* () { for (;;) { try { yield await rl.question("sabia › "); } catch { return; } } })();
935
+ try {
936
+ for await (const linha of linhas) {
937
+ const args = linha.trim().split(/\s+/).filter(Boolean);
938
+ if (args[0] === "sabia") args.shift();
939
+ if (!args.length) continue;
940
+ if (["sair", "exit", "quit"].includes(args[0])) break;
941
+ await main(args.length === 1 && args[0] === "ajuda" ? ["--ajuda"] : args, { dentro: true });
942
+ }
943
+ } finally {
944
+ ctx.perguntar = antes;
945
+ rl?.close();
946
+ }
947
+ return 0;
948
+ }
949
+
950
+ export async function main(argv = process.argv.slice(2), { dentro = false } = {}) {
925
951
  let args;
926
952
  try { args = lerArgs(argv); } catch (e) { console.error(`sabia: ${e.message}`); return 1; }
927
953
  const { posicionais: [cmd, sub, arg], opcoes } = args;
954
+ if (!cmd && !opcoes.ajuda && !opcoes.help && !dentro && process.stdin.isTTY && process.stdout.isTTY) return interativo();
955
+ const perguntarAntes = ctx.perguntar; // o --sim vale só para este comando (no modo interativo vêm outros)
928
956
  if (opcoes.sim) { // cópia alterada à mão continua perguntando: só o --forcar passa por cima
929
957
  const antes = ctx.perguntar;
930
958
  ctx.perguntar = async (texto, padrao) => (/alterado à mão/.test(texto) ? antes(texto, padrao) : /\[s\/N\]/.test(texto) ? "s" : padrao);
@@ -940,11 +968,13 @@ export async function main(argv = process.argv.slice(2)) {
940
968
  else if (cmd === "toolkits" && sub === "remover" && arg) await removerToolkit(arg, opcoes);
941
969
  else if (cmd === "rota" && (sub || opcoes.fluxo || opcoes.mapa))
942
970
  ctx.log(opcoes.mapa ? rotaMapa(opcoes) : opcoes.fluxo ? rotaFluxo(opcoes.fluxo, opcoes) : rota(sub, opcoes));
943
- else { ctx.log(AJUDA); return cmd && !opcoes.ajuda && !opcoes.help ? 1 : 0; }
971
+ else { ctx.log((!dentro && process.stdout.isTTY ? BANNER + "\n\n" : "") + AJUDA); return cmd && !opcoes.ajuda && !opcoes.help ? 1 : 0; }
944
972
  return 0;
945
973
  } catch (e) {
946
974
  console.error(`sabia: ${e.message}`);
947
975
  return 1;
976
+ } finally {
977
+ ctx.perguntar = perguntarAntes;
948
978
  }
949
979
  }
950
980