@nimbuslab/cli 0.16.5 → 0.17.0

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 (3) hide show
  1. package/README.md +34 -1
  2. package/dist/index.js +704 -26
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,14 @@ CLI para criar projetos com a stack moderna da nimbuslab.
5
5
  ## Instalacao
6
6
 
7
7
  ```bash
8
- bun add -g @nimbuslab/cli
8
+ # Instalar CLI
9
+ npm install -g @nimbuslab/cli
10
+
11
+ # IMPORTANTE: Configurar ambiente Node.js (remove fnm/nvm, instala Volta)
12
+ nimbus setup node
13
+
14
+ # Instalar Lola (Code Agent)
15
+ nimbus lola install
9
16
  ```
10
17
 
11
18
  ## Comandos
@@ -15,6 +22,8 @@ nimbus create # Criar novo projeto (interativo)
15
22
  nimbus analyze # Analisar stack do projeto atual
16
23
  nimbus upgrade # Planejar upgrades de dependencias
17
24
  nimbus update # Atualizar o CLI
25
+ nimbus setup node # Configurar ambiente Node.js (Volta)
26
+ nimbus lola install # Instalar Lola (Code Agent)
18
27
  nimbus help # Ajuda
19
28
  ```
20
29
 
@@ -44,6 +53,30 @@ nimbus create meu-projeto --turborepo
44
53
 
45
54
  Stack: Turborepo + apps/packages compartilhados
46
55
 
56
+ ## Setup Node (Volta)
57
+
58
+ O comando `nimbus setup node` configura o ambiente Node.js usando [Volta](https://volta.sh).
59
+
60
+ **Por que Volta?**
61
+ - fnm e nvm causam problemas de cache do shell
62
+ - Volta nao tem esse problema (binarios nativos)
63
+ - Funciona igual no Linux e Windows
64
+ - Gerencia Node, npm e pacotes globais automaticamente
65
+
66
+ ```bash
67
+ # Verificar ambiente atual
68
+ nimbus setup node --check
69
+
70
+ # Migrar para Volta (interativo)
71
+ nimbus setup node
72
+ ```
73
+
74
+ O comando:
75
+ 1. Detecta fnm/nvm instalados
76
+ 2. Remove automaticamente
77
+ 3. Instala Volta
78
+ 4. Reinstala pacotes globais
79
+
47
80
  ## Analyze e Upgrade
48
81
 
49
82
  ```bash
