@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.
@@ -0,0 +1,251 @@
1
+ import * as p from "@clack/prompts"
2
+ import pc from "picocolors"
3
+ import { analyze } from "./analyze"
4
+
5
+ interface UpgradePlan {
6
+ current: string
7
+ target: string
8
+ breakingChanges: string[]
9
+ steps: string[]
10
+ complexity: "low" | "medium" | "high"
11
+ }
12
+
13
+ const UPGRADE_PLANS: Record<string, (currentVersion: string) => UpgradePlan | null> = {
14
+ next: (current) => {
15
+ const major = parseInt(current.replace(/[^0-9]/g, "").slice(0, 2))
16
+ if (major >= 16) return null
17
+
18
+ return {
19
+ current: current,
20
+ target: "16.x",
21
+ complexity: major < 15 ? "high" : "medium",
22
+ breakingChanges: [
23
+ "next/image: Mudancas na API de otimizacao",
24
+ "Middleware: Novo formato de config",
25
+ "next.config: Algumas opcoes depreciadas",
26
+ "Turbopack: Agora e o bundler padrao",
27
+ ],
28
+ steps: [
29
+ "Atualizar next para ^16.0.0",
30
+ "Atualizar react para ^19.0.0",
31
+ "Atualizar react-dom para ^19.0.0",
32
+ "Revisar next.config.ts",
33
+ "Testar build: bun run build",
34
+ "Testar dev: bun dev",
35
+ ],
36
+ }
37
+ },
38
+
39
+ react: (current) => {
40
+ if (current.startsWith("19") || current.startsWith("^19")) return null
41
+
42
+ return {
43
+ current: current,
44
+ target: "19.x",
45
+ complexity: "medium",
46
+ breakingChanges: [
47
+ "forwardRef: Nao mais necessario, ref e prop regular",
48
+ "useContext: Pode ser substituido por use(Context)",
49
+ "Suspense: Mudancas em fallback behavior",
50
+ "Async components: Novo suporte nativo",
51
+ ],
52
+ steps: [
53
+ "Atualizar react para ^19.0.0",
54
+ "Atualizar react-dom para ^19.0.0",
55
+ "Atualizar @types/react para ^19.0.0",
56
+ "Remover forwardRef (usar ref como prop)",
57
+ "Revisar Suspense boundaries",
58
+ "Testar todos os componentes",
59
+ ],
60
+ }
61
+ },
62
+
63
+ tailwind: (current) => {
64
+ if (current.startsWith("4") || current.startsWith("^4")) return null
65
+
66
+ return {
67
+ current: current,
68
+ target: "4.x",
69
+ complexity: "medium",
70
+ breakingChanges: [
71
+ "Config: Agora e CSS-first (nao mais tailwind.config.js)",
72
+ "@apply: Sintaxe mudou",
73
+ "Cores: Novo sistema de tokens",
74
+ "Plugins: API diferente",
75
+ ],
76
+ steps: [
77
+ "Atualizar tailwindcss para ^4.0.0",
78
+ "Converter tailwind.config.js para CSS",
79
+ "Atualizar globals.css com @import 'tailwindcss'",
80
+ "Revisar @apply usages",
81
+ "Atualizar plugins para v4",
82
+ "Testar todas as paginas",
83
+ ],
84
+ }
85
+ },
86
+
87
+ bun: () => ({
88
+ current: "pnpm/npm/yarn",
89
+ target: "bun",
90
+ complexity: "low",
91
+ breakingChanges: [
92
+ "Lockfile: Formato diferente (bun.lockb)",
93
+ "Scripts: Alguns podem precisar ajuste",
94
+ "Workspaces: Sintaxe levemente diferente",
95
+ ],
96
+ steps: [
97
+ "Remover node_modules",
98
+ "Remover pnpm-lock.yaml / package-lock.json / yarn.lock",
99
+ "Executar: bun install",
100
+ "Atualizar scripts no package.json (npx -> bunx)",
101
+ "Atualizar CI/CD configs",
102
+ "Testar: bun dev, bun build",
103
+ ],
104
+ }),
105
+
106
+ drizzle: () => ({
107
+ current: "prisma",
108
+ target: "drizzle",
109
+ complexity: "high",
110
+ breakingChanges: [
111
+ "Schema: Formato TypeScript (nao mais .prisma)",
112
+ "Queries: API completamente diferente",
113
+ "Migrations: Sistema diferente",
114
+ "Relations: Declaracao diferente",
115
+ ],
116
+ steps: [
117
+ "Instalar drizzle-orm e drizzle-kit",
118
+ "Converter schema.prisma para drizzle/schema.ts",
119
+ "Configurar drizzle.config.ts",
120
+ "Gerar migrations: bunx drizzle-kit generate",
121
+ "Atualizar todas as queries",
122
+ "Atualizar auth config (se usar)",
123
+ "Remover @prisma/client e prisma",
124
+ "Testar todas as operacoes de banco",
125
+ ],
126
+ }),
127
+ }
128
+
129
+ export async function upgrade(args: string[]) {
130
+ const showPlan = args.includes("--plan")
131
+ const target = args.find(a => !a.startsWith("-"))
132
+
133
+ console.log()
134
+
135
+ if (showPlan || !target) {
136
+ // Analyze first
137
+ console.log(pc.cyan(" Analisando projeto para plano de upgrade..."))
138
+ console.log()
139
+
140
+ const analysis = await analyze([".", "--quiet"])
141
+
142
+ console.log(pc.bold(" Upgrades Disponiveis:"))
143
+ console.log()
144
+
145
+ let hasUpgrades = false
146
+
147
+ // Check Next.js
148
+ if (analysis.frameworkVersion && analysis.framework === "nextjs") {
149
+ const planFn = UPGRADE_PLANS["next"]
150
+ if (planFn) {
151
+ const plan = planFn(analysis.frameworkVersion)
152
+ if (plan) {
153
+ hasUpgrades = true
154
+ printUpgradePlan("Next.js", plan)
155
+ }
156
+ }
157
+ }
158
+
159
+ // Check React
160
+ if (analysis.dependencies["react"]) {
161
+ const planFn = UPGRADE_PLANS["react"]
162
+ if (planFn) {
163
+ const plan = planFn(analysis.dependencies["react"])
164
+ if (plan) {
165
+ hasUpgrades = true
166
+ printUpgradePlan("React", plan)
167
+ }
168
+ }
169
+ }
170
+
171
+ // Check Tailwind
172
+ const tailwindDep = analysis.dependencies["tailwindcss"] || analysis.devDependencies["tailwindcss"]
173
+ if (tailwindDep) {
174
+ const planFn = UPGRADE_PLANS["tailwind"]
175
+ if (planFn) {
176
+ const plan = planFn(tailwindDep)
177
+ if (plan) {
178
+ hasUpgrades = true
179
+ printUpgradePlan("Tailwind CSS", plan)
180
+ }
181
+ }
182
+ }
183
+
184
+ // Check package manager
185
+ if (analysis.packageManager !== "bun") {
186
+ const planFn = UPGRADE_PLANS["bun"]
187
+ if (planFn) {
188
+ const plan = planFn("")
189
+ if (plan) {
190
+ hasUpgrades = true
191
+ printUpgradePlan("Package Manager", plan)
192
+ }
193
+ }
194
+ }
195
+
196
+ // Check Prisma -> Drizzle
197
+ if (analysis.database === "prisma") {
198
+ const planFn = UPGRADE_PLANS["drizzle"]
199
+ if (planFn) {
200
+ const plan = planFn("")
201
+ if (plan) {
202
+ hasUpgrades = true
203
+ printUpgradePlan("Database", plan)
204
+ }
205
+ }
206
+ }
207
+
208
+ if (!hasUpgrades) {
209
+ console.log(pc.green(" Projeto ja esta atualizado!"))
210
+ }
211
+
212
+ console.log()
213
+ console.log(pc.dim(" Para executar um upgrade especifico:"))
214
+ console.log(pc.dim(" nimbus upgrade next"))
215
+ console.log(pc.dim(" nimbus upgrade tailwind"))
216
+ console.log(pc.dim(" nimbus upgrade bun"))
217
+ console.log()
218
+
219
+ return
220
+ }
221
+
222
+ // Execute specific upgrade
223
+ console.log(pc.yellow(` Upgrade ${target} ainda nao implementado.`))
224
+ console.log(pc.dim(" Por enquanto, siga os passos do --plan manualmente."))
225
+ console.log()
226
+ }
227
+
228
+ function printUpgradePlan(name: string, plan: UpgradePlan) {
229
+ const complexityColor = {
230
+ low: pc.green,
231
+ medium: pc.yellow,
232
+ high: pc.red,
233
+ }
234
+
235
+ console.log(` ${pc.bold(name)}`)
236
+ console.log(` ${pc.dim("Atual:")} ${plan.current} ${pc.dim("->")} ${pc.cyan(plan.target)}`)
237
+ console.log(` ${pc.dim("Complexidade:")} ${complexityColor[plan.complexity](plan.complexity)}`)
238
+ console.log()
239
+
240
+ console.log(` ${pc.dim("Breaking Changes:")}`)
241
+ plan.breakingChanges.forEach(bc => {
242
+ console.log(` ${pc.yellow("!")} ${bc}`)
243
+ })
244
+ console.log()
245
+
246
+ console.log(` ${pc.dim("Passos:")}`)
247
+ plan.steps.forEach((step, i) => {
248
+ console.log(` ${pc.dim(`${i + 1}.`)} ${step}`)
249
+ })
250
+ console.log()
251
+ }
package/src/index.ts CHANGED
@@ -3,9 +3,11 @@
3
3
  import * as p from "@clack/prompts"
