@nimbuslab/cli 0.13.6 → 0.15.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.
@@ -16,27 +16,52 @@ jobs:
16
16
  - name: Checkout
17
17
  uses: actions/checkout@v4
18
18
 
19
+ - name: Check if version changed
20
+ id: version_check
21
+ run: |
22
+ LOCAL_VERSION=$(node -p "require('./package.json').version")
23
+ NPM_VERSION=$(npm view @nimbuslab/cli version 2>/dev/null || echo "0.0.0")
24
+ echo "local=$LOCAL_VERSION" >> $GITHUB_OUTPUT
25
+ echo "npm=$NPM_VERSION" >> $GITHUB_OUTPUT
26
+ if [ "$LOCAL_VERSION" = "$NPM_VERSION" ]; then
27
+ echo "changed=false" >> $GITHUB_OUTPUT
28
+ echo "Versao $LOCAL_VERSION ja existe no npm. Pulando publish."
29
+ else
30
+ echo "changed=true" >> $GITHUB_OUTPUT
31
+ echo "Nova versao detectada: $NPM_VERSION -> $LOCAL_VERSION"
32
+ fi
33
+
19
34
  - name: Setup Bun
35
+ if: steps.version_check.outputs.changed == 'true'
20
36
  uses: oven-sh/setup-bun@v2
21
37
  with:
22
38
  bun-version: latest
23
39
 
24
40
  - name: Setup Node (for npm publish)
41
+ if: steps.version_check.outputs.changed == 'true'
25
42
  uses: actions/setup-node@v4
26
43
  with:
27
44
  node-version: "24"
28
45
  registry-url: "https://registry.npmjs.org"
29
46
 
30
47
  - name: Install dependencies
48
+ if: steps.version_check.outputs.changed == 'true'
31
49
  run: bun install
32
50
 
33
51
  - name: Typecheck
52
+ if: steps.version_check.outputs.changed == 'true'
34
53
  run: bun run typecheck
35
54
 
36
55
  - name: Build
56
+ if: steps.version_check.outputs.changed == 'true'
37
57
  run: bun run build
38
58
 
39
59
  - name: Publish to npm
60
+ if: steps.version_check.outputs.changed == 'true'
40
61
  run: npm publish --access public
41
62
  env:
42
63
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
64
+
65
+ - name: Skip message
66
+ if: steps.version_check.outputs.changed == 'false'
67
+ run: echo "Publish pulado - versao ${{ steps.version_check.outputs.local }} ja existe no npm"
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.13.6",
153
+ version: "0.15.0",
154
154
  description: "CLI para criar projetos nimbuslab",
155
155
  type: "module",