package/dist/index.js CHANGED
@@ -150,7 +150,7 @@ var require_src = __commonJS((exports, module) => {
150
150
  var require_package = __commonJS((exports, module) => {
151
151
  module.exports = {
152
152
  name: "@nimbuslab/cli",
153
- version: "0.16.4",
153
+ version: "0.16.7",
154
154
  description: "CLI para criar projetos nimbuslab",
155
155
  type: "module",
156
156
  bin: {
@@ -202,7 +202,7 @@ var require_package = __commonJS((exports, module) => {
202
202
  });
203
203
 
204
204
  // src/index.ts
205
- var import_picocolors8 = __toESM(require_picocolors(), 1);
205
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
206
206
 
207
207
  // node_modules/@clack/core/dist/index.mjs
208
208
  var import_sisteransi = __toESM(require_src(), 1);
@@ -2590,7 +2590,11 @@ async function update(args) {
2590
2590
  } else {
2591
2591
  M2.success(`${PACKAGE_NAME} atualizado: ${currentVersion} -> ${newVersion}`);
2592
2592
  }
2593
- if (isUsingFnm()) {
2593
+ const isWindows = process.platform === "win32";
2594
+ if (isWindows) {
2595
+ console.log();
2596
+ console.log(import_picocolors6.default.yellow(" Reinicie o terminal para aplicar a atualizacao."));
2597
+ } else if (isUsingFnm()) {
2594
2598
  console.log();
2595
2599
  console.log(import_picocolors6.default.yellow(" fnm detectado - execute para aplicar:"));
2596
2600
  console.log(import_picocolors6.default.cyan(" hash -r"));
@@ -2623,6 +2627,8 @@ var HOME = homedir();
2623
2627
  var LOLA_DIR = join3(HOME, ".lola");
2624
2628
  var LOLA_REPO = "git@github.com:nimbuslab/lola.git";
2625
2629
  var USER_MEMORY = join3(HOME, ".claude", "USER_MEMORY.md");
2630
+ var CLAUDE_COMMANDS_DIR = join3(HOME, ".claude", "commands");
2631
+ var LOLA_COMMANDS_DIR = join3(LOLA_DIR, "commands");
2626
2632
  var LOLA_MEMORY_URL = "https://lola.nimbuslab.com.br/sse";
2627
2633
  var LOLA_MEMORY_NAME = "lola-memory";
2628
2634
  var GEMINI_DIR = join3(HOME, ".gemini");
@@ -2679,6 +2685,33 @@ async function installLolaMemoryMCP() {
2679
2685
  console.log(import_picocolors7.default.dim(' learn "content" - Salvar conhecimento'));
2680
2686
  console.log(import_picocolors7.default.dim(" memory_stats - Ver estatisticas"));
2681
2687
  }
2688
+ async function installLolaCommands() {
2689
+ console.log();
2690
+ console.log(import_picocolors7.default.cyan(" Instalando comandos da Lola..."));
2691
+ if (!existsSync2(LOLA_COMMANDS_DIR)) {
2692
+ console.log(import_picocolors7.default.dim(" Pasta de comandos nao encontrada em ~/.lola/commands"));
2693
+ return;
2694
+ }
2695
+ if (!existsSync2(CLAUDE_COMMANDS_DIR)) {
2696
+ await Bun.$`mkdir -p ${CLAUDE_COMMANDS_DIR}`;
2697
+ }
2698
+ const glob = new Bun.Glob("*.md");
2699
+ const files = Array.from(glob.scanSync({ cwd: LOLA_COMMANDS_DIR }));
2700
+ if (files.length === 0) {
2701
+ console.log(import_picocolors7.default.dim(" Nenhum comando encontrado"));
2702
+ return;
2703
+ }
2704
+ let installed = 0;
2705
+ for (const file of files) {
2706
+ const src = join3(LOLA_COMMANDS_DIR, file);
2707
+ const dest = join3(CLAUDE_COMMANDS_DIR, file);
2708
+ const content = await Bun.file(src).text();
2709
+ await Bun.write(dest, content);
2710
+ installed++;
2711
+ }
2712
+ console.log(import_picocolors7.default.green(` ${installed} comandos instalados!`));
2713
+ console.log(import_picocolors7.default.dim(" Comandos: /inbox, /sent, /msg, /conversation"));
2714
+ }
2682
2715
  async function installGeminiCLI() {
2683
2716
  console.log();
2684
2717
  console.log(import_picocolors7.default.cyan(" Instalando Gemini CLI..."));
@@ -3352,6 +3385,7 @@ fi
3352
3385
  }
3353
3386
  }
3354
3387
  await installLolaMemoryMCP();
3388
+ await installLolaCommands();
3355
3389
  const claudeDir = join3(HOME, ".claude");
3356
3390
  if (!existsSync2(USER_MEMORY)) {
3357
3391
  console.log();
@@ -3455,6 +3489,635 @@ function showLolaHelp() {
3455
3489
  console.log();
3456
3490
  }
3457
3491
 
3492
+ // src/commands/setup-node.ts
3493
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
3494
+ import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
3495
+ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync } from "fs";
3496
+ import { homedir as homedir2 } from "os";
3497
+ import { join as join4 } from "path";
3498
+ var HOME2 = homedir2();
3499
+ var IS_WINDOWS = process.platform === "win32";
3500
+ var CHECK_CMD2 = IS_WINDOWS ? "where" : "which";
3501
+ function detectFnm() {
3502
+ const result = { name: "fnm", installed: false };
3503
+ const check = spawnSync2(CHECK_CMD2, ["fnm"], { encoding: "utf-8", shell: true });
3504
+ const fnmLocations = IS_WINDOWS ? [
3505
+ join4(HOME2, "scoop", "shims", "fnm.exe"),
3506
+ join4(HOME2, "scoop", "apps", "fnm", "current", "fnm.exe"),
3507
+ join4("C:", "ProgramData", "chocolatey", "bin", "fnm.exe"),
3508
+ join4(HOME2, ".cargo", "bin", "fnm.exe"),
3509
+ join4(HOME2, ".fnm", "fnm.exe"),
3510
+ join4(HOME2, "AppData", "Local", "fnm", "fnm.exe"),
3511
+ join4(HOME2, "AppData", "Roaming", "fnm", "fnm.exe")
3512
+ ] : [
3513
+ join4(HOME2, ".local", "share", "fnm", "fnm"),
3514
+ join4(HOME2, ".fnm", "fnm"),
3515
+ join4(HOME2, ".local", "bin", "fnm"),
3516
+ "/opt/homebrew/bin/fnm",
3517
+ "/usr/local/bin/fnm",
3518
+ join4(HOME2, ".cargo", "bin", "fnm")
3519
+ ];
3520
+ let fnmPath = null;
3521
+ if (check.exitCode === 0) {
3522
+ fnmPath = check.stdout?.trim().split(`
3523
+ `)[0] || null;
3524
+ } else {
3525
+ for (const loc of fnmLocations) {
3526
+ if (existsSync3(loc)) {
3527
+ fnmPath = loc;
3528
+ break;
3529
+ }
3530
+ }
3531
+ }
3532
+ if (!fnmPath)
3533
+ return result;
3534
+ result.installed = true;
3535
+ result.path = fnmPath;
3536
+ try {
3537
+ const fnmCmd = fnmPath || "fnm";
3538
+ const version = spawnSync2(fnmCmd, ["--version"], { encoding: "utf-8", shell: true });
3539
+ result.version = version.stdout?.trim().replace("fnm ", "");
3540
+ } catch {}
3541
+ result.configFiles = [];
3542
+ if (IS_WINDOWS) {
3543
+ const ps5Profile = join4(HOME2, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
3544
+ const ps7Profile = join4(HOME2, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
3545
+ const psProfile = join4(HOME2, "Documents", "PowerShell", "profile.ps1");
3546
+ if (existsSync3(ps5Profile))
3547
+ result.configFiles.push(ps5Profile);
3548
+ if (existsSync3(ps7Profile))
3549
+ result.configFiles.push(ps7Profile);
3550
+ if (existsSync3(psProfile))
3551
+ result.configFiles.push(psProfile);
3552
+ } else {
3553
+ const configs = [
3554
+ join4(HOME2, ".bashrc"),
3555
+ join4(HOME2, ".bash_profile"),
3556
+ join4(HOME2, ".profile"),
3557
+ join4(HOME2, ".zshrc"),
3558
+ join4(HOME2, ".zprofile"),
3559
+ join4(HOME2, ".config", "fish", "config.fish")
3560
+ ];
3561
+ for (const cfg of configs) {
3562
+ if (existsSync3(cfg))
3563
+ result.configFiles.push(cfg);
3564
+ }
3565
+ }
3566
+ return result;
3567
+ }
3568
+ function detectNvm() {
3569
+ const result = { name: "nvm", installed: false };
3570
+ if (IS_WINDOWS) {
3571
+ const check = spawnSync2(CHECK_CMD2, ["nvm"], { encoding: "utf-8", shell: true });
3572
+ const nvmWinLocations = [
3573
+ join4(HOME2, "AppData", "Roaming", "nvm", "nvm.exe"),
3574
+ join4("C:", "Program Files", "nvm", "nvm.exe"),
3575
+ join4("C:", "ProgramData", "nvm", "nvm.exe")
3576
+ ];
3577
+ let nvmPath = null;
3578
+ if (check.exitCode === 0) {
3579
+ nvmPath = check.stdout?.trim().split(`
3580
+ `)[0] || null;
3581
+ } else {
3582
+ for (const loc of nvmWinLocations) {
3583
+ if (existsSync3(loc)) {
3584
+ nvmPath = loc;
3585
+ break;
3586
+ }
3587
+ }
3588
+ }
3589
+ if (!nvmPath)
3590
+ return result;
3591
+ result.installed = true;
3592
+ result.path = nvmPath;
3593
+ try {
3594
+ const version = spawnSync2("nvm", ["version"], { encoding: "utf-8", shell: true });
3595
+ result.version = version.stdout?.trim();
3596
+ } catch {}
3597
+ result.configFiles = [];
3598
+ const configs = [
3599
+ join4(HOME2, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1"),
3600
+ join4(HOME2, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1"),
3601
+ join4(HOME2, "Documents", "PowerShell", "profile.ps1")
3602
+ ];
3603
+ for (const cfg of configs) {
3604
+ if (existsSync3(cfg))
3605
+ result.configFiles.push(cfg);
3606
+ }
3607
+ } else {
3608
+ const nvmDir = process.env.NVM_DIR || join4(HOME2, ".nvm");
3609
+ if (!existsSync3(nvmDir))
3610
+ return result;
3611
+ result.installed = true;
3612
+ result.path = nvmDir;
3613
+ result.configFiles = [];
3614
+ const configs = [
3615
+ join4(HOME2, ".bashrc"),
3616
+ join4(HOME2, ".bash_profile"),
3617
+ join4(HOME2, ".profile"),
3618
+ join4(HOME2, ".zshrc"),
3619
+ join4(HOME2, ".zprofile"),
3620
+ join4(HOME2, ".config", "fish", "config.fish")
3621
+ ];
3622
+ for (const cfg of configs) {
3623
+ if (existsSync3(cfg))
3624
+ result.configFiles.push(cfg);
3625
+ }
3626
+ }
3627
+ return result;
3628
+ }
3629
+ function detectVolta() {
3630
+ const result = { name: "volta", installed: false };
3631
+ const check = spawnSync2(CHECK_CMD2, ["volta"], { encoding: "utf-8", shell: true });
3632
+ if (check.exitCode !== 0)
3633
+ return result;
3634
+ result.installed = true;
3635
+ result.path = check.stdout?.trim().split(`
3636
+ `)[0];
3637
+ try {
3638
+ const version = spawnSync2("volta", ["--version"], { encoding: "utf-8", shell: true });
3639
+ result.version = version.stdout?.trim();
3640
+ } catch {}
3641
+ return result;
3642
+ }
3643
+ function detectNode() {
3644
+ const check = spawnSync2(CHECK_CMD2, ["node"], { encoding: "utf-8", shell: true });
3645
+ if (check.exitCode !== 0)
3646
+ return { version: null, manager: null };
3647
+ const nodePath = check.stdout?.trim().split(`
3648
+ `)[0] || "";
3649
+ let manager = null;
3650
+ if (nodePath.includes("fnm"))
3651
+ manager = "fnm";
3652
+ else if (nodePath.includes("nvm"))
3653
+ manager = "nvm";
3654
+ else if (nodePath.includes("volta"))
3655
+ manager = "volta";
3656
+ else if (nodePath.includes(".local") || nodePath.includes("Program Files"))
3657
+ manager = "system";
3658
+ let version = null;
3659
+ try {
3660
+ const v2 = spawnSync2("node", ["--version"], { encoding: "utf-8", shell: true });
3661
+ version = v2.stdout?.trim();
3662
+ } catch {}
3663
+ return { version, manager };
3664
+ }
3665
+ function getGlobalPackages() {
3666
+ const packages = [];
3667
+ try {
3668
+ const result = spawnSync2("npm", ["ls", "-g", "--depth=0", "--json"], {
3669
+ encoding: "utf-8",
3670
+ shell: true,
3671
+ timeout: 1e4
3672
+ });
3673
+ if (result.stdout) {
3674
+ const data = JSON.parse(result.stdout);
3675
+ const deps = data.dependencies || {};
3676
+ for (const pkg of Object.keys(deps)) {
3677
+ if (pkg !== "npm" && pkg !== "corepack") {
3678
+ packages.push(pkg);
3679
+ }
3680
+ }
3681
+ }
3682
+ } catch {}
3683
+ return packages;
3684
+ }
3685
+ function removeFnmFromConfig(configFile) {
3686
+ if (!existsSync3(configFile))
3687
+ return false;
3688
+ try {
3689
+ let content = readFileSync2(configFile, "utf-8");
3690
+ const originalLength = content.length;
3691
+ const patterns = [
3692
+ /^.*fnm.*$/gm,
3693
+ /^.*FNM_.*$/gm,
3694
+ /^eval "\$\(fnm env.*\)"$/gm,
3695
+ /^# fnm.*$/gm
3696
+ ];
3697
+ for (const pattern of patterns) {
3698
+ content = content.replace(pattern, "");
3699
+ }
3700
+ content = content.replace(/\n{3,}/g, `
3701
+
3702
+ `);
3703
+ if (content.length !== originalLength) {
3704
+ writeFileSync(configFile, content);
3705
+ return true;
3706
+ }
3707
+ } catch {}
3708
+ return false;
3709
+ }
3710
+ function removeNvmFromConfig(configFile) {
3711
+ if (!existsSync3(configFile))
3712
+ return false;
3713
+ try {
3714
+ let content = readFileSync2(configFile, "utf-8");
3715
+ const originalLength = content.length;
3716
+ const patterns = [
3717
+ /^export NVM_DIR=.*$/gm,
3718
+ /^.*nvm\.sh.*$/gm,
3719
+ /^.*nvm.*bash_completion.*$/gm,
3720
+ /^# NVM.*$/gm,
3721
+ /^# nvm.*$/gm,
3722
+ /^\[ -s ".*nvm.*" \].*$/gm
3723
+ ];
3724
+ for (const pattern of patterns) {
3725
+ content = content.replace(pattern, "");
3726
+ }
3727
+ content = content.replace(/\n{3,}/g, `
3728
+
3729
+ `);
3730
+ if (content.length !== originalLength) {
3731
+ writeFileSync(configFile, content);
3732
+ return true;
3733
+ }
3734
+ } catch {}
3735
+ return false;
3736
+ }
3737
+ async function removeFnm(fnm) {
3738
+ const spinner = Y2();
3739
+ try {
3740
+ if (IS_WINDOWS) {
3741
+ spinner.start("Removendo fnm...");
3742
+ let removed = false;
3743
+ try {
3744
+ const scoopCheck = spawnSync2("scoop", ["list"], { encoding: "utf-8", shell: true });
3745
+ if (scoopCheck.stdout?.includes("fnm")) {
3746
+ execSync2("scoop uninstall fnm", { stdio: "pipe" });
3747
+ console.log(import_picocolors8.default.dim(" Removido via Scoop"));
3748
+ removed = true;
3749
+ }
3750
+ } catch {}
3751
+ if (!removed) {
3752
+ try {
3753
+ const chocoCheck = spawnSync2("choco", ["list", "--local-only"], { encoding: "utf-8", shell: true });
3754
+ if (chocoCheck.stdout?.includes("fnm")) {
3755
+ execSync2("choco uninstall fnm -y", { stdio: "pipe" });
3756
+ console.log(import_picocolors8.default.dim(" Removido via Chocolatey"));
3757
+ removed = true;
3758
+ }
3759
+ } catch {}
3760
+ }
3761
+ if (!removed) {
3762
+ try {
3763
+ const wingetCheck = spawnSync2("winget", ["list", "--name", "fnm"], { encoding: "utf-8", shell: true });
3764
+ if (wingetCheck.stdout?.includes("fnm")) {
3765
+ execSync2("winget uninstall fnm --silent", { stdio: "pipe" });
3766
+ console.log(import_picocolors8.default.dim(" Removido via winget"));
3767
+ removed = true;
3768
+ }
3769
+ } catch {}
3770
+ }
3771
+ const winFnmDirs = [
3772
+ join4(HOME2, ".fnm"),
3773
+ join4(HOME2, "AppData", "Local", "fnm"),
3774
+ join4(HOME2, "AppData", "Roaming", "fnm")
3775
+ ];
3776
+ for (const dir of winFnmDirs) {
3777
+ if (existsSync3(dir)) {
3778
+ try {
3779
+ execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: true });
3780
+ console.log(import_picocolors8.default.dim(` Removido ${dir}`));
3781
+ removed = true;
3782
+ } catch {}
3783
+ }
3784
+ }
3785
+ for (const configFile of fnm.configFiles || []) {
3786
+ if (removeFnmFromConfig(configFile)) {
3787
+ console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3788
+ removed = true;
3789
+ }
3790
+ }
3791
+ spinner.stop(removed ? "fnm removido!" : import_picocolors8.default.yellow("fnm nao encontrado"));
3792
+ return removed;
3793
+ } else {
3794
+ spinner.start("Removendo fnm...");
3795
+ let removed = false;
3796
+ try {
3797
+ const brewCheck = spawnSync2("brew", ["list", "fnm"], { encoding: "utf-8", shell: true });
3798
+ if (brewCheck.exitCode === 0) {
3799
+ execSync2("brew uninstall fnm", { stdio: "pipe" });
3800
+ console.log(import_picocolors8.default.dim(" Removido via Homebrew"));
3801
+ removed = true;
3802
+ }
3803
+ } catch {}
3804
+ for (const configFile of fnm.configFiles || []) {
3805
+ if (removeFnmFromConfig(configFile)) {
3806
+ console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3807
+ removed = true;
3808
+ }
3809
+ }
3810
+ const fnmDirs = [
3811
+ join4(HOME2, ".fnm"),
3812
+ join4(HOME2, ".local", "share", "fnm")
3813
+ ];
3814
+ for (const fnmDir of fnmDirs) {
3815
+ if (existsSync3(fnmDir)) {
3816
+ execSync2(`rm -rf "${fnmDir}"`, { stdio: "pipe" });
3817
+ console.log(import_picocolors8.default.dim(` Removido ${fnmDir}`));
3818
+ removed = true;
3819
+ }
3820
+ }
3821
+ const fnmBins = [
3822
+ join4(HOME2, ".local", "bin", "fnm"),
3823
+ join4(HOME2, ".cargo", "bin", "fnm")
3824
+ ];
3825
+ for (const bin of fnmBins) {
3826
+ if (existsSync3(bin)) {
3827
+ execSync2(`rm -f "${bin}"`, { stdio: "pipe" });
3828
+ console.log(import_picocolors8.default.dim(` Removido ${bin}`));
3829
+ removed = true;
3830
+ }
3831
+ }
3832
+ spinner.stop(removed ? "fnm removido!" : "fnm nao encontrado nos locais padrao");
3833
+ return removed;
3834
+ }
3835
+ } catch (error) {
3836
+ spinner.stop(import_picocolors8.default.red("Erro ao remover fnm"));
3837
+ return false;
3838
+ }
3839
+ }
3840
+ async function removeNvm(nvm) {
3841
+ const spinner = Y2();
3842
+ try {
3843
+ if (IS_WINDOWS) {
3844
+ spinner.start("Removendo nvm-windows...");
3845
+ let removed = false;
3846
+ try {
3847
+ const wingetCheck = spawnSync2("winget", ["list", "--name", "nvm"], { encoding: "utf-8", shell: true });
3848
+ if (wingetCheck.stdout?.toLowerCase().includes("nvm")) {
3849
+ execSync2("winget uninstall nvm --silent", { stdio: "pipe" });
3850
+ console.log(import_picocolors8.default.dim(" Removido via winget"));
3851
+ removed = true;
3852
+ }
3853
+ } catch {}
3854
+ const nvmWinDirs = [
3855
+ join4(HOME2, "AppData", "Roaming", "nvm"),
3856
+ join4("C:", "Program Files", "nvm"),
3857
+ join4("C:", "ProgramData", "nvm")
3858
+ ];
3859
+ for (const dir of nvmWinDirs) {
3860
+ if (existsSync3(dir)) {
3861
+ try {
3862
+ execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: true });
3863
+ console.log(import_picocolors8.default.dim(` Removido ${dir}`));
3864
+ removed = true;
3865
+ } catch {}
3866
+ }
3867
+ }
3868
+ for (const configFile of nvm.configFiles || []) {
3869
+ if (removeNvmFromConfig(configFile)) {
3870
+ console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3871
+ removed = true;
3872
+ }
3873
+ }
3874
+ if (!removed) {
3875
+ console.log(import_picocolors8.default.yellow(`
3876
+ nvm-windows pode precisar de remocao manual:`));
3877
+ console.log(import_picocolors8.default.dim(" 1. Abra 'Adicionar ou remover programas'"));
3878
+ console.log(import_picocolors8.default.dim(" 2. Procure por 'NVM for Windows'"));
3879
+ console.log(import_picocolors8.default.dim(" 3. Clique em Desinstalar"));
3880
+ }
3881
+ spinner.stop(removed ? "nvm removido!" : import_picocolors8.default.yellow("Verifique manualmente"));
3882
+ return removed;
3883
+ } else {
3884
+ spinner.start("Removendo nvm...");
3885
+ let removed = false;
3886
+ for (const configFile of nvm.configFiles || []) {
3887
+ if (removeNvmFromConfig(configFile)) {
3888
+ console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3889
+ removed = true;
3890
+ }
3891
+ }
3892
+ const nvmDir = process.env.NVM_DIR || join4(HOME2, ".nvm");
3893
+ if (existsSync3(nvmDir)) {
3894
+ execSync2(`rm -rf "${nvmDir}"`, { stdio: "pipe" });
3895
+ console.log(import_picocolors8.default.dim(` Removido ${nvmDir}`));
3896
+ removed = true;
3897
+ }
3898
+ spinner.stop(removed ? "nvm removido!" : "nvm nao encontrado");
3899
+ return removed;
3900
+ }
3901
+ } catch (error) {
3902
+ spinner.stop(import_picocolors8.default.red("Erro ao remover nvm"));
3903
+ return false;
3904
+ }
3905
+ }
3906
+ async function installVolta() {
3907
+ const spinner = Y2();
3908
+ try {
3909
+ if (IS_WINDOWS) {
3910
+ spinner.start("Verificando metodo de instalacao...");
3911
+ const chocoCheck = spawnSync2(CHECK_CMD2, ["choco"], { encoding: "utf-8", shell: true });
3912
+ if (chocoCheck.exitCode === 0) {
3913
+ spinner.stop("Chocolatey detectado");
3914
+ spinner.start("Instalando Volta via Chocolatey...");
3915
+ execSync2("choco install volta -y", { stdio: "pipe" });
3916
+ spinner.stop("Volta instalado!");
3917
+ return true;
3918
+ }
3919
+ const wingetCheck = spawnSync2(CHECK_CMD2, ["winget"], { encoding: "utf-8", shell: true });
3920
+ if (wingetCheck.exitCode === 0) {
3921
+ spinner.stop("winget detectado");
3922
+ spinner.start("Instalando Volta via winget...");
3923
+ execSync2("winget install Volta.Volta --silent", { stdio: "pipe" });
3924
+ spinner.stop("Volta instalado!");
3925
+ return true;
3926
+ }
3927
+ spinner.stop(import_picocolors8.default.yellow("Instale manualmente"));
3928
+ console.log();
3929
+ console.log(import_picocolors8.default.bold(" Baixe o instalador:"));
3930
+ console.log(import_picocolors8.default.cyan(" https://github.com/volta-cli/volta/releases/latest"));
3931
+ console.log();
3932
+ console.log(import_picocolors8.default.dim(" Ou instale Chocolatey primeiro:"));
3933
+ console.log(import_picocolors8.default.dim(" https://chocolatey.org/install"));
3934
+ return false;
3935
+ } else {
3936
+ spinner.start("Baixando e instalando Volta...");
3937
+ execSync2("curl https://get.volta.sh | bash -s -- --skip-setup", {
3938
+ stdio: "pipe",
3939
+ shell: "/bin/bash"
3940
+ });
3941
+ const shellConfig = existsSync3(join4(HOME2, ".zshrc")) ? join4(HOME2, ".zshrc") : join4(HOME2, ".bashrc");
3942
+ const voltaSetup = `
3943
+ # Volta - Node.js version manager
3944
+ export VOLTA_HOME="$HOME/.volta"
3945
+ export PATH="$VOLTA_HOME/bin:$PATH"
3946
+ `;
3947
+ if (existsSync3(shellConfig)) {
3948
+ const content = readFileSync2(shellConfig, "utf-8");
3949
+ if (!content.includes("VOLTA_HOME")) {
3950
+ writeFileSync(shellConfig, content + voltaSetup);
3951
+ console.log(import_picocolors8.default.dim(` Adicionado ao ${shellConfig}`));
3952
+ }
3953
+ }
3954
+ spinner.stop("Volta instalado!");
3955
+ return true;
3956
+ }
3957
+ } catch (error) {
3958
+ spinner.stop(import_picocolors8.default.red("Erro ao instalar Volta"));
3959
+ console.log(import_picocolors8.default.dim(` ${error}`));
3960
+ return false;
3961
+ }
3962
+ }
3963
+ async function installNodeWithVolta() {
3964
+ const spinner = Y2();
3965
+ try {
3966
+ const voltaBin = IS_WINDOWS ? "volta" : join4(HOME2, ".volta", "bin", "volta");
3967
+ spinner.start("Instalando Node.js LTS via Volta...");
3968
+ execSync2(`"${voltaBin}" install node`, { stdio: "pipe", shell: true });
3969
+ spinner.stop("Node.js instalado!");
3970
+ return true;
3971
+ } catch (error) {
3972
+ spinner.stop(import_picocolors8.default.red("Erro ao instalar Node.js"));
3973
+ return false;
3974
+ }
3975
+ }
3976
+ async function reinstallGlobalPackages(packages) {
3977
+ if (packages.length === 0)
3978
+ return;
3979
+ const spinner = Y2();
3980
+ const voltaBin = IS_WINDOWS ? "volta" : join4(HOME2, ".volta", "bin", "volta");
3981
+ for (const pkg of packages) {
3982
+ spinner.start(`Instalando ${pkg}...`);
3983
+ try {
3984
+ execSync2(`"${voltaBin}" install ${pkg}`, { stdio: "pipe", shell: true });
3985
+ spinner.stop(`${pkg} instalado!`);
3986
+ } catch {
3987
+ spinner.stop(import_picocolors8.default.yellow(`${pkg} - falha (instale manualmente)`));
3988
+ }
3989
+ }
3990
+ }
3991
+ async function setupNode(args) {
3992
+ const checkOnly = args.includes("--check") || args.includes("-c");
3993
+ console.log();
3994
+ Ie(import_picocolors8.default.bgCyan(import_picocolors8.default.black(" nimbus setup node ")));
3995
+ console.log();
3996
+ console.log(import_picocolors8.default.bold(" Detectando ambiente..."));
3997
+ console.log();
3998
+ const fnm = detectFnm();
3999
+ const nvm = detectNvm();
4000
+ const volta = detectVolta();
4001
+ const node = detectNode();
4002
+ const status = (installed, version) => {
4003
+ if (!installed)
4004
+ return import_picocolors8.default.dim("nao instalado");
4005
+ return import_picocolors8.default.green(`instalado${version ? ` (${version})` : ""}`);
4006
+ };
4007
+ console.log(` ${import_picocolors8.default.bold("fnm:")} ${status(fnm.installed, fnm.version)}`);
4008
+ console.log(` ${import_picocolors8.default.bold("nvm:")} ${status(nvm.installed, nvm.version)}`);
4009
+ console.log(` ${import_picocolors8.default.bold("volta:")} ${status(volta.installed, volta.version)}`);
4010
+ console.log();
4011
+ console.log(` ${import_picocolors8.default.bold("node:")} ${node.version || import_picocolors8.default.dim("nao encontrado")}`);
4012
+ if (node.manager) {
4013
+ console.log(` ${import_picocolors8.default.dim(`gerenciado por: ${node.manager}`)}`);
4014
+ }
4015
+ console.log();
4016
+ if (volta.installed && !fnm.installed && !nvm.installed) {
4017
+ M2.success("Ambiente OK! Volta instalado e configurado.");
4018
+ Se(import_picocolors8.default.green("Nada a fazer."));
4019
+ return;
4020
+ }
4021
+ if (checkOnly) {
4022
+ if (fnm.installed || nvm.installed) {
4023
+ console.log(import_picocolors8.default.yellow(" Recomendacao: migre para Volta"));
4024
+ console.log(import_picocolors8.default.dim(" Execute: nimbus setup node"));
4025
+ }
4026
+ Se("");
4027
+ return;
4028
+ }
4029
+ const hasOldManager = fnm.installed || nvm.installed;
4030
+ const globalPackages = getGlobalPackages();
4031
+ if (hasOldManager) {
4032
+ console.log(import_picocolors8.default.yellow(" Gerenciadores antigos detectados!"));
4033
+ console.log();
4034
+ console.log(import_picocolors8.default.dim(" fnm e nvm causam problemas de cache do shell."));
4035
+ console.log(import_picocolors8.default.dim(" Volta resolve isso e funciona melhor no Windows."));
4036
+ console.log();
4037
+ if (globalPackages.length > 0) {
4038
+ console.log(import_picocolors8.default.bold(" Pacotes globais encontrados:"));
4039
+ for (const pkg of globalPackages) {
4040
+ console.log(import_picocolors8.default.dim(` - ${pkg}`));
4041
+ }
4042
+ console.log();
4043
+ }
4044
+ }
4045
+ const actions = [];
4046
+ if (fnm.installed)
4047
+ actions.push("Remover fnm");
4048
+ if (nvm.installed)
4049
+ actions.push("Remover nvm");
4050
+ if (!volta.installed)
4051
+ actions.push("Instalar Volta");
4052
+ actions.push("Instalar Node.js via Volta");
4053
+ if (globalPackages.length > 0)
4054
+ actions.push(`Reinstalar ${globalPackages.length} pacotes globais`);
4055
+ console.log(import_picocolors8.default.bold(" O que sera feito:"));
4056
+ for (const action of actions) {
4057
+ console.log(import_picocolors8.default.cyan(` -> ${action}`));
4058
+ }
4059
+ console.log();
4060
+ const confirm = await ye({
4061
+ message: "Continuar com a migracao para Volta?",
4062
+ initialValue: true
4063
+ });
4064
+ if (pD(confirm) || !confirm) {
4065
+ xe("Migracao cancelada");
4066
+ return;
4067
+ }
4068
+ console.log();
4069
+ if (fnm.installed) {
4070
+ console.log(import_picocolors8.default.bold(" Removendo fnm..."));
4071
+ await removeFnm(fnm);
4072
+ console.log();
4073
+ }
4074
+ if (nvm.installed) {
4075
+ console.log(import_picocolors8.default.bold(" Removendo nvm..."));
4076
+ await removeNvm(nvm);
4077
+ console.log();
4078
+ }
4079
+ if (!volta.installed) {
4080
+ console.log(import_picocolors8.default.bold(" Instalando Volta..."));
4081
+ const installed = await installVolta();
4082
+ if (!installed) {
4083
+ Se(import_picocolors8.default.red("Falha na instalacao. Tente manualmente."));
4084
+ return;
4085
+ }
4086
+ console.log();
4087
+ }
4088
+ console.log(import_picocolors8.default.bold(" Instalando Node.js..."));
4089
+ await installNodeWithVolta();
4090
+ console.log();
4091
+ if (globalPackages.length > 0) {
4092
+ console.log(import_picocolors8.default.bold(" Reinstalando pacotes globais..."));
4093
+ await reinstallGlobalPackages(globalPackages);
4094
+ console.log();
4095
+ }
4096
+ console.log(import_picocolors8.default.green(" ====================================="));
4097
+ console.log(import_picocolors8.default.green(" Migracao concluida!"));
4098
+ console.log(import_picocolors8.default.green(" ====================================="));
4099
+ console.log();
4100
+ if (IS_WINDOWS) {
4101
+ console.log(import_picocolors8.default.yellow(" IMPORTANTE: Reinicie o terminal!"));
4102
+ console.log();
4103
+ console.log(import_picocolors8.default.dim(" Feche todas as janelas do PowerShell/Terminal"));
4104
+ console.log(import_picocolors8.default.dim(" e abra novamente para aplicar as mudancas."));
4105
+ } else {
4106
+ console.log(import_picocolors8.default.yellow(" IMPORTANTE: Reinicie o terminal ou execute:"));
4107
+ console.log();
4108
+ console.log(import_picocolors8.default.cyan(" source ~/.zshrc"));
4109
+ console.log(import_picocolors8.default.dim(" # ou"));
4110
+ console.log(import_picocolors8.default.cyan(" source ~/.bashrc"));
4111
+ }
4112
+ console.log();
4113
+ console.log(import_picocolors8.default.bold(" Depois, verifique:"));
4114
+ console.log(import_picocolors8.default.dim(" volta --version"));
4115
+ console.log(import_picocolors8.default.dim(" node --version"));
4116
+ console.log(import_picocolors8.default.dim(" nimbus --version"));
4117
+ console.log();
4118
+ Se(import_picocolors8.default.green("Pronto! Volta configurado."));
4119
+ }
4120
+
3458
4121
  // src/index.ts
3459
4122
  var PACKAGE_NAME2 = "@nimbuslab/cli";
3460
4123
  var pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
@@ -3494,18 +4157,18 @@ function showUpdateNotice(latestVersion) {
3494
4157
  const line2 = ` Atualize com: ${command}`;
3495
4158
  const maxLen = Math.max(line1.length, line2.length);
3496
4159
  const border = "\u2500".repeat(maxLen + 2);
3497
- console.log(import_picocolors8.default.yellow(` \u250C${border}\u2510`));
3498
- console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.white(line1.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3499
- console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3500
- console.log(import_picocolors8.default.yellow(` \u2514${border}\u2518`));
4160
+ console.log(import_picocolors9.default.yellow(` \u250C${border}\u2510`));
4161
+ console.log(import_picocolors9.default.yellow(` \u2502`) + import_picocolors9.default.white(line1.padEnd(maxLen + 2)) + import_picocolors9.default.yellow(`\u2502`));
4162
+ console.log(import_picocolors9.default.yellow(` \u2502`) + import_picocolors9.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors9.default.yellow(`\u2502`));
4163
+ console.log(import_picocolors9.default.yellow(` \u2514${border}\u2518`));
3501
4164
  console.log();
3502
4165
  }
3503
4166
  async function main() {
3504
4167
  const args = process.argv.slice(2);
3505
4168
  const command = args[0];
3506
- console.log(import_picocolors8.default.cyan(LOGO));
3507
- console.log(import_picocolors8.default.white(" nimbuslab CLI"));
3508
- console.log(import_picocolors8.default.dim(" Create awesome projects"));
4169
+ console.log(import_picocolors9.default.cyan(LOGO));
4170
+ console.log(import_picocolors9.default.white(" nimbuslab CLI"));
4171
+ console.log(import_picocolors9.default.dim(" Create awesome projects"));
3509
4172
  console.log();
3510
4173
  const latestVersion = await checkForUpdates();
3511
4174
  if (latestVersion) {
@@ -3521,70 +4184,85 @@ async function main() {
3521
4184
  await update(args.slice(1));
3522
4185
  } else if (command === "lola") {
3523
4186
  await lola(args.slice(1));
4187
+ } else if (command === "setup") {
4188
+ const subcommand = args[1];
4189
+ if (subcommand === "node") {
4190
+ await setupNode(args.slice(2));
4191
+ } else {
4192
+ console.log(import_picocolors9.default.red(`Subcomando desconhecido: ${subcommand || "(vazio)"}`));
4193
+ console.log(import_picocolors9.default.dim(" Uso: nimbus setup node"));
4194
+ process.exit(1);
4195
+ }
3524
4196
  } else if (command === "help" || command === "--help" || command === "-h") {
3525
4197
  showHelp();
3526
4198
  } else if (command === "version" || command === "--version" || command === "-v") {
3527
4199
  showVersion();
3528
4200
  } else {
3529
- console.log(import_picocolors8.default.red(`Comando desconhecido: ${command}`));
4201
+ console.log(import_picocolors9.default.red(`Comando desconhecido: ${command}`));
3530
4202
  showHelp();
3531
4203
  process.exit(1);
3532
4204
  }
3533
4205
  }
3534
4206
  function showHelp() {
3535
4207
  console.log(`
3536
- ${import_picocolors8.default.bold("Uso:")} nimbus [comando] [op\xE7\xF5es]
4208
+ ${import_picocolors9.default.bold("Uso:")} nimbus [comando] [op\xE7\xF5es]
3537
4209
 
3538
- ${import_picocolors8.default.bold("Comandos:")}
4210
+ ${import_picocolors9.default.bold("Comandos:")}
3539
4211
  create [nome] Criar novo projeto
3540
4212
  analyze [dir] Analisar stack do projeto
3541
4213
  upgrade [alvo] Atualizar depend\xEAncias
3542
4214
  update [vers\xE3o] Atualizar o CLI
4215
+ setup [alvo] Configurar ambiente
3543
4216
  lola [a\xE7\xE3o] Lola - Code Agent
3544
4217
  help Mostrar esta ajuda
3545
4218
  version Mostrar vers\xE3o
3546
4219
 
3547
- ${import_picocolors8.default.bold("Templates:")}
4220
+ ${import_picocolors9.default.bold("Templates:")}
3548
4221
  --landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
3549
4222
  --app Web app (Landing + Better Auth + Drizzle)
3550
4223
  --turborepo Monorepo (Turborepo + apps/packages)
3551
4224
 
3552
- ${import_picocolors8.default.bold("Analyze & Upgrade:")}
4225
+ ${import_picocolors9.default.bold("Analyze & Upgrade:")}
3553
4226
  analyze . Detectar stack e mostrar recomenda\xE7\xF5es
3554
4227
  analyze --json Output em JSON
3555
4228
  upgrade --plan Mostrar plano de upgrade
3556
4229
  upgrade next Atualizar Next.js
3557
4230
  upgrade tailwind Atualizar Tailwind CSS
3558
4231
 
3559
- ${import_picocolors8.default.bold("Update (CLI):")}
4232
+ ${import_picocolors9.default.bold("Update (CLI):")}
3560
4233
  update Atualizar para ultima versao
3561
4234
  update 0.11.0 Instalar versao especifica
3562
4235
  update --list Listar versoes disponiveis
3563
4236
  update --force Forcar reinstalacao (limpa cache)
3564
4237
 
3565
- ${import_picocolors8.default.bold("Op\xE7\xF5es:")}
4238
+ ${import_picocolors9.default.bold("Setup (Ambiente):")}
4239
+ setup node Migrar para Volta (remove fnm/nvm)
4240
+ setup node --check Verificar ambiente atual
4241
+
4242
+ ${import_picocolors9.default.bold("Op\xE7\xF5es:")}
3566
4243
  -y, --yes Aceitar padr\xF5es
3567
4244
  --no-git N\xE3o inicializar Git
3568
4245
  --no-install N\xE3o instalar depend\xEAncias
3569
4246
  --template <url> Usar template customizado
3570
4247
 
3571
- ${import_picocolors8.default.bold("Lola (Code Agent):")}
4248
+ ${import_picocolors9.default.bold("Lola (Code Agent):")}
3572
4249
  lola install Instalar/atualizar Lola
3573
4250
  lola suggest Sugerir melhoria (cria issue)
3574
4251
 
3575
- ${import_picocolors8.default.bold("Exemplos:")}
3576
- ${import_picocolors8.default.dim("$")} nimbus create my-landing --landing
3577
- ${import_picocolors8.default.dim("$")} nimbus create my-app --app
3578
- ${import_picocolors8.default.dim("$")} nimbus analyze ./my-project
3579
- ${import_picocolors8.default.dim("$")} nimbus upgrade --plan
3580
- ${import_picocolors8.default.dim("$")} nimbus update
3581
- ${import_picocolors8.default.dim("$")} nimbus lola install
4252
+ ${import_picocolors9.default.bold("Exemplos:")}
4253
+ ${import_picocolors9.default.dim("$")} nimbus create my-landing --landing
4254
+ ${import_picocolors9.default.dim("$")} nimbus create my-app --app
4255
+ ${import_picocolors9.default.dim("$")} nimbus analyze ./my-project
4256
+ ${import_picocolors9.default.dim("$")} nimbus upgrade --plan
4257
+ ${import_picocolors9.default.dim("$")} nimbus update
4258
+ ${import_picocolors9.default.dim("$")} nimbus setup node
4259
+ ${import_picocolors9.default.dim("$")} nimbus lola install
3582
4260
  `);
3583
4261
  }
3584
4262
  function showVersion() {
3585
4263
  console.log(`${PACKAGE_NAME2} v${CURRENT_VERSION}`);
3586
4264
  }
3587
4265
  main().catch((err) => {
3588
- console.error(import_picocolors8.default.red("Erro:"), err.message);
4266
+ console.error(import_picocolors9.default.red("Erro:"), err.message);
3589
4267
  process.exit(1);
3590
4268
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nimbuslab/cli",
3
- "version": "0.16.5",
3
+ "version": "0.17.0",
4
4
  "description": "CLI para criar projetos nimbuslab",
5
5
  "type": "module",
6
6
  "bin": {