@nimbuslab/cli 0.7.0 → 0.9.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.
package/dist/index.js CHANGED
@@ -147,7 +147,7 @@ var require_src = __commonJS((exports, module) => {
147
147
  });
148
148
 
149
149
  // src/index.ts
150
- var import_picocolors4 = __toESM(require_picocolors(), 1);
150
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
151
151
 
152
152
  // node_modules/@clack/core/dist/index.mjs
153
153
  var import_sisteransi = __toESM(require_src(), 1);
@@ -844,12 +844,133 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
844
844
  // src/commands/create.ts
845
845
  var import_picocolors3 = __toESM(require_picocolors(), 1);
846
846
  var {$: $2 } = globalThis.Bun;
847
- import { rm } from "fs/promises";
847
+ import { rm, mkdir } from "fs/promises";
848
848
  import { join } from "path";
849
+ var AI_CONFIGS = {
850
+ claude: {
851
+ filename: "CLAUDE.md",
852
+ content: (type) => `# ${type === "landing" ? "Landing Page" : type === "app" ? "Web App" : "Monorepo"}
853
+
854
+ ## Stack
855
+ - Next.js 16 (App Router, Turbopack)
856
+ - React 19 (Server Components)
857
+ - TypeScript (strict)
858
+ - Tailwind CSS 4
859
+ - shadcn/ui
860
+ - Bun
861
+ ${type === "app" ? `- Better Auth
862
+ - Drizzle + PostgreSQL` : ""}
863
+
864
+ ## Commands
865
+ \`\`\`bash
866
+ bun dev # Start development
867
+ bun build # Production build
868
+ bun lint # Run ESLint
869
+ ${type === "app" ? "bun setup # Setup database" : ""}
870
+ \`\`\`
871
+
872
+ ## Conventions
873
+ - Use \`bun\` for all package operations
874
+ - Server Components by default
875
+ - Dark mode first design
876
+ - Use \`cn()\` for conditional classes
877
+ - Add components: \`bunx --bun shadcn@latest add [component]\`
878
+ `
879
+ },
880
+ cursor: {
881
+ filename: ".cursorrules",
882
+ content: (type) => `# Cursor Rules
883
+
884
+ Stack: Next.js 16, React 19, TypeScript, Tailwind CSS 4, shadcn/ui, Bun
885
+ ${type === "app" ? "Auth: Better Auth | DB: Drizzle + PostgreSQL" : ""}
886
+
887
+ - Server Components by default
888
+ - "use client" only when needed
889
+ - Tailwind utility classes
890
+ - cn() for conditional classes
891
+ - Dark mode first
892
+ `
893
+ },
894
+ gemini: {
895
+ filename: ".gemini/GEMINI.md",
896
+ content: (type) => `# ${type === "landing" ? "Landing Page" : type === "app" ? "Web App" : "Monorepo"}
897
+
898
+ ## Stack
899
+ - Next.js 16 (App Router, Turbopack)
900
+ - React 19 (Server Components)
901
+ - TypeScript (strict)
902
+ - Tailwind CSS 4
903
+ - shadcn/ui
904
+ - Bun
905
+ ${type === "app" ? `- Better Auth
906
+ - Drizzle + PostgreSQL` : ""}
907
+
908
+ ## Conventions
909
+ - Use \`bun\` for all package operations
910
+ - Server Components by default
911
+ - Dark mode first design
912
+ - Use \`cn()\` for conditional classes
913
+ `
914
+ },
915
+ copilot: {
916
+ filename: ".github/copilot-instructions.md",
917
+ content: (type) => `# GitHub Copilot Instructions
918
+
919
+ Stack: Next.js 16, React 19, TypeScript, Tailwind CSS 4, shadcn/ui, Bun
920
+ ${type === "app" ? "Auth: Better Auth | DB: Drizzle + PostgreSQL" : ""}
921
+
922
+ ## Do
923
+ - Use TypeScript strict mode
924
+ - Prefer Server Components
925
+ - Use Tailwind for styling
926
+ - Use cn() for class merging
927
+
928
+ ## Don't
929
+ - Use CSS modules or styled-components
930
+ - Use class components
931
+ - Add unnecessary dependencies
932
+ `
933
+ },
934
+ windsurf: {
935
+ filename: ".windsurfrules",
936
+ content: (type) => `# Windsurf Rules
937
+
938
+ Stack: Next.js 16, React 19, TypeScript, Tailwind CSS 4, shadcn/ui, Bun
939
+ ${type === "app" ? "Auth: Better Auth | DB: Drizzle + PostgreSQL" : ""}
940
+
941
+ - Server Components by default
942
+ - "use client" only when needed
943
+ - Tailwind utility classes
944
+ - cn() for conditional classes
945
+ - Dark mode first
946
+ `
947
+ }
948
+ };
949
+ async function checkGitHubCli() {
950
+ const checkCmd = process.platform === "win32" ? "where" : "which";
951
+ try {
952
+ const hasGh = await $2`${checkCmd} gh`.quiet().nothrow();
953
+ if (hasGh.exitCode !== 0) {
954
+ return { installed: false, authenticated: false, username: null, orgs: [] };
955
+ }
956
+ const authStatus = await $2`gh auth status`.quiet().nothrow();
957
+ if (authStatus.exitCode !== 0) {
958
+ return { installed: true, authenticated: false, username: null, orgs: [] };
959
+ }
960
+ const username = (await $2`gh api user --jq '.login'`.quiet().text()).trim();
961
+ const orgsJson = await $2`gh api user/orgs --jq '.[].login'`.quiet().text();
962
+ const orgs = orgsJson.trim().split(`
963
+ `).filter(Boolean);
964
+ return { installed: true, authenticated: true, username, orgs };
965
+ } catch {
966
+ return { installed: false, authenticated: false, username: null, orgs: [] };
967
+ }
968
+ }
849
969
  var PRIVATE_TEMPLATES = {
850
970
  fast: "nimbuslab-templates/fast-template",
851
971
  "fast+": "nimbuslab-templates/fastplus-template",
852
- "fast+-monorepo": "nimbuslab-templates/fastplus-monorepo-template"
972
+ "fast+-monorepo": "nimbuslab-templates/fastplus-monorepo-template",
973
+ "nimbus-core": "nimbuslab/nimbus-core"
853
974
  };
