kooni-bot 0.3.0 → 0.3.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.
Files changed (2) hide show
  1. package/bin/kooni.js +38 -11
  2. package/package.json +1 -1
package/bin/kooni.js CHANGED
@@ -16,13 +16,24 @@ import { emitKeypressEvents } from "node:readline";
16
16
  import { stdin as input, stdout as output } from "node:process";
17
17
  import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync, readdirSync, statSync, cpSync } from "node:fs";
18
18
  import { realpathSync } from "node:fs";
19
- import { join, basename } from "node:path";
19
+ import { join, basename, dirname } from "node:path";
20
20
  import { homedir } from "node:os";
21
21
  import { execFileSync, spawnSync } from "node:child_process";
22
22
  import { randomUUID, createPublicKey, verify as edVerify } from "node:crypto";
23
23
  import { fileURLToPath } from "node:url";
24
24
 
25
- const CLI_VERSION = "0.2.17";
25
+ // Leída del package.json publicado junto a este archivo — nunca hardcodeada,
26
+ // para que --version y la telemetría (cliVersion) no se desincronicen del
27
+ // número real publicado en npm (bug encontrado: quedó fija en "0.2.17" tras
28
+ // el bump a 0.3.0).
29
+ const CLI_VERSION = (() => {
30
+ try {
31
+ const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
32
+ return JSON.parse(readFileSync(pkgPath, "utf8")).version || "0.0.0";
33
+ } catch {
34
+ return "0.0.0";
35
+ }
36
+ })();
26
37
 
27
38
  const REPO = process.env.KOONI_REPO || "iamnocodeveloper/kooni-bot";
28
39
  const BRANCH = process.env.KOONI_BRANCH || "main";
@@ -443,12 +454,27 @@ async function downloadTemplate(dest) {
443
454
  writeFileSync(dest, Buffer.from(await res.arrayBuffer()));
444
455
  }
445
456
 
446
- // ── extracción (rutas NATIVAS: el tar de Windows no entiende /c/...) ────────
457
+ // ── extracción ───────────────────────────────────────────────────────────────
458
+ // Compat de tar entre shells: el bsdtar de Windows (System32\tar.exe) entiende
459
+ // rutas "C:\…", pero el GNU tar de Git-Bash/MSYS cree que "C:" es un host remoto
460
+ // y falla ("tar: Cannot connect to C: resolve failed"). Solución portátil:
461
+ // correr tar con cwd fijado y pasarle SOLO nombres relativos (sin dos puntos).
462
+ function relTo(base, p) {
463
+ const b = String(base).replace(/[\\/]+$/, "");
464
+ if (p === b) return ".";
465
+ if (p.startsWith(b + "\\") || p.startsWith(b + "/")) return p.slice(b.length + 1) || ".";
466
+ return p; // fuera de base: último recurso
467
+ }
468
+ function tarExtract(tgz, outDir) {
469
+ mkdirSync(outDir, { recursive: true });
470
+ const cwd = dirname(tgz);
471
+ execFileSync("tar", ["-xzf", basename(tgz), "-C", relTo(cwd, outDir)], { cwd });
472
+ }
473
+
447
474
  function extractFresh(tgz, dir) {
448
475
  mkdirSync(dir, { recursive: true });
449
476
  const tmp = join(dir, ".kooni-extract");
450
- mkdirSync(tmp, { recursive: true });
451
- execFileSync("tar", ["-xzf", tgz, "-C", tmp]);
477
+ tarExtract(tgz, tmp);
452
478
  const root = readdirSync(tmp)[0];
453
479
  const src = join(tmp, root);
454
480
  for (const e of readdirSync(src)) {
@@ -462,8 +488,7 @@ function extractFresh(tgz, dir) {
462
488
 
463
489
  // Extrae a un dir TEMP (sin pisar nada) para leer la versión y archivos del template.
464
490
  function extractToTemp(tgz, outDir) {
465
- mkdirSync(outDir, { recursive: true });
466
- execFileSync("tar", ["-xzf", tgz, "-C", outDir]);
491
+ tarExtract(tgz, outDir);
467
492
  const root = readdirSync(outDir)[0];
468
493
  return join(outDir, root);
469
494
  }
@@ -494,10 +519,11 @@ function backupBeforeUpdate(dir, version) {
494
519
  const dest = join(backDir, `${stamp}_v${version}.tgz`);
495
520
  try {
496
521
  mkdirSync(backDir, { recursive: true });
497
- execFileSync("tar", ["-czf", dest, "-C", dir,
522
+ // cwd = dir + ruta relativa del archivo → tar portátil (ver relTo/tarExtract).
523
+ execFileSync("tar", ["-czf", relTo(dir, dest), "-C", ".",
498
524
  "--exclude=./node_modules", "--exclude=./.kooni-backups", "--exclude=./.kooni-extract",
499
525
  "--exclude=./.git", "--exclude=./.wrangler", "--exclude=./.dev.vars", "--exclude=./.dev.vars.*",
500
- "--exclude=./.env", "--exclude=./.env.*", "."]);
526
+ "--exclude=./.env", "--exclude=./.env.*", "."], { cwd: dir });
501
527
  const olds = readdirSync(backDir).filter((f) => f.endsWith(".tgz")).sort();
502
528
  for (const f of olds.slice(0, -5)) rmSync(join(backDir, f), { force: true });
503
529
  return dest;
@@ -896,8 +922,9 @@ async function onboarding(rl, answers, defaultDir) {
896
922
  }
897
923
 
898
924
  // Licencia Pro: si el usuario dice que es Pro, pide el código y lo valida
899
- // localmente (HMAC con la master key). Si es válido se guarda tras el deploy
900
- // (settings pro_license límites quitados). Si es inválido, se avisa y sigue gratis.
925
+ // localmente (Ed25519 con la clave PÚBLICA embebida solo verifica, no firma).
926
+ // Si es válido se guarda tras el deploy (settings pro_license límites
927
+ // quitados). Si es inválido, se avisa y sigue gratis.
901
928
  const wantsPro = interactive()
902
929
  ? await confirm(rl, m("¿Tu bot será Pro (tienes una licencia)?", "Will your bot be Pro (do you have a license)?"))
903
930
  : !!(flags.license || answers.licenseCode);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kooni-bot",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Kooni — instala tu asistente de IA multicanal (WhatsApp, Instagram, Messenger, Telegram) en TU Cloudflare, en un comando.",
5
5
  "license": "MIT",
6
6
  "type": "module",