@nimbuslab/cli 0.16.7 → 0.17.1

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 +669 -25
  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.6",
153
+ version: "0.17.0",
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);
@@ -3489,6 +3489,635 @@ function showLolaHelp() {
3489
3489
  console.log();
3490
3490
  }
3491
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
+
3492
4121
  // src/index.ts
3493
4122
  var PACKAGE_NAME2 = "@nimbuslab/cli";
3494
4123
  var pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
@@ -3528,18 +4157,18 @@ function showUpdateNotice(latestVersion) {
3528
4157
  const line2 = ` Atualize com: ${command}`;
3529
4158
  const maxLen = Math.max(line1.length, line2.length);
3530
4159
  const border = "\u2500".repeat(maxLen + 2);
3531
- console.log(import_picocolors8.default.yellow(` \u250C${border}\u2510`));
3532
- console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.white(line1.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3533
- console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3534
- 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`));
3535
4164
  console.log();
3536
4165
  }
3537
4166
  async function main() {
3538
4167
  const args = process.argv.slice(2);
3539
4168
  const command = args[0];
3540
- console.log(import_picocolors8.default.cyan(LOGO));
3541
- console.log(import_picocolors8.default.white(" nimbuslab CLI"));
3542
- 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"));
3543
4172
  console.log();
3544
4173
  const latestVersion = await checkForUpdates();
3545
4174
  if (latestVersion) {
@@ -3555,70 +4184,85 @@ async function main() {
3555
4184
  await update(args.slice(1));
3556
4185
  } else if (command === "lola") {
3557
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
+ }
3558
4196
  } else if (command === "help" || command === "--help" || command === "-h") {
3559
4197
  showHelp();
3560
4198
  } else if (command === "version" || command === "--version" || command === "-v") {
3561
4199
  showVersion();
3562
4200
  } else {
3563
- console.log(import_picocolors8.default.red(`Comando desconhecido: ${command}`));
4201
+ console.log(import_picocolors9.default.red(`Comando desconhecido: ${command}`));
3564
4202
  showHelp();
3565
4203
  process.exit(1);
3566
4204
  }
3567
4205
  }
3568
4206
  function showHelp() {
3569
4207
  console.log(`
3570
- ${import_picocolors8.default.bold("Uso:")} nimbus [comando] [op\xE7\xF5es]
4208
+ ${import_picocolors9.default.bold("Uso:")} nimbus [comando] [op\xE7\xF5es]
3571
4209
 
3572
- ${import_picocolors8.default.bold("Comandos:")}
4210
+ ${import_picocolors9.default.bold("Comandos:")}
3573
4211
  create [nome] Criar novo projeto
3574
4212
  analyze [dir] Analisar stack do projeto
3575
4213
  upgrade [alvo] Atualizar depend\xEAncias
3576
4214
  update [vers\xE3o] Atualizar o CLI
4215
+ setup [alvo] Configurar ambiente
3577
4216
  lola [a\xE7\xE3o] Lola - Code Agent
3578
4217
  help Mostrar esta ajuda
3579
4218
  version Mostrar vers\xE3o
3580
4219
 
3581
- ${import_picocolors8.default.bold("Templates:")}
4220
+ ${import_picocolors9.default.bold("Templates:")}
3582
4221
  --landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
3583
4222
  --app Web app (Landing + Better Auth + Drizzle)
3584
4223
  --turborepo Monorepo (Turborepo + apps/packages)
3585
4224
 
3586
- ${import_picocolors8.default.bold("Analyze & Upgrade:")}
4225
+ ${import_picocolors9.default.bold("Analyze & Upgrade:")}
3587
4226
  analyze . Detectar stack e mostrar recomenda\xE7\xF5es
3588
4227
  analyze --json Output em JSON
3589
4228
  upgrade --plan Mostrar plano de upgrade
3590
4229
  upgrade next Atualizar Next.js
3591
4230
  upgrade tailwind Atualizar Tailwind CSS
3592
4231
 
3593
- ${import_picocolors8.default.bold("Update (CLI):")}
4232
+ ${import_picocolors9.default.bold("Update (CLI):")}
3594
4233
  update Atualizar para ultima versao
3595
4234
  update 0.11.0 Instalar versao especifica
3596
4235
  update --list Listar versoes disponiveis
3597
4236
  update --force Forcar reinstalacao (limpa cache)
3598
4237
 
3599
- ${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:")}
3600
4243
  -y, --yes Aceitar padr\xF5es
3601
4244
  --no-git N\xE3o inicializar Git
3602
4245
  --no-install N\xE3o instalar depend\xEAncias
3603
4246
  --template <url> Usar template customizado
3604
4247
 
3605
- ${import_picocolors8.default.bold("Lola (Code Agent):")}
4248
+ ${import_picocolors9.default.bold("Lola (Code Agent):")}
3606
4249
  lola install Instalar/atualizar Lola
3607
4250
  lola suggest Sugerir melhoria (cria issue)
3608
4251
 
3609
- ${import_picocolors8.default.bold("Exemplos:")}
3610
- ${import_picocolors8.default.dim("$")} nimbus create my-landing --landing
3611
- ${import_picocolors8.default.dim("$")} nimbus create my-app --app
3612
- ${import_picocolors8.default.dim("$")} nimbus analyze ./my-project
3613
- ${import_picocolors8.default.dim("$")} nimbus upgrade --plan
3614
- ${import_picocolors8.default.dim("$")} nimbus update
3615
- ${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
3616
4260
  `);
3617
4261
  }
3618
4262
  function showVersion() {
3619
4263
  console.log(`${PACKAGE_NAME2} v${CURRENT_VERSION}`);
3620
4264
  }
3621
4265
  main().catch((err) => {
3622
- console.error(import_picocolors8.default.red("Erro:"), err.message);
4266
+ console.error(import_picocolors9.default.red("Erro:"), err.message);
3623
4267
  process.exit(1);
3624
4268
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nimbuslab/cli",
3
- "version": "0.16.7",
3
+ "version": "0.17.1",
4
4
  "description": "CLI para criar projetos nimbuslab",
5
5
  "type": "module",
6
6
  "bin": {