@nimbuslab/cli 0.16.3 → 0.16.5
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/README.md +41 -75
- package/dist/index.js +72 -10
- package/package.json +12 -2
- package/.github/workflows/publish.yml +0 -67
- package/CLAUDE.md +0 -106
- package/MIGRATION-ROADMAP.md +0 -201
- package/bun.lock +0 -36
- package/docs/CI-CD.md +0 -181
- package/docs/analyze.md +0 -148
- package/docs/create.md +0 -219
- package/docs/migrate.md +0 -177
- package/docs/package.md +0 -229
- package/docs/upgrade.md +0 -152
- package/src/commands/analyze.ts +0 -210
- package/src/commands/create.ts +0 -1323
- package/src/commands/lola.ts +0 -1026
- package/src/commands/update.ts +0 -267
- package/src/commands/upgrade.ts +0 -251
- package/src/index.ts +0 -161
- package/tsconfig.json +0 -29
package/src/commands/update.ts
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts"
|
|
2
|
-
import pc from "picocolors"
|
|
3
|
-
import { execSync, spawnSync } from "child_process"
|
|
4
|
-
|
|
5
|
-
const PACKAGE_NAME = "@nimbuslab/cli"
|
|
6
|
-
|
|
7
|
-
type PackageManager = "bun" | "npm" | "unknown"
|
|
8
|
-
|
|
9
|
-
// Detecta se está usando fnm (Fast Node Manager)
|
|
10
|
-
function isUsingFnm(): boolean {
|
|
11
|
-
const fnmDir = process.env.FNM_DIR || process.env.FNM_MULTISHELL_PATH
|
|
12
|
-
const whichNode = spawnSync("which", ["node"], { encoding: "utf-8", shell: true })
|
|
13
|
-
return !!(fnmDir || (whichNode.stdout && whichNode.stdout.includes("fnm")))
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async function getAvailableVersions(): Promise<string[]> {
|
|
17
|
-
try {
|
|
18
|
-
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}`)
|
|
19
|
-
if (!res.ok) return []
|
|
20
|
-
const data = await res.json() as { versions?: Record<string, unknown> }
|
|
21
|
-
return Object.keys(data.versions || {}).reverse()
|
|
22
|
-
} catch {
|
|
23
|
-
return []
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function getLatestVersion(): Promise<string | null> {
|
|
28
|
-
try {
|
|
29
|
-
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`)
|
|
30
|
-
if (!res.ok) return null
|
|
31
|
-
const data = await res.json() as { version?: string }
|
|
32
|
-
return data.version || null
|
|
33
|
-
} catch {
|
|
34
|
-
return null
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Detecta qual package manager tem o pacote instalado globalmente
|
|
39
|
-
// Prioriza npm (mais comum com fnm/nvm)
|
|
40
|
-
function detectPackageManager(): PackageManager {
|
|
41
|
-
// Tentar npm primeiro (prioridade)
|
|
42
|
-
try {
|
|
43
|
-
const npmResult = spawnSync("npm", ["ls", "-g", PACKAGE_NAME, "--json"], {
|
|
44
|
-
encoding: "utf-8",
|
|
45
|
-
shell: true,
|
|
46
|
-
timeout: 5000,
|
|
47
|
-
})
|
|
48
|
-
if (npmResult.stdout) {
|
|
49
|
-
const data = JSON.parse(npmResult.stdout)
|
|
50
|
-
if (data.dependencies?.[PACKAGE_NAME]) {
|
|
51
|
-
return "npm"
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
} catch {
|
|
55
|
-
// ignore
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Fallback para bun
|
|
59
|
-
try {
|
|
60
|
-
const bunResult = spawnSync("bun", ["pm", "ls", "-g"], {
|
|
61
|
-
encoding: "utf-8",
|
|
62
|
-
shell: true,
|
|
63
|
-
timeout: 5000,
|
|
64
|
-
})
|
|
65
|
-
if (bunResult.stdout && bunResult.stdout.includes(PACKAGE_NAME)) {
|
|
66
|
-
return "bun"
|
|
67
|
-
}
|
|
68
|
-
} catch {
|
|
69
|
-
// ignore
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return "unknown"
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function getCurrentVersion(): string {
|
|
76
|
-
// Tentar npm primeiro (prioridade)
|
|
77
|
-
try {
|
|
78
|
-
const result = spawnSync("npm", ["ls", "-g", PACKAGE_NAME, "--json"], {
|
|
79
|
-
encoding: "utf-8",
|
|
80
|
-
shell: true,
|
|
81
|
-
timeout: 5000,
|
|
82
|
-
})
|
|
83
|
-
if (result.stdout) {
|
|
84
|
-
const data = JSON.parse(result.stdout)
|
|
85
|
-
if (data.dependencies?.[PACKAGE_NAME]?.version) {
|
|
86
|
-
return data.dependencies[PACKAGE_NAME].version
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} catch {
|
|
90
|
-
// ignore
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Fallback para bun
|
|
94
|
-
try {
|
|
95
|
-
const bunResult = spawnSync("bun", ["pm", "ls", "-g"], {
|
|
96
|
-
encoding: "utf-8",
|
|
97
|
-
shell: true,
|
|
98
|
-
timeout: 5000,
|
|
99
|
-
})
|
|
100
|
-
if (bunResult.stdout) {
|
|
101
|
-
// Formato: "@nimbuslab/cli@0.14.0"
|
|
102
|
-
const match = bunResult.stdout.match(new RegExp(`${PACKAGE_NAME.replace("/", "\\/")}@([\\d.]+)`))
|
|
103
|
-
if (match?.[1]) {
|
|
104
|
-
return match[1]
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// ignore
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return "unknown"
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export async function update(args: string[]) {
|
|
115
|
-
// Parse flags
|
|
116
|
-
const forceFlag = args.includes("--force") || args.includes("-f")
|
|
117
|
-
const filteredArgs = args.filter(a => a !== "--force" && a !== "-f")
|
|
118
|
-
const flag = filteredArgs[0]
|
|
119
|
-
|
|
120
|
-
// nimbus update --list
|
|
121
|
-
if (flag === "--list" || flag === "-l") {
|
|
122
|
-
p.intro(pc.cyan("Versoes disponiveis"))
|
|
123
|
-
|
|
124
|
-
const spinner = p.spinner()
|
|
125
|
-
spinner.start("Buscando versoes...")
|
|
126
|
-
|
|
127
|
-
const versions = await getAvailableVersions()
|
|
128
|
-
spinner.stop("Versoes encontradas")
|
|
129
|
-
|
|
130
|
-
if (versions.length === 0) {
|
|
131
|
-
p.log.error("Nao foi possivel buscar as versoes")
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const current = getCurrentVersion()
|
|
136
|
-
const pm = detectPackageManager()
|
|
137
|
-
|
|
138
|
-
console.log()
|
|
139
|
-
console.log(pc.bold("Ultimas 10 versoes:"))
|
|
140
|
-
versions.slice(0, 10).forEach((v, i) => {
|
|
141
|
-
const isCurrent = v === current
|
|
142
|
-
const prefix = isCurrent ? pc.green("-> ") : " "
|
|
143
|
-
const suffix = isCurrent ? pc.dim(" (instalada)") : ""
|
|
144
|
-
const isLatest = i === 0 ? pc.yellow(" (latest)") : ""
|
|
145
|
-
console.log(`${prefix}${v}${suffix}${isLatest}`)
|
|
146
|
-
})
|
|
147
|
-
console.log()
|
|
148
|
-
console.log(pc.dim(`Total: ${versions.length} versoes`))
|
|
149
|
-
console.log(pc.dim(`Package manager detectado: ${pm === "unknown" ? "nenhum" : pm}`))
|
|
150
|
-
console.log(pc.dim(`Instalar versao especifica: nimbus update <versao>`))
|
|
151
|
-
console.log(pc.dim(`Forcar reinstalacao: nimbus update --force`))
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// nimbus update [version]
|
|
156
|
-
const targetVersion = flag || "latest"
|
|
157
|
-
const isSpecificVersion = flag && flag !== "latest" && !flag.startsWith("-")
|
|
158
|
-
|
|
159
|
-
p.intro(pc.cyan(`Atualizando ${PACKAGE_NAME}`))
|
|
160
|
-
|
|
161
|
-
const spinner = p.spinner()
|
|
162
|
-
|
|
163
|
-
// Detectar package manager
|
|
164
|
-
spinner.start("Detectando package manager...")
|
|
165
|
-
const detectedPm = detectPackageManager()
|
|
166
|
-
// Usar npm como padrao se nenhum detectado (compativel com fnm/nvm)
|
|
167
|
-
const pm = detectedPm === "unknown" ? "npm" : detectedPm
|
|
168
|
-
spinner.stop(`Package manager: ${pm}${detectedPm === "unknown" ? " (padrao)" : ""}`)
|
|
169
|
-
|
|
170
|
-
// Verificar versao atual
|
|
171
|
-
spinner.start("Verificando versao atual...")
|
|
172
|
-
const currentVersion = getCurrentVersion()
|
|
173
|
-
spinner.stop(`Versao atual: ${currentVersion === "unknown" ? "nao instalado" : currentVersion}`)
|
|
174
|
-
|
|
175
|
-
// Verificar versao alvo
|
|
176
|
-
let latestVersion: string | null = null
|
|
177
|
-
if (!isSpecificVersion) {
|
|
178
|
-
spinner.start("Verificando ultima versao no npm...")
|
|
179
|
-
latestVersion = await getLatestVersion()
|
|
180
|
-
spinner.stop(`Ultima versao: ${latestVersion || "desconhecida"}`)
|
|
181
|
-
|
|
182
|
-
if (!forceFlag && latestVersion && latestVersion === currentVersion) {
|
|
183
|
-
p.log.success("Voce ja esta na ultima versao!")
|
|
184
|
-
console.log(pc.dim(" Use --force para reinstalar"))
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Confirmar
|
|
190
|
-
const versionText = isSpecificVersion ? targetVersion : (latestVersion || "latest")
|
|
191
|
-
const actionText = forceFlag ? "Reinstalar" : "Atualizar"
|
|
192
|
-
const confirmUpdate = await p.confirm({
|
|
193
|
-
message: `${actionText} para ${versionText} usando ${pm}?`,
|
|
194
|
-
initialValue: true,
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
if (p.isCancel(confirmUpdate) || !confirmUpdate) {
|
|
198
|
-
p.cancel("Atualizacao cancelada")
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Executar update
|
|
203
|
-
spinner.start("Atualizando...")
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
const packageSpec = isSpecificVersion
|
|
207
|
-
? `${PACKAGE_NAME}@${targetVersion}`
|
|
208
|
-
: latestVersion
|
|
209
|
-
? `${PACKAGE_NAME}@${latestVersion}`
|
|
210
|
-
: PACKAGE_NAME
|
|
211
|
-
|
|
212
|
-
// Usar o package manager detectado
|
|
213
|
-
if (pm === "bun") {
|
|
214
|
-
// Bun: remover primeiro se --force, depois instalar
|
|
215
|
-
if (forceFlag) {
|
|
216
|
-
try {
|
|
217
|
-
execSync(`bun remove -g ${PACKAGE_NAME}`, { stdio: "pipe", encoding: "utf-8" })
|
|
218
|
-
} catch {
|
|
219
|
-
// ignore - pode nao estar instalado
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
execSync(`bun add -g ${packageSpec}`, { stdio: "pipe", encoding: "utf-8" })
|
|
223
|
-
} else {
|
|
224
|
-
// npm: usar --force se solicitado
|
|
225
|
-
const forceArg = forceFlag ? " --force" : ""
|
|
226
|
-
execSync(`npm install -g ${packageSpec}${forceArg}`, { stdio: "pipe", encoding: "utf-8" })
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
spinner.stop("Atualizacao concluida!")
|
|
230
|
-
|
|
231
|
-
// Verificar nova versao
|
|
232
|
-
const newVersion = getCurrentVersion()
|
|
233
|
-
|
|
234
|
-
if (currentVersion === newVersion && !forceFlag) {
|
|
235
|
-
p.log.warn("Versao nao mudou. Tente com --force")
|
|
236
|
-
} else {
|
|
237
|
-
p.log.success(`${PACKAGE_NAME} atualizado: ${currentVersion} -> ${newVersion}`)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Se usa fnm, avisar sobre hash
|
|
241
|
-
if (isUsingFnm()) {
|
|
242
|
-
console.log()
|
|
243
|
-
console.log(pc.yellow(" fnm detectado - execute para aplicar:"))
|
|
244
|
-
console.log(pc.cyan(" hash -r"))
|
|
245
|
-
console.log(pc.dim(" Ou abra um novo terminal."))
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
p.outro(pc.green("Pronto!"))
|
|
249
|
-
} catch (error) {
|
|
250
|
-
spinner.stop("Erro na atualizacao")
|
|
251
|
-
|
|
252
|
-
const err = error as Error & { stderr?: string }
|
|
253
|
-
p.log.error("Falha ao atualizar")
|
|
254
|
-
|
|
255
|
-
if (err.stderr) {
|
|
256
|
-
console.log(pc.dim(err.stderr))
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
console.log()
|
|
260
|
-
console.log(pc.yellow("Tente manualmente:"))
|
|
261
|
-
if (pm === "bun") {
|
|
262
|
-
console.log(pc.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`))
|
|
263
|
-
} else {
|
|
264
|
-
console.log(pc.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`))
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
package/src/commands/upgrade.ts
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
import * as p from "@clack/prompts"
|
|
4
|
-
import pc from "picocolors"
|
|
5
|
-
import { create } from "./commands/create"
|
|
6
|
-
import { analyze } from "./commands/analyze"
|
|
7
|
-
import { upgrade } from "./commands/upgrade"
|
|
8
|
-
import { update } from "./commands/update"
|
|
9
|
-
import { lola } from "./commands/lola"
|
|
10
|
-
|
|
11
|
-
const PACKAGE_NAME = "@nimbuslab/cli"
|
|
12
|
-
|
|
13
|
-
// Lê versão do package.json em runtime
|
|
14
|
-
const pkg = await import("../package.json")
|
|
15
|
-
const CURRENT_VERSION = pkg.version
|
|
16
|
-
|
|
17
|
-
const LOGO = `
|
|
18
|
-
███╗ ██╗██╗███╗ ███╗██████╗ ██╗ ██╗███████╗
|
|
19
|
-
████╗ ██║██║████╗ ████║██╔══██╗██║ ██║██╔════╝
|
|
20
|
-
██╔██╗ ██║██║██╔████╔██║██████╔╝██║ ██║███████╗
|
|
21
|
-
██║╚██╗██║██║██║╚██╔╝██║██╔══██╗██║ ██║╚════██║
|
|
22
|
-
██║ ╚████║██║██║ ╚═╝ ██║██████╔╝╚██████╔╝███████║
|
|
23
|
-
╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝`
|
|
24
|
-
|
|
25
|
-
async function checkForUpdates(): Promise<string | null> {
|
|
26
|
-
try {
|
|
27
|
-
const controller = new AbortController()
|
|
28
|
-
const timeout = setTimeout(() => controller.abort(), 3000)
|
|
29
|
-
|
|
30
|
-
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
|
|
31
|
-
signal: controller.signal,
|
|
32
|
-
})
|
|
33
|
-
clearTimeout(timeout)
|
|
34
|
-
|
|
35
|
-
if (!res.ok) return null
|
|
36
|
-
|
|
37
|
-
const data = await res.json() as { version?: string }
|
|
38
|
-
const latestVersion = data.version
|
|
39
|
-
|
|
40
|
-
if (latestVersion && latestVersion !== CURRENT_VERSION) {
|
|
41
|
-
return latestVersion
|
|
42
|
-
}
|
|
43
|
-
return null
|
|
44
|
-
} catch {
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function showUpdateNotice(latestVersion: string) {
|
|
50
|
-
const current = CURRENT_VERSION
|
|
51
|
-
const latest = latestVersion
|
|
52
|
-
const command = "nimbus update"
|
|
53
|
-
|
|
54
|
-
const line1 = ` Nova versão disponível: ${current} → ${latest}`
|
|
55
|
-
const line2 = ` Atualize com: ${command}`
|
|
56
|
-
|
|
57
|
-
const maxLen = Math.max(line1.length, line2.length)
|
|
58
|
-
const border = "─".repeat(maxLen + 2)
|
|
59
|
-
|
|
60
|
-
console.log(pc.yellow(` ┌${border}┐`))
|
|
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
|
-
console.log(pc.yellow(` └${border}┘`))
|
|
64
|
-
console.log()
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async function main() {
|
|
68
|
-
const args = process.argv.slice(2)
|
|
69
|
-
const command = args[0]
|
|
70
|
-
|
|
71
|
-
console.log(pc.cyan(LOGO))
|
|
72
|
-
console.log(pc.white(" nimbuslab CLI"))
|
|
73
|
-
console.log(pc.dim(" Create awesome projects"))
|
|
74
|
-
console.log()
|
|
75
|
-
|
|
76
|
-
// Check for updates (non-blocking)
|
|
77
|
-
const latestVersion = await checkForUpdates()
|
|
78
|
-
if (latestVersion) {
|
|
79
|
-
showUpdateNotice(latestVersion)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!command || command === "create") {
|
|
83
|
-
await create(args.slice(1))
|
|
84
|
-
} else if (command === "analyze") {
|
|
85
|
-
await analyze(args.slice(1))
|
|
86
|
-
} else if (command === "upgrade") {
|
|
87
|
-
await upgrade(args.slice(1))
|
|
88
|
-
} else if (command === "update") {
|
|
89
|
-
await update(args.slice(1))
|
|
90
|
-
} else if (command === "lola") {
|
|
91
|
-
await lola(args.slice(1))
|
|
92
|
-
} else if (command === "help" || command === "--help" || command === "-h") {
|
|
93
|
-
showHelp()
|
|
94
|
-
} else if (command === "version" || command === "--version" || command === "-v") {
|
|
95
|
-
showVersion()
|
|
96
|
-
} else {
|
|
97
|
-
console.log(pc.red(`Comando desconhecido: ${command}`))
|
|
98
|
-
showHelp()
|
|
99
|
-
process.exit(1)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function showHelp() {
|
|
104
|
-
console.log(`
|
|
105
|
-
${pc.bold("Uso:")} nimbus [comando] [opções]
|
|
106
|
-
|
|
107
|
-
${pc.bold("Comandos:")}
|
|
108
|
-
create [nome] Criar novo projeto
|
|
109
|
-
analyze [dir] Analisar stack do projeto
|
|
110
|
-
upgrade [alvo] Atualizar dependências
|
|
111
|
-
update [versão] Atualizar o CLI
|
|
112
|
-
lola [ação] Lola - Code Agent
|
|
113
|
-
help Mostrar esta ajuda
|
|
114
|
-
version Mostrar versão
|
|
115
|
-
|
|
116
|
-
${pc.bold("Templates:")}
|
|
117
|
-
--landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
|
|
118
|
-
--app Web app (Landing + Better Auth + Drizzle)
|
|
119
|
-
--turborepo Monorepo (Turborepo + apps/packages)
|
|
120
|
-
|
|
121
|
-
${pc.bold("Analyze & Upgrade:")}
|
|
122
|
-
analyze . Detectar stack e mostrar recomendações
|
|
123
|
-
analyze --json Output em JSON
|
|
124
|
-
upgrade --plan Mostrar plano de upgrade
|
|
125
|
-
upgrade next Atualizar Next.js
|
|
126
|
-
upgrade tailwind Atualizar Tailwind CSS
|
|
127
|
-
|
|
128
|
-
${pc.bold("Update (CLI):")}
|
|
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)
|
|
133
|
-
|
|
134
|
-
${pc.bold("Opções:")}
|
|
135
|
-
-y, --yes Aceitar padrões
|
|
136
|
-
--no-git Não inicializar Git
|
|
137
|
-
--no-install Não instalar dependências
|
|
138
|
-
--template <url> Usar template customizado
|
|
139
|
-
|
|
140
|
-
${pc.bold("Lola (Code Agent):")}
|
|
141
|
-
lola install Instalar/atualizar Lola
|
|
142
|
-
lola suggest Sugerir melhoria (cria issue)
|
|
143
|
-
|
|
144
|
-
${pc.bold("Exemplos:")}
|
|
145
|
-
${pc.dim("$")} nimbus create my-landing --landing
|
|
146
|
-
${pc.dim("$")} nimbus create my-app --app
|
|
147
|
-
${pc.dim("$")} nimbus analyze ./my-project
|
|
148
|
-
${pc.dim("$")} nimbus upgrade --plan
|
|
149
|
-
${pc.dim("$")} nimbus update
|
|
150
|
-
${pc.dim("$")} nimbus lola install
|
|
151
|
-
`)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function showVersion() {
|
|
155
|
-
console.log(`${PACKAGE_NAME} v${CURRENT_VERSION}`)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
main().catch((err) => {
|
|
159
|
-
console.error(pc.red("Erro:"), err.message)
|
|
160
|
-
process.exit(1)
|
|
161
|
-
})
|
package/tsconfig.json
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
// Environment setup & latest features
|
|
4
|
-
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "Preserve",
|
|
7
|
-
"moduleDetection": "force",
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
|
|
11
|
-
// Bundler mode
|
|
12
|
-
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true,
|
|
14
|
-
"verbatimModuleSyntax": true,
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
// Best practices
|
|
18
|
-
"strict": true,
|
|
19
|
-
"skipLibCheck": true,
|
|
20
|
-
"noFallthroughCasesInSwitch": true,
|
|
21
|
-
"noUncheckedIndexedAccess": true,
|
|
22
|
-
"noImplicitOverride": true,
|
|
23
|
-
|
|
24
|
-
// Some stricter flags (disabled by default)
|
|
25
|
-
"noUnusedLocals": false,
|
|
26
|
-
"noUnusedParameters": false,
|
|
27
|
-
"noPropertyAccessFromIndexSignature": false
|
|
28
|
-
}
|
|
29
|
-
}
|