854
975
  var PUBLIC_TEMPLATES = {
855
976
  landing: "nimbuslab/create-next-landing",
@@ -877,6 +998,7 @@ function parseFlags(args) {
877
998
  fast: false,
878
999
  fastPlus: false,
879
1000
  fastTurborepo: false,
1001
+ core: false,
880
1002
  noGit: false,
881
1003
  noInstall: false,
882
1004
  railway: false,
@@ -900,6 +1022,8 @@ function parseFlags(args) {
900
1022
  flags.fastPlus = true;
901
1023
  } else if (arg === "--fast-turborepo") {
902
1024
  flags.fastTurborepo = true;
1025
+ } else if (arg === "--core") {
1026
+ flags.core = true;
903
1027
  } else if (arg === "--no-git") {
904
1028
  flags.noGit = true;
905
1029
  } else if (arg === "--no-install") {
@@ -978,22 +1102,9 @@ async function create(args) {
978
1102
  process.exit(1);
979
1103
  }
980
1104
  if (!hasGh) {
981
- console.log(import_picocolors3.default.red("Error: GitHub CLI (gh) not found."));
982
- console.log(import_picocolors3.default.dim("Install from: https://cli.github.com"));
983
- console.log();
984
- if (process.platform === "win32") {
985
- console.log(import_picocolors3.default.cyan("winget install GitHub.cli"));
986
- } else {
987
- console.log(import_picocolors3.default.cyan("sudo apt install gh # ou brew install gh"));
988
- }
1105
+ console.log(import_picocolors3.default.dim(" GitHub CLI not found (repo creation will be skipped)"));
1106
+ console.log(import_picocolors3.default.dim(" Install from: https://cli.github.com"));
989
1107
  console.log();
990
- process.exit(1);
991
- }
992
- const ghAuth = await $2`gh auth status`.quiet().then(() => true).catch(() => false);
993
- if (!ghAuth) {
994
- console.log(import_picocolors3.default.red("Error: GitHub CLI not authenticated."));
995
- console.log(import_picocolors3.default.dim("Run: gh auth login"));
996
- process.exit(1);
997
1108
  }
998
1109
  const hasRailway = await ensureRailwayCli();
999
1110
  if (hasRailway) {
@@ -1007,8 +1118,8 @@ async function create(args) {
1007
1118
  const { flags, projectName } = parseFlags(args);
1008
1119
  Ie(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" New nimbuslab Project ")));
1009
1120
  let config;
1010
- const hasTypeFlag = flags.landing || flags.app || flags.turborepo || flags.fast || flags.fastPlus || flags.fastTurborepo;
1011
- const typeFromFlag = flags.landing ? "landing" : flags.app ? "app" : flags.turborepo ? "turborepo" : flags.fastTurborepo ? "fast+" : flags.fastPlus ? "fast+" : flags.fast ? "fast" : null;
1121
+ const hasTypeFlag = flags.landing || flags.app || flags.turborepo || flags.fast || flags.fastPlus || flags.fastTurborepo || flags.core;
1122
+ const typeFromFlag = flags.landing ? "landing" : flags.app ? "app" : flags.turborepo ? "turborepo" : flags.fastTurborepo ? "fast+" : flags.fastPlus ? "fast+" : flags.fast ? "fast" : flags.core ? "nimbus-core" : null;
1012
1123
  const monorepoFromFlag = flags.fastTurborepo;
1013
1124
  if ((flags.yes || hasTypeFlag) && projectName) {
1014
1125
  const defaultType = flags.landing || flags.app || flags.turborepo ? "landing" : "fast";
@@ -1021,6 +1132,8 @@ async function create(args) {
1021
1132
  github: false,
1022
1133
  githubOrg: null,
1023
1134
  githubDescription: "",
1135
+ theme: "dark",
1136
+ aiAssistant: null,
1024
1137
  contractNumber: "",
1025
1138
  resendApiKey: "",
1026
1139
  resendFromEmail: "",
@@ -1107,7 +1220,7 @@ async function promptConfig(initialName, flags) {
1107
1220
  {
1108
1221
  value: "app",
1109
1222
  label: "Web App",
1110
- hint: "Landing + Better Auth + Prisma"
1223
+ hint: "Landing + Better Auth + Drizzle"
1111
1224
  },
1112
1225
  {
1113
1226
  value: "turborepo",
@@ -1125,6 +1238,11 @@ async function promptConfig(initialName, flags) {
1125
1238
  value: "fast+",
1126
1239
  label: "fast+",
1127
1240
  hint: "Complete SaaS"
1241
+ },
1242
+ {
1243
+ value: "nimbus-core",
1244
+ label: "nimbus-core",
1245
+ hint: "External projects (stealth mode)"
1128
1246
  }
1129
1247
  ] : [];
1130
1248
  const type = await ve({
@@ -1138,6 +1256,44 @@ async function promptConfig(initialName, flags) {
1138
1256
  console.log(import_picocolors3.default.red("Error: Template available only for nimbuslab members"));
1139
1257
  process.exit(1);
1140
1258
  }
1259
+ if (type === "nimbus-core") {
1260
+ console.log();
1261
+ console.log(import_picocolors3.default.dim(" nimbus-core: Motor para projetos externos (stealth mode)"));
1262
+ console.log();
1263
+ const createGithub = await ye({
1264
+ message: "Create GitHub repository? (nimbuslab, private)",
1265
+ initialValue: true
1266
+ });
1267
+ if (pD(createGithub))
1268
+ return createGithub;
1269
+ const clientRepo = await he({
1270
+ message: "Client repo URL (optional, to clone in workspace):",
1271
+ placeholder: "git@github.com:client/repo.git"
1272
+ });
1273
+ if (pD(clientRepo))
1274
+ return clientRepo;
1275
+ return {
1276
+ name,
1277
+ type: "nimbus-core",
1278
+ monorepo: false,
1279
+ git: true,
1280
+ install: false,
1281
+ github: createGithub,
1282
+ githubOrg: "nimbuslab",
1283
+ githubDescription: `nimbus-core for ${name} - external project`,
1284
+ theme: "dark",
1285
+ aiAssistant: null,
1286
+ contractNumber: "",
1287
+ resendApiKey: "",
1288
+ resendFromEmail: "",
1289
+ contactEmail: "",
1290
+ railwayProject: "",
1291
+ railwayToken: "",
1292
+ stagingUrl: "",
1293
+ productionUrl: "",
1294
+ customTemplate: clientRepo || null
1295
+ };
1296
+ }
1141
1297
  let monorepo = false;
1142
1298
  if (type === "fast+") {
1143
1299
  const useMonorepo = await ye({
@@ -1200,6 +1356,66 @@ async function promptConfig(initialName, flags) {
1200
1356
  contractNumber = contract;
1201
1357
  }
1202
1358
  if (isPublicTemplate) {
1359
+ const theme = await ve({
1360
+ message: "Default theme:",
1361
+ options: [
1362
+ { value: "dark", label: "Dark", hint: "recommended" },
1363
+ { value: "light", label: "Light" },
1364
+ { value: "system", label: "System", hint: "follows OS preference" }
1365
+ ]
1366
+ });
1367
+ if (pD(theme))
1368
+ return theme;
1369
+ const aiAssistant = await ve({
1370
+ message: "Which AI assistant do you use?",
1371
+ options: [
1372
+ { value: "claude", label: "Claude Code", hint: "Anthropic" },
1373
+ { value: "cursor", label: "Cursor", hint: "AI-first editor" },
1374
+ { value: "gemini", label: "Gemini CLI", hint: "Google" },
1375
+ { value: "copilot", label: "GitHub Copilot" },
1376
+ { value: "windsurf", label: "Windsurf", hint: "Codeium" },
1377
+ { value: "none", label: "None", hint: "skip AI config" }
1378
+ ]
1379
+ });
1380
+ if (pD(aiAssistant))
1381
+ return aiAssistant;
1382
+ let publicGithub = false;
1383
+ let publicGithubOrg = null;
1384
+ if (git) {
1385
+ const gh = await checkGitHubCli();
1386
+ if (gh.installed && gh.authenticated) {
1387
+ const createRepo = await ye({
1388
+ message: "Create GitHub repository?",
1389
+ initialValue: false
1390
+ });
1391
+ if (pD(createRepo))
1392
+ return createRepo;
1393
+ publicGithub = createRepo;
1394
+ if (publicGithub) {
1395
+ const repoOptions = [
1396
+ { value: gh.username, label: gh.username, hint: "personal account" },
1397
+ ...gh.orgs.map((org) => ({ value: org, label: org }))
1398
+ ];
1399
+ const repoOwner = await ve({
1400
+ message: "Where to create the repository?",
1401
+ options: repoOptions
1402
+ });
1403
+ if (pD(repoOwner))
1404
+ return repoOwner;
1405
+ publicGithubOrg = repoOwner;
1406
+ const repoVisibility = await ve({
1407
+ message: "Repository visibility:",
1408
+ options: [
1409
+ { value: "private", label: "Private", hint: "recommended" },
1410
+ { value: "public", label: "Public" }
1411
+ ]
1412
+ });
1413
+ if (pD(repoVisibility))
1414
+ return repoVisibility;
1415
+ githubDescription = repoVisibility;
1416
+ }
1417
+ }
1418
+ }
1203
1419
  const install2 = await ye({
1204
1420
  message: "Install dependencies?",
1205
1421
  initialValue: true
@@ -1212,9 +1428,11 @@ async function promptConfig(initialName, flags) {
1212
1428
  monorepo: false,
1213
1429
  git,
1214
1430
  install: install2,
1215
- github,
1216
- githubOrg,
1431
+ github: publicGithub,
1432
+ githubOrg: publicGithubOrg,
1217
1433
  githubDescription,
1434
+ theme,
1435
+ aiAssistant: aiAssistant === "none" ? null : aiAssistant,
1218
1436
  contractNumber: "",
1219
1437
  resendApiKey: "",
1220
1438
  resendFromEmail: "",
@@ -1362,6 +1580,8 @@ async function promptConfig(initialName, flags) {
1362
1580
  github,
1363
1581
  githubOrg,
1364
1582
  githubDescription,
1583
+ theme: "dark",
1584
+ aiAssistant: null,
1365
1585
  contractNumber,
1366
1586
  resendApiKey,
1367
1587
  resendFromEmail,
@@ -1400,15 +1620,59 @@ async function createProject(config) {
1400
1620
  s.stop("Error cloning template");
1401
1621
  throw new Error(`Failed to clone template ${templateRepo}. Check your connection or repository access.`);
1402
1622
  }
1403
- s.start("Configuring project...");
1404
- try {
1405
- const pkgPath = `${config.name}/package.json`;
1406
- const pkg = await Bun.file(pkgPath).json();
1407
- pkg.name = config.name;
1408
- await Bun.write(pkgPath, JSON.stringify(pkg, null, 2));
1409
- s.stop("Project configured");
1410
- } catch (error) {
1411
- s.stop("Error configuring");
1623
+ if (config.type === "nimbus-core" && config.customTemplate) {
1624
+ const clientRepoUrl = config.customTemplate;
1625
+ s.start(`Cloning client repo in workspace...`);
1626
+ try {
1627
+ const projectName = clientRepoUrl.split("/").pop()?.replace(".git", "") || "client-project";
1628
+ await $2`git clone ${clientRepoUrl} ${config.name}/workspace/${projectName}`.quiet();
1629
+ s.stop(`Client repo cloned: workspace/${projectName}`);
1630
+ } catch (error) {
1631
+ s.stop("Error cloning client repo");
1632
+ console.log(import_picocolors3.default.dim(" You can clone manually: cd workspace && git clone <url>"));
1633
+ }
1634
+ }
1635
+ if (config.type !== "nimbus-core") {
1636
+ s.start("Configuring project...");
1637
+ try {
1638
+ const pkgPath = `${config.name}/package.json`;
1639
+ const pkg = await Bun.file(pkgPath).json();
1640
+ pkg.name = config.name;
1641
+ await Bun.write(pkgPath, JSON.stringify(pkg, null, 2));
1642
+ s.stop("Project configured");
1643
+ } catch (error) {
1644
+ s.stop("Error configuring");
1645
+ }
1646
+ }
1647
+ if (isPublicTemplate && config.theme) {
1648
+ s.start(`Setting theme to ${config.theme}...`);
1649
+ try {
1650
+ const layoutPath = `${config.name}/src/app/layout.tsx`;
1651
+ let layout = await Bun.file(layoutPath).text();
1652
+ layout = layout.replace(/defaultTheme="(dark|light|system)"/, `defaultTheme="${config.theme}"`);
1653
+ await Bun.write(layoutPath, layout);
1654
+ s.stop(`Theme set to ${config.theme}`);
1655
+ } catch {
1656
+ s.stop("Theme config skipped");
1657
+ }
1658
+ }
1659
+ if (isPublicTemplate && config.aiAssistant) {
1660
+ const aiConfig = AI_CONFIGS[config.aiAssistant];
1661
+ if (aiConfig) {
1662
+ s.start(`Generating ${config.aiAssistant} config...`);
1663
+ try {
1664
+ const content = aiConfig.content(config.type);
1665
+ const filePath = `${config.name}/${aiConfig.filename}`;
1666
+ if (aiConfig.filename.includes("/")) {
1667
+ const dir = aiConfig.filename.split("/").slice(0, -1).join("/");
1668
+ await mkdir(`${config.name}/${dir}`, { recursive: true });
1669
+ }
1670
+ await Bun.write(filePath, content);
1671
+ s.stop(`${aiConfig.filename} created`);
1672
+ } catch {
1673
+ s.stop("AI config skipped");
1674
+ }
1675
+ }
1412
1676
  }
1413
1677
  if (config.type === "fast+") {
1414
1678
  s.start("Configurando fast+ (SaaS)...");
@@ -1432,15 +1696,26 @@ async function createProject(config) {
1432
1696
  try {
1433
1697
  const cwd = config.name;
1434
1698
  const repoName = config.githubOrg ? `${config.githubOrg}/${config.name}` : config.name;
1435
- const visibility = config.githubOrg === "fast-by-nimbuslab" ? "--private" : "--public";
1436
- await $2`gh repo create ${repoName} ${visibility} --description ${config.githubDescription} --source . --remote origin`.cwd(cwd).quiet();
1699
+ let visibility;
1700
+ if (config.type === "nimbus-core") {
1701
+ visibility = "--private";
1702
+ } else if (isPublicTemplate) {
1703
+ visibility = config.githubDescription === "public" ? "--public" : "--private";
1704
+ } else {
1705
+ visibility = config.githubOrg === "fast-by-nimbuslab" ? "--private" : "--public";
1706
+ }
1707
+ if (isPublicTemplate) {
1708
+ await $2`gh repo create ${repoName} ${visibility} --source . --remote origin`.cwd(cwd).quiet();
1709
+ } else {
1710
+ await $2`gh repo create ${repoName} ${visibility} --description ${config.githubDescription} --source . --remote origin`.cwd(cwd).quiet();
1711
+ }
1437
1712
  await $2`git checkout main`.cwd(cwd).quiet();
1438
1713
  await $2`git push -u origin main`.cwd(cwd).quiet();
1439
1714
  await $2`git checkout staging`.cwd(cwd).quiet();
1440
1715
  await $2`git push -u origin staging`.cwd(cwd).quiet();
1441
1716
  await $2`git checkout develop`.cwd(cwd).quiet();
1442
1717
  await $2`git push -u origin develop`.cwd(cwd).quiet();
1443
- s.stop(`GitHub: ${repoName} criado`);
1718
+ s.stop(`GitHub: ${repoName}`);
1444
1719
  } catch (error) {
1445
1720
  s.stop("Error creating GitHub repository");
1446
1721
  console.log(import_picocolors3.default.dim(" You can create manually with: gh repo create"));
@@ -1518,56 +1793,499 @@ function generateEnvFile(config) {
1518
1793
  }
1519
1794
  function showNextSteps(config) {
1520
1795
  const isPublicTemplate = ["landing", "app", "turborepo"].includes(config.type);
1796
+ const needsSetup = config.type === "app";
1521
1797
  console.log();
1522
1798
  console.log(import_picocolors3.default.bold("Next steps:"));
1523
1799
  console.log();
1524
1800
  console.log(` ${import_picocolors3.default.cyan("cd")} ${config.name}`);
1801
+ if (config.type === "nimbus-core") {
1802
+ console.log();
1803
+ console.log(import_picocolors3.default.dim(" nimbus-core: Motor para projetos externos"));
1804
+ console.log();
1805
+ console.log(import_picocolors3.default.dim(" Para clonar repo do cliente:"));
1806
+ console.log(` ${import_picocolors3.default.cyan("cd")} workspace`);
1807
+ console.log(` ${import_picocolors3.default.cyan("git clone")} <repo-do-cliente>`);
1808
+ console.log();
1809
+ console.log(import_picocolors3.default.dim(" Para usar a Lola:"));
1810
+ console.log(` ${import_picocolors3.default.cyan("gemini")} ${import_picocolors3.default.dim("# Gemini CLI")}`);
1811
+ console.log(` ${import_picocolors3.default.cyan("claude --append-system-prompt-file .claude/agents/lola.md")}`);
1812
+ console.log();
1813
+ console.log(import_picocolors3.default.yellow(" STEALTH MODE: Commits sem mencao a nimbuslab/Lola/IA"));
1814
+ console.log();
1815
+ if (config.github) {
1816
+ const repoUrl = `https://github.com/nimbuslab/${config.name}`;
1817
+ console.log(import_picocolors3.default.green(` GitHub (private): ${repoUrl}`));
1818
+ console.log();
1819
+ }
1820
+ console.log(import_picocolors3.default.dim(" Docs: See README.md for full instructions"));
1821
+ console.log();
1822
+ return;
1823
+ }
1525
1824
  if (!config.install) {
1526
1825
  console.log(` ${import_picocolors3.default.cyan("bun")} install`);
1527
1826
  }
1528
- if (!isPublicTemplate) {
1827
+ if (!isPublicTemplate || needsSetup) {
1529
1828
  console.log(` ${import_picocolors3.default.cyan("bun")} setup`);
1530
1829
  }
1531
1830
  console.log(` ${import_picocolors3.default.cyan("bun")} dev`);
1532
1831
  console.log();
1533
- if (config.git) {
1534
- console.log(import_picocolors3.default.dim(" Git flow: main -> staging -> develop (current branch)"));
1832
+ if (needsSetup && isPublicTemplate) {
1833
+ console.log(import_picocolors3.default.dim(" bun setup will:"));
1834
+ console.log(import_picocolors3.default.dim(" - Start PostgreSQL with Docker"));
1835
+ console.log(import_picocolors3.default.dim(" - Run database migrations"));
1836
+ console.log(import_picocolors3.default.dim(" - Create demo user (demo@example.com / demo1234)"));
1535
1837
  console.log();
1838
+ }
1839
+ if (config.git) {
1840
+ console.log(import_picocolors3.default.dim(" Git: main -> staging -> develop (current branch)"));
1536
1841
  if (config.github) {
1537
1842
  const repoUrl = config.githubOrg ? `https://github.com/${config.githubOrg}/${config.name}` : `https://github.com/${config.name}`;
1538
1843
  console.log(import_picocolors3.default.green(` GitHub: ${repoUrl}`));
1539
- console.log();
1540
- } else {
1541
- console.log(import_picocolors3.default.yellow(" Tip: To create GitHub repo, use 'gh repo create' ou 'bun setup'."));
1844
+ }
1845
+ console.log();
1846
+ }
1847
+ if (isPublicTemplate) {
1848
+ if (config.theme !== "dark") {
1849
+ console.log(import_picocolors3.default.dim(` Theme: ${config.theme}`));
1850
+ }
1851
+ if (config.aiAssistant) {
1852
+ const aiConfig = AI_CONFIGS[config.aiAssistant];
1853
+ if (aiConfig) {
1854
+ console.log(import_picocolors3.default.dim(` AI config: ${aiConfig.filename}`));
1855
+ }
1856
+ }
1857
+ if (config.theme !== "dark" || config.aiAssistant) {
1542
1858
  console.log();
1543
1859
  }
1544
1860
  }
1545
1861
  if (config.type === "fast+") {
1546
- console.log(import_picocolors3.default.dim(" Tip: For fast+, configure DATABASE_URL e BETTER_AUTH_SECRET no .env"));
1862
+ console.log(import_picocolors3.default.dim(" bun setup will:"));
1863
+ console.log(import_picocolors3.default.dim(" - Start PostgreSQL with Docker"));
1864
+ console.log(import_picocolors3.default.dim(" - Run database migrations"));
1865
+ console.log(import_picocolors3.default.dim(" - Create demo user (demo@example.com / demo1234)"));
1866
+ console.log();
1867
+ console.log(import_picocolors3.default.dim(" Tip: Configure DATABASE_URL and BETTER_AUTH_SECRET in .env"));
1547
1868
  if (!config.railwayToken) {
1548
1869
  console.log(import_picocolors3.default.dim(" Railway: Create a project at https://railway.app/new"));
1549
1870
  }
1550
1871
  console.log();
1551
1872
  }
1552
- if (config.resendApiKey || config.stagingUrl) {
1553
- console.log(import_picocolors3.default.green(" .env configured successfully!"));
1554
- console.log();
1555
- } else {
1556
- console.log(import_picocolors3.default.yellow(" Tip: Configure .env manually or use 'bun setup'."));
1557
- console.log();
1873
+ if (!isPublicTemplate) {
1874
+ if (config.resendApiKey || config.stagingUrl) {
1875
+ console.log(import_picocolors3.default.green(" .env configured!"));
1876
+ console.log();
1877
+ } else {
1878
+ console.log(import_picocolors3.default.yellow(" Tip: Configure .env manually or use 'bun setup'."));
1879
+ console.log();
1880
+ }
1558
1881
  }
1559
1882
  if (isPublicTemplate) {
1560
1883
  console.log(import_picocolors3.default.dim(" Open source template (MIT) by nimbuslab"));
1561
- console.log(import_picocolors3.default.dim(` Documentation: https://github.com/nimbuslab/create-next-${config.type === "turborepo" ? "turborepo" : config.type}`));
1884
+ console.log(import_picocolors3.default.dim(` https://github.com/nimbuslab/create-next-${config.type === "turborepo" ? "turborepo" : config.type}`));
1562
1885
  } else {
1563
- console.log(import_picocolors3.default.dim(" Documentation: https://github.com/nimbuslab-templates"));
1886
+ console.log(import_picocolors3.default.dim(" https://github.com/nimbuslab-templates"));
1564
1887
  }
1565
1888
  console.log();
1566
1889
  }
1567
1890
 
1891
+ // src/commands/analyze.ts
1892
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
1893
+ import { existsSync, readFileSync } from "fs";
1894
+ import { join as join2 } from "path";
1895
+ function detectPackageManager(dir) {
1896
+ if (existsSync(join2(dir, "bun.lockb")))
1897
+ return "bun";
1898
+ if (existsSync(join2(dir, "pnpm-lock.yaml")))
1899
+ return "pnpm";
1900
+ if (existsSync(join2(dir, "yarn.lock")))
1901
+ return "yarn";
1902
+ if (existsSync(join2(dir, "package-lock.json")))
1903
+ return "npm";
1904
+ return "unknown";
1905
+ }
1906
+ function detectMonorepo(dir, pkg) {
1907
+ if (existsSync(join2(dir, "turbo.json")))
1908
+ return "turborepo";
1909
+ if (existsSync(join2(dir, "nx.json")))
1910
+ return "nx";
1911
+ if (existsSync(join2(dir, "lerna.json")))
1912
+ return "lerna";
1913
+ if (pkg.workspaces)
1914
+ return "workspaces";
1915
+ return null;
1916
+ }
1917
+ function detectFramework(deps) {
1918
+ if (deps["next"])
1919
+ return { name: "nextjs", version: deps["next"] };
1920
+ if (deps["@angular/core"])
1921
+ return { name: "angular", version: deps["@angular/core"] };
1922
+ if (deps["vue"])
1923
+ return { name: "vue", version: deps["vue"] };
1924
+ if (deps["svelte"])
1925
+ return { name: "svelte", version: deps["svelte"] };
1926
+ if (deps["react"] && !deps["next"])
1927
+ return { name: "react", version: deps["react"] };
1928
+ return { name: null, version: null };
1929
+ }
1930
+ function detectStyling(deps, devDeps) {
1931
+ const styling = [];
1932
+ const allDeps = { ...deps, ...devDeps };
1933
+ if (allDeps["tailwindcss"])
1934
+ styling.push(`tailwind@${allDeps["tailwindcss"]}`);
1935
+ if (allDeps["styled-components"])
1936
+ styling.push("styled-components");
1937
+ if (allDeps["@emotion/react"])
1938
+ styling.push("emotion");
1939
+ if (allDeps["sass"])
1940
+ styling.push("sass");
1941
+ if (allDeps["less"])
1942
+ styling.push("less");
1943
+ return styling.length > 0 ? styling : ["css"];
1944
+ }
1945
+ function detectAuth(deps) {
1946
+ if (deps["better-auth"])
1947
+ return "better-auth";
1948
+ if (deps["next-auth"])
1949
+ return "next-auth";
1950
+ if (deps["@clerk/nextjs"])
1951
+ return "clerk";
1952
+ if (deps["@auth0/nextjs-auth0"])
1953
+ return "auth0";
1954
+ if (deps["@supabase/supabase-js"])
1955
+ return "supabase";
1956
+ return null;
1957
+ }
1958
+ function detectDatabase(deps) {
1959
+ if (deps["drizzle-orm"])
1960
+ return "drizzle";
1961
+ if (deps["@prisma/client"])
1962
+ return "prisma";
1963
+ if (deps["typeorm"])
1964
+ return "typeorm";
1965
+ if (deps["mongoose"])
1966
+ return "mongoose";
1967
+ if (deps["pg"])
1968
+ return "pg";
1969
+ if (deps["mysql2"])
1970
+ return "mysql";
1971
+ return null;
1972
+ }
1973
+ function generateRecommendations(result) {
1974
+ const recs = [];
1975
+ if (result.packageManager !== "bun") {
1976
+ recs.push(`Migrar ${result.packageManager} -> bun (nimbus codemod bun)`);
1977
+ }
1978
+ if (result.framework === "nextjs" && result.frameworkVersion) {
1979
+ const majorVersion = parseInt(result.frameworkVersion.replace(/[^0-9]/g, "").slice(0, 2));
1980
+ if (majorVersion < 16) {
1981
+ recs.push(`Atualizar Next.js ${result.frameworkVersion} -> 16 (nimbus upgrade next)`);
1982
+ }
1983
+ }
1984
+ const tailwind = result.styling.find((s) => s.startsWith("tailwind"));
1985
+ if (tailwind) {
1986
+ const version = tailwind.split("@")[1] || "";
1987
+ if (version.startsWith("3")) {
1988
+ recs.push(`Atualizar Tailwind 3 -> 4 (nimbus upgrade tailwind)`);
1989
+ }
1990
+ } else if (!result.styling.includes("tailwind")) {
1991
+ recs.push(`Considerar adicionar Tailwind CSS (nimbus add tailwind)`);
1992
+ }
1993
+ if (result.dependencies["react"]) {
1994
+ const reactVersion = result.dependencies["react"];
1995
+ if (reactVersion.startsWith("18") || reactVersion.startsWith("^18")) {
1996
+ recs.push(`Atualizar React 18 -> 19 (nimbus upgrade react)`);
1997
+ }
1998
+ }
1999
+ if (result.database === "prisma") {
2000
+ recs.push(`Considerar migrar Prisma -> Drizzle (nimbus codemod drizzle)`);
2001
+ } else if (!result.database && result.framework === "nextjs") {
2002
+ recs.push(`Considerar adicionar banco de dados (nimbus add db)`);
2003
+ }
2004
+ if (!result.auth && result.framework === "nextjs") {
2005
+ recs.push(`Considerar adicionar autenticacao (nimbus add auth)`);
2006
+ } else if (result.auth === "next-auth") {
2007
+ recs.push(`Considerar migrar NextAuth -> Better Auth`);
2008
+ }
2009
+ if (result.monorepo === "workspaces" && !result.monorepo) {
2010
+ recs.push(`Considerar usar Turborepo para monorepo (nimbus add monorepo)`);
2011
+ }
2012
+ return recs;
2013
+ }
2014
+ async function analyze(args) {
2015
+ const targetDir = args[0] || ".";
2016
+ const absoluteDir = targetDir.startsWith("/") ? targetDir : join2(process.cwd(), targetDir);
2017
+ console.log();
2018
+ console.log(import_picocolors4.default.cyan(" Analisando projeto..."));
2019
+ console.log();
2020
+ const pkgPath = join2(absoluteDir, "package.json");
2021
+ if (!existsSync(pkgPath)) {
2022
+ console.log(import_picocolors4.default.red(" Erro: package.json nao encontrado"));
2023
+ console.log(import_picocolors4.default.dim(` Diretorio: ${absoluteDir}`));
2024
+ process.exit(1);
2025
+ }
2026
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
2027
+ const deps = pkg.dependencies || {};
2028
+ const devDeps = pkg.devDependencies || {};
2029
+ const framework = detectFramework(deps);
2030
+ const result = {
2031
+ name: pkg.name || "unknown",
2032
+ version: pkg.version || "0.0.0",
2033
+ framework: framework.name,
2034
+ frameworkVersion: framework.version,
2035
+ styling: detectStyling(deps, devDeps),
2036
+ packageManager: detectPackageManager(absoluteDir),
2037
+ monorepo: detectMonorepo(absoluteDir, pkg),
2038
+ auth: detectAuth(deps),
2039
+ database: detectDatabase(deps),
2040
+ typescript: existsSync(join2(absoluteDir, "tsconfig.json")),
2041
+ dependencies: deps,
2042
+ devDependencies: devDeps,
2043
+ recommendations: []
2044
+ };
2045
+ result.recommendations = generateRecommendations(result);
2046
+ console.log(import_picocolors4.default.bold(" Projeto: ") + import_picocolors4.default.cyan(result.name) + import_picocolors4.default.dim(` v${result.version}`));
2047
+ console.log();
2048
+ console.log(import_picocolors4.default.bold(" Stack Detectada:"));
2049
+ console.log(` Framework: ${result.framework ? import_picocolors4.default.green(result.framework + "@" + result.frameworkVersion) : import_picocolors4.default.dim("nenhum")}`);
2050
+ console.log(` Styling: ${result.styling.map((s) => import_picocolors4.default.green(s)).join(", ")}`);
2051
+ console.log(` Package Manager: ${result.packageManager === "bun" ? import_picocolors4.default.green(result.packageManager) : import_picocolors4.default.yellow(result.packageManager)}`);
2052
+ console.log(` TypeScript: ${result.typescript ? import_picocolors4.default.green("sim") : import_picocolors4.default.dim("nao")}`);
2053
+ console.log(` Monorepo: ${result.monorepo ? import_picocolors4.default.green(result.monorepo) : import_picocolors4.default.dim("nao")}`);
2054
+ console.log(` Auth: ${result.auth ? import_picocolors4.default.green(result.auth) : import_picocolors4.default.dim("nenhum")}`);
2055
+ console.log(` Database: ${result.database ? import_picocolors4.default.green(result.database) : import_picocolors4.default.dim("nenhum")}`);
2056
+ console.log();
2057
+ if (result.recommendations.length > 0) {
2058
+ console.log(import_picocolors4.default.bold(" Recomendacoes:"));
2059
+ result.recommendations.forEach((rec, i) => {
2060
+ console.log(import_picocolors4.default.yellow(` ${i + 1}. ${rec}`));
2061
+ });
2062
+ console.log();
2063
+ } else {
2064
+ console.log(import_picocolors4.default.green(" Projeto ja esta na stack recomendada!"));
2065
+ console.log();
2066
+ }
2067
+ if (args.includes("--json")) {
2068
+ console.log(import_picocolors4.default.dim(" JSON:"));
2069
+ console.log(JSON.stringify(result, null, 2));
2070
+ }
2071
+ return result;
2072
+ }
2073
+
2074
+ // src/commands/upgrade.ts
2075
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
2076
+ var UPGRADE_PLANS = {
2077
+ next: (current) => {
2078
+ const major = parseInt(current.replace(/[^0-9]/g, "").slice(0, 2));
2079
+ if (major >= 16)
2080
+ return null;
2081
+ return {
2082
+ current,
2083
+ target: "16.x",
2084
+ complexity: major < 15 ? "high" : "medium",
2085
+ breakingChanges: [
2086
+ "next/image: Mudancas na API de otimizacao",
2087
+ "Middleware: Novo formato de config",
2088
+ "next.config: Algumas opcoes depreciadas",
2089
+ "Turbopack: Agora e o bundler padrao"
2090
+ ],
2091
+ steps: [
2092
+ "Atualizar next para ^16.0.0",
2093
+ "Atualizar react para ^19.0.0",
2094
+ "Atualizar react-dom para ^19.0.0",
2095
+ "Revisar next.config.ts",
2096
+ "Testar build: bun run build",
2097
+ "Testar dev: bun dev"
2098
+ ]
2099
+ };
2100
+ },
2101
+ react: (current) => {
2102
+ if (current.startsWith("19") || current.startsWith("^19"))
2103
+ return null;
2104
+ return {
2105
+ current,
2106
+ target: "19.x",
2107
+ complexity: "medium",
2108
+ breakingChanges: [
2109
+ "forwardRef: Nao mais necessario, ref e prop regular",
2110
+ "useContext: Pode ser substituido por use(Context)",
2111
+ "Suspense: Mudancas em fallback behavior",
2112
+ "Async components: Novo suporte nativo"
2113
+ ],
2114
+ steps: [
2115
+ "Atualizar react para ^19.0.0",
2116
+ "Atualizar react-dom para ^19.0.0",
2117
+ "Atualizar @types/react para ^19.0.0",
2118
+ "Remover forwardRef (usar ref como prop)",
2119
+ "Revisar Suspense boundaries",
2120
+ "Testar todos os componentes"
2121
+ ]
2122
+ };
2123
+ },
2124
+ tailwind: (current) => {
2125
+ if (current.startsWith("4") || current.startsWith("^4"))
2126
+ return null;
2127
+ return {
2128
+ current,
2129
+ target: "4.x",
2130
+ complexity: "medium",
2131
+ breakingChanges: [
2132
+ "Config: Agora e CSS-first (nao mais tailwind.config.js)",
2133
+ "@apply: Sintaxe mudou",
2134
+ "Cores: Novo sistema de tokens",
2135
+ "Plugins: API diferente"
2136
+ ],
2137
+ steps: [
2138
+ "Atualizar tailwindcss para ^4.0.0",
2139
+ "Converter tailwind.config.js para CSS",
2140
+ "Atualizar globals.css com @import 'tailwindcss'",
2141
+ "Revisar @apply usages",
2142
+ "Atualizar plugins para v4",
2143
+ "Testar todas as paginas"
2144
+ ]
2145
+ };
2146
+ },
2147
+ bun: () => ({
2148
+ current: "pnpm/npm/yarn",
2149
+ target: "bun",
2150
+ complexity: "low",
2151
+ breakingChanges: [
2152
+ "Lockfile: Formato diferente (bun.lockb)",
2153
+ "Scripts: Alguns podem precisar ajuste",
2154
+ "Workspaces: Sintaxe levemente diferente"
2155
+ ],
2156
+ steps: [
2157
+ "Remover node_modules",
2158
+ "Remover pnpm-lock.yaml / package-lock.json / yarn.lock",
2159
+ "Executar: bun install",
2160
+ "Atualizar scripts no package.json (npx -> bunx)",
2161
+ "Atualizar CI/CD configs",
2162
+ "Testar: bun dev, bun build"
2163
+ ]
2164
+ }),
2165
+ drizzle: () => ({
2166
+ current: "prisma",
2167
+ target: "drizzle",
2168
+ complexity: "high",
2169
+ breakingChanges: [
2170
+ "Schema: Formato TypeScript (nao mais .prisma)",
2171
+ "Queries: API completamente diferente",
2172
+ "Migrations: Sistema diferente",
2173
+ "Relations: Declaracao diferente"
2174
+ ],
2175
+ steps: [
2176
+ "Instalar drizzle-orm e drizzle-kit",
2177
+ "Converter schema.prisma para drizzle/schema.ts",
2178
+ "Configurar drizzle.config.ts",
2179
+ "Gerar migrations: bunx drizzle-kit generate",
2180
+ "Atualizar todas as queries",
2181
+ "Atualizar auth config (se usar)",
2182
+ "Remover @prisma/client e prisma",
2183
+ "Testar todas as operacoes de banco"
2184
+ ]
2185
+ })
2186
+ };
2187
+ async function upgrade(args) {
2188
+ const showPlan = args.includes("--plan");
2189
+ const target = args.find((a) => !a.startsWith("-"));
2190
+ console.log();
2191
+ if (showPlan || !target) {
2192
+ console.log(import_picocolors5.default.cyan(" Analisando projeto para plano de upgrade..."));
2193
+ console.log();
2194
+ const analysis = await analyze([".", "--quiet"]);
2195
+ console.log(import_picocolors5.default.bold(" Upgrades Disponiveis:"));
2196
+ console.log();
2197
+ let hasUpgrades = false;
2198
+ if (analysis.frameworkVersion && analysis.framework === "nextjs") {
2199
+ const planFn = UPGRADE_PLANS["next"];
2200
+ if (planFn) {
2201
+ const plan = planFn(analysis.frameworkVersion);
2202
+ if (plan) {
2203
+ hasUpgrades = true;
2204
+ printUpgradePlan("Next.js", plan);
2205
+ }
2206
+ }
2207
+ }
2208
+ if (analysis.dependencies["react"]) {
2209
+ const planFn = UPGRADE_PLANS["react"];
2210
+ if (planFn) {
2211
+ const plan = planFn(analysis.dependencies["react"]);
2212
+ if (plan) {
2213
+ hasUpgrades = true;
2214
+ printUpgradePlan("React", plan);
2215
+ }
2216
+ }
2217
+ }
2218
+ const tailwindDep = analysis.dependencies["tailwindcss"] || analysis.devDependencies["tailwindcss"];
2219
+ if (tailwindDep) {
2220
+ const planFn = UPGRADE_PLANS["tailwind"];
2221
+ if (planFn) {
2222
+ const plan = planFn(tailwindDep);
2223
+ if (plan) {
2224
+ hasUpgrades = true;
2225
+ printUpgradePlan("Tailwind CSS", plan);
2226
+ }
2227
+ }
2228
+ }
2229
+ if (analysis.packageManager !== "bun") {
2230
+ const planFn = UPGRADE_PLANS["bun"];
2231
+ if (planFn) {
2232
+ const plan = planFn("");
2233
+ if (plan) {
2234
+ hasUpgrades = true;
2235
+ printUpgradePlan("Package Manager", plan);
2236
+ }
2237
+ }
2238
+ }
2239
+ if (analysis.database === "prisma") {
2240
+ const planFn = UPGRADE_PLANS["drizzle"];
2241
+ if (planFn) {
2242
+ const plan = planFn("");
2243
+ if (plan) {
2244
+ hasUpgrades = true;
2245
+ printUpgradePlan("Database", plan);
2246
+ }
2247
+ }
2248
+ }
2249
+ if (!hasUpgrades) {
2250
+ console.log(import_picocolors5.default.green(" Projeto ja esta atualizado!"));
2251
+ }
2252
+ console.log();
2253
+ console.log(import_picocolors5.default.dim(" Para executar um upgrade especifico:"));
2254
+ console.log(import_picocolors5.default.dim(" nimbus upgrade next"));
2255
+ console.log(import_picocolors5.default.dim(" nimbus upgrade tailwind"));
2256
+ console.log(import_picocolors5.default.dim(" nimbus upgrade bun"));
2257
+ console.log();
2258
+ return;
2259
+ }
2260
+ console.log(import_picocolors5.default.yellow(` Upgrade ${target} ainda nao implementado.`));
2261
+ console.log(import_picocolors5.default.dim(" Por enquanto, siga os passos do --plan manualmente."));
2262
+ console.log();
2263
+ }
2264
+ function printUpgradePlan(name, plan) {
2265
+ const complexityColor = {
2266
+ low: import_picocolors5.default.green,
2267
+ medium: import_picocolors5.default.yellow,
2268
+ high: import_picocolors5.default.red
2269
+ };
2270
+ console.log(` ${import_picocolors5.default.bold(name)}`);
2271
+ console.log(` ${import_picocolors5.default.dim("Atual:")} ${plan.current} ${import_picocolors5.default.dim("->")} ${import_picocolors5.default.cyan(plan.target)}`);
2272
+ console.log(` ${import_picocolors5.default.dim("Complexidade:")} ${complexityColor[plan.complexity](plan.complexity)}`);
2273
+ console.log();
2274
+ console.log(` ${import_picocolors5.default.dim("Breaking Changes:")}`);
2275
+ plan.breakingChanges.forEach((bc) => {
2276
+ console.log(` ${import_picocolors5.default.yellow("!")} ${bc}`);
2277
+ });
2278
+ console.log();
2279
+ console.log(` ${import_picocolors5.default.dim("Passos:")}`);
2280
+ plan.steps.forEach((step, i) => {
2281
+ console.log(` ${import_picocolors5.default.dim(`${i + 1}.`)} ${step}`);
2282
+ });
2283
+ console.log();
2284
+ }
2285
+
1568
2286
  // src/index.ts
1569
2287
  var PACKAGE_NAME = "@nimbuslab/cli";
1570
- var CURRENT_VERSION = "0.7.0";
2288
+ var CURRENT_VERSION = "0.9.0";
1571
2289
  var LOGO = `
1572
2290
  \u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
1573
2291
  \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
@@ -1603,18 +2321,18 @@ function showUpdateNotice(latestVersion) {
1603
2321
  const line2 = ` Update with: ${command}`;
1604
2322
  const maxLen = Math.max(line1.length, line2.length);
1605
2323
  const border = "\u2500".repeat(maxLen + 2);
1606
- console.log(import_picocolors4.default.yellow(` \u250C${border}\u2510`));
1607
- console.log(import_picocolors4.default.yellow(` \u2502`) + import_picocolors4.default.white(line1.padEnd(maxLen + 1)) + import_picocolors4.default.yellow(`\u2502`));
1608
- console.log(import_picocolors4.default.yellow(` \u2502`) + import_picocolors4.default.cyan(line2.padEnd(maxLen + 1)) + import_picocolors4.default.yellow(`\u2502`));
1609
- console.log(import_picocolors4.default.yellow(` \u2514${border}\u2518`));
2324
+ console.log(import_picocolors6.default.yellow(` \u250C${border}\u2510`));
2325
+ console.log(import_picocolors6.default.yellow(` \u2502`) + import_picocolors6.default.white(line1.padEnd(maxLen + 1)) + import_picocolors6.default.yellow(`\u2502`));
2326
+ console.log(import_picocolors6.default.yellow(` \u2502`) + import_picocolors6.default.cyan(line2.padEnd(maxLen + 1)) + import_picocolors6.default.yellow(`\u2502`));
2327
+ console.log(import_picocolors6.default.yellow(` \u2514${border}\u2518`));
1610
2328
  console.log();
1611
2329
  }
1612
2330
  async function main() {
1613
2331
  const args = process.argv.slice(2);
1614
2332
  const command = args[0];
1615
- console.log(import_picocolors4.default.cyan(LOGO));
1616
- console.log(import_picocolors4.default.white(" nimbuslab CLI"));
1617
- console.log(import_picocolors4.default.dim(" Create awesome projects"));
2333
+ console.log(import_picocolors6.default.cyan(LOGO));
2334
+ console.log(import_picocolors6.default.white(" nimbuslab CLI"));
2335
+ console.log(import_picocolors6.default.dim(" Create awesome projects"));
1618
2336
  console.log();
1619
2337
  const latestVersion = await checkForUpdates();
1620
2338
  if (latestVersion) {
@@ -1622,46 +2340,60 @@ async function main() {
1622
2340
  }
1623
2341
  if (!command || command === "create") {
1624
2342
  await create(args.slice(1));
2343
+ } else if (command === "analyze") {
2344
+ await analyze(args.slice(1));
2345
+ } else if (command === "upgrade") {
2346
+ await upgrade(args.slice(1));
1625
2347
  } else if (command === "help" || command === "--help" || command === "-h") {
1626
2348
  showHelp();
1627
2349
  } else if (command === "version" || command === "--version" || command === "-v") {
1628
2350
  showVersion();
1629
2351
  } else {
1630
- console.log(import_picocolors4.default.red(`Unknown command: ${command}`));
2352
+ console.log(import_picocolors6.default.red(`Unknown command: ${command}`));
1631
2353
  showHelp();
1632
2354
  process.exit(1);
1633
2355
  }
1634
2356
  }
1635
2357
  function showHelp() {
1636
2358
  console.log(`
1637
- ${import_picocolors4.default.bold("Usage:")} nimbus [command] [options]
2359
+ ${import_picocolors6.default.bold("Usage:")} nimbus [command] [options]
1638
2360
 
1639
- ${import_picocolors4.default.bold("Commands:")}
2361
+ ${import_picocolors6.default.bold("Commands:")}
1640
2362
  create [name] Create a new project
2363
+ analyze [dir] Analyze project stack
2364
+ upgrade [target] Upgrade dependencies
1641
2365
  help Show this help
1642
2366
  version Show version
1643
2367
 
1644
- ${import_picocolors4.default.bold("Templates:")}
2368
+ ${import_picocolors6.default.bold("Templates:")}
1645
2369
  --landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
1646
- --app Web app (Landing + Better Auth + Prisma)
2370
+ --app Web app (Landing + Better Auth + Drizzle)
1647
2371
  --turborepo Monorepo (Turborepo + apps/packages)
1648
2372
 
1649
- ${import_picocolors4.default.bold("Options:")}
2373
+ ${import_picocolors6.default.bold("Analyze & Upgrade:")}
2374
+ analyze . Detect stack and show recommendations
2375
+ analyze --json Output as JSON
2376
+ upgrade --plan Show upgrade plan
2377
+ upgrade next Upgrade Next.js
2378
+ upgrade tailwind Upgrade Tailwind CSS
2379
+
2380
+ ${import_picocolors6.default.bold("Options:")}
1650
2381
  -y, --yes Accept defaults
1651
2382
  --no-git Don't initialize Git
1652
2383
  --no-install Don't install dependencies
1653
2384
  --template <url> Use custom template
1654
2385
 
1655
- ${import_picocolors4.default.bold("Examples:")}
1656
- ${import_picocolors4.default.dim("$")} nimbus create my-landing --landing
1657
- ${import_picocolors4.default.dim("$")} nimbus create my-app --app
1658
- ${import_picocolors4.default.dim("$")} nimbus create my-monorepo --turborepo
2386
+ ${import_picocolors6.default.bold("Examples:")}
2387
+ ${import_picocolors6.default.dim("$")} nimbus create my-landing --landing
2388
+ ${import_picocolors6.default.dim("$")} nimbus create my-app --app
2389
+ ${import_picocolors6.default.dim("$")} nimbus analyze ./my-project
2390
+ ${import_picocolors6.default.dim("$")} nimbus upgrade --plan
1659
2391
  `);
1660
2392
  }
1661
2393
  function showVersion() {
1662
2394
  console.log(`${PACKAGE_NAME} v${CURRENT_VERSION}`);
1663
2395
  }
1664
2396
  main().catch((err) => {
1665
- console.error(import_picocolors4.default.red("Erro:"), err.message);
2397
+ console.error(import_picocolors6.default.red("Erro:"), err.message);
1666
2398
  process.exit(1);
1667
2399
  });