156
156
  bin: {
@@ -1328,15 +1328,18 @@ async function promptConfig(initialName, flags) {
1328
1328
  console.log();
1329
1329
  console.log(import_picocolors3.default.dim(" nimbus-core: Motor para projetos externos (stealth mode)"));
1330
1330
  console.log();
1331
- const createGithub = await ye({
1332
- message: "Create GitHub repository? (nimbuslab, private)",
1333
- initialValue: true
1331
+ const repoOption = await ve({
1332
+ message: "Create repository for this project?",
1333
+ options: [
1334
+ { value: "github", label: "GitHub (nimbuslab, private)", hint: "recommended" },
1335
+ { value: "none", label: "No repository", hint: "just local" }
1336
+ ]
1334
1337
  });
1335
- if (pD(createGithub))
1336
- return createGithub;
1338
+ if (pD(repoOption))
1339
+ return repoOption;
1337
1340
  const clientRepo = await he({
1338
- message: "Client repo URL (optional, to clone in workspace):",
1339
- placeholder: "git@github.com:client/repo.git"
1341
+ message: "Client repo URL (to clone in workspace):",
1342
+ placeholder: "git@github.com:client/repo.git ou Azure DevOps URL"
1340
1343
  });
1341
1344
  if (pD(clientRepo))
1342
1345
  return clientRepo;
@@ -1346,7 +1349,7 @@ async function promptConfig(initialName, flags) {
1346
1349
  monorepo: false,
1347
1350
  git: true,
1348
1351
  install: false,
1349
- github: createGithub,
1352
+ github: repoOption === "github",
1350
1353
  githubOrg: "nimbuslab",
1351
1354
  githubDescription: `nimbus-core for ${name} - external project`,
1352
1355
  theme: "dark",
@@ -1359,7 +1362,8 @@ async function promptConfig(initialName, flags) {
1359
1362
  railwayToken: "",
1360
1363
  stagingUrl: "",
1361
1364
  productionUrl: "",
1362
- customTemplate: clientRepo || null
1365
+ customTemplate: null,
1366
+ clientRepoUrl: clientRepo || null
1363
1367
  };
1364
1368
  }
1365
1369
  let monorepo = false;
@@ -1688,11 +1692,17 @@ async function createProject(config) {
1688
1692
  s.stop("Error cloning template");
1689
1693
  throw new Error(`Failed to clone template ${templateRepo}. Check your connection or repository access.`);
1690
1694
  }
1691
- if (config.type === "nimbus-core" && config.customTemplate) {
1692
- const clientRepoUrl = config.customTemplate;
1695
+ if (config.type === "nimbus-core" && config.clientRepoUrl) {
1696
+ const clientRepoUrl = config.clientRepoUrl;
1693
1697
  s.start(`Cloning client repo in workspace...`);
1694
1698
  try {
1695
- const projectName = clientRepoUrl.split("/").pop()?.replace(".git", "") || "client-project";
1699
+ let projectName = "client-project";
1700
+ if (clientRepoUrl.includes("visualstudio.com") || clientRepoUrl.includes("dev.azure.com")) {
1701
+ const parts = clientRepoUrl.split("/");
1702
+ projectName = parts[parts.length - 1] || "client-project";
1703
+ } else {
1704
+ projectName = clientRepoUrl.split("/").pop()?.replace(".git", "") || "client-project";
1705
+ }
1696
1706
  await $2`git clone ${clientRepoUrl} ${config.name}/workspace/${projectName}`.quiet();
1697
1707
  s.stop(`Client repo cloned: workspace/${projectName}`);
1698
1708
  } catch (error) {
@@ -1870,13 +1880,8 @@ function showNextSteps(config) {
1870
1880
  console.log();
1871
1881
  console.log(import_picocolors3.default.dim(" nimbus-core: Motor para projetos externos"));
1872
1882
  console.log();
1873
- console.log(import_picocolors3.default.dim(" Para clonar repo do cliente:"));
1874
- console.log(` ${import_picocolors3.default.cyan("cd")} workspace`);
1875
- console.log(` ${import_picocolors3.default.cyan("git clone")} <repo-do-cliente>`);
1876
- console.log();
1877
1883
  console.log(import_picocolors3.default.dim(" Para usar a Lola:"));
1878
- console.log(` ${import_picocolors3.default.cyan("gemini")} ${import_picocolors3.default.dim("# Gemini CLI")}`);
1879
- console.log(` ${import_picocolors3.default.cyan("claude --append-system-prompt-file .claude/agents/lola.md")}`);
1884
+ console.log(` ${import_picocolors3.default.cyan("lola")}`);
1880
1885
  console.log();
1881
1886
  console.log(import_picocolors3.default.yellow(" STEALTH MODE: Commits sem mencao a nimbuslab/Lola/IA"));
1882
1887
  console.log();
@@ -2377,84 +2382,149 @@ async function getLatestVersion() {
2377
2382
  return null;
2378
2383
  }
2379
2384
  }
2385
+ function detectPackageManager2() {
2386
+ try {
2387
+ const bunResult = spawnSync("bun", ["pm", "ls", "-g"], {
2388
+ encoding: "utf-8",
2389
+ shell: true,
2390
+ timeout: 5000
2391
+ });
2392
+ if (bunResult.stdout && bunResult.stdout.includes(PACKAGE_NAME)) {
2393
+ return "bun";
2394
+ }
2395
+ } catch {}
2396
+ try {
2397
+ const npmResult = spawnSync("npm", ["ls", "-g", PACKAGE_NAME, "--json"], {
2398
+ encoding: "utf-8",
2399
+ shell: true,
2400
+ timeout: 5000
2401
+ });
2402
+ if (npmResult.stdout) {
2403
+ const data = JSON.parse(npmResult.stdout);
2404
+ if (data.dependencies?.[PACKAGE_NAME]) {
2405
+ return "npm";
2406
+ }
2407
+ }
2408
+ } catch {}
2409
+ return "unknown";
2410
+ }
2380
2411
  function getCurrentVersion() {
2412
+ try {
2413
+ const bunResult = spawnSync("bun", ["pm", "ls", "-g"], {
2414
+ encoding: "utf-8",
2415
+ shell: true,
2416
+ timeout: 5000
2417
+ });
2418
+ if (bunResult.stdout) {
2419
+ const match = bunResult.stdout.match(new RegExp(`${PACKAGE_NAME.replace("/", "\\/")}@([\\d.]+)`));
2420
+ if (match?.[1]) {
2421
+ return match[1];
2422
+ }
2423
+ }
2424
+ } catch {}
2381
2425
  try {
2382
2426
  const result = spawnSync("npm", ["ls", "-g", PACKAGE_NAME, "--json"], {
2383
2427
  encoding: "utf-8",
2384
- shell: true
2428
+ shell: true,
2429
+ timeout: 5000
2385
2430
  });
2386
2431
  if (result.stdout) {
2387
2432
  const data = JSON.parse(result.stdout);
2388
- return data.dependencies?.[PACKAGE_NAME]?.version || "unknown";
2433
+ if (data.dependencies?.[PACKAGE_NAME]?.version) {
2434
+ return data.dependencies[PACKAGE_NAME].version;
2435
+ }
2389
2436
  }
2390
2437
  } catch {}
2391
2438
  return "unknown";
2392
2439
  }
2393
2440
  async function update(args) {
2394
- const flag = args[0];
2441
+ const forceFlag = args.includes("--force") || args.includes("-f");
2442
+ const filteredArgs = args.filter((a) => a !== "--force" && a !== "-f");
2443
+ const flag = filteredArgs[0];
2395
2444
  if (flag === "--list" || flag === "-l") {
2396
- Ie(import_picocolors6.default.cyan("Vers\xF5es dispon\xEDveis"));
2445
+ Ie(import_picocolors6.default.cyan("Versoes disponiveis"));
2397
2446
  const spinner2 = Y2();
2398
- spinner2.start("Buscando vers\xF5es...");
2447
+ spinner2.start("Buscando versoes...");
2399
2448
  const versions = await getAvailableVersions();
2400
- spinner2.stop("Vers\xF5es encontradas");
2449
+ spinner2.stop("Versoes encontradas");
2401
2450
  if (versions.length === 0) {
2402
- M2.error("N\xE3o foi poss\xEDvel buscar as vers\xF5es");
2451
+ M2.error("Nao foi possivel buscar as versoes");
2403
2452
  return;
2404
2453
  }
2405
2454
  const current = getCurrentVersion();
2455
+ const pm2 = detectPackageManager2();
2406
2456
  console.log();
2407
- console.log(import_picocolors6.default.bold("\xDAltimas 10 vers\xF5es:"));
2457
+ console.log(import_picocolors6.default.bold("Ultimas 10 versoes:"));
2408
2458
  versions.slice(0, 10).forEach((v2, i) => {
2409
2459
  const isCurrent = v2 === current;
2410
- const prefix = isCurrent ? import_picocolors6.default.green("\u2192 ") : " ";
2460
+ const prefix = isCurrent ? import_picocolors6.default.green("-> ") : " ";
2411
2461
  const suffix = isCurrent ? import_picocolors6.default.dim(" (instalada)") : "";
2412
2462
  const isLatest = i === 0 ? import_picocolors6.default.yellow(" (latest)") : "";
2413
2463
  console.log(`${prefix}${v2}${suffix}${isLatest}`);
2414
2464
  });
2415
2465
  console.log();
2416
- console.log(import_picocolors6.default.dim(`Total: ${versions.length} vers\xF5es`));
2417
- console.log(import_picocolors6.default.dim(`Instalar vers\xE3o espec\xEDfica: nimbus update <vers\xE3o>`));
2466
+ console.log(import_picocolors6.default.dim(`Total: ${versions.length} versoes`));
2467
+ console.log(import_picocolors6.default.dim(`Package manager detectado: ${pm2 === "unknown" ? "nenhum" : pm2}`));
2468
+ console.log(import_picocolors6.default.dim(`Instalar versao especifica: nimbus update <versao>`));
2469
+ console.log(import_picocolors6.default.dim(`Forcar reinstalacao: nimbus update --force`));
2418
2470
  return;
2419
2471
  }
2420
2472
  const targetVersion = flag || "latest";
2421
- const isSpecificVersion = flag && flag !== "latest";
2473
+ const isSpecificVersion = flag && flag !== "latest" && !flag.startsWith("-");
2422
2474
  Ie(import_picocolors6.default.cyan(`Atualizando ${PACKAGE_NAME}`));
2423
2475
  const spinner = Y2();
2424
- spinner.start("Verificando vers\xE3o atual...");
2476
+ spinner.start("Detectando package manager...");
2477
+ const detectedPm = detectPackageManager2();
2478
+ const pm = detectedPm === "unknown" ? "bun" : detectedPm;
2479
+ spinner.stop(`Package manager: ${pm}${detectedPm === "unknown" ? " (padrao)" : ""}`);
2480
+ spinner.start("Verificando versao atual...");
2425
2481
  const currentVersion = getCurrentVersion();
2426
- spinner.stop(`Vers\xE3o atual: ${currentVersion}`);
2482
+ spinner.stop(`Versao atual: ${currentVersion === "unknown" ? "nao instalado" : currentVersion}`);
2483
+ let latestVersion = null;
2427
2484
  if (!isSpecificVersion) {
2428
- spinner.start("Verificando \xFAltima vers\xE3o...");
2429
- const latest = await getLatestVersion();
2430
- spinner.stop(`\xDAltima vers\xE3o: ${latest || "desconhecida"}`);
2431
- if (latest && latest === currentVersion) {
2432
- M2.success("Voc\xEA j\xE1 est\xE1 na \xFAltima vers\xE3o!");
2485
+ spinner.start("Verificando ultima versao no npm...");
2486
+ latestVersion = await getLatestVersion();
2487
+ spinner.stop(`Ultima versao: ${latestVersion || "desconhecida"}`);
2488
+ if (!forceFlag && latestVersion && latestVersion === currentVersion) {
2489
+ M2.success("Voce ja esta na ultima versao!");
2490
+ console.log(import_picocolors6.default.dim(" Use --force para reinstalar"));
2433
2491
  return;
2434
2492
  }
2435
2493
  }
2436
- const versionText = isSpecificVersion ? targetVersion : "latest";
2494
+ const versionText = isSpecificVersion ? targetVersion : latestVersion || "latest";
2495
+ const actionText = forceFlag ? "Reinstalar" : "Atualizar";
2437
2496
  const confirmUpdate = await ye({
2438
- message: `Atualizar para ${versionText}?`,
2497
+ message: `${actionText} para ${versionText} usando ${pm}?`,
2439
2498
  initialValue: true
2440
2499
  });
2441
2500
  if (pD(confirmUpdate) || !confirmUpdate) {
2442
- xe("Atualiza\xE7\xE3o cancelada");
2501
+ xe("Atualizacao cancelada");
2443
2502
  return;
2444
2503
  }
2445
2504
  spinner.start("Atualizando...");
2446
2505
  try {
2447
- const packageSpec = isSpecificVersion ? `${PACKAGE_NAME}@${targetVersion}` : PACKAGE_NAME;
2448
- execSync(`npm install -g ${packageSpec}`, {
2449
- stdio: "pipe",
2450
- encoding: "utf-8"
2451
- });
2452
- spinner.stop("Atualiza\xE7\xE3o conclu\xEDda!");
2506
+ const packageSpec = isSpecificVersion ? `${PACKAGE_NAME}@${targetVersion}` : latestVersion ? `${PACKAGE_NAME}@${latestVersion}` : PACKAGE_NAME;
2507
+ if (pm === "bun") {
2508
+ if (forceFlag) {
2509
+ try {
2510
+ execSync(`bun remove -g ${PACKAGE_NAME}`, { stdio: "pipe", encoding: "utf-8" });
2511
+ } catch {}
2512
+ }
2513
+ execSync(`bun add -g ${packageSpec}`, { stdio: "pipe", encoding: "utf-8" });
2514
+ } else {
2515
+ const forceArg = forceFlag ? " --force" : "";
2516
+ execSync(`npm install -g ${packageSpec}${forceArg}`, { stdio: "pipe", encoding: "utf-8" });
2517
+ }
2518
+ spinner.stop("Atualizacao concluida!");
2453
2519
  const newVersion = getCurrentVersion();
2454
- M2.success(`${PACKAGE_NAME} atualizado: ${currentVersion} \u2192 ${newVersion}`);
2520
+ if (currentVersion === newVersion && !forceFlag) {
2521
+ M2.warn("Versao nao mudou. Tente com --force");
2522
+ } else {
2523
+ M2.success(`${PACKAGE_NAME} atualizado: ${currentVersion} -> ${newVersion}`);
2524
+ }
2455
2525
  Se(import_picocolors6.default.green("Pronto!"));
2456
2526
  } catch (error) {
2457
- spinner.stop("Erro na atualiza\xE7\xE3o");
2527
+ spinner.stop("Erro na atualizacao");
2458
2528
  const err = error;
2459
2529
  M2.error("Falha ao atualizar");
2460
2530
  if (err.stderr) {
@@ -2462,7 +2532,11 @@ async function update(args) {
2462
2532
  }
2463
2533
  console.log();
2464
2534
  console.log(import_picocolors6.default.yellow("Tente manualmente:"));
2465
- console.log(import_picocolors6.default.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
2535
+ if (pm === "bun") {
2536
+ console.log(import_picocolors6.default.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
2537
+ } else {
2538
+ console.log(import_picocolors6.default.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
2539
+ }
2466
2540
  }
2467
2541
  }
2468
2542
 
@@ -2475,6 +2549,53 @@ var HOME = homedir();
2475
2549
  var LOLA_DIR = join3(HOME, ".lola");
2476
2550
  var LOLA_REPO = "git@github.com:nimbuslab/lola.git";
2477
2551
  var USER_MEMORY = join3(HOME, ".claude", "USER_MEMORY.md");
2552
+ var LOLA_MEMORY_URL = "https://lola.nimbuslab.com.br/sse";
2553
+ var LOLA_MEMORY_NAME = "lola-memory";
2554
+ async function installLolaMemoryMCP() {
2555
+ console.log();
2556
+ console.log(import_picocolors7.default.cyan(" Configurando lola-memory MCP..."));
2557
+ const claudeCheck = Bun.spawnSync(["which", "claude"], { stdout: "pipe" });
2558
+ if (claudeCheck.exitCode !== 0) {
2559
+ console.log(import_picocolors7.default.yellow(" Claude CLI nao encontrado, pulando MCP"));
2560
+ console.log(import_picocolors7.default.dim(" Instale o Claude CLI e rode 'nimbus lola install' novamente"));
2561
+ return;
2562
+ }
2563
+ const mcpList = Bun.spawnSync(["claude", "mcp", "list"], { stdout: "pipe", stderr: "pipe" });
2564
+ const mcpOutput = mcpList.stdout.toString();
2565
+ if (mcpOutput.includes(LOLA_MEMORY_NAME)) {
2566
+ console.log(import_picocolors7.default.green(" MCP lola-memory ja configurado"));
2567
+ return;
2568
+ }
2569
+ console.log(import_picocolors7.default.dim(" Adicionando MCP lola-memory..."));
2570
+ const result = Bun.spawnSync([
2571
+ "claude",
2572
+ "mcp",
2573
+ "add",
2574
+ "-t",
2575
+ "sse",
2576
+ "-s",
2577
+ "user",
2578
+ LOLA_MEMORY_NAME,
2579
+ "--",
2580
+ "bunx",
2581
+ "mcp-remote",
2582
+ LOLA_MEMORY_URL
2583
+ ], {
2584
+ stdout: "inherit",
2585
+ stderr: "inherit"
2586
+ });
2587
+ if (result.exitCode !== 0) {
2588
+ console.log(import_picocolors7.default.yellow(" Erro ao adicionar MCP, pode ser adicionado manualmente:"));
2589
+ console.log(import_picocolors7.default.dim(` claude mcp add -t sse -s user ${LOLA_MEMORY_NAME} -- bunx mcp-remote ${LOLA_MEMORY_URL}`));
2590
+ return;
2591
+ }
2592
+ console.log(import_picocolors7.default.green(" MCP lola-memory instalado!"));
2593
+ console.log();
2594
+ console.log(import_picocolors7.default.dim(" Comandos disponiveis:"));
2595
+ console.log(import_picocolors7.default.dim(' remember "query" - Buscar conhecimento'));
2596
+ console.log(import_picocolors7.default.dim(' learn "content" - Salvar conhecimento'));
2597
+ console.log(import_picocolors7.default.dim(" memory_stats - Ver estatisticas"));
2598
+ }
2478
2599
  async function installLola() {
2479
2600
  console.log();
2480
2601
  console.log(import_picocolors7.default.cyan(" Lola - Code Agent da nimbuslab"));
@@ -2484,11 +2605,36 @@ async function installLola() {
2484
2605
  if (isUpdate) {
2485
2606
  console.log(import_picocolors7.default.dim(` Lola ja instalada em ${LOLA_DIR}`));
2486
2607
  console.log(import_picocolors7.default.cyan(" Atualizando..."));
2608
+ const statusCheck = Bun.spawnSync(["git", "status", "--porcelain"], {
2609
+ cwd: LOLA_DIR,
2610
+ stdout: "pipe"
2611
+ });
2612
+ const hasLocalChanges = statusCheck.stdout.toString().trim().length > 0;
2613
+ if (hasLocalChanges) {
2614
+ console.log(import_picocolors7.default.dim(" Salvando mudancas locais..."));
2615
+ Bun.spawnSync(["git", "stash", "--quiet"], {
2616
+ cwd: LOLA_DIR,
2617
+ stdout: "pipe",
2618
+ stderr: "pipe"
2619
+ });
2620
+ }
2487
2621
  const result = Bun.spawnSync(["git", "pull", "--quiet"], {
2488
2622
  cwd: LOLA_DIR,
2489
2623
  stdout: "inherit",
2490
2624
  stderr: "inherit"
2491
2625
  });
2626
+ if (hasLocalChanges) {
2627
+ console.log(import_picocolors7.default.dim(" Restaurando mudancas locais..."));
2628
+ const stashPop = Bun.spawnSync(["git", "stash", "pop", "--quiet"], {
2629
+ cwd: LOLA_DIR,
2630
+ stdout: "pipe",
2631
+ stderr: "pipe"
2632
+ });
2633
+ if (stashPop.exitCode !== 0) {
2634
+ console.log(import_picocolors7.default.yellow(" Aviso: conflito ao restaurar mudancas locais"));
2635
+ console.log(import_picocolors7.default.dim(" Verifique ~/.lola e resolva manualmente: git stash pop"));
2636
+ }
2637
+ }
2492
2638
  if (result.exitCode !== 0) {
2493
2639
  console.log(import_picocolors7.default.red(" Erro ao atualizar Lola"));
2494
2640
  process.exit(1);
@@ -2596,6 +2742,7 @@ fi
2596
2742
  console.log(import_picocolors7.default.green(" Script lola ja existe"));
2597
2743
  }
2598
2744
  }
2745
+ await installLolaMemoryMCP();
2599
2746
  const claudeDir = join3(HOME, ".claude");
2600
2747
  if (!existsSync2(USER_MEMORY)) {
2601
2748
  console.log();
@@ -2644,7 +2791,11 @@ lola_profile: millennial
2644
2791
  console.log();
2645
2792
  console.log(import_picocolors7.default.bold(" Para usar a Lola:"));
2646
2793
  console.log(import_picocolors7.default.dim(" lola ") + import_picocolors7.default.white("# Iniciar sessao"));
2647
- console.log(import_picocolors7.default.dim(' lola suggest "x" ') + import_picocolors7.default.white("# Sugerir melhoria"));
2794
+ console.log();
2795
+ console.log(import_picocolors7.default.bold(" lola-memory (conhecimento compartilhado):"));
2796
+ console.log(import_picocolors7.default.dim(' remember "query" ') + import_picocolors7.default.white("# Buscar conhecimento"));
2797
+ console.log(import_picocolors7.default.dim(' learn "content" ') + import_picocolors7.default.white("# Salvar conhecimento"));
2798
+ console.log(import_picocolors7.default.dim(" memory_stats ") + import_picocolors7.default.white("# Ver estatisticas"));
2648
2799
  console.log();
2649
2800
  console.log(import_picocolors7.default.bold(" Para mudar perfil, edite ~/.claude/USER_MEMORY.md:"));
2650
2801
  console.log(import_picocolors7.default.dim(" lola_profile: millennial|genz|profissional|nerd|chill"));
@@ -2996,7 +3147,7 @@ function showLolaHelp() {
2996
3147
  console.log(import_picocolors7.default.bold(" Uso:") + " nimbus lola [subcomando]");
2997
3148
  console.log();
2998
3149
  console.log(import_picocolors7.default.bold(" Subcomandos:"));
2999
- console.log(import_picocolors7.default.dim(" install ") + import_picocolors7.default.white("Instalar/atualizar Lola"));
3150
+ console.log(import_picocolors7.default.dim(" install ") + import_picocolors7.default.white("Instalar/atualizar Lola + MCP"));
3000
3151
  console.log(import_picocolors7.default.dim(" sync ") + import_picocolors7.default.white("Alias para install"));
3001
3152
  console.log(import_picocolors7.default.dim(" onboard ") + import_picocolors7.default.white("Configurar perfil (novos devs)"));
3002
3153
  console.log(import_picocolors7.default.dim(" quiz ") + import_picocolors7.default.white("Quiz sobre a nimbuslab"));
@@ -3009,6 +3160,12 @@ function showLolaHelp() {
3009
3160
  console.log(import_picocolors7.default.dim(" $ nimbus lola quiz"));
3010
3161
  console.log(import_picocolors7.default.dim(' $ nimbus lola suggest "adicionar suporte a X"'));
3011
3162
  console.log();
3163
+ console.log(import_picocolors7.default.bold(" lola-memory (dentro do Claude):"));
3164
+ console.log(import_picocolors7.default.dim(' remember "query" ') + import_picocolors7.default.white("Buscar conhecimento"));
3165
+ console.log(import_picocolors7.default.dim(' learn "content" ') + import_picocolors7.default.white("Salvar conhecimento"));
3166
+ console.log(import_picocolors7.default.dim(" memory_stats ") + import_picocolors7.default.white("Ver estatisticas"));
3167
+ console.log(import_picocolors7.default.dim(" get_context ") + import_picocolors7.default.white("Perfil + memorias recentes"));
3168
+ console.log();
3012
3169
  }
3013
3170
 
3014
3171
  // src/index.ts
@@ -3051,8 +3208,8 @@ function showUpdateNotice(latestVersion) {
3051
3208
  const maxLen = Math.max(line1.length, line2.length);
3052
3209
  const border = "\u2500".repeat(maxLen + 2);
3053
3210
  console.log(import_picocolors8.default.yellow(` \u250C${border}\u2510`));
3054
- console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.white(line1.padEnd(maxLen + 1)) + import_picocolors8.default.yellow(`\u2502`));
3055
- console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.cyan(line2.padEnd(maxLen + 1)) + import_picocolors8.default.yellow(`\u2502`));
3211
+ console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.white(line1.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3212
+ console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3056
3213
  console.log(import_picocolors8.default.yellow(` \u2514${border}\u2518`));
3057
3214
  console.log();
3058
3215
  }
@@ -3113,9 +3270,10 @@ ${import_picocolors8.default.bold("Analyze & Upgrade:")}
3113
3270
  upgrade tailwind Atualizar Tailwind CSS
3114
3271
 
3115
3272
  ${import_picocolors8.default.bold("Update (CLI):")}
3116
- update Atualizar para \xFAltima vers\xE3o
3117
- update 0.11.0 Instalar vers\xE3o espec\xEDfica
3118
- update --list Listar vers\xF5es dispon\xEDveis
3273
+ update Atualizar para ultima versao
3274
+ update 0.11.0 Instalar versao especifica
3275
+ update --list Listar versoes disponiveis
3276
+ update --force Forcar reinstalacao (limpa cache)
3119
3277
 
3120
3278
  ${import_picocolors8.default.bold("Op\xE7\xF5es:")}
3121
3279
  -y, --yes Aceitar padr\xF5es
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nimbuslab/cli",
3
- "version": "0.13.6",
3
+ "version": "0.15.0",
4
4
  "description": "CLI para criar projetos nimbuslab",
5
5
  "type": "module",
6
6
  "bin": {
@@ -196,6 +196,8 @@ interface ProjectConfig {
196
196
  productionUrl: string
197
197
  // Template customizado
198
198
  customTemplate: string | null
199
+ // nimbus-core: URL do repo do cliente
200
+ clientRepoUrl?: string | null
199
201
  }
200
202
 
201
203
  interface CreateFlags {
@@ -547,17 +549,20 @@ async function promptConfig(initialName?: string, flags?: CreateFlags): Promise<
547
549
  console.log(pc.dim(" nimbus-core: Motor para projetos externos (stealth mode)"))
548
550
  console.log()
549
551
 
550
- // Sempre cria repo no GitHub (org nimbuslab, privado)
551
- const createGithub = await p.confirm({
552
- message: "Create GitHub repository? (nimbuslab, private)",
553
- initialValue: true,
552
+ // Perguntar se quer criar repo (GitHub ou nenhum)
553
+ const repoOption = await p.select({
554
+ message: "Create repository for this project?",
555
+ options: [
556
+ { value: "github", label: "GitHub (nimbuslab, private)", hint: "recommended" },
557
+ { value: "none", label: "No repository", hint: "just local" },
558
+ ],
554
559
  })
555
- if (p.isCancel(createGithub)) return createGithub
560
+ if (p.isCancel(repoOption)) return repoOption
556
561
 
557
562
  // Perguntar URL do repo do cliente para clonar no workspace
558
563
  const clientRepo = await p.text({
559
- message: "Client repo URL (optional, to clone in workspace):",
560
- placeholder: "git@github.com:client/repo.git",
564
+ message: "Client repo URL (to clone in workspace):",
565
+ placeholder: "git@github.com:client/repo.git ou Azure DevOps URL",
561
566
  })
562
567
  if (p.isCancel(clientRepo)) return clientRepo
563
568
 
@@ -567,7 +572,7 @@ async function promptConfig(initialName?: string, flags?: CreateFlags): Promise<
567
572
  monorepo: false,
568
573
  git: true, // sempre init git
569
574
  install: false, // nimbus-core não tem package.json
570
- github: createGithub as boolean,
575
+ github: repoOption === "github",
571
576
  githubOrg: "nimbuslab", // sempre na org nimbuslab
572
577
  githubDescription: `nimbus-core for ${name} - external project`,
573
578
  theme: "dark" as const,
@@ -580,7 +585,8 @@ async function promptConfig(initialName?: string, flags?: CreateFlags): Promise<
580
585
  railwayToken: "",
581
586
  stagingUrl: "",
582
587
  productionUrl: "",
583
- customTemplate: (clientRepo as string) || null, // reusa campo para URL do cliente
588
+ customTemplate: null, // não usa template customizado
589
+ clientRepoUrl: (clientRepo as string) || null, // URL do cliente separada
584
590
  }
585
591
  }
586
592
 
@@ -972,11 +978,20 @@ async function createProject(config: ProjectConfig) {
972
978
  }
973
979
 
974
980
  // nimbus-core: clone client repo in workspace if provided
975
- if (config.type === "nimbus-core" && config.customTemplate) {
976
- const clientRepoUrl = config.customTemplate
981
+ if (config.type === "nimbus-core" && config.clientRepoUrl) {
982
+ const clientRepoUrl = config.clientRepoUrl
977
983
  s.start(`Cloning client repo in workspace...`)
978
984
  try {
979
- const projectName = clientRepoUrl.split("/").pop()?.replace(".git", "") || "client-project"
985
+ // Extrair nome do projeto da URL (funciona com GitHub, GitLab, Azure DevOps)
986
+ let projectName = "client-project"
987
+ if (clientRepoUrl.includes("visualstudio.com") || clientRepoUrl.includes("dev.azure.com")) {
988
+ // Azure DevOps: serel@vs-ssh.visualstudio.com:v3/serel/Project/Repo
989
+ const parts = clientRepoUrl.split("/")
990
+ projectName = parts[parts.length - 1] || "client-project"
991
+ } else {
992
+ // GitHub/GitLab: git@github.com:org/repo.git
993
+ projectName = clientRepoUrl.split("/").pop()?.replace(".git", "") || "client-project"
994
+ }
980
995
  await $`git clone ${clientRepoUrl} ${config.name}/workspace/${projectName}`.quiet()
981
996
  s.stop(`Client repo cloned: workspace/${projectName}`)
982
997
  } catch (error) {
@@ -1204,13 +1219,8 @@ function showNextSteps(config: ProjectConfig) {
1204
1219
  console.log()
1205
1220
  console.log(pc.dim(" nimbus-core: Motor para projetos externos"))
1206
1221
  console.log()
1207
- console.log(pc.dim(" Para clonar repo do cliente:"))
1208
- console.log(` ${pc.cyan("cd")} workspace`)
1209
- console.log(` ${pc.cyan("git clone")} <repo-do-cliente>`)
1210
- console.log()
1211
1222
  console.log(pc.dim(" Para usar a Lola:"))
1212
- console.log(` ${pc.cyan("gemini")} ${pc.dim("# Gemini CLI")}`)
1213
- console.log(` ${pc.cyan("claude --append-system-prompt-file .claude/agents/lola.md")}`)
1223
+ console.log(` ${pc.cyan("lola")}`)
1214
1224
  console.log()
1215
1225
  console.log(pc.yellow(" STEALTH MODE: Commits sem mencao a nimbuslab/Lola/IA"))
1216
1226
  console.log()
@@ -8,6 +8,58 @@ const HOME = homedir()
8
8
  const LOLA_DIR = join(HOME, ".lola")
9
9
  const LOLA_REPO = "git@github.com:nimbuslab/lola.git"
10
10
  const USER_MEMORY = join(HOME, ".claude", "USER_MEMORY.md")
11
+ const LOLA_MEMORY_URL = "https://lola.nimbuslab.com.br/sse"
12
+ const LOLA_MEMORY_NAME = "lola-memory"
13
+
14
+ async function installLolaMemoryMCP(): Promise<void> {
15
+ console.log()
16
+ console.log(pc.cyan(" Configurando lola-memory MCP..."))
17
+
18
+ // Verificar se claude CLI existe
19
+ const claudeCheck = Bun.spawnSync(["which", "claude"], { stdout: "pipe" })
20
+ if (claudeCheck.exitCode !== 0) {
21
+ console.log(pc.yellow(" Claude CLI nao encontrado, pulando MCP"))
22
+ console.log(pc.dim(" Instale o Claude CLI e rode 'nimbus lola install' novamente"))
23
+ return
24
+ }
25
+
26
+ // Verificar se MCP já está configurado
27
+ const mcpList = Bun.spawnSync(["claude", "mcp", "list"], { stdout: "pipe", stderr: "pipe" })
28
+ const mcpOutput = mcpList.stdout.toString()
29
+
30
+ if (mcpOutput.includes(LOLA_MEMORY_NAME)) {
31
+ console.log(pc.green(" MCP lola-memory ja configurado"))
32
+ return
33
+ }
34
+
35
+ // Adicionar MCP lola-memory
36
+ console.log(pc.dim(" Adicionando MCP lola-memory..."))
37
+
38
+ const result = Bun.spawnSync([
39
+ "claude", "mcp", "add",
40
+ "-t", "sse",
41
+ "-s", "user",
42
+ LOLA_MEMORY_NAME,
43
+ "--",
44
+ "bunx", "mcp-remote", LOLA_MEMORY_URL
45
+ ], {
46
+ stdout: "inherit",
47
+ stderr: "inherit",
48
+ })
49
+
50
+ if (result.exitCode !== 0) {
51
+ console.log(pc.yellow(" Erro ao adicionar MCP, pode ser adicionado manualmente:"))
52
+ console.log(pc.dim(` claude mcp add -t sse -s user ${LOLA_MEMORY_NAME} -- bunx mcp-remote ${LOLA_MEMORY_URL}`))
53
+ return
54
+ }
55
+
56
+ console.log(pc.green(" MCP lola-memory instalado!"))
57
+ console.log()
58
+ console.log(pc.dim(" Comandos disponiveis:"))
59
+ console.log(pc.dim(" remember \"query\" - Buscar conhecimento"))
60
+ console.log(pc.dim(" learn \"content\" - Salvar conhecimento"))
61
+ console.log(pc.dim(" memory_stats - Ver estatisticas"))
62
+ }
11
63
 
12
64
  async function installLola(): Promise<void> {
13
65
  console.log()
@@ -21,12 +73,45 @@ async function installLola(): Promise<void> {
21
73
  console.log(pc.dim(` Lola ja instalada em ${LOLA_DIR}`))
22
74
  console.log(pc.cyan(" Atualizando..."))
23
75
 
76
+ // Verificar se tem mudancas locais
77
+ const statusCheck = Bun.spawnSync(["git", "status", "--porcelain"], {
78
+ cwd: LOLA_DIR,
79
+ stdout: "pipe",
80
+ })
81
+ const hasLocalChanges = statusCheck.stdout.toString().trim().length > 0
82
+
83
+ // Stash se tiver mudancas locais
84
+ if (hasLocalChanges) {
85
+ console.log(pc.dim(" Salvando mudancas locais..."))
86
+ Bun.spawnSync(["git", "stash", "--quiet"], {
87
+ cwd: LOLA_DIR,
88
+ stdout: "pipe",
89
+ stderr: "pipe",
90
+ })
91
+ }
92
+
93
+ // Pull
24
94
  const result = Bun.spawnSync(["git", "pull", "--quiet"], {
25
95
  cwd: LOLA_DIR,
26
96
  stdout: "inherit",
27
97
  stderr: "inherit",
28
98
  })
29
99
 
100
+ // Restaurar mudancas locais se tinha
101
+ if (hasLocalChanges) {
102
+ console.log(pc.dim(" Restaurando mudancas locais..."))
103
+ const stashPop = Bun.spawnSync(["git", "stash", "pop", "--quiet"], {
104
+ cwd: LOLA_DIR,
105
+ stdout: "pipe",
106
+ stderr: "pipe",
107
+ })
108
+
109
+ if (stashPop.exitCode !== 0) {
110
+ console.log(pc.yellow(" Aviso: conflito ao restaurar mudancas locais"))
111
+ console.log(pc.dim(" Verifique ~/.lola e resolva manualmente: git stash pop"))
112
+ }
113
+ }
114
+
30
115
  if (result.exitCode !== 0) {
31
116
  console.log(pc.red(" Erro ao atualizar Lola"))
32
117
  process.exit(1)
@@ -162,6 +247,9 @@ fi
162
247
  }
163
248
  }
164
249
 
250
+ // Instalar MCP lola-memory
251
+ await installLolaMemoryMCP()
252
+
165
253
  // Verificar USER_MEMORY.md
166
254
  const claudeDir = join(HOME, ".claude")
167
255
  if (!existsSync(USER_MEMORY)) {
@@ -217,7 +305,11 @@ lola_profile: millennial
217
305
  console.log()
218
306
  console.log(pc.bold(" Para usar a Lola:"))
219
307
  console.log(pc.dim(" lola ") + pc.white("# Iniciar sessao"))
220
- console.log(pc.dim(" lola suggest \"x\" ") + pc.white("# Sugerir melhoria"))
308
+ console.log()
309
+ console.log(pc.bold(" lola-memory (conhecimento compartilhado):"))
310
+ console.log(pc.dim(" remember \"query\" ") + pc.white("# Buscar conhecimento"))
311
+ console.log(pc.dim(" learn \"content\" ") + pc.white("# Salvar conhecimento"))
312
+ console.log(pc.dim(" memory_stats ") + pc.white("# Ver estatisticas"))
221
313
  console.log()
222
314
  console.log(pc.bold(" Para mudar perfil, edite ~/.claude/USER_MEMORY.md:"))
223
315
  console.log(pc.dim(" lola_profile: millennial|genz|profissional|nerd|chill"))
@@ -620,7 +712,7 @@ function showLolaHelp() {
620
712
  console.log(pc.bold(" Uso:") + " nimbus lola [subcomando]")
621
713
  console.log()
622
714
  console.log(pc.bold(" Subcomandos:"))
623
- console.log(pc.dim(" install ") + pc.white("Instalar/atualizar Lola"))
715
+ console.log(pc.dim(" install ") + pc.white("Instalar/atualizar Lola + MCP"))
624
716
  console.log(pc.dim(" sync ") + pc.white("Alias para install"))
625
717
  console.log(pc.dim(" onboard ") + pc.white("Configurar perfil (novos devs)"))
626
718
  console.log(pc.dim(" quiz ") + pc.white("Quiz sobre a nimbuslab"))
@@ -633,4 +725,10 @@ function showLolaHelp() {
633
725
  console.log(pc.dim(" $ nimbus lola quiz"))
634
726
  console.log(pc.dim(" $ nimbus lola suggest \"adicionar suporte a X\""))
635
727
  console.log()
728
+ console.log(pc.bold(" lola-memory (dentro do Claude):"))
729
+ console.log(pc.dim(" remember \"query\" ") + pc.white("Buscar conhecimento"))
730
+ console.log(pc.dim(" learn \"content\" ") + pc.white("Salvar conhecimento"))
731
+ console.log(pc.dim(" memory_stats ") + pc.white("Ver estatisticas"))
732
+ console.log(pc.dim(" get_context ") + pc.white("Perfil + memorias recentes"))
733
+ console.log()
636
734
  }
@@ -4,6 +4,8 @@ import { execSync, spawnSync } from "child_process"
4
4
 
5
5
  const PACKAGE_NAME = "@nimbuslab/cli"
6
6
 
7
+ type PackageManager = "bun" | "npm" | "unknown"
8
+
7
9
  async function getAvailableVersions(): Promise<string[]> {
8
10
  try {
9
11
  const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}`)
@@ -26,91 +28,166 @@ async function getLatestVersion(): Promise<string | null> {
26
28
  }
27
29
  }
28
30
 
31
+ // Detecta qual package manager tem o pacote instalado globalmente
32
+ function detectPackageManager(): PackageManager {
33
+ // Tentar bun primeiro
34
+ try {
35
+ const bunResult = spawnSync("bun", ["pm", "ls", "-g"], {
36
+ encoding: "utf-8",
37
+ shell: true,
38
+ timeout: 5000,
39
+ })
40
+ if (bunResult.stdout && bunResult.stdout.includes(PACKAGE_NAME)) {
41
+ return "bun"
42
+ }
43
+ } catch {
44
+ // ignore
45
+ }
46
+
47
+ // Tentar npm
48
+ try {
49
+ const npmResult = spawnSync("npm", ["ls", "-g", PACKAGE_NAME, "--json"], {
50
+ encoding: "utf-8",
51
+ shell: true,
52
+ timeout: 5000,
53
+ })
54
+ if (npmResult.stdout) {
55
+ const data = JSON.parse(npmResult.stdout)
56
+ if (data.dependencies?.[PACKAGE_NAME]) {
57
+ return "npm"
58
+ }
59
+ }
60
+ } catch {
61
+ // ignore
62
+ }
63
+
64
+ return "unknown"
65
+ }
66
+
29
67
  function getCurrentVersion(): string {
68
+ // Tentar bun primeiro
69
+ try {
70
+ const bunResult = spawnSync("bun", ["pm", "ls", "-g"], {
71
+ encoding: "utf-8",
72
+ shell: true,
73
+ timeout: 5000,
74
+ })
75
+ if (bunResult.stdout) {
76
+ // Formato: "@nimbuslab/cli@0.14.0"
77
+ const match = bunResult.stdout.match(new RegExp(`${PACKAGE_NAME.replace("/", "\\/")}@([\\d.]+)`))
78
+ if (match?.[1]) {
79
+ return match[1]
80
+ }
81
+ }
82
+ } catch {
83
+ // ignore
84
+ }
85
+
86
+ // Fallback para npm
30
87
  try {
31
88
  const result = spawnSync("npm", ["ls", "-g", PACKAGE_NAME, "--json"], {
32
89
  encoding: "utf-8",
33
90
  shell: true,
91
+ timeout: 5000,
34
92
  })
35
93
  if (result.stdout) {
36
94
  const data = JSON.parse(result.stdout)
37
- return data.dependencies?.[PACKAGE_NAME]?.version || "unknown"
95
+ if (data.dependencies?.[PACKAGE_NAME]?.version) {
96
+ return data.dependencies[PACKAGE_NAME].version
97
+ }
38
98
  }
39
99
  } catch {
40
100
  // ignore
41
101
  }
102
+
42
103
  return "unknown"
43
104
  }
44
105
 
45
106
  export async function update(args: string[]) {
46
- const flag = args[0]
107
+ // Parse flags
108
+ const forceFlag = args.includes("--force") || args.includes("-f")
109
+ const filteredArgs = args.filter(a => a !== "--force" && a !== "-f")
110
+ const flag = filteredArgs[0]
47
111
 
48
112
  // nimbus update --list
49
113
  if (flag === "--list" || flag === "-l") {
50
- p.intro(pc.cyan("Versões disponíveis"))
114
+ p.intro(pc.cyan("Versoes disponiveis"))
51
115
 
52
116
  const spinner = p.spinner()
53
- spinner.start("Buscando versões...")
117
+ spinner.start("Buscando versoes...")
54
118
 
55
119
  const versions = await getAvailableVersions()
56
- spinner.stop("Versões encontradas")
120
+ spinner.stop("Versoes encontradas")
57
121
 
58
122
  if (versions.length === 0) {
59
- p.log.error("Não foi possível buscar as versões")
123
+ p.log.error("Nao foi possivel buscar as versoes")
60
124
  return
61
125
  }
62
126
 
63
127
  const current = getCurrentVersion()
128
+ const pm = detectPackageManager()
64
129
 
65
130
  console.log()
66
- console.log(pc.bold("Últimas 10 versões:"))
131
+ console.log(pc.bold("Ultimas 10 versoes:"))
67
132
  versions.slice(0, 10).forEach((v, i) => {
68
133
  const isCurrent = v === current
69
- const prefix = isCurrent ? pc.green(" ") : " "
134
+ const prefix = isCurrent ? pc.green("-> ") : " "
70
135
  const suffix = isCurrent ? pc.dim(" (instalada)") : ""
71
136
  const isLatest = i === 0 ? pc.yellow(" (latest)") : ""
72
137
  console.log(`${prefix}${v}${suffix}${isLatest}`)
73
138
  })
74
139
  console.log()
75
- console.log(pc.dim(`Total: ${versions.length} versões`))
76
- console.log(pc.dim(`Instalar versão específica: nimbus update <versão>`))
140
+ console.log(pc.dim(`Total: ${versions.length} versoes`))
141
+ console.log(pc.dim(`Package manager detectado: ${pm === "unknown" ? "nenhum" : pm}`))
142
+ console.log(pc.dim(`Instalar versao especifica: nimbus update <versao>`))
143
+ console.log(pc.dim(`Forcar reinstalacao: nimbus update --force`))
77
144
  return
78
145
  }
79
146
 
80
147
  // nimbus update [version]
81
148
  const targetVersion = flag || "latest"
82
- const isSpecificVersion = flag && flag !== "latest"
149
+ const isSpecificVersion = flag && flag !== "latest" && !flag.startsWith("-")
83
150
 
84
151
  p.intro(pc.cyan(`Atualizando ${PACKAGE_NAME}`))
85
152
 
86
153
  const spinner = p.spinner()
87
154
 
88
- // Verificar versão atual
89
- spinner.start("Verificando versão atual...")
155
+ // Detectar package manager
156
+ spinner.start("Detectando package manager...")
157
+ const detectedPm = detectPackageManager()
158
+ // Usar bun como padrao se nenhum detectado
159
+ const pm = detectedPm === "unknown" ? "bun" : detectedPm
160
+ spinner.stop(`Package manager: ${pm}${detectedPm === "unknown" ? " (padrao)" : ""}`)
161
+
162
+ // Verificar versao atual
163
+ spinner.start("Verificando versao atual...")
90
164
  const currentVersion = getCurrentVersion()
91
- spinner.stop(`Versão atual: ${currentVersion}`)
165
+ spinner.stop(`Versao atual: ${currentVersion === "unknown" ? "nao instalado" : currentVersion}`)
92
166
 
93
- // Verificar versão alvo
167
+ // Verificar versao alvo
168
+ let latestVersion: string | null = null
94
169
  if (!isSpecificVersion) {
95
- spinner.start("Verificando última versão...")
96
- const latest = await getLatestVersion()
97
- spinner.stop(`Última versão: ${latest || "desconhecida"}`)
170
+ spinner.start("Verificando ultima versao no npm...")
171
+ latestVersion = await getLatestVersion()
172
+ spinner.stop(`Ultima versao: ${latestVersion || "desconhecida"}`)
98
173
 
99
- if (latest && latest === currentVersion) {
100
- p.log.success("Você está na última versão!")
174
+ if (!forceFlag && latestVersion && latestVersion === currentVersion) {
175
+ p.log.success("Voce ja esta na ultima versao!")
176
+ console.log(pc.dim(" Use --force para reinstalar"))
101
177
  return
102
178
  }
103
179
  }
104
180
 
105
181
  // Confirmar
106
- const versionText = isSpecificVersion ? targetVersion : "latest"
182
+ const versionText = isSpecificVersion ? targetVersion : (latestVersion || "latest")
183
+ const actionText = forceFlag ? "Reinstalar" : "Atualizar"
107
184
  const confirmUpdate = await p.confirm({
108
- message: `Atualizar para ${versionText}?`,
185
+ message: `${actionText} para ${versionText} usando ${pm}?`,
109
186
  initialValue: true,
110
187
  })
111
188
 
112
189
  if (p.isCancel(confirmUpdate) || !confirmUpdate) {
113
- p.cancel("Atualização cancelada")
190
+ p.cancel("Atualizacao cancelada")
114
191
  return
115
192
  }
116
193
 
@@ -120,23 +197,40 @@ export async function update(args: string[]) {
120
197
  try {
121
198
  const packageSpec = isSpecificVersion
122
199
  ? `${PACKAGE_NAME}@${targetVersion}`
123
- : PACKAGE_NAME
124
-
125
- // Usar npm para instalação global (mais estável que bun)
126
- execSync(`npm install -g ${packageSpec}`, {
127
- stdio: "pipe",
128
- encoding: "utf-8",
129
- })
200
+ : latestVersion
201
+ ? `${PACKAGE_NAME}@${latestVersion}`
202
+ : PACKAGE_NAME
203
+
204
+ // Usar o package manager detectado
205
+ if (pm === "bun") {
206
+ // Bun: remover primeiro se --force, depois instalar
207
+ if (forceFlag) {
208
+ try {
209
+ execSync(`bun remove -g ${PACKAGE_NAME}`, { stdio: "pipe", encoding: "utf-8" })
210
+ } catch {
211
+ // ignore - pode nao estar instalado
212
+ }
213
+ }
214
+ execSync(`bun add -g ${packageSpec}`, { stdio: "pipe", encoding: "utf-8" })
215
+ } else {
216
+ // npm: usar --force se solicitado
217
+ const forceArg = forceFlag ? " --force" : ""
218
+ execSync(`npm install -g ${packageSpec}${forceArg}`, { stdio: "pipe", encoding: "utf-8" })
219
+ }
130
220
 
131
- spinner.stop("Atualização concluída!")
221
+ spinner.stop("Atualizacao concluida!")
132
222
 
133
- // Verificar nova versão
223
+ // Verificar nova versao
134
224
  const newVersion = getCurrentVersion()
135
225
 
136
- p.log.success(`${PACKAGE_NAME} atualizado: ${currentVersion} ${newVersion}`)
226
+ if (currentVersion === newVersion && !forceFlag) {
227
+ p.log.warn("Versao nao mudou. Tente com --force")
228
+ } else {
229
+ p.log.success(`${PACKAGE_NAME} atualizado: ${currentVersion} -> ${newVersion}`)
230
+ }
137
231
  p.outro(pc.green("Pronto!"))
138
232
  } catch (error) {
139
- spinner.stop("Erro na atualização")
233
+ spinner.stop("Erro na atualizacao")
140
234
 
141
235
  const err = error as Error & { stderr?: string }
142
236
  p.log.error("Falha ao atualizar")
@@ -147,6 +241,10 @@ export async function update(args: string[]) {
147
241
 
148
242
  console.log()
149
243
  console.log(pc.yellow("Tente manualmente:"))
150
- console.log(pc.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`))
244
+ if (pm === "bun") {
245
+ console.log(pc.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`))
246
+ } else {
247
+ console.log(pc.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`))
248
+ }
151
249
  }
152
250
  }
package/src/index.ts CHANGED
@@ -58,8 +58,8 @@ function showUpdateNotice(latestVersion: string) {
58
58
  const border = "─".repeat(maxLen + 2)
59
59
 
60
60
  console.log(pc.yellow(` ┌${border}┐`))
61
- console.log(pc.yellow(` │`) + pc.white(line1.padEnd(maxLen + 1)) + pc.yellow(`│`))
62
- console.log(pc.yellow(` │`) + pc.cyan(line2.padEnd(maxLen + 1)) + pc.yellow(`│`))
61
+ console.log(pc.yellow(` │`) + pc.white(line1.padEnd(maxLen + 2)) + pc.yellow(`│`))
62
+ console.log(pc.yellow(` │`) + pc.cyan(line2.padEnd(maxLen + 2)) + pc.yellow(`│`))
63
63
  console.log(pc.yellow(` └${border}┘`))
64
64
  console.log()
65
65
  }
@@ -126,9 +126,10 @@ ${pc.bold("Analyze & Upgrade:")}
126
126
  upgrade tailwind Atualizar Tailwind CSS
127
127
 
128
128
  ${pc.bold("Update (CLI):")}
129
- update Atualizar para última versão
130
- update 0.11.0 Instalar versão específica
131
- update --list Listar versões disponíveis
129
+ update Atualizar para ultima versao
130
+ update 0.11.0 Instalar versao especifica
131
+ update --list Listar versoes disponiveis
132
+ update --force Forcar reinstalacao (limpa cache)
132
133
 
133
134
  ${pc.bold("Opções:")}
134
135
  -y, --yes Aceitar padrões