4
4
  import pc from "picocolors"
5
5
  import { create } from "./commands/create"
6
+ import { analyze } from "./commands/analyze"
7
+ import { upgrade } from "./commands/upgrade"
6
8
 
7
9
  const PACKAGE_NAME = "@nimbuslab/cli"
8
- const CURRENT_VERSION = "0.7.0"
10
+ const CURRENT_VERSION = "0.9.0"
9
11
 
10
12
  const LOGO = `
11
13
  ███╗ ██╗██╗███╗ ███╗██████╗ ██╗ ██╗███████╗
@@ -74,6 +76,10 @@ async function main() {
74
76
 
75
77
  if (!command || command === "create") {
76
78
  await create(args.slice(1))
79
+ } else if (command === "analyze") {
80
+ await analyze(args.slice(1))
81
+ } else if (command === "upgrade") {
82
+ await upgrade(args.slice(1))
77
83
  } else if (command === "help" || command === "--help" || command === "-h") {
78
84
  showHelp()
79
85
  } else if (command === "version" || command === "--version" || command === "-v") {
@@ -91,14 +97,23 @@ ${pc.bold("Usage:")} nimbus [command] [options]
91
97
 
92
98
  ${pc.bold("Commands:")}
93
99
  create [name] Create a new project
100
+ analyze [dir] Analyze project stack
101
+ upgrade [target] Upgrade dependencies
94
102
  help Show this help
95
103
  version Show version
96
104
 
97
105
  ${pc.bold("Templates:")}
98
106
  --landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
99
- --app Web app (Landing + Better Auth + Prisma)
107
+ --app Web app (Landing + Better Auth + Drizzle)
100
108
  --turborepo Monorepo (Turborepo + apps/packages)
101
109
 
110
+ ${pc.bold("Analyze & Upgrade:")}
111
+ analyze . Detect stack and show recommendations
112
+ analyze --json Output as JSON
113
+ upgrade --plan Show upgrade plan
114
+ upgrade next Upgrade Next.js
115
+ upgrade tailwind Upgrade Tailwind CSS
116
+
102
117
  ${pc.bold("Options:")}
103
118
  -y, --yes Accept defaults
104
119
  --no-git Don't initialize Git
@@ -108,7 +123,8 @@ ${pc.bold("Options:")}
108
123
  ${pc.bold("Examples:")}
109
124
  ${pc.dim("$")} nimbus create my-landing --landing
110
125
  ${pc.dim("$")} nimbus create my-app --app
111
- ${pc.dim("$")} nimbus create my-monorepo --turborepo
126
+ ${pc.dim("$")} nimbus analyze ./my-project
127
+ ${pc.dim("$")} nimbus upgrade --plan
112
128
  `)
113
129
  }
114
130