@nimbuslab/cli 1.0.0 → 1.2.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/README.md +176 -57
- package/dist/index.js +1388 -312
- package/package.json +2 -2
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
|
|
150
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
151
151
|
|
|
152
152
|
// node_modules/@clack/core/dist/index.mjs
|
|
153
153
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
@@ -865,10 +865,1041 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
865
865
|
};
|
|
866
866
|
|
|
867
867
|
// src/commands/create.ts
|
|
868
|
-
var
|
|
868
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
869
869
|
var {$: $2 } = globalThis.Bun;
|
|
870
870
|
import { rm, mkdir } from "fs/promises";
|
|
871
|
+
import { join as join2 } from "path";
|
|
872
|
+
|
|
873
|
+
// src/lib/generators/ai-docs.ts
|
|
871
874
|
import { join } from "path";
|
|
875
|
+
async function generateAIFriendlyDocs(projectPath, config) {
|
|
876
|
+
await generateAgentsFile(projectPath, config);
|
|
877
|
+
await generateLLMsFile(projectPath, config);
|
|
878
|
+
await generateArchitectureDoc(projectPath, config);
|
|
879
|
+
await generateExamplesDoc(projectPath, config);
|
|
880
|
+
await generateModificationsDoc(projectPath, config);
|
|
881
|
+
await createCompatibilitySymlinks(projectPath);
|
|
882
|
+
}
|
|
883
|
+
async function generateAgentsFile(projectPath, config) {
|
|
884
|
+
const content = `# Project Context for AI Assistants
|
|
885
|
+
|
|
886
|
+
> This file is automatically loaded by Claude Code, Cursor, GitHub Copilot, and other AI coding assistants.
|
|
887
|
+
|
|
888
|
+
## Project Overview
|
|
889
|
+
|
|
890
|
+
**Name:** ${config.name}
|
|
891
|
+
**Type:** ${config.type}
|
|
892
|
+
**Description:** ${config.description}
|
|
893
|
+
|
|
894
|
+
## Quick Start
|
|
895
|
+
|
|
896
|
+
\`\`\`bash
|
|
897
|
+
bun install
|
|
898
|
+
bun dev # http://localhost:3000
|
|
899
|
+
bun build # Production build
|
|
900
|
+
bun lint # ESLint
|
|
901
|
+
bun typecheck # TypeScript check
|
|
902
|
+
\`\`\`
|
|
903
|
+
|
|
904
|
+
## Tech Stack
|
|
905
|
+
|
|
906
|
+
| Category | Technology | Why? |
|
|
907
|
+
|----------|-----------|------|
|
|
908
|
+
| Framework | ${config.stack.framework} | App Router, Turbopack, best DX |
|
|
909
|
+
| Styling | ${config.stack.styling} | Fast, composable, CSS-first |
|
|
910
|
+
| Components | ${config.stack.components} | Copy-paste, zero lock-in |
|
|
911
|
+
${config.stack.forms ? `| Forms | ${config.stack.forms} | Type-safe validation |
|
|
912
|
+
` : ""}${config.stack.email ? `| Email | ${config.stack.email} | Transactional emails |
|
|
913
|
+
` : ""}${config.stack.auth ? `| Auth | ${config.stack.auth} | Secure authentication |
|
|
914
|
+
` : ""}
|
|
915
|
+
## Architecture Decisions
|
|
916
|
+
|
|
917
|
+
### Server vs Client Components
|
|
918
|
+
|
|
919
|
+
**Default: Server Components**
|
|
920
|
+
- Better performance (less JS shipped)
|
|
921
|
+
- SEO-friendly
|
|
922
|
+
- Direct data access
|
|
923
|
+
|
|
924
|
+
**Use Client Components when:**
|
|
925
|
+
- Need \`useState\`/\`useEffect\`
|
|
926
|
+
- Browser APIs (\`localStorage\`, \`window\`)
|
|
927
|
+
- Event handlers (\`onClick\`, \`onChange\`)
|
|
928
|
+
- Third-party libraries that require \`'use client'\`
|
|
929
|
+
|
|
930
|
+
### File Structure
|
|
931
|
+
|
|
932
|
+
\`\`\`
|
|
933
|
+
app/
|
|
934
|
+
\u251C\u2500\u2500 layout.tsx # Root layout
|
|
935
|
+
\u251C\u2500\u2500 page.tsx # Home page
|
|
936
|
+
${config.features.contactForm ? `\u251C\u2500\u2500 api/
|
|
937
|
+
\u2502 \u2514\u2500\u2500 contact/ # Form API
|
|
938
|
+
` : ""}\u2514\u2500\u2500 ...
|
|
939
|
+
|
|
940
|
+
components/
|
|
941
|
+
\u251C\u2500\u2500 ui/ # shadcn/ui components (DON'T EDIT)
|
|
942
|
+
${config.type === "landing" ? `\u251C\u2500\u2500 sections/ # Landing sections
|
|
943
|
+
` : ""}${config.type === "app" ? `\u251C\u2500\u2500 dashboard/ # Dashboard components
|
|
944
|
+
` : ""}\u2514\u2500\u2500 forms/ # Form components
|
|
945
|
+
|
|
946
|
+
lib/
|
|
947
|
+
\u251C\u2500\u2500 utils.ts # Helpers (cn, etc)
|
|
948
|
+
${config.features.contactForm ? `\u251C\u2500\u2500 validations.ts # Zod schemas
|
|
949
|
+
` : ""}${config.stack.email ? `\u251C\u2500\u2500 email.ts # Email client
|
|
950
|
+
` : ""}${config.stack.auth ? `\u251C\u2500\u2500 auth.ts # Auth config
|
|
951
|
+
` : ""}\u2514\u2500\u2500 ...
|
|
952
|
+
\`\`\`
|
|
953
|
+
|
|
954
|
+
## Coding Conventions
|
|
955
|
+
|
|
956
|
+
### Naming
|
|
957
|
+
- Components: \`PascalCase\` (UserProfile.tsx)
|
|
958
|
+
- Files: \`kebab-case\` (user-profile.tsx)
|
|
959
|
+
- Hooks: \`useCamelCase\` (useAuth.ts)
|
|
960
|
+
- Utils: \`camelCase\` (formatDate)
|
|
961
|
+
- Constants: \`SCREAMING_SNAKE_CASE\`
|
|
962
|
+
|
|
963
|
+
### Imports Order
|
|
964
|
+
\`\`\`typescript
|
|
965
|
+
// 1. External
|
|
966
|
+
import { useState } from 'react'
|
|
967
|
+
import { cn } from '@/lib/utils'
|
|
968
|
+
|
|
969
|
+
// 2. Internal components
|
|
970
|
+
import { Button } from '@/components/ui/button'
|
|
971
|
+
|
|
972
|
+
// 3. Local
|
|
973
|
+
import { schema } from './validations'
|
|
974
|
+
|
|
975
|
+
// 4. Types
|
|
976
|
+
import type { User } from '@/types'
|
|
977
|
+
\`\`\`
|
|
978
|
+
|
|
979
|
+
### TypeScript
|
|
980
|
+
- Always use \`type\` for objects
|
|
981
|
+
- Use \`interface\` only for extendable contracts
|
|
982
|
+
- Prefer \`const\` over \`let\`
|
|
983
|
+
- Use arrow functions for components
|
|
984
|
+
- Explicit return types for exported functions
|
|
985
|
+
|
|
986
|
+
## Project Inventory
|
|
987
|
+
|
|
988
|
+
${generateProjectInventory(config)}
|
|
989
|
+
|
|
990
|
+
## Feature Dependencies
|
|
991
|
+
|
|
992
|
+
${generateFeatureDependencies(config)}
|
|
993
|
+
|
|
994
|
+
## Common Tasks
|
|
995
|
+
|
|
996
|
+
### Add a new section
|
|
997
|
+
\`\`\`bash
|
|
998
|
+
# 1. Create component
|
|
999
|
+
touch components/sections/pricing.tsx
|
|
1000
|
+
|
|
1001
|
+
# 2. Add to page
|
|
1002
|
+
# app/page.tsx
|
|
1003
|
+
import { Pricing } from '@/components/sections/pricing'
|
|
1004
|
+
\`\`\`
|
|
1005
|
+
|
|
1006
|
+
${config.features.contactForm ? `### Add form validation
|
|
1007
|
+
\`\`\`typescript
|
|
1008
|
+
// lib/validations.ts
|
|
1009
|
+
export const contactSchema = z.object({
|
|
1010
|
+
email: z.string().email('Email inv\xE1lido'),
|
|
1011
|
+
message: z.string().min(10, 'M\xEDnimo 10 caracteres'),
|
|
1012
|
+
})
|
|
1013
|
+
|
|
1014
|
+
// components/forms/contact-form.tsx
|
|
1015
|
+
const form = useForm<z.infer<typeof contactSchema>>({
|
|
1016
|
+
resolver: zodResolver(contactSchema),
|
|
1017
|
+
})
|
|
1018
|
+
\`\`\`
|
|
1019
|
+
|
|
1020
|
+
` : ""}${config.stack.email ? `### Send email
|
|
1021
|
+
\`\`\`typescript
|
|
1022
|
+
// app/api/contact/route.ts
|
|
1023
|
+
import { resend } from '@/lib/email'
|
|
1024
|
+
|
|
1025
|
+
await resend.emails.send({
|
|
1026
|
+
from: 'noreply@example.com',
|
|
1027
|
+
to: 'contact@example.com',
|
|
1028
|
+
subject: 'Novo contato',
|
|
1029
|
+
react: ContactEmail({ name, email, message }),
|
|
1030
|
+
})
|
|
1031
|
+
\`\`\`
|
|
1032
|
+
|
|
1033
|
+
` : ""}## Performance Targets
|
|
1034
|
+
|
|
1035
|
+
| Metric | Target |
|
|
1036
|
+
|--------|--------|
|
|
1037
|
+
| Lighthouse Performance | 95+ |
|
|
1038
|
+
| LCP | < 2.0s |
|
|
1039
|
+
| CLS | < 0.05 |
|
|
1040
|
+
| Bundle Size | < 100KB |
|
|
1041
|
+
|
|
1042
|
+
## Environment Variables
|
|
1043
|
+
|
|
1044
|
+
\`\`\`env
|
|
1045
|
+
# Required
|
|
1046
|
+
${config.stack.email ? `RESEND_API_KEY=re_*** # Get: https://resend.com/api-keys
|
|
1047
|
+
` : ""}${config.stack.auth ? `NEXTAUTH_SECRET=*** # Generate: openssl rand -base64 32
|
|
1048
|
+
` : ""}
|
|
1049
|
+
# Optional
|
|
1050
|
+
NEXT_PUBLIC_GA_ID=G-*** # Google Analytics
|
|
1051
|
+
\`\`\`
|
|
1052
|
+
|
|
1053
|
+
## Testing
|
|
1054
|
+
|
|
1055
|
+
\`\`\`bash
|
|
1056
|
+
bun test # Unit tests
|
|
1057
|
+
bun test:e2e # E2E tests
|
|
1058
|
+
bun lint # ESLint
|
|
1059
|
+
bun typecheck # TypeScript
|
|
1060
|
+
\`\`\`
|
|
1061
|
+
|
|
1062
|
+
## Deployment
|
|
1063
|
+
|
|
1064
|
+
Auto-deploys to Vercel on push to \`main\`.
|
|
1065
|
+
|
|
1066
|
+
**Manual:**
|
|
1067
|
+
\`\`\`bash
|
|
1068
|
+
vercel --prod
|
|
1069
|
+
\`\`\`
|
|
1070
|
+
|
|
1071
|
+
## Troubleshooting
|
|
1072
|
+
|
|
1073
|
+
### Build errors
|
|
1074
|
+
- Clear \`.next\`: \`rm -rf .next\`
|
|
1075
|
+
- Clear cache: \`bun install --force\`
|
|
1076
|
+
|
|
1077
|
+
### Type errors
|
|
1078
|
+
- Restart TS server in IDE
|
|
1079
|
+
- Check \`tsconfig.json\` paths
|
|
1080
|
+
|
|
1081
|
+
## Resources
|
|
1082
|
+
|
|
1083
|
+
- [Next.js Docs](https://nextjs.org/docs)
|
|
1084
|
+
- [Tailwind Docs](https://tailwindcss.com/docs)
|
|
1085
|
+
- [shadcn/ui](https://ui.shadcn.com)
|
|
1086
|
+
${config.stack.email ? `- [Resend Docs](https://resend.com/docs)
|
|
1087
|
+
` : ""}${config.stack.auth ? `- [NextAuth Docs](https://authjs.dev)
|
|
1088
|
+
` : ""}
|
|
1089
|
+
---
|
|
1090
|
+
|
|
1091
|
+
*Generated by @nimbuslab/cli*
|
|
1092
|
+
*Last updated: ${new Date().toISOString().split("T")[0]}*
|
|
1093
|
+
`;
|
|
1094
|
+
await Bun.write(join(projectPath, "AGENTS.md"), content);
|
|
1095
|
+
}
|
|
1096
|
+
async function generateLLMsFile(projectPath, config) {
|
|
1097
|
+
const content = `# ${config.name}
|
|
1098
|
+
|
|
1099
|
+
> AI-friendly documentation index
|
|
1100
|
+
|
|
1101
|
+
## Navigation
|
|
1102
|
+
|
|
1103
|
+
- [Project Overview](./AGENTS.md)
|
|
1104
|
+
- [Architecture](./ARCHITECTURE.md)
|
|
1105
|
+
- [Examples](./EXAMPLES.md)
|
|
1106
|
+
- [How to Modify](./MODIFICATIONS.md)
|
|
1107
|
+
- [Contributing](./CONTRIBUTING.md)
|
|
1108
|
+
|
|
1109
|
+
## Quick Context
|
|
1110
|
+
|
|
1111
|
+
${config.description}
|
|
1112
|
+
|
|
1113
|
+
**Stack:** ${config.stack.framework}, ${config.stack.styling}, ${config.stack.components}
|
|
1114
|
+
|
|
1115
|
+
## Common Questions
|
|
1116
|
+
|
|
1117
|
+
### How do I start development?
|
|
1118
|
+
\`\`\`bash
|
|
1119
|
+
bun install && bun dev
|
|
1120
|
+
\`\`\`
|
|
1121
|
+
|
|
1122
|
+
${config.features.contactForm ? `### How do I configure email?
|
|
1123
|
+
See [AGENTS.md#send-email](./AGENTS.md#send-email)
|
|
1124
|
+
|
|
1125
|
+
` : ""}${config.features.auth ? `### How do I set up authentication?
|
|
1126
|
+
See [AGENTS.md#environment-variables](./AGENTS.md#environment-variables)
|
|
1127
|
+
|
|
1128
|
+
` : ""}### How do I deploy?
|
|
1129
|
+
Push to \`main\` branch - auto-deploys to Vercel.
|
|
1130
|
+
|
|
1131
|
+
## File Structure
|
|
1132
|
+
|
|
1133
|
+
\`\`\`
|
|
1134
|
+
app/ # Next.js app router
|
|
1135
|
+
components/ # React components
|
|
1136
|
+
ui/ # shadcn/ui (auto-generated)
|
|
1137
|
+
lib/ # Utilities
|
|
1138
|
+
public/ # Static assets
|
|
1139
|
+
\`\`\`
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
*Auto-generated for LLM consumption*
|
|
1144
|
+
*Learn more: https://mintlify.com/blog/simplifying-docs-with-llms-txt*
|
|
1145
|
+
`;
|
|
1146
|
+
await Bun.write(join(projectPath, "llms.txt"), content);
|
|
1147
|
+
}
|
|
1148
|
+
async function generateArchitectureDoc(projectPath, config) {
|
|
1149
|
+
const content = `# Architecture
|
|
1150
|
+
|
|
1151
|
+
## Design Decisions
|
|
1152
|
+
|
|
1153
|
+
### 1. Next.js App Router
|
|
1154
|
+
|
|
1155
|
+
**Why:**
|
|
1156
|
+
- React Server Components by default
|
|
1157
|
+
- Better performance (less client JS)
|
|
1158
|
+
- Simplified data fetching
|
|
1159
|
+
- Native TypeScript support
|
|
1160
|
+
|
|
1161
|
+
**Trade-offs:**
|
|
1162
|
+
- Learning curve vs Pages Router
|
|
1163
|
+
- Some libraries require \`'use client'\`
|
|
1164
|
+
|
|
1165
|
+
### 2. ${config.stack.styling}
|
|
1166
|
+
|
|
1167
|
+
**Why:**
|
|
1168
|
+
- Zero runtime (pure CSS)
|
|
1169
|
+
- Better performance
|
|
1170
|
+
- Smaller bundle size
|
|
1171
|
+
- Familiar DX
|
|
1172
|
+
|
|
1173
|
+
### 3. ${config.stack.components}
|
|
1174
|
+
|
|
1175
|
+
**Why:**
|
|
1176
|
+
- Copy-paste workflow (no lock-in)
|
|
1177
|
+
- Full control over components
|
|
1178
|
+
- Customizable without ejecting
|
|
1179
|
+
- Built on Radix UI (accessibility)
|
|
1180
|
+
|
|
1181
|
+
**Trade-offs:**
|
|
1182
|
+
- Manual updates (not auto-updated via npm)
|
|
1183
|
+
- More files in your repo
|
|
1184
|
+
- Worth it for flexibility
|
|
1185
|
+
|
|
1186
|
+
${config.type === "landing" ? `### 4. Landing Page Structure
|
|
1187
|
+
|
|
1188
|
+
\`\`\`
|
|
1189
|
+
Hero
|
|
1190
|
+
\u2193
|
|
1191
|
+
Social Proof / Features
|
|
1192
|
+
\u2193
|
|
1193
|
+
How It Works
|
|
1194
|
+
\u2193
|
|
1195
|
+
Testimonials
|
|
1196
|
+
\u2193
|
|
1197
|
+
FAQ
|
|
1198
|
+
\u2193
|
|
1199
|
+
CTA
|
|
1200
|
+
\u2193
|
|
1201
|
+
Footer
|
|
1202
|
+
\`\`\`
|
|
1203
|
+
|
|
1204
|
+
**Why this order:**
|
|
1205
|
+
- Hero grabs attention first
|
|
1206
|
+
- Features build interest
|
|
1207
|
+
- FAQ reduces friction
|
|
1208
|
+
- CTA when ready to convert
|
|
1209
|
+
|
|
1210
|
+
` : ""}## This Project's Specific Decisions
|
|
1211
|
+
|
|
1212
|
+
${generateProjectDecisions(config)}
|
|
1213
|
+
|
|
1214
|
+
## Data Flow
|
|
1215
|
+
|
|
1216
|
+
\`\`\`
|
|
1217
|
+
User Action
|
|
1218
|
+
\u2193
|
|
1219
|
+
Client Component (onClick)
|
|
1220
|
+
\u2193
|
|
1221
|
+
${config.features.contactForm ? `Server Action / API Route
|
|
1222
|
+
\u2193
|
|
1223
|
+
Validation (Zod)
|
|
1224
|
+
\u2193
|
|
1225
|
+
` : ""}${config.stack.email ? `External API (Resend)
|
|
1226
|
+
\u2193
|
|
1227
|
+
` : ""}Response to client
|
|
1228
|
+
\`\`\`
|
|
1229
|
+
|
|
1230
|
+
## Performance Strategy
|
|
1231
|
+
|
|
1232
|
+
### 1. Server Components First
|
|
1233
|
+
- Default to Server Components
|
|
1234
|
+
- Only use Client when needed
|
|
1235
|
+
- Less JavaScript shipped
|
|
1236
|
+
|
|
1237
|
+
### 2. Image Optimization
|
|
1238
|
+
- Always use \`next/image\`
|
|
1239
|
+
- Lazy loading by default
|
|
1240
|
+
- Modern formats (WebP, AVIF)
|
|
1241
|
+
|
|
1242
|
+
### 3. Code Splitting
|
|
1243
|
+
- Dynamic imports for heavy components
|
|
1244
|
+
- Route-based splitting (automatic)
|
|
1245
|
+
|
|
1246
|
+
## Security
|
|
1247
|
+
|
|
1248
|
+
### 1. Environment Variables
|
|
1249
|
+
- Never commit \`.env\`
|
|
1250
|
+
- Use \`.env.example\` for templates
|
|
1251
|
+
- Validate on startup
|
|
1252
|
+
|
|
1253
|
+
${config.features.contactForm ? `### 2. Form Validation
|
|
1254
|
+
- Client + Server validation
|
|
1255
|
+
- Zod schemas shared
|
|
1256
|
+
- Sanitize inputs
|
|
1257
|
+
|
|
1258
|
+
` : ""}### 3. Rate Limiting
|
|
1259
|
+
- API routes protected
|
|
1260
|
+
- Per-IP limits
|
|
1261
|
+
|
|
1262
|
+
---
|
|
1263
|
+
|
|
1264
|
+
*This document explains WHY, not HOW.*
|
|
1265
|
+
*For HOW, see AGENTS.md*
|
|
1266
|
+
`;
|
|
1267
|
+
await Bun.write(join(projectPath, "ARCHITECTURE.md"), content);
|
|
1268
|
+
}
|
|
1269
|
+
async function generateExamplesDoc(projectPath, config) {
|
|
1270
|
+
const content = `# Examples
|
|
1271
|
+
|
|
1272
|
+
Common tasks with complete code examples.
|
|
1273
|
+
|
|
1274
|
+
## Adding a New Component
|
|
1275
|
+
|
|
1276
|
+
\`\`\`tsx
|
|
1277
|
+
// components/ui/card.tsx
|
|
1278
|
+
export function Card({ children, className }: {
|
|
1279
|
+
children: React.ReactNode
|
|
1280
|
+
className?: string
|
|
1281
|
+
}) {
|
|
1282
|
+
return (
|
|
1283
|
+
<div className={cn("rounded-lg border p-6", className)}>
|
|
1284
|
+
{children}
|
|
1285
|
+
</div>
|
|
1286
|
+
)
|
|
1287
|
+
}
|
|
1288
|
+
\`\`\`
|
|
1289
|
+
|
|
1290
|
+
${config.features.contactForm ? `## Form with Validation
|
|
1291
|
+
|
|
1292
|
+
\`\`\`tsx
|
|
1293
|
+
// lib/validations.ts
|
|
1294
|
+
export const contactSchema = z.object({
|
|
1295
|
+
name: z.string().min(2, 'Nome muito curto'),
|
|
1296
|
+
email: z.string().email('Email inv\xE1lido'),
|
|
1297
|
+
message: z.string().min(10, 'Mensagem muito curta'),
|
|
1298
|
+
})
|
|
1299
|
+
|
|
1300
|
+
// components/forms/contact.tsx
|
|
1301
|
+
'use client'
|
|
1302
|
+
|
|
1303
|
+
import { useForm } from 'react-hook-form'
|
|
1304
|
+
import { zodResolver } from '@hookform/resolvers/zod'
|
|
1305
|
+
|
|
1306
|
+
export function ContactForm() {
|
|
1307
|
+
const form = useForm({
|
|
1308
|
+
resolver: zodResolver(contactSchema),
|
|
1309
|
+
})
|
|
1310
|
+
|
|
1311
|
+
async function onSubmit(data) {
|
|
1312
|
+
const res = await fetch('/api/contact', {
|
|
1313
|
+
method: 'POST',
|
|
1314
|
+
body: JSON.stringify(data),
|
|
1315
|
+
})
|
|
1316
|
+
// Handle response
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
return <form onSubmit={form.handleSubmit(onSubmit)}>...</form>
|
|
1320
|
+
}
|
|
1321
|
+
\`\`\`
|
|
1322
|
+
|
|
1323
|
+
` : ""}## Adding Animation
|
|
1324
|
+
|
|
1325
|
+
\`\`\`tsx
|
|
1326
|
+
'use client'
|
|
1327
|
+
|
|
1328
|
+
import { motion } from 'framer-motion'
|
|
1329
|
+
|
|
1330
|
+
export function FadeIn({ children }: { children: React.ReactNode }) {
|
|
1331
|
+
return (
|
|
1332
|
+
<motion.div
|
|
1333
|
+
initial={{ opacity: 0, y: 20 }}
|
|
1334
|
+
animate={{ opacity: 1, y: 0 }}
|
|
1335
|
+
transition={{ duration: 0.5 }}
|
|
1336
|
+
>
|
|
1337
|
+
{children}
|
|
1338
|
+
</motion.div>
|
|
1339
|
+
)
|
|
1340
|
+
}
|
|
1341
|
+
\`\`\`
|
|
1342
|
+
|
|
1343
|
+
## Environment Variables
|
|
1344
|
+
|
|
1345
|
+
\`\`\`typescript
|
|
1346
|
+
// lib/env.ts
|
|
1347
|
+
import { z } from 'zod'
|
|
1348
|
+
|
|
1349
|
+
const envSchema = z.object({
|
|
1350
|
+
${config.stack.email ? `RESEND_API_KEY: z.string().min(1),
|
|
1351
|
+
` : ""}NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
1352
|
+
})
|
|
1353
|
+
|
|
1354
|
+
export const env = envSchema.parse(process.env)
|
|
1355
|
+
\`\`\`
|
|
1356
|
+
|
|
1357
|
+
---
|
|
1358
|
+
|
|
1359
|
+
*For more examples, see the component files*
|
|
1360
|
+
`;
|
|
1361
|
+
await Bun.write(join(projectPath, "EXAMPLES.md"), content);
|
|
1362
|
+
}
|
|
1363
|
+
function generateProjectDecisions(config) {
|
|
1364
|
+
let decisions = "";
|
|
1365
|
+
if (config.stack.email) {
|
|
1366
|
+
decisions += `### Email Provider: ${config.stack.email}
|
|
1367
|
+
|
|
1368
|
+
**Why chosen:**
|
|
1369
|
+
- 3,000 emails/month free tier
|
|
1370
|
+
- React Email support (type-safe templates)
|
|
1371
|
+
- Simple API, great DX
|
|
1372
|
+
|
|
1373
|
+
**Alternatives considered:**
|
|
1374
|
+
- SendGrid: More complex, steeper pricing
|
|
1375
|
+
- Postmark: Great but no free tier
|
|
1376
|
+
- AWS SES: Requires more setup
|
|
1377
|
+
|
|
1378
|
+
**If you need to change:**
|
|
1379
|
+
1. Update \`lib/email.ts\` client
|
|
1380
|
+
2. Update env vars (\`.env\`)
|
|
1381
|
+
3. Update API route implementation
|
|
1382
|
+
|
|
1383
|
+
`;
|
|
1384
|
+
}
|
|
1385
|
+
if (config.stack.forms) {
|
|
1386
|
+
decisions += `### Form Library: ${config.stack.forms}
|
|
1387
|
+
|
|
1388
|
+
**Why chosen:**
|
|
1389
|
+
- Better performance than Formik
|
|
1390
|
+
- Smaller bundle size
|
|
1391
|
+
- Native TypeScript support
|
|
1392
|
+
- Works great with Zod
|
|
1393
|
+
|
|
1394
|
+
**Trade-off:**
|
|
1395
|
+
- More verbose than simple useState
|
|
1396
|
+
- Worth it for complex forms with validation
|
|
1397
|
+
|
|
1398
|
+
**If you need simpler forms:**
|
|
1399
|
+
- Use plain \`<form>\` + \`useState\`
|
|
1400
|
+
- Good for 1-2 field forms
|
|
1401
|
+
|
|
1402
|
+
`;
|
|
1403
|
+
}
|
|
1404
|
+
if (config.features.contactForm) {
|
|
1405
|
+
decisions += `### Contact Form Implementation
|
|
1406
|
+
|
|
1407
|
+
**Current setup:**
|
|
1408
|
+
- Client-side validation (instant feedback)
|
|
1409
|
+
- Server-side validation (security)
|
|
1410
|
+
- Rate limiting (spam prevention)
|
|
1411
|
+
|
|
1412
|
+
**Why both validations:**
|
|
1413
|
+
- Client: Better UX (immediate feedback)
|
|
1414
|
+
- Server: Security (never trust client)
|
|
1415
|
+
|
|
1416
|
+
`;
|
|
1417
|
+
}
|
|
1418
|
+
if (!decisions) {
|
|
1419
|
+
decisions = `No specific architectural decisions documented yet. As you make choices, document them here.
|
|
1420
|
+
`;
|
|
1421
|
+
}
|
|
1422
|
+
return decisions;
|
|
1423
|
+
}
|
|
1424
|
+
function generateProjectInventory(config) {
|
|
1425
|
+
let inventory = `**Implemented Components:**
|
|
1426
|
+
`;
|
|
1427
|
+
if (config.type === "landing") {
|
|
1428
|
+
inventory += `- Hero (\`components/sections/hero.tsx\`) - Main value proposition and CTA
|
|
1429
|
+
- Features (\`components/sections/features.tsx\`) - Product features grid
|
|
1430
|
+
- FAQ (\`components/sections/faq.tsx\`) - Frequently asked questions
|
|
1431
|
+
`;
|
|
1432
|
+
if (config.features.contactForm) {
|
|
1433
|
+
inventory += `- Contact Form (\`components/forms/contact-form.tsx\`) - Email contact with validation
|
|
1434
|
+
`;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
if (config.type === "app") {
|
|
1438
|
+
inventory += `- Dashboard Layout (\`components/dashboard/layout.tsx\`) - Main app layout
|
|
1439
|
+
- Auth Forms (\`components/auth/\`) - Login/signup components
|
|
1440
|
+
`;
|
|
1441
|
+
}
|
|
1442
|
+
inventory += `
|
|
1443
|
+
**API Routes:**
|
|
1444
|
+
`;
|
|
1445
|
+
if (config.features.contactForm) {
|
|
1446
|
+
inventory += `- \`/api/contact\` - Form submission handler (rate-limited, ${config.stack.email || "email"} integration)
|
|
1447
|
+
`;
|
|
1448
|
+
}
|
|
1449
|
+
if (config.features.auth) {
|
|
1450
|
+
inventory += `- \`/api/auth/[...nextauth]\` - Authentication endpoints
|
|
1451
|
+
`;
|
|
1452
|
+
}
|
|
1453
|
+
if (!config.features.contactForm && !config.features.auth) {
|
|
1454
|
+
inventory += `- None yet (add API routes in \`app/api/\`)
|
|
1455
|
+
`;
|
|
1456
|
+
}
|
|
1457
|
+
inventory += `
|
|
1458
|
+
**Utilities:**
|
|
1459
|
+
`;
|
|
1460
|
+
if (config.stack.email) {
|
|
1461
|
+
inventory += `- \`lib/email.ts\` - ${config.stack.email} client configuration
|
|
1462
|
+
`;
|
|
1463
|
+
}
|
|
1464
|
+
if (config.features.contactForm) {
|
|
1465
|
+
inventory += `- \`lib/validations.ts\` - Zod schemas (contactSchema: name, email, message)
|
|
1466
|
+
`;
|
|
1467
|
+
}
|
|
1468
|
+
inventory += `- \`lib/utils.ts\` - Helper functions (cn, formatters)
|
|
1469
|
+
`;
|
|
1470
|
+
return inventory;
|
|
1471
|
+
}
|
|
1472
|
+
function generateFeatureDependencies(config) {
|
|
1473
|
+
let deps = "";
|
|
1474
|
+
if (config.features.contactForm) {
|
|
1475
|
+
deps += `**Contact Form** depends on:
|
|
1476
|
+
\`\`\`
|
|
1477
|
+
\u251C\u2500 React Hook Form (form state management)
|
|
1478
|
+
\u251C\u2500 Zod (validation schemas)
|
|
1479
|
+
${config.stack.email ? `\u251C\u2500 ${config.stack.email} (email sending)
|
|
1480
|
+
` : ""}\u2514\u2500 /api/contact (server endpoint)
|
|
1481
|
+
\`\`\`
|
|
1482
|
+
|
|
1483
|
+
**To modify contact form:**
|
|
1484
|
+
1. Update validation: \`lib/validations.ts\` (contactSchema)
|
|
1485
|
+
2. Update UI: \`components/forms/contact-form.tsx\`
|
|
1486
|
+
3. Update API: \`app/api/contact/route.ts\`
|
|
1487
|
+
4. Update email template: \`emails/contact-email.tsx\` (if exists)
|
|
1488
|
+
|
|
1489
|
+
`;
|
|
1490
|
+
}
|
|
1491
|
+
if (config.features.auth) {
|
|
1492
|
+
deps += `**Authentication** depends on:
|
|
1493
|
+
\`\`\`
|
|
1494
|
+
\u251C\u2500 ${config.stack.auth} (auth provider)
|
|
1495
|
+
\u251C\u2500 Database (user storage)
|
|
1496
|
+
\u2514\u2500 /api/auth/[...nextauth] (auth endpoints)
|
|
1497
|
+
\`\`\`
|
|
1498
|
+
|
|
1499
|
+
**To modify auth:**
|
|
1500
|
+
1. Update config: \`lib/auth.ts\`
|
|
1501
|
+
2. Update providers: Add/remove in auth config
|
|
1502
|
+
3. Update callbacks: Customize JWT/session
|
|
1503
|
+
|
|
1504
|
+
`;
|
|
1505
|
+
}
|
|
1506
|
+
if (!deps) {
|
|
1507
|
+
deps = `No complex feature dependencies yet. Add features and their dependency maps will appear here.
|
|
1508
|
+
`;
|
|
1509
|
+
}
|
|
1510
|
+
return deps;
|
|
1511
|
+
}
|
|
1512
|
+
async function generateModificationsDoc(projectPath, config) {
|
|
1513
|
+
let content = `# Modification Guide
|
|
1514
|
+
|
|
1515
|
+
This file shows you exactly how to modify existing features in this project.
|
|
1516
|
+
|
|
1517
|
+
> **Context-aware:** These are the actual files in YOUR project, not generic examples.
|
|
1518
|
+
|
|
1519
|
+
`;
|
|
1520
|
+
if (config.type === "landing") {
|
|
1521
|
+
content += `## Landing Page Sections
|
|
1522
|
+
|
|
1523
|
+
### Change Hero Text
|
|
1524
|
+
|
|
1525
|
+
**File:** \`components/sections/hero.tsx\`
|
|
1526
|
+
**What to edit:** Lines with \`<h1>\` and \`<p>\` tags
|
|
1527
|
+
**Current pattern:** Value proposition + subheading + CTA
|
|
1528
|
+
**Example change:**
|
|
1529
|
+
\`\`\`tsx
|
|
1530
|
+
<h1 className="text-4xl font-bold">
|
|
1531
|
+
Your New Headline Here
|
|
1532
|
+
</h1>
|
|
1533
|
+
<p className="text-xl text-muted-foreground">
|
|
1534
|
+
Your new subheading
|
|
1535
|
+
</p>
|
|
1536
|
+
\`\`\`
|
|
1537
|
+
|
|
1538
|
+
### Add/Remove Feature Cards
|
|
1539
|
+
|
|
1540
|
+
**File:** \`components/sections/features.tsx\`
|
|
1541
|
+
**What to edit:** \`features\` array (usually lines 10-25)
|
|
1542
|
+
**Current:** 3 feature cards
|
|
1543
|
+
**To add:** Push new object to array: \`{ icon: Icon, title: "", description: "" }\`
|
|
1544
|
+
**To remove:** Delete object from array or filter it out
|
|
1545
|
+
|
|
1546
|
+
### Modify FAQ Questions
|
|
1547
|
+
|
|
1548
|
+
**File:** \`components/sections/faq.tsx\`
|
|
1549
|
+
**What to edit:** \`questions\` array
|
|
1550
|
+
**Current:** Pre-populated with common questions
|
|
1551
|
+
**Pattern:** Keep answers concise (< 100 chars) for better UX
|
|
1552
|
+
**To add:** \`{ question: "...", answer: "..." }\`
|
|
1553
|
+
|
|
1554
|
+
`;
|
|
1555
|
+
}
|
|
1556
|
+
if (config.features.contactForm) {
|
|
1557
|
+
content += `## Contact Form
|
|
1558
|
+
|
|
1559
|
+
### Change Form Fields
|
|
1560
|
+
|
|
1561
|
+
**Files to modify:**
|
|
1562
|
+
1. \`lib/validations.ts\` - Add field to schema
|
|
1563
|
+
2. \`components/forms/contact-form.tsx\` - Add UI input
|
|
1564
|
+
3. \`app/api/contact/route.ts\` - Handle new field
|
|
1565
|
+
|
|
1566
|
+
**Example: Add phone field**
|
|
1567
|
+
\`\`\`typescript
|
|
1568
|
+
// 1. lib/validations.ts
|
|
1569
|
+
export const contactSchema = z.object({
|
|
1570
|
+
name: z.string().min(2),
|
|
1571
|
+
email: z.string().email(),
|
|
1572
|
+
phone: z.string().min(10), // NEW
|
|
1573
|
+
message: z.string().min(10),
|
|
1574
|
+
})
|
|
1575
|
+
|
|
1576
|
+
// 2. components/forms/contact-form.tsx
|
|
1577
|
+
<FormField
|
|
1578
|
+
name="phone"
|
|
1579
|
+
control={form.control}
|
|
1580
|
+
render={({ field }) => (
|
|
1581
|
+
<Input placeholder="Phone" {...field} />
|
|
1582
|
+
)}
|
|
1583
|
+
/>
|
|
1584
|
+
|
|
1585
|
+
// 3. app/api/contact/route.ts
|
|
1586
|
+
// Phone is now available in validated data
|
|
1587
|
+
const { name, email, phone, message } = validated.data
|
|
1588
|
+
\`\`\`
|
|
1589
|
+
|
|
1590
|
+
### Change Email Template
|
|
1591
|
+
|
|
1592
|
+
**File:** \`emails/contact-email.tsx\` (if using React Email)
|
|
1593
|
+
**Alternative:** Inline in \`app/api/contact/route.ts\`
|
|
1594
|
+
**What to edit:** Subject, body content, styling
|
|
1595
|
+
**Test locally:** \`bun run email:dev\` (if available)
|
|
1596
|
+
|
|
1597
|
+
### Change Email Recipient
|
|
1598
|
+
|
|
1599
|
+
**File:** \`app/api/contact/route.ts\`
|
|
1600
|
+
**What to edit:** The \`to:\` field in email send
|
|
1601
|
+
\`\`\`typescript
|
|
1602
|
+
await resend.emails.send({
|
|
1603
|
+
to: 'your-new-email@example.com', // CHANGE THIS
|
|
1604
|
+
// ...
|
|
1605
|
+
})
|
|
1606
|
+
\`\`\`
|
|
1607
|
+
|
|
1608
|
+
`;
|
|
1609
|
+
}
|
|
1610
|
+
content += `## Styling Changes
|
|
1611
|
+
|
|
1612
|
+
### Update Colors
|
|
1613
|
+
|
|
1614
|
+
**File:** \`app/globals.css\`
|
|
1615
|
+
**What to edit:** CSS variables in \`:root\` and \`.dark\`
|
|
1616
|
+
\`\`\`css
|
|
1617
|
+
:root {
|
|
1618
|
+
--primary: 220 90% 56%; /* Change this */
|
|
1619
|
+
}
|
|
1620
|
+
\`\`\`
|
|
1621
|
+
**Tip:** Use [shadcn theme editor](https://ui.shadcn.com/themes) to generate new colors
|
|
1622
|
+
|
|
1623
|
+
### Change Fonts
|
|
1624
|
+
|
|
1625
|
+
**File:** \`app/layout.tsx\`
|
|
1626
|
+
**What to edit:** Font imports and \`className\` on \`<body>\`
|
|
1627
|
+
\`\`\`tsx
|
|
1628
|
+
import { Inter } from 'next/font/google'
|
|
1629
|
+
|
|
1630
|
+
const font = Inter({ subsets: ['latin'] })
|
|
1631
|
+
|
|
1632
|
+
<body className={font.className}>
|
|
1633
|
+
\`\`\`
|
|
1634
|
+
|
|
1635
|
+
## Adding New Features
|
|
1636
|
+
|
|
1637
|
+
### Add a New Page
|
|
1638
|
+
|
|
1639
|
+
\`\`\`bash
|
|
1640
|
+
# 1. Create route
|
|
1641
|
+
touch app/about/page.tsx
|
|
1642
|
+
|
|
1643
|
+
# 2. Add navigation link
|
|
1644
|
+
# Edit: components/layout/header.tsx or footer.tsx
|
|
1645
|
+
\`\`\`
|
|
1646
|
+
|
|
1647
|
+
### Add shadcn/ui Component
|
|
1648
|
+
|
|
1649
|
+
\`\`\`bash
|
|
1650
|
+
bunx --bun shadcn@latest add [component-name]
|
|
1651
|
+
# Example: bunx --bun shadcn@latest add dialog
|
|
1652
|
+
\`\`\`
|
|
1653
|
+
|
|
1654
|
+
## Environment Variables
|
|
1655
|
+
|
|
1656
|
+
**File:** \`.env\` (create from \`.env.example\`)
|
|
1657
|
+
|
|
1658
|
+
${config.stack.email ? `### ${config.stack.email} API Key
|
|
1659
|
+
\`\`\`env
|
|
1660
|
+
RESEND_API_KEY=re_xxxxxxxxxxxx
|
|
1661
|
+
\`\`\`
|
|
1662
|
+
**Get key:** [${config.stack.email} Dashboard](https://resend.com/api-keys)
|
|
1663
|
+
|
|
1664
|
+
` : ""}${config.features.analytics ? `### Google Analytics
|
|
1665
|
+
\`\`\`env
|
|
1666
|
+
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
|
|
1667
|
+
\`\`\`
|
|
1668
|
+
**Get ID:** [Google Analytics](https://analytics.google.com)
|
|
1669
|
+
|
|
1670
|
+
` : ""}## Common Modifications
|
|
1671
|
+
|
|
1672
|
+
### Change Site Metadata (SEO)
|
|
1673
|
+
|
|
1674
|
+
**File:** \`app/layout.tsx\`
|
|
1675
|
+
**What to edit:** \`metadata\` export
|
|
1676
|
+
\`\`\`tsx
|
|
1677
|
+
export const metadata = {
|
|
1678
|
+
title: 'Your New Title',
|
|
1679
|
+
description: 'Your new description',
|
|
1680
|
+
// ...
|
|
1681
|
+
}
|
|
1682
|
+
\`\`\`
|
|
1683
|
+
|
|
1684
|
+
### Add Custom Font from File
|
|
1685
|
+
|
|
1686
|
+
\`\`\`tsx
|
|
1687
|
+
// app/layout.tsx
|
|
1688
|
+
import localFont from 'next/font/local'
|
|
1689
|
+
|
|
1690
|
+
const customFont = localFont({
|
|
1691
|
+
src: './fonts/CustomFont.woff2',
|
|
1692
|
+
variable: '--font-custom',
|
|
1693
|
+
})
|
|
1694
|
+
\`\`\`
|
|
1695
|
+
|
|
1696
|
+
---
|
|
1697
|
+
|
|
1698
|
+
**Pro tip:** Before modifying, search the codebase for the text/component you want to change:
|
|
1699
|
+
\`\`\`bash
|
|
1700
|
+
grep -r "text to find" .
|
|
1701
|
+
\`\`\`
|
|
1702
|
+
`;
|
|
1703
|
+
await Bun.write(join(projectPath, "MODIFICATIONS.md"), content);
|
|
1704
|
+
}
|
|
1705
|
+
async function createCompatibilitySymlinks(projectPath) {
|
|
1706
|
+
const agentsContent = await Bun.file(join(projectPath, "AGENTS.md")).text();
|
|
1707
|
+
await Bun.write(join(projectPath, ".cursorrules"), agentsContent);
|
|
1708
|
+
const githubDir = join(projectPath, ".github");
|
|
1709
|
+
await Bun.$`mkdir -p ${githubDir}`.quiet();
|
|
1710
|
+
await Bun.write(join(githubDir, "copilot-instructions.md"), agentsContent);
|
|
1711
|
+
}
|
|
1712
|
+
// src/lib/generators/interactive-setup.ts
|
|
1713
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
1714
|
+
var SERVICE_INFO = {
|
|
1715
|
+
resend: {
|
|
1716
|
+
name: "Resend",
|
|
1717
|
+
description: "Servi\xE7o de email transacional",
|
|
1718
|
+
pricing: "Gr\xE1tis: 3,000 emails/m\xEAs",
|
|
1719
|
+
signupUrl: "https://resend.com/signup",
|
|
1720
|
+
apiKeyUrl: "https://resend.com/api-keys",
|
|
1721
|
+
keyPrefix: "re_"
|
|
1722
|
+
},
|
|
1723
|
+
googleAnalytics: {
|
|
1724
|
+
name: "Google Analytics",
|
|
1725
|
+
description: "Analytics e m\xE9tricas do site",
|
|
1726
|
+
pricing: "Gr\xE1tis",
|
|
1727
|
+
setupUrl: "https://analytics.google.com",
|
|
1728
|
+
keyFormat: "G-XXXXXXXXXX"
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
async function interactiveSetup(templateType) {
|
|
1732
|
+
console.log();
|
|
1733
|
+
console.log(import_picocolors3.default.cyan(" Configura\xE7\xE3o Interativa"));
|
|
1734
|
+
console.log(import_picocolors3.default.dim(" ======================="));
|
|
1735
|
+
console.log();
|
|
1736
|
+
const skipSetup = await ye({
|
|
1737
|
+
message: "Deseja configurar integra\xE7\xF5es agora?",
|
|
1738
|
+
initialValue: true
|
|
1739
|
+
});
|
|
1740
|
+
if (pD(skipSetup) || !skipSetup) {
|
|
1741
|
+
return {
|
|
1742
|
+
features: {
|
|
1743
|
+
contactForm: false,
|
|
1744
|
+
newsletter: false,
|
|
1745
|
+
analytics: false
|
|
1746
|
+
},
|
|
1747
|
+
apiKeys: {},
|
|
1748
|
+
skipSetup: true
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
const result = {
|
|
1752
|
+
features: {
|
|
1753
|
+
contactForm: false,
|
|
1754
|
+
newsletter: false,
|
|
1755
|
+
analytics: false
|
|
1756
|
+
},
|
|
1757
|
+
apiKeys: {},
|
|
1758
|
+
skipSetup: false
|
|
1759
|
+
};
|
|
1760
|
+
if (templateType === "landing" || templateType === "app") {
|
|
1761
|
+
const contactFormSetup = await setupContactForm();
|
|
1762
|
+
if (!pD(contactFormSetup)) {
|
|
1763
|
+
result.features.contactForm = contactFormSetup.enabled;
|
|
1764
|
+
if (contactFormSetup.apiKey) {
|
|
1765
|
+
result.apiKeys.resend = contactFormSetup.apiKey;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
const analyticsSetup = await setupAnalytics();
|
|
1770
|
+
if (!pD(analyticsSetup)) {
|
|
1771
|
+
result.features.analytics = analyticsSetup.enabled;
|
|
1772
|
+
if (analyticsSetup.trackingId) {
|
|
1773
|
+
result.apiKeys.ga = analyticsSetup.trackingId;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
return result;
|
|
1777
|
+
}
|
|
1778
|
+
async function setupContactForm() {
|
|
1779
|
+
console.log();
|
|
1780
|
+
console.log(import_picocolors3.default.cyan(" \uD83D\uDCE7 Formul\xE1rio de Contato"));
|
|
1781
|
+
console.log();
|
|
1782
|
+
const needsForm = await ve({
|
|
1783
|
+
message: "Incluir formul\xE1rio de contato?",
|
|
1784
|
+
options: [
|
|
1785
|
+
{ value: "now", label: "Sim, configurar agora" },
|
|
1786
|
+
{ value: "later", label: "Sim, mas configurar depois" },
|
|
1787
|
+
{ value: "no", label: "N\xE3o incluir" }
|
|
1788
|
+
]
|
|
1789
|
+
});
|
|
1790
|
+
if (pD(needsForm) || needsForm === "no") {
|
|
1791
|
+
return { enabled: false };
|
|
1792
|
+
}
|
|
1793
|
+
if (needsForm === "later") {
|
|
1794
|
+
return { enabled: true };
|
|
1795
|
+
}
|
|
1796
|
+
showServiceInfo("resend");
|
|
1797
|
+
const apiKey = await he({
|
|
1798
|
+
message: "Resend API Key (deixe vazio para configurar depois):",
|
|
1799
|
+
placeholder: "re_...",
|
|
1800
|
+
validate: (v2) => {
|
|
1801
|
+
if (!v2)
|
|
1802
|
+
return;
|
|
1803
|
+
if (!v2.startsWith(SERVICE_INFO.resend.keyPrefix)) {
|
|
1804
|
+
return `Key inv\xE1lida (deve come\xE7ar com ${SERVICE_INFO.resend.keyPrefix})`;
|
|
1805
|
+
}
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
});
|
|
1809
|
+
if (pD(apiKey)) {
|
|
1810
|
+
return { enabled: true };
|
|
1811
|
+
}
|
|
1812
|
+
return {
|
|
1813
|
+
enabled: true,
|
|
1814
|
+
apiKey: apiKey || undefined
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
async function setupAnalytics() {
|
|
1818
|
+
console.log();
|
|
1819
|
+
console.log(import_picocolors3.default.cyan(" \uD83D\uDCCA Analytics"));
|
|
1820
|
+
console.log();
|
|
1821
|
+
const needsAnalytics = await ye({
|
|
1822
|
+
message: "Incluir Google Analytics?",
|
|
1823
|
+
initialValue: false
|
|
1824
|
+
});
|
|
1825
|
+
if (pD(needsAnalytics) || !needsAnalytics) {
|
|
1826
|
+
return { enabled: false };
|
|
1827
|
+
}
|
|
1828
|
+
showServiceInfo("googleAnalytics");
|
|
1829
|
+
const trackingId = await he({
|
|
1830
|
+
message: "Google Analytics Tracking ID (deixe vazio para configurar depois):",
|
|
1831
|
+
placeholder: "G-XXXXXXXXXX",
|
|
1832
|
+
validate: (v2) => {
|
|
1833
|
+
if (!v2)
|
|
1834
|
+
return;
|
|
1835
|
+
if (!v2.startsWith("G-")) {
|
|
1836
|
+
return "ID inv\xE1lido (deve come\xE7ar com G-)";
|
|
1837
|
+
}
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
});
|
|
1841
|
+
if (pD(trackingId)) {
|
|
1842
|
+
return { enabled: false };
|
|
1843
|
+
}
|
|
1844
|
+
return {
|
|
1845
|
+
enabled: true,
|
|
1846
|
+
trackingId: trackingId || undefined
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
function showServiceInfo(service) {
|
|
1850
|
+
const info = SERVICE_INFO[service];
|
|
1851
|
+
console.log();
|
|
1852
|
+
console.log(import_picocolors3.default.bold(` ${info.name}`));
|
|
1853
|
+
console.log(import_picocolors3.default.dim(` ${info.description}`));
|
|
1854
|
+
console.log(import_picocolors3.default.dim(` ${info.pricing}`));
|
|
1855
|
+
if ("apiKeyUrl" in info) {
|
|
1856
|
+
console.log(import_picocolors3.default.cyan(` ${info.apiKeyUrl}`));
|
|
1857
|
+
} else if ("setupUrl" in info) {
|
|
1858
|
+
console.log(import_picocolors3.default.cyan(` ${info.setupUrl}`));
|
|
1859
|
+
}
|
|
1860
|
+
console.log();
|
|
1861
|
+
}
|
|
1862
|
+
async function generateEnvFile(projectPath, apiKeys, features) {
|
|
1863
|
+
const lines = [
|
|
1864
|
+
"# ====================================",
|
|
1865
|
+
"# Environment Variables",
|
|
1866
|
+
"# ====================================",
|
|
1867
|
+
"",
|
|
1868
|
+
"# IMPORTANT: Add this file to .gitignore",
|
|
1869
|
+
"# Never commit API keys to version control!",
|
|
1870
|
+
""
|
|
1871
|
+
];
|
|
1872
|
+
if (features.contactForm) {
|
|
1873
|
+
lines.push("# Email (Resend)");
|
|
1874
|
+
lines.push("# Get your key: https://resend.com/api-keys");
|
|
1875
|
+
lines.push(`RESEND_API_KEY=${apiKeys.resend || "your_api_key_here"}`);
|
|
1876
|
+
lines.push("");
|
|
1877
|
+
}
|
|
1878
|
+
if (features.analytics) {
|
|
1879
|
+
lines.push("# Analytics (Google Analytics)");
|
|
1880
|
+
lines.push("# Get your ID: https://analytics.google.com");
|
|
1881
|
+
lines.push(`NEXT_PUBLIC_GA_ID=${apiKeys.ga || "G-XXXXXXXXXX"}`);
|
|
1882
|
+
lines.push("");
|
|
1883
|
+
}
|
|
1884
|
+
lines.push("# ====================================");
|
|
1885
|
+
lines.push("# Docs completa em README.md");
|
|
1886
|
+
lines.push("# ====================================");
|
|
1887
|
+
const content = lines.join(`
|
|
1888
|
+
`);
|
|
1889
|
+
await Bun.write(`${projectPath}/.env`, content);
|
|
1890
|
+
const exampleLines = lines.map((line) => {
|
|
1891
|
+
if (line.includes("RESEND_API_KEY=") && !line.startsWith("#")) {
|
|
1892
|
+
return "RESEND_API_KEY=re_your_key_here";
|
|
1893
|
+
}
|
|
1894
|
+
if (line.includes("NEXT_PUBLIC_GA_ID=") && !line.startsWith("#")) {
|
|
1895
|
+
return "NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX";
|
|
1896
|
+
}
|
|
1897
|
+
return line;
|
|
1898
|
+
});
|
|
1899
|
+
await Bun.write(`${projectPath}/.env.example`, exampleLines.join(`
|
|
1900
|
+
`));
|
|
1901
|
+
}
|
|
1902
|
+
// src/commands/create.ts
|
|
872
1903
|
var AI_CONFIGS = {
|
|
873
1904
|
claude: {
|
|
874
1905
|
filename: "CLAUDE.md",
|
|
@@ -1068,7 +2099,7 @@ async function ensureRailwayCli() {
|
|
|
1068
2099
|
const hasRailway = await $2`${checkCmd} railway`.quiet().then(() => true).catch(() => false);
|
|
1069
2100
|
if (hasRailway)
|
|
1070
2101
|
return true;
|
|
1071
|
-
console.log(
|
|
2102
|
+
console.log(import_picocolors4.default.yellow("Railway CLI not found. Installing..."));
|
|
1072
2103
|
console.log();
|
|
1073
2104
|
try {
|
|
1074
2105
|
if (process.platform === "win32") {
|
|
@@ -1076,11 +2107,11 @@ async function ensureRailwayCli() {
|
|
|
1076
2107
|
} else {
|
|
1077
2108
|
await $2`curl -fsSL https://railway.app/install.sh | sh`.quiet();
|
|
1078
2109
|
}
|
|
1079
|
-
console.log(
|
|
2110
|
+
console.log(import_picocolors4.default.green("Railway CLI installed successfully!"));
|
|
1080
2111
|
return true;
|
|
1081
2112
|
} catch (error) {
|
|
1082
|
-
console.log(
|
|
1083
|
-
console.log(
|
|
2113
|
+
console.log(import_picocolors4.default.red("Error installing Railway CLI."));
|
|
2114
|
+
console.log(import_picocolors4.default.dim("Install manually: https://docs.railway.app/guides/cli"));
|
|
1084
2115
|
return false;
|
|
1085
2116
|
}
|
|
1086
2117
|
}
|
|
@@ -1108,38 +2139,38 @@ async function create(args) {
|
|
|
1108
2139
|
const hasGit = await $2`${checkCmd} git`.quiet().then(() => true).catch(() => false);
|
|
1109
2140
|
const hasGh = await $2`${checkCmd} gh`.quiet().then(() => true).catch(() => false);
|
|
1110
2141
|
if (!hasBun) {
|
|
1111
|
-
console.log(
|
|
1112
|
-
console.log(
|
|
2142
|
+
console.log(import_picocolors4.default.red("Error: Bun not found."));
|
|
2143
|
+
console.log(import_picocolors4.default.dim("Install from: https://bun.sh"));
|
|
1113
2144
|
console.log();
|
|
1114
2145
|
if (process.platform === "win32") {
|
|
1115
|
-
console.log(
|
|
2146
|
+
console.log(import_picocolors4.default.cyan('powershell -c "irm bun.sh/install.ps1 | iex"'));
|
|
1116
2147
|
} else {
|
|
1117
|
-
console.log(
|
|
2148
|
+
console.log(import_picocolors4.default.cyan("curl -fsSL https://bun.sh/install | bash"));
|
|
1118
2149
|
}
|
|
1119
2150
|
console.log();
|
|
1120
2151
|
process.exit(1);
|
|
1121
2152
|
}
|
|
1122
2153
|
if (!hasGit) {
|
|
1123
|
-
console.log(
|
|
1124
|
-
console.log(
|
|
2154
|
+
console.log(import_picocolors4.default.red("Error: Git not found."));
|
|
2155
|
+
console.log(import_picocolors4.default.dim("Install git to continue."));
|
|
1125
2156
|
process.exit(1);
|
|
1126
2157
|
}
|
|
1127
2158
|
if (!hasGh) {
|
|
1128
|
-
console.log(
|
|
1129
|
-
console.log(
|
|
2159
|
+
console.log(import_picocolors4.default.dim(" GitHub CLI not found (repo creation will be skipped)"));
|
|
2160
|
+
console.log(import_picocolors4.default.dim(" Install from: https://cli.github.com"));
|
|
1130
2161
|
console.log();
|
|
1131
2162
|
}
|
|
1132
2163
|
const hasRailway = await ensureRailwayCli();
|
|
1133
2164
|
if (hasRailway) {
|
|
1134
2165
|
const railwayAuth = await isRailwayAuthenticated();
|
|
1135
2166
|
if (!railwayAuth) {
|
|
1136
|
-
console.log(
|
|
1137
|
-
console.log(
|
|
2167
|
+
console.log(import_picocolors4.default.yellow("Railway CLI not authenticated."));
|
|
2168
|
+
console.log(import_picocolors4.default.dim("Run: railway login"));
|
|
1138
2169
|
console.log();
|
|
1139
2170
|
}
|
|
1140
2171
|
}
|
|
1141
2172
|
const { flags, projectName } = parseFlags(args);
|
|
1142
|
-
Ie(
|
|
2173
|
+
Ie(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" New nimbuslab Project ")));
|
|
1143
2174
|
let config;
|
|
1144
2175
|
const hasTypeFlag = flags.landing || flags.app || flags.turborepo || flags.fast || flags.fastPlus || flags.fastTurborepo || flags.core;
|
|
1145
2176
|
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;
|
|
@@ -1168,14 +2199,14 @@ async function create(args) {
|
|
|
1168
2199
|
customTemplate: flags.template
|
|
1169
2200
|
};
|
|
1170
2201
|
const typeLabel = flags.turborepo ? "fast+ (monorepo)" : config.type;
|
|
1171
|
-
console.log(
|
|
1172
|
-
console.log(
|
|
1173
|
-
console.log(
|
|
1174
|
-
console.log(
|
|
2202
|
+
console.log(import_picocolors4.default.dim(` Project: ${projectName}`));
|
|
2203
|
+
console.log(import_picocolors4.default.dim(` Type: ${typeLabel}`));
|
|
2204
|
+
console.log(import_picocolors4.default.dim(` Git: ${config.git ? "yes" : "no"}`));
|
|
2205
|
+
console.log(import_picocolors4.default.dim(` Install: ${config.install ? "yes" : "no"}`));
|
|
1175
2206
|
if (flags.railway)
|
|
1176
|
-
console.log(
|
|
2207
|
+
console.log(import_picocolors4.default.dim(` Railway: configurar`));
|
|
1177
2208
|
if (flags.template)
|
|
1178
|
-
console.log(
|
|
2209
|
+
console.log(import_picocolors4.default.dim(` Template: ${flags.template}`));
|
|
1179
2210
|
console.log();
|
|
1180
2211
|
if (flags.railway) {
|
|
1181
2212
|
const railwayAuthenticated = await isRailwayAuthenticated();
|
|
@@ -1185,21 +2216,21 @@ async function create(args) {
|
|
|
1185
2216
|
const fastProject = projects.find((p2) => p2.toLowerCase().includes("fast by nimbuslab"));
|
|
1186
2217
|
if (fastProject) {
|
|
1187
2218
|
config.railwayProject = fastProject;
|
|
1188
|
-
console.log(
|
|
2219
|
+
console.log(import_picocolors4.default.green(` Railway: ${fastProject}`));
|
|
1189
2220
|
}
|
|
1190
2221
|
} else {
|
|
1191
|
-
console.log(
|
|
2222
|
+
console.log(import_picocolors4.default.dim(` Creating project Railway: ${projectName}...`));
|
|
1192
2223
|
try {
|
|
1193
2224
|
const result = await $2`echo "" | railway init -n ${projectName} -w nimbuslab --json`.text();
|
|
1194
2225
|
const newProject = JSON.parse(result);
|
|
1195
2226
|
config.railwayProject = newProject.name || projectName;
|
|
1196
|
-
console.log(
|
|
2227
|
+
console.log(import_picocolors4.default.green(` Railway: ${config.railwayProject} criado`));
|
|
1197
2228
|
} catch {
|
|
1198
|
-
console.log(
|
|
2229
|
+
console.log(import_picocolors4.default.yellow(` Railway: erro ao criar projeto`));
|
|
1199
2230
|
}
|
|
1200
2231
|
}
|
|
1201
2232
|
} else {
|
|
1202
|
-
console.log(
|
|
2233
|
+
console.log(import_picocolors4.default.yellow(` Railway: not authenticated (railway login)`));
|
|
1203
2234
|
}
|
|
1204
2235
|
console.log();
|
|
1205
2236
|
}
|
|
@@ -1211,13 +2242,58 @@ async function create(args) {
|
|
|
1211
2242
|
process.exit(0);
|
|
1212
2243
|
}
|
|
1213
2244
|
await createProject(config);
|
|
1214
|
-
|
|
2245
|
+
const finalConfig = config;
|
|
2246
|
+
const isPublicTemplate = ["landing", "app", "turborepo"].includes(finalConfig.type);
|
|
2247
|
+
if (isPublicTemplate) {
|
|
2248
|
+
const s = Y2();
|
|
2249
|
+
s.start("Configura\xE7\xE3o de servi\xE7os...");
|
|
2250
|
+
const setupResult = await interactiveSetup(finalConfig.type);
|
|
2251
|
+
s.stop("Configura\xE7\xE3o conclu\xEDda");
|
|
2252
|
+
s.start("Gerando documenta\xE7\xE3o AI-friendly...");
|
|
2253
|
+
try {
|
|
2254
|
+
const generatorConfig = {
|
|
2255
|
+
name: finalConfig.name,
|
|
2256
|
+
type: finalConfig.type,
|
|
2257
|
+
description: finalConfig.githubDescription || `${finalConfig.type} criado com nimbus-cli`,
|
|
2258
|
+
stack: {
|
|
2259
|
+
framework: "Next.js 16 (App Router)",
|
|
2260
|
+
styling: "Tailwind CSS 4",
|
|
2261
|
+
components: "shadcn/ui (default)",
|
|
2262
|
+
forms: setupResult.features.contactForm ? "React Hook Form + Zod" : undefined,
|
|
2263
|
+
email: setupResult.features.contactForm ? "Resend" : undefined,
|
|
2264
|
+
auth: finalConfig.type === "app" ? "Better Auth" : undefined
|
|
2265
|
+
},
|
|
2266
|
+
features: {
|
|
2267
|
+
contactForm: setupResult.features.contactForm,
|
|
2268
|
+
newsletter: setupResult.features.newsletter,
|
|
2269
|
+
analytics: setupResult.features.analytics,
|
|
2270
|
+
auth: finalConfig.type === "app"
|
|
2271
|
+
}
|
|
2272
|
+
};
|
|
2273
|
+
await generateAIFriendlyDocs(finalConfig.name, generatorConfig);
|
|
2274
|
+
s.stop("Documenta\xE7\xE3o AI-friendly gerada");
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
s.stop("Erro ao gerar documenta\xE7\xE3o AI-friendly");
|
|
2277
|
+
console.log(import_picocolors4.default.dim(" Voc\xEA pode gerar manualmente depois"));
|
|
2278
|
+
}
|
|
2279
|
+
if (!setupResult.skipSetup && (setupResult.apiKeys.resend || setupResult.apiKeys.ga)) {
|
|
2280
|
+
s.start("Gerando arquivos .env...");
|
|
2281
|
+
try {
|
|
2282
|
+
await generateEnvFile(finalConfig.name, setupResult.apiKeys, setupResult.features);
|
|
2283
|
+
s.stop("Arquivos .env gerados (.env e .env.example)");
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
s.stop("Erro ao gerar .env");
|
|
2286
|
+
console.log(import_picocolors4.default.dim(" Voc\xEA pode criar manualmente depois"));
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
Se(import_picocolors4.default.green("Project created successfully!"));
|
|
1215
2291
|
showNextSteps(config);
|
|
1216
2292
|
}
|
|
1217
2293
|
async function promptConfig(initialName, flags) {
|
|
1218
2294
|
const { isMember, user } = await isNimbuslabMember();
|
|
1219
2295
|
const greeting = user ? `Hello, ${user}!` : "Hello!";
|
|
1220
|
-
console.log(
|
|
2296
|
+
console.log(import_picocolors4.default.dim(` ${greeting}`));
|
|
1221
2297
|
console.log();
|
|
1222
2298
|
const name = await he({
|
|
1223
2299
|
message: "Project name:",
|
|
@@ -1276,12 +2352,12 @@ async function promptConfig(initialName, flags) {
|
|
|
1276
2352
|
return type;
|
|
1277
2353
|
const isPublicTemplate = ["landing", "app", "turborepo"].includes(type);
|
|
1278
2354
|
if (!isMember && !isPublicTemplate) {
|
|
1279
|
-
console.log(
|
|
2355
|
+
console.log(import_picocolors4.default.red("Error: Template available only for nimbuslab members"));
|
|
1280
2356
|
process.exit(1);
|
|
1281
2357
|
}
|
|
1282
2358
|
if (type === "nimbus-core") {
|
|
1283
2359
|
console.log();
|
|
1284
|
-
console.log(
|
|
2360
|
+
console.log(import_picocolors4.default.dim(" nimbus-core: Motor para projetos externos (stealth mode)"));
|
|
1285
2361
|
console.log();
|
|
1286
2362
|
const repoOption = await ve({
|
|
1287
2363
|
message: "Create repository for this project?",
|
|
@@ -1496,7 +2572,7 @@ async function promptConfig(initialName, flags) {
|
|
|
1496
2572
|
const configItems = infraOptions;
|
|
1497
2573
|
if (configItems.includes("urls")) {
|
|
1498
2574
|
console.log();
|
|
1499
|
-
console.log(
|
|
2575
|
+
console.log(import_picocolors4.default.dim(" Project URLs"));
|
|
1500
2576
|
const staging = await he({
|
|
1501
2577
|
message: "Staging URL:",
|
|
1502
2578
|
placeholder: defaultStagingUrl,
|
|
@@ -1516,7 +2592,7 @@ async function promptConfig(initialName, flags) {
|
|
|
1516
2592
|
}
|
|
1517
2593
|
if (configItems.includes("resend")) {
|
|
1518
2594
|
console.log();
|
|
1519
|
-
console.log(
|
|
2595
|
+
console.log(import_picocolors4.default.dim(" Resend (Email)"));
|
|
1520
2596
|
const resendKey = await he({
|
|
1521
2597
|
message: "RESEND_API_KEY:",
|
|
1522
2598
|
placeholder: "re_xxxxxxxxxxxx"
|
|
@@ -1545,16 +2621,16 @@ async function promptConfig(initialName, flags) {
|
|
|
1545
2621
|
const railwayAuthenticated = await isRailwayAuthenticated();
|
|
1546
2622
|
if (railwayAuthenticated) {
|
|
1547
2623
|
console.log();
|
|
1548
|
-
console.log(
|
|
2624
|
+
console.log(import_picocolors4.default.dim(" Railway"));
|
|
1549
2625
|
const projects = await listRailwayProjects();
|
|
1550
2626
|
if (type === "fast") {
|
|
1551
2627
|
const fastProject = projects.find((p2) => p2.toLowerCase().includes("fast by nimbuslab"));
|
|
1552
2628
|
if (fastProject) {
|
|
1553
2629
|
railwayProject = fastProject;
|
|
1554
|
-
console.log(
|
|
2630
|
+
console.log(import_picocolors4.default.green(` Project: ${fastProject} (automatico)`));
|
|
1555
2631
|
} else {
|
|
1556
|
-
console.log(
|
|
1557
|
-
console.log(
|
|
2632
|
+
console.log(import_picocolors4.default.yellow(" Project 'Fast by nimbuslab' not found."));
|
|
2633
|
+
console.log(import_picocolors4.default.dim(" Configure manually in .env"));
|
|
1558
2634
|
}
|
|
1559
2635
|
} else {
|
|
1560
2636
|
const projectOptions = [
|
|
@@ -1570,26 +2646,26 @@ async function promptConfig(initialName, flags) {
|
|
|
1570
2646
|
return selectedProject;
|
|
1571
2647
|
if (selectedProject === "__new__") {
|
|
1572
2648
|
const projectNameForRailway = name;
|
|
1573
|
-
console.log(
|
|
2649
|
+
console.log(import_picocolors4.default.dim(` Creating project "${projectNameForRailway}" on Railway...`));
|
|
1574
2650
|
try {
|
|
1575
2651
|
const result = await $2`echo "" | railway init -n ${projectNameForRailway} -w nimbuslab --json`.text();
|
|
1576
2652
|
const newProject = JSON.parse(result);
|
|
1577
2653
|
railwayProject = newProject.name || projectNameForRailway;
|
|
1578
|
-
console.log(
|
|
1579
|
-
console.log(
|
|
2654
|
+
console.log(import_picocolors4.default.green(` Projeto "${railwayProject}" created successfully!`));
|
|
2655
|
+
console.log(import_picocolors4.default.dim(` ID: ${newProject.id || "N/A"}`));
|
|
1580
2656
|
} catch (error) {
|
|
1581
|
-
console.log(
|
|
1582
|
-
console.log(
|
|
2657
|
+
console.log(import_picocolors4.default.yellow(" Error creating project via CLI."));
|
|
2658
|
+
console.log(import_picocolors4.default.dim(" Create manually at: https://railway.app/new"));
|
|
1583
2659
|
}
|
|
1584
2660
|
} else if (selectedProject !== "__skip__") {
|
|
1585
2661
|
railwayProject = selectedProject;
|
|
1586
|
-
console.log(
|
|
2662
|
+
console.log(import_picocolors4.default.green(` Project selected: ${railwayProject}`));
|
|
1587
2663
|
}
|
|
1588
2664
|
}
|
|
1589
2665
|
} else {
|
|
1590
2666
|
console.log();
|
|
1591
|
-
console.log(
|
|
1592
|
-
console.log(
|
|
2667
|
+
console.log(import_picocolors4.default.yellow(" Railway: not authenticated (railway login)"));
|
|
2668
|
+
console.log(import_picocolors4.default.dim(" Configure manually in .env"));
|
|
1593
2669
|
}
|
|
1594
2670
|
}
|
|
1595
2671
|
const install = await ye({
|
|
@@ -1641,7 +2717,7 @@ async function createProject(config) {
|
|
|
1641
2717
|
} else {
|
|
1642
2718
|
await $2`gh repo clone ${templateRepo} ${config.name} -- --depth 1`.quiet();
|
|
1643
2719
|
}
|
|
1644
|
-
await rm(
|
|
2720
|
+
await rm(join2(config.name, ".git"), { recursive: true, force: true });
|
|
1645
2721
|
s.stop(`Template cloned`);
|
|
1646
2722
|
} catch (error) {
|
|
1647
2723
|
s.stop("Error cloning template");
|
|
@@ -1662,7 +2738,7 @@ async function createProject(config) {
|
|
|
1662
2738
|
s.stop(`Client repo cloned: workspace/${projectName}`);
|
|
1663
2739
|
} catch (error) {
|
|
1664
2740
|
s.stop("Error cloning client repo");
|
|
1665
|
-
console.log(
|
|
2741
|
+
console.log(import_picocolors4.default.dim(" You can clone manually: cd workspace && git clone <url>"));
|
|
1666
2742
|
}
|
|
1667
2743
|
}
|
|
1668
2744
|
if (config.type !== "nimbus-core") {
|
|
@@ -1751,7 +2827,7 @@ async function createProject(config) {
|
|
|
1751
2827
|
s.stop(`GitHub: ${repoName}`);
|
|
1752
2828
|
} catch (error) {
|
|
1753
2829
|
s.stop("Error creating GitHub repository");
|
|
1754
|
-
console.log(
|
|
2830
|
+
console.log(import_picocolors4.default.dim(" You can create manually with: gh repo create"));
|
|
1755
2831
|
}
|
|
1756
2832
|
}
|
|
1757
2833
|
}
|
|
@@ -1762,13 +2838,13 @@ async function createProject(config) {
|
|
|
1762
2838
|
s.stop(`Railway linkado: ${config.railwayProject}`);
|
|
1763
2839
|
} catch (error) {
|
|
1764
2840
|
s.stop("Error linking Railway");
|
|
1765
|
-
console.log(
|
|
2841
|
+
console.log(import_picocolors4.default.dim(" Run manually: railway link"));
|
|
1766
2842
|
}
|
|
1767
2843
|
}
|
|
1768
2844
|
if (config.resendApiKey || config.stagingUrl) {
|
|
1769
2845
|
s.start("Gerando arquivo .env...");
|
|
1770
2846
|
try {
|
|
1771
|
-
const envContent =
|
|
2847
|
+
const envContent = generateEnvFile2(config);
|
|
1772
2848
|
await Bun.write(`${config.name}/.env`, envContent);
|
|
1773
2849
|
s.stop("Arquivo .env criado");
|
|
1774
2850
|
} catch (error) {
|
|
@@ -1785,7 +2861,7 @@ async function createProject(config) {
|
|
|
1785
2861
|
}
|
|
1786
2862
|
}
|
|
1787
2863
|
}
|
|
1788
|
-
function
|
|
2864
|
+
function generateEnvFile2(config) {
|
|
1789
2865
|
const lines = [
|
|
1790
2866
|
"# Gerado automaticamente pelo nimbus-cli",
|
|
1791
2867
|
"# Nao commitar este arquivo!",
|
|
@@ -1828,58 +2904,58 @@ function showNextSteps(config) {
|
|
|
1828
2904
|
const isPublicTemplate = ["landing", "app", "turborepo"].includes(config.type);
|
|
1829
2905
|
const needsSetup = config.type === "app";
|
|
1830
2906
|
console.log();
|
|
1831
|
-
console.log(
|
|
2907
|
+
console.log(import_picocolors4.default.bold("Next steps:"));
|
|
1832
2908
|
console.log();
|
|
1833
|
-
console.log(` ${
|
|
2909
|
+
console.log(` ${import_picocolors4.default.cyan("cd")} ${config.name}`);
|
|
1834
2910
|
if (config.type === "nimbus-core") {
|
|
1835
2911
|
console.log();
|
|
1836
|
-
console.log(
|
|
2912
|
+
console.log(import_picocolors4.default.dim(" nimbus-core: Motor para projetos externos"));
|
|
1837
2913
|
console.log();
|
|
1838
|
-
console.log(
|
|
1839
|
-
console.log(` ${
|
|
2914
|
+
console.log(import_picocolors4.default.dim(" Para usar a Lola:"));
|
|
2915
|
+
console.log(` ${import_picocolors4.default.cyan("lola")}`);
|
|
1840
2916
|
console.log();
|
|
1841
|
-
console.log(
|
|
2917
|
+
console.log(import_picocolors4.default.yellow(" STEALTH MODE: Commits sem mencao a nimbuslab/Lola/IA"));
|
|
1842
2918
|
console.log();
|
|
1843
2919
|
if (config.github) {
|
|
1844
2920
|
const repoUrl = `https://github.com/nimbuslab/${config.name}`;
|
|
1845
|
-
console.log(
|
|
2921
|
+
console.log(import_picocolors4.default.green(` GitHub (private): ${repoUrl}`));
|
|
1846
2922
|
console.log();
|
|
1847
2923
|
}
|
|
1848
|
-
console.log(
|
|
2924
|
+
console.log(import_picocolors4.default.dim(" Docs: See README.md for full instructions"));
|
|
1849
2925
|
console.log();
|
|
1850
2926
|
return;
|
|
1851
2927
|
}
|
|
1852
2928
|
if (!config.install) {
|
|
1853
|
-
console.log(` ${
|
|
2929
|
+
console.log(` ${import_picocolors4.default.cyan("bun")} install`);
|
|
1854
2930
|
}
|
|
1855
2931
|
if (!isPublicTemplate || needsSetup) {
|
|
1856
|
-
console.log(` ${
|
|
2932
|
+
console.log(` ${import_picocolors4.default.cyan("bun")} setup`);
|
|
1857
2933
|
}
|
|
1858
|
-
console.log(` ${
|
|
2934
|
+
console.log(` ${import_picocolors4.default.cyan("bun")} dev`);
|
|
1859
2935
|
console.log();
|
|
1860
2936
|
if (needsSetup && isPublicTemplate) {
|
|
1861
|
-
console.log(
|
|
1862
|
-
console.log(
|
|
1863
|
-
console.log(
|
|
1864
|
-
console.log(
|
|
2937
|
+
console.log(import_picocolors4.default.dim(" bun setup will:"));
|
|
2938
|
+
console.log(import_picocolors4.default.dim(" - Start PostgreSQL with Docker"));
|
|
2939
|
+
console.log(import_picocolors4.default.dim(" - Run database migrations"));
|
|
2940
|
+
console.log(import_picocolors4.default.dim(" - Create demo user (demo@example.com / demo1234)"));
|
|
1865
2941
|
console.log();
|
|
1866
2942
|
}
|
|
1867
2943
|
if (config.git) {
|
|
1868
|
-
console.log(
|
|
2944
|
+
console.log(import_picocolors4.default.dim(" Git: main -> staging -> develop (current branch)"));
|
|
1869
2945
|
if (config.github) {
|
|
1870
2946
|
const repoUrl = config.githubOrg ? `https://github.com/${config.githubOrg}/${config.name}` : `https://github.com/${config.name}`;
|
|
1871
|
-
console.log(
|
|
2947
|
+
console.log(import_picocolors4.default.green(` GitHub: ${repoUrl}`));
|
|
1872
2948
|
}
|
|
1873
2949
|
console.log();
|
|
1874
2950
|
}
|
|
1875
2951
|
if (isPublicTemplate) {
|
|
1876
2952
|
if (config.theme !== "dark") {
|
|
1877
|
-
console.log(
|
|
2953
|
+
console.log(import_picocolors4.default.dim(` Theme: ${config.theme}`));
|
|
1878
2954
|
}
|
|
1879
2955
|
if (config.aiAssistant) {
|
|
1880
2956
|
const aiConfig = AI_CONFIGS[config.aiAssistant];
|
|
1881
2957
|
if (aiConfig) {
|
|
1882
|
-
console.log(
|
|
2958
|
+
console.log(import_picocolors4.default.dim(` AI config: ${aiConfig.filename}`));
|
|
1883
2959
|
}
|
|
1884
2960
|
}
|
|
1885
2961
|
if (config.theme !== "dark" || config.aiAssistant) {
|
|
@@ -1887,56 +2963,56 @@ function showNextSteps(config) {
|
|
|
1887
2963
|
}
|
|
1888
2964
|
}
|
|
1889
2965
|
if (config.type === "fast+") {
|
|
1890
|
-
console.log(
|
|
1891
|
-
console.log(
|
|
1892
|
-
console.log(
|
|
1893
|
-
console.log(
|
|
2966
|
+
console.log(import_picocolors4.default.dim(" bun setup will:"));
|
|
2967
|
+
console.log(import_picocolors4.default.dim(" - Start PostgreSQL with Docker"));
|
|
2968
|
+
console.log(import_picocolors4.default.dim(" - Run database migrations"));
|
|
2969
|
+
console.log(import_picocolors4.default.dim(" - Create demo user (demo@example.com / demo1234)"));
|
|
1894
2970
|
console.log();
|
|
1895
|
-
console.log(
|
|
2971
|
+
console.log(import_picocolors4.default.dim(" Tip: Configure DATABASE_URL and BETTER_AUTH_SECRET in .env"));
|
|
1896
2972
|
if (!config.railwayToken) {
|
|
1897
|
-
console.log(
|
|
2973
|
+
console.log(import_picocolors4.default.dim(" Railway: Create a project at https://railway.app/new"));
|
|
1898
2974
|
}
|
|
1899
2975
|
console.log();
|
|
1900
2976
|
}
|
|
1901
2977
|
if (!isPublicTemplate) {
|
|
1902
2978
|
if (config.resendApiKey || config.stagingUrl) {
|
|
1903
|
-
console.log(
|
|
2979
|
+
console.log(import_picocolors4.default.green(" .env configured!"));
|
|
1904
2980
|
console.log();
|
|
1905
2981
|
} else {
|
|
1906
|
-
console.log(
|
|
2982
|
+
console.log(import_picocolors4.default.yellow(" Tip: Configure .env manually or use 'bun setup'."));
|
|
1907
2983
|
console.log();
|
|
1908
2984
|
}
|
|
1909
2985
|
}
|
|
1910
2986
|
if (isPublicTemplate) {
|
|
1911
|
-
console.log(
|
|
1912
|
-
console.log(
|
|
2987
|
+
console.log(import_picocolors4.default.dim(" Open source template (MIT) by nimbuslab"));
|
|
2988
|
+
console.log(import_picocolors4.default.dim(` https://github.com/nimbuslab/create-next-${config.type === "turborepo" ? "turborepo" : config.type}`));
|
|
1913
2989
|
} else {
|
|
1914
|
-
console.log(
|
|
2990
|
+
console.log(import_picocolors4.default.dim(" https://github.com/nimbuslab-templates"));
|
|
1915
2991
|
}
|
|
1916
2992
|
console.log();
|
|
1917
2993
|
}
|
|
1918
2994
|
|
|
1919
2995
|
// src/commands/analyze.ts
|
|
1920
|
-
var
|
|
2996
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
1921
2997
|
import { existsSync, readFileSync } from "fs";
|
|
1922
|
-
import { join as
|
|
2998
|
+
import { join as join3 } from "path";
|
|
1923
2999
|
function detectPackageManager(dir) {
|
|
1924
|
-
if (existsSync(
|
|
3000
|
+
if (existsSync(join3(dir, "bun.lockb")))
|
|
1925
3001
|
return "bun";
|
|
1926
|
-
if (existsSync(
|
|
3002
|
+
if (existsSync(join3(dir, "pnpm-lock.yaml")))
|
|
1927
3003
|
return "pnpm";
|
|
1928
|
-
if (existsSync(
|
|
3004
|
+
if (existsSync(join3(dir, "yarn.lock")))
|
|
1929
3005
|
return "yarn";
|
|
1930
|
-
if (existsSync(
|
|
3006
|
+
if (existsSync(join3(dir, "package-lock.json")))
|
|
1931
3007
|
return "npm";
|
|
1932
3008
|
return "unknown";
|
|
1933
3009
|
}
|
|
1934
3010
|
function detectMonorepo(dir, pkg) {
|
|
1935
|
-
if (existsSync(
|
|
3011
|
+
if (existsSync(join3(dir, "turbo.json")))
|
|
1936
3012
|
return "turborepo";
|
|
1937
|
-
if (existsSync(
|
|
3013
|
+
if (existsSync(join3(dir, "nx.json")))
|
|
1938
3014
|
return "nx";
|
|
1939
|
-
if (existsSync(
|
|
3015
|
+
if (existsSync(join3(dir, "lerna.json")))
|
|
1940
3016
|
return "lerna";
|
|
1941
3017
|
if (pkg.workspaces)
|
|
1942
3018
|
return "workspaces";
|
|
@@ -2041,14 +3117,14 @@ function generateRecommendations(result) {
|
|
|
2041
3117
|
}
|
|
2042
3118
|
async function analyze(args) {
|
|
2043
3119
|
const targetDir = args[0] || ".";
|
|
2044
|
-
const absoluteDir = targetDir.startsWith("/") ? targetDir :
|
|
3120
|
+
const absoluteDir = targetDir.startsWith("/") ? targetDir : join3(process.cwd(), targetDir);
|
|
2045
3121
|
console.log();
|
|
2046
|
-
console.log(
|
|
3122
|
+
console.log(import_picocolors5.default.cyan(" Analisando projeto..."));
|
|
2047
3123
|
console.log();
|
|
2048
|
-
const pkgPath =
|
|
3124
|
+
const pkgPath = join3(absoluteDir, "package.json");
|
|
2049
3125
|
if (!existsSync(pkgPath)) {
|
|
2050
|
-
console.log(
|
|
2051
|
-
console.log(
|
|
3126
|
+
console.log(import_picocolors5.default.red(" Erro: package.json nao encontrado"));
|
|
3127
|
+
console.log(import_picocolors5.default.dim(` Diretorio: ${absoluteDir}`));
|
|
2052
3128
|
process.exit(1);
|
|
2053
3129
|
}
|
|
2054
3130
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -2065,42 +3141,42 @@ async function analyze(args) {
|
|
|
2065
3141
|
monorepo: detectMonorepo(absoluteDir, pkg),
|
|
2066
3142
|
auth: detectAuth(deps),
|
|
2067
3143
|
database: detectDatabase(deps),
|
|
2068
|
-
typescript: existsSync(
|
|
3144
|
+
typescript: existsSync(join3(absoluteDir, "tsconfig.json")),
|
|
2069
3145
|
dependencies: deps,
|
|
2070
3146
|
devDependencies: devDeps,
|
|
2071
3147
|
recommendations: []
|
|
2072
3148
|
};
|
|
2073
3149
|
result.recommendations = generateRecommendations(result);
|
|
2074
|
-
console.log(
|
|
3150
|
+
console.log(import_picocolors5.default.bold(" Projeto: ") + import_picocolors5.default.cyan(result.name) + import_picocolors5.default.dim(` v${result.version}`));
|
|
2075
3151
|
console.log();
|
|
2076
|
-
console.log(
|
|
2077
|
-
console.log(` Framework: ${result.framework ?
|
|
2078
|
-
console.log(` Styling: ${result.styling.map((s) =>
|
|
2079
|
-
console.log(` Package Manager: ${result.packageManager === "bun" ?
|
|
2080
|
-
console.log(` TypeScript: ${result.typescript ?
|
|
2081
|
-
console.log(` Monorepo: ${result.monorepo ?
|
|
2082
|
-
console.log(` Auth: ${result.auth ?
|
|
2083
|
-
console.log(` Database: ${result.database ?
|
|
3152
|
+
console.log(import_picocolors5.default.bold(" Stack Detectada:"));
|
|
3153
|
+
console.log(` Framework: ${result.framework ? import_picocolors5.default.green(result.framework + "@" + result.frameworkVersion) : import_picocolors5.default.dim("nenhum")}`);
|
|
3154
|
+
console.log(` Styling: ${result.styling.map((s) => import_picocolors5.default.green(s)).join(", ")}`);
|
|
3155
|
+
console.log(` Package Manager: ${result.packageManager === "bun" ? import_picocolors5.default.green(result.packageManager) : import_picocolors5.default.yellow(result.packageManager)}`);
|
|
3156
|
+
console.log(` TypeScript: ${result.typescript ? import_picocolors5.default.green("sim") : import_picocolors5.default.dim("nao")}`);
|
|
3157
|
+
console.log(` Monorepo: ${result.monorepo ? import_picocolors5.default.green(result.monorepo) : import_picocolors5.default.dim("nao")}`);
|
|
3158
|
+
console.log(` Auth: ${result.auth ? import_picocolors5.default.green(result.auth) : import_picocolors5.default.dim("nenhum")}`);
|
|
3159
|
+
console.log(` Database: ${result.database ? import_picocolors5.default.green(result.database) : import_picocolors5.default.dim("nenhum")}`);
|
|
2084
3160
|
console.log();
|
|
2085
3161
|
if (result.recommendations.length > 0) {
|
|
2086
|
-
console.log(
|
|
3162
|
+
console.log(import_picocolors5.default.bold(" Recomendacoes:"));
|
|
2087
3163
|
result.recommendations.forEach((rec, i) => {
|
|
2088
|
-
console.log(
|
|
3164
|
+
console.log(import_picocolors5.default.yellow(` ${i + 1}. ${rec}`));
|
|
2089
3165
|
});
|
|
2090
3166
|
console.log();
|
|
2091
3167
|
} else {
|
|
2092
|
-
console.log(
|
|
3168
|
+
console.log(import_picocolors5.default.green(" Projeto ja esta na stack recomendada!"));
|
|
2093
3169
|
console.log();
|
|
2094
3170
|
}
|
|
2095
3171
|
if (args.includes("--json")) {
|
|
2096
|
-
console.log(
|
|
3172
|
+
console.log(import_picocolors5.default.dim(" JSON:"));
|
|
2097
3173
|
console.log(JSON.stringify(result, null, 2));
|
|
2098
3174
|
}
|
|
2099
3175
|
return result;
|
|
2100
3176
|
}
|
|
2101
3177
|
|
|
2102
3178
|
// src/commands/upgrade.ts
|
|
2103
|
-
var
|
|
3179
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
2104
3180
|
var UPGRADE_PLANS = {
|
|
2105
3181
|
next: (current) => {
|
|
2106
3182
|
const major = parseInt(current.replace(/[^0-9]/g, "").slice(0, 2));
|
|
@@ -2217,10 +3293,10 @@ async function upgrade(args) {
|
|
|
2217
3293
|
const target = args.find((a) => !a.startsWith("-"));
|
|
2218
3294
|
console.log();
|
|
2219
3295
|
if (showPlan || !target) {
|
|
2220
|
-
console.log(
|
|
3296
|
+
console.log(import_picocolors6.default.cyan(" Analisando projeto para plano de upgrade..."));
|
|
2221
3297
|
console.log();
|
|
2222
3298
|
const analysis = await analyze([".", "--quiet"]);
|
|
2223
|
-
console.log(
|
|
3299
|
+
console.log(import_picocolors6.default.bold(" Upgrades Disponiveis:"));
|
|
2224
3300
|
console.log();
|
|
2225
3301
|
let hasUpgrades = false;
|
|
2226
3302
|
if (analysis.frameworkVersion && analysis.framework === "nextjs") {
|
|
@@ -2275,44 +3351,44 @@ async function upgrade(args) {
|
|
|
2275
3351
|
}
|
|
2276
3352
|
}
|
|
2277
3353
|
if (!hasUpgrades) {
|
|
2278
|
-
console.log(
|
|
3354
|
+
console.log(import_picocolors6.default.green(" Projeto ja esta atualizado!"));
|
|
2279
3355
|
}
|
|
2280
3356
|
console.log();
|
|
2281
|
-
console.log(
|
|
2282
|
-
console.log(
|
|
2283
|
-
console.log(
|
|
2284
|
-
console.log(
|
|
3357
|
+
console.log(import_picocolors6.default.dim(" Para executar um upgrade especifico:"));
|
|
3358
|
+
console.log(import_picocolors6.default.dim(" nimbus upgrade next"));
|
|
3359
|
+
console.log(import_picocolors6.default.dim(" nimbus upgrade tailwind"));
|
|
3360
|
+
console.log(import_picocolors6.default.dim(" nimbus upgrade bun"));
|
|
2285
3361
|
console.log();
|
|
2286
3362
|
return;
|
|
2287
3363
|
}
|
|
2288
|
-
console.log(
|
|
2289
|
-
console.log(
|
|
3364
|
+
console.log(import_picocolors6.default.yellow(` Upgrade ${target} ainda nao implementado.`));
|
|
3365
|
+
console.log(import_picocolors6.default.dim(" Por enquanto, siga os passos do --plan manualmente."));
|
|
2290
3366
|
console.log();
|
|
2291
3367
|
}
|
|
2292
3368
|
function printUpgradePlan(name, plan) {
|
|
2293
3369
|
const complexityColor = {
|
|
2294
|
-
low:
|
|
2295
|
-
medium:
|
|
2296
|
-
high:
|
|
3370
|
+
low: import_picocolors6.default.green,
|
|
3371
|
+
medium: import_picocolors6.default.yellow,
|
|
3372
|
+
high: import_picocolors6.default.red
|
|
2297
3373
|
};
|
|
2298
|
-
console.log(` ${
|
|
2299
|
-
console.log(` ${
|
|
2300
|
-
console.log(` ${
|
|
3374
|
+
console.log(` ${import_picocolors6.default.bold(name)}`);
|
|
3375
|
+
console.log(` ${import_picocolors6.default.dim("Atual:")} ${plan.current} ${import_picocolors6.default.dim("->")} ${import_picocolors6.default.cyan(plan.target)}`);
|
|
3376
|
+
console.log(` ${import_picocolors6.default.dim("Complexidade:")} ${complexityColor[plan.complexity](plan.complexity)}`);
|
|
2301
3377
|
console.log();
|
|
2302
|
-
console.log(` ${
|
|
3378
|
+
console.log(` ${import_picocolors6.default.dim("Breaking Changes:")}`);
|
|
2303
3379
|
plan.breakingChanges.forEach((bc) => {
|
|
2304
|
-
console.log(` ${
|
|
3380
|
+
console.log(` ${import_picocolors6.default.yellow("!")} ${bc}`);
|
|
2305
3381
|
});
|
|
2306
3382
|
console.log();
|
|
2307
|
-
console.log(` ${
|
|
3383
|
+
console.log(` ${import_picocolors6.default.dim("Passos:")}`);
|
|
2308
3384
|
plan.steps.forEach((step, i) => {
|
|
2309
|
-
console.log(` ${
|
|
3385
|
+
console.log(` ${import_picocolors6.default.dim(`${i + 1}.`)} ${step}`);
|
|
2310
3386
|
});
|
|
2311
3387
|
console.log();
|
|
2312
3388
|
}
|
|
2313
3389
|
|
|
2314
3390
|
// src/commands/update.ts
|
|
2315
|
-
var
|
|
3391
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
2316
3392
|
import { execSync, spawnSync } from "child_process";
|
|
2317
3393
|
var PACKAGE_NAME = "@nimbuslab/cli";
|
|
2318
3394
|
function hasBunInstall() {
|
|
@@ -2448,7 +3524,7 @@ async function update(args) {
|
|
|
2448
3524
|
const filteredArgs = args.filter((a) => a !== "--force" && a !== "-f");
|
|
2449
3525
|
const flag = filteredArgs[0];
|
|
2450
3526
|
if (flag === "--list" || flag === "-l") {
|
|
2451
|
-
Ie(
|
|
3527
|
+
Ie(import_picocolors7.default.cyan("Versoes disponiveis"));
|
|
2452
3528
|
const spinner2 = Y2();
|
|
2453
3529
|
spinner2.start("Buscando versoes...");
|
|
2454
3530
|
const versions = await getAvailableVersions();
|
|
@@ -2460,29 +3536,29 @@ async function update(args) {
|
|
|
2460
3536
|
const current = getCurrentVersion();
|
|
2461
3537
|
const pm2 = detectPackageManager2();
|
|
2462
3538
|
console.log();
|
|
2463
|
-
console.log(
|
|
3539
|
+
console.log(import_picocolors7.default.bold("Ultimas 10 versoes:"));
|
|
2464
3540
|
versions.slice(0, 10).forEach((v2, i) => {
|
|
2465
3541
|
const isCurrent = v2 === current;
|
|
2466
|
-
const prefix = isCurrent ?
|
|
2467
|
-
const suffix = isCurrent ?
|
|
2468
|
-
const isLatest = i === 0 ?
|
|
3542
|
+
const prefix = isCurrent ? import_picocolors7.default.green("-> ") : " ";
|
|
3543
|
+
const suffix = isCurrent ? import_picocolors7.default.dim(" (instalada)") : "";
|
|
3544
|
+
const isLatest = i === 0 ? import_picocolors7.default.yellow(" (latest)") : "";
|
|
2469
3545
|
console.log(`${prefix}${v2}${suffix}${isLatest}`);
|
|
2470
3546
|
});
|
|
2471
3547
|
console.log();
|
|
2472
|
-
console.log(
|
|
2473
|
-
console.log(
|
|
2474
|
-
console.log(
|
|
2475
|
-
console.log(
|
|
3548
|
+
console.log(import_picocolors7.default.dim(`Total: ${versions.length} versoes`));
|
|
3549
|
+
console.log(import_picocolors7.default.dim(`Package manager detectado: ${pm2 === "unknown" ? "nenhum" : pm2}`));
|
|
3550
|
+
console.log(import_picocolors7.default.dim(`Instalar versao especifica: nimbus update <versao>`));
|
|
3551
|
+
console.log(import_picocolors7.default.dim(`Forcar reinstalacao: nimbus update --force`));
|
|
2476
3552
|
return;
|
|
2477
3553
|
}
|
|
2478
3554
|
const targetVersion = flag || "latest";
|
|
2479
3555
|
const isSpecificVersion = flag && flag !== "latest" && !flag.startsWith("-");
|
|
2480
|
-
Ie(
|
|
3556
|
+
Ie(import_picocolors7.default.cyan(`Atualizando ${PACKAGE_NAME}`));
|
|
2481
3557
|
const spinner = Y2();
|
|
2482
3558
|
spinner.start("Verificando instalacoes...");
|
|
2483
3559
|
const cleanup = cleanupDuplicateInstalls();
|
|
2484
3560
|
if (cleanup.cleaned) {
|
|
2485
|
-
spinner.stop(
|
|
3561
|
+
spinner.stop(import_picocolors7.default.yellow(cleanup.message));
|
|
2486
3562
|
} else {
|
|
2487
3563
|
spinner.stop("OK");
|
|
2488
3564
|
}
|
|
@@ -2500,7 +3576,7 @@ async function update(args) {
|
|
|
2500
3576
|
spinner.stop(`Ultima versao: ${latestVersion || "desconhecida"}`);
|
|
2501
3577
|
if (!forceFlag && latestVersion && latestVersion === currentVersion) {
|
|
2502
3578
|
M2.success("Voce ja esta na ultima versao!");
|
|
2503
|
-
console.log(
|
|
3579
|
+
console.log(import_picocolors7.default.dim(" Use --force para reinstalar"));
|
|
2504
3580
|
return;
|
|
2505
3581
|
}
|
|
2506
3582
|
}
|
|
@@ -2538,37 +3614,37 @@ async function update(args) {
|
|
|
2538
3614
|
const isWindows = process.platform === "win32";
|
|
2539
3615
|
if (isWindows) {
|
|
2540
3616
|
console.log();
|
|
2541
|
-
console.log(
|
|
3617
|
+
console.log(import_picocolors7.default.yellow(" Reinicie o terminal para aplicar a atualizacao."));
|
|
2542
3618
|
} else if (isUsingFnm()) {
|
|
2543
3619
|
console.log();
|
|
2544
|
-
console.log(
|
|
2545
|
-
console.log(
|
|
2546
|
-
console.log(
|
|
3620
|
+
console.log(import_picocolors7.default.yellow(" fnm detectado - execute para aplicar:"));
|
|
3621
|
+
console.log(import_picocolors7.default.cyan(" hash -r"));
|
|
3622
|
+
console.log(import_picocolors7.default.dim(" Ou abra um novo terminal."));
|
|
2547
3623
|
}
|
|
2548
|
-
Se(
|
|
3624
|
+
Se(import_picocolors7.default.green("Pronto!"));
|
|
2549
3625
|
} catch (error) {
|
|
2550
3626
|
spinner.stop("Erro na atualizacao");
|
|
2551
3627
|
const err = error;
|
|
2552
3628
|
M2.error("Falha ao atualizar");
|
|
2553
3629
|
if (err.stderr) {
|
|
2554
|
-
console.log(
|
|
3630
|
+
console.log(import_picocolors7.default.dim(err.stderr));
|
|
2555
3631
|
}
|
|
2556
3632
|
console.log();
|
|
2557
|
-
console.log(
|
|
3633
|
+
console.log(import_picocolors7.default.yellow("Tente manualmente:"));
|
|
2558
3634
|
if (pm === "bun") {
|
|
2559
|
-
console.log(
|
|
3635
|
+
console.log(import_picocolors7.default.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
|
|
2560
3636
|
} else {
|
|
2561
|
-
console.log(
|
|
3637
|
+
console.log(import_picocolors7.default.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
|
|
2562
3638
|
}
|
|
2563
3639
|
}
|
|
2564
3640
|
}
|
|
2565
3641
|
|
|
2566
3642
|
// src/commands/setup-node.ts
|
|
2567
|
-
var
|
|
3643
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
2568
3644
|
import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
|
|
2569
3645
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
2570
3646
|
import { homedir } from "os";
|
|
2571
|
-
import { join as
|
|
3647
|
+
import { join as join4 } from "path";
|
|
2572
3648
|
var HOME = homedir();
|
|
2573
3649
|
var IS_WINDOWS = process.platform === "win32";
|
|
2574
3650
|
var CHECK_CMD = IS_WINDOWS ? "where" : "which";
|
|
@@ -2576,23 +3652,23 @@ function detectFnm() {
|
|
|
2576
3652
|
const result = { name: "fnm", installed: false };
|
|
2577
3653
|
const check = spawnSync2(CHECK_CMD, ["fnm"], { encoding: "utf-8", shell: true });
|
|
2578
3654
|
const fnmLocations = IS_WINDOWS ? [
|
|
2579
|
-
|
|
2580
|
-
|
|
3655
|
+
join4(HOME, "scoop", "shims", "fnm.exe"),
|
|
3656
|
+
join4(HOME, "scoop", "apps", "fnm", "current", "fnm.exe"),
|
|
2581
3657
|
"C:\\ProgramData\\chocolatey\\bin\\fnm.exe",
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
3658
|
+
join4(HOME, ".cargo", "bin", "fnm.exe"),
|
|
3659
|
+
join4(HOME, ".fnm", "fnm.exe"),
|
|
3660
|
+
join4(HOME, "AppData", "Local", "fnm", "fnm.exe"),
|
|
3661
|
+
join4(HOME, "AppData", "Roaming", "fnm", "fnm.exe"),
|
|
3662
|
+
join4(HOME, "AppData", "Local", "Microsoft", "fnm", "fnm.exe"),
|
|
3663
|
+
join4(HOME, "AppData", "Roaming", "fnm"),
|
|
3664
|
+
join4(HOME, "AppData", "Local", "fnm_multishells")
|
|
2589
3665
|
] : [
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
3666
|
+
join4(HOME, ".local", "share", "fnm", "fnm"),
|
|
3667
|
+
join4(HOME, ".fnm", "fnm"),
|
|
3668
|
+
join4(HOME, ".local", "bin", "fnm"),
|
|
2593
3669
|
"/opt/homebrew/bin/fnm",
|
|
2594
3670
|
"/usr/local/bin/fnm",
|
|
2595
|
-
|
|
3671
|
+
join4(HOME, ".cargo", "bin", "fnm")
|
|
2596
3672
|
];
|
|
2597
3673
|
let fnmPath = null;
|
|
2598
3674
|
if (check.status === 0) {
|
|
@@ -2612,7 +3688,7 @@ function detectFnm() {
|
|
|
2612
3688
|
}
|
|
2613
3689
|
}
|
|
2614
3690
|
if (!fnmPath && IS_WINDOWS) {
|
|
2615
|
-
const fnmMultishells =
|
|
3691
|
+
const fnmMultishells = join4(HOME, "AppData", "Local", "fnm_multishells");
|
|
2616
3692
|
if (existsSync2(fnmMultishells)) {
|
|
2617
3693
|
fnmPath = fnmMultishells;
|
|
2618
3694
|
}
|
|
@@ -2628,9 +3704,9 @@ function detectFnm() {
|
|
|
2628
3704
|
} catch {}
|
|
2629
3705
|
result.configFiles = [];
|
|
2630
3706
|
if (IS_WINDOWS) {
|
|
2631
|
-
const ps5Profile =
|
|
2632
|
-
const ps7Profile =
|
|
2633
|
-
const psProfile =
|
|
3707
|
+
const ps5Profile = join4(HOME, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
3708
|
+
const ps7Profile = join4(HOME, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
3709
|
+
const psProfile = join4(HOME, "Documents", "PowerShell", "profile.ps1");
|
|
2634
3710
|
if (existsSync2(ps5Profile))
|
|
2635
3711
|
result.configFiles.push(ps5Profile);
|
|
2636
3712
|
if (existsSync2(ps7Profile))
|
|
@@ -2639,12 +3715,12 @@ function detectFnm() {
|
|
|
2639
3715
|
result.configFiles.push(psProfile);
|
|
2640
3716
|
} else {
|
|
2641
3717
|
const configs = [
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
3718
|
+
join4(HOME, ".bashrc"),
|
|
3719
|
+
join4(HOME, ".bash_profile"),
|
|
3720
|
+
join4(HOME, ".profile"),
|
|
3721
|
+
join4(HOME, ".zshrc"),
|
|
3722
|
+
join4(HOME, ".zprofile"),
|
|
3723
|
+
join4(HOME, ".config", "fish", "config.fish")
|
|
2648
3724
|
];
|
|
2649
3725
|
for (const cfg of configs) {
|
|
2650
3726
|
if (existsSync2(cfg))
|
|
@@ -2658,10 +3734,10 @@ function detectNvm() {
|
|
|
2658
3734
|
if (IS_WINDOWS) {
|
|
2659
3735
|
const check = spawnSync2(CHECK_CMD, ["nvm"], { encoding: "utf-8", shell: true });
|
|
2660
3736
|
const nvmWinLocations = [
|
|
2661
|
-
|
|
3737
|
+
join4(HOME, "AppData", "Roaming", "nvm", "nvm.exe"),
|
|
2662
3738
|
"C:\\Program Files\\nvm\\nvm.exe",
|
|
2663
3739
|
"C:\\ProgramData\\nvm\\nvm.exe",
|
|
2664
|
-
|
|
3740
|
+
join4(HOME, "nvm", "nvm.exe")
|
|
2665
3741
|
];
|
|
2666
3742
|
let nvmPath = null;
|
|
2667
3743
|
if (check.status === 0) {
|
|
@@ -2685,28 +3761,28 @@ function detectNvm() {
|
|
|
2685
3761
|
} catch {}
|
|
2686
3762
|
result.configFiles = [];
|
|
2687
3763
|
const configs = [
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
3764
|
+
join4(HOME, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1"),
|
|
3765
|
+
join4(HOME, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1"),
|
|
3766
|
+
join4(HOME, "Documents", "PowerShell", "profile.ps1")
|
|
2691
3767
|
];
|
|
2692
3768
|
for (const cfg of configs) {
|
|
2693
3769
|
if (existsSync2(cfg))
|
|
2694
3770
|
result.configFiles.push(cfg);
|
|
2695
3771
|
}
|
|
2696
3772
|
} else {
|
|
2697
|
-
const nvmDir = process.env.NVM_DIR ||
|
|
3773
|
+
const nvmDir = process.env.NVM_DIR || join4(HOME, ".nvm");
|
|
2698
3774
|
if (!existsSync2(nvmDir))
|
|
2699
3775
|
return result;
|
|
2700
3776
|
result.installed = true;
|
|
2701
3777
|
result.path = nvmDir;
|
|
2702
3778
|
result.configFiles = [];
|
|
2703
3779
|
const configs = [
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
3780
|
+
join4(HOME, ".bashrc"),
|
|
3781
|
+
join4(HOME, ".bash_profile"),
|
|
3782
|
+
join4(HOME, ".profile"),
|
|
3783
|
+
join4(HOME, ".zshrc"),
|
|
3784
|
+
join4(HOME, ".zprofile"),
|
|
3785
|
+
join4(HOME, ".config", "fish", "config.fish")
|
|
2710
3786
|
];
|
|
2711
3787
|
for (const cfg of configs) {
|
|
2712
3788
|
if (existsSync2(cfg))
|
|
@@ -2833,7 +3909,7 @@ async function removeFnm(fnm) {
|
|
|
2833
3909
|
const scoopCheck = spawnSync2("scoop", ["list"], { encoding: "utf-8", shell: true });
|
|
2834
3910
|
if (scoopCheck.stdout?.includes("fnm")) {
|
|
2835
3911
|
execSync2("scoop uninstall fnm", { stdio: "pipe" });
|
|
2836
|
-
console.log(
|
|
3912
|
+
console.log(import_picocolors8.default.dim(" Removido via Scoop"));
|
|
2837
3913
|
removed = true;
|
|
2838
3914
|
}
|
|
2839
3915
|
} catch {}
|
|
@@ -2842,7 +3918,7 @@ async function removeFnm(fnm) {
|
|
|
2842
3918
|
const chocoCheck = spawnSync2("choco", ["list", "--local-only"], { encoding: "utf-8", shell: true });
|
|
2843
3919
|
if (chocoCheck.stdout?.includes("fnm")) {
|
|
2844
3920
|
execSync2("choco uninstall fnm -y", { stdio: "pipe" });
|
|
2845
|
-
console.log(
|
|
3921
|
+
console.log(import_picocolors8.default.dim(" Removido via Chocolatey"));
|
|
2846
3922
|
removed = true;
|
|
2847
3923
|
}
|
|
2848
3924
|
} catch {}
|
|
@@ -2852,28 +3928,28 @@ async function removeFnm(fnm) {
|
|
|
2852
3928
|
const wingetCheck = spawnSync2("winget", ["list", "--name", "fnm"], { encoding: "utf-8", shell: true });
|
|
2853
3929
|
if (wingetCheck.stdout?.includes("fnm")) {
|
|
2854
3930
|
execSync2("winget uninstall fnm --silent", { stdio: "pipe" });
|
|
2855
|
-
console.log(
|
|
3931
|
+
console.log(import_picocolors8.default.dim(" Removido via winget"));
|
|
2856
3932
|
removed = true;
|
|
2857
3933
|
}
|
|
2858
3934
|
} catch {}
|
|
2859
3935
|
}
|
|
2860
3936
|
const winFnmDirs = [
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
3937
|
+
join4(HOME, ".fnm"),
|
|
3938
|
+
join4(HOME, "AppData", "Local", "fnm"),
|
|
3939
|
+
join4(HOME, "AppData", "Roaming", "fnm"),
|
|
3940
|
+
join4(HOME, "AppData", "Local", "fnm_multishells"),
|
|
3941
|
+
join4(HOME, "AppData", "Local", "Microsoft", "fnm")
|
|
2866
3942
|
];
|
|
2867
3943
|
for (const dir of winFnmDirs) {
|
|
2868
3944
|
if (existsSync2(dir)) {
|
|
2869
3945
|
try {
|
|
2870
3946
|
execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: "cmd.exe" });
|
|
2871
|
-
console.log(
|
|
3947
|
+
console.log(import_picocolors8.default.dim(` Removido ${dir}`));
|
|
2872
3948
|
removed = true;
|
|
2873
3949
|
} catch {
|
|
2874
3950
|
try {
|
|
2875
3951
|
execSync2(`powershell -Command "Remove-Item -Path '${dir}' -Recurse -Force"`, { stdio: "pipe" });
|
|
2876
|
-
console.log(
|
|
3952
|
+
console.log(import_picocolors8.default.dim(` Removido ${dir}`));
|
|
2877
3953
|
removed = true;
|
|
2878
3954
|
} catch {}
|
|
2879
3955
|
}
|
|
@@ -2882,16 +3958,16 @@ async function removeFnm(fnm) {
|
|
|
2882
3958
|
try {
|
|
2883
3959
|
execSync2(`powershell -Command "[Environment]::SetEnvironmentVariable('FNM_DIR', $null, 'User')"`, { stdio: "pipe" });
|
|
2884
3960
|
execSync2(`powershell -Command "[Environment]::SetEnvironmentVariable('FNM_MULTISHELL_PATH', $null, 'User')"`, { stdio: "pipe" });
|
|
2885
|
-
console.log(
|
|
3961
|
+
console.log(import_picocolors8.default.dim(" Variaveis de ambiente FNM removidas"));
|
|
2886
3962
|
removed = true;
|
|
2887
3963
|
} catch {}
|
|
2888
3964
|
for (const configFile of fnm.configFiles || []) {
|
|
2889
3965
|
if (removeFnmFromConfig(configFile)) {
|
|
2890
|
-
console.log(
|
|
3966
|
+
console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
|
|
2891
3967
|
removed = true;
|
|
2892
3968
|
}
|
|
2893
3969
|
}
|
|
2894
|
-
spinner.stop(removed ? "fnm removido!" :
|
|
3970
|
+
spinner.stop(removed ? "fnm removido!" : import_picocolors8.default.yellow("fnm nao encontrado"));
|
|
2895
3971
|
return removed;
|
|
2896
3972
|
} else {
|
|
2897
3973
|
spinner.start("Removendo fnm...");
|
|
@@ -2900,35 +3976,35 @@ async function removeFnm(fnm) {
|
|
|
2900
3976
|
const brewCheck = spawnSync2("brew", ["list", "fnm"], { encoding: "utf-8", shell: true });
|
|
2901
3977
|
if (brewCheck.status === 0) {
|
|
2902
3978
|
execSync2("brew uninstall fnm", { stdio: "pipe" });
|
|
2903
|
-
console.log(
|
|
3979
|
+
console.log(import_picocolors8.default.dim(" Removido via Homebrew"));
|
|
2904
3980
|
removed = true;
|
|
2905
3981
|
}
|
|
2906
3982
|
} catch {}
|
|
2907
3983
|
for (const configFile of fnm.configFiles || []) {
|
|
2908
3984
|
if (removeFnmFromConfig(configFile)) {
|
|
2909
|
-
console.log(
|
|
3985
|
+
console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
|
|
2910
3986
|
removed = true;
|
|
2911
3987
|
}
|
|
2912
3988
|
}
|
|
2913
3989
|
const fnmDirs = [
|
|
2914
|
-
|
|
2915
|
-
|
|
3990
|
+
join4(HOME, ".fnm"),
|
|
3991
|
+
join4(HOME, ".local", "share", "fnm")
|
|
2916
3992
|
];
|
|
2917
3993
|
for (const fnmDir of fnmDirs) {
|
|
2918
3994
|
if (existsSync2(fnmDir)) {
|
|
2919
3995
|
execSync2(`rm -rf "${fnmDir}"`, { stdio: "pipe" });
|
|
2920
|
-
console.log(
|
|
3996
|
+
console.log(import_picocolors8.default.dim(` Removido ${fnmDir}`));
|
|
2921
3997
|
removed = true;
|
|
2922
3998
|
}
|
|
2923
3999
|
}
|
|
2924
4000
|
const fnmBins = [
|
|
2925
|
-
|
|
2926
|
-
|
|
4001
|
+
join4(HOME, ".local", "bin", "fnm"),
|
|
4002
|
+
join4(HOME, ".cargo", "bin", "fnm")
|
|
2927
4003
|
];
|
|
2928
4004
|
for (const bin of fnmBins) {
|
|
2929
4005
|
if (existsSync2(bin)) {
|
|
2930
4006
|
execSync2(`rm -f "${bin}"`, { stdio: "pipe" });
|
|
2931
|
-
console.log(
|
|
4007
|
+
console.log(import_picocolors8.default.dim(` Removido ${bin}`));
|
|
2932
4008
|
removed = true;
|
|
2933
4009
|
}
|
|
2934
4010
|
}
|
|
@@ -2936,7 +4012,7 @@ async function removeFnm(fnm) {
|
|
|
2936
4012
|
return removed;
|
|
2937
4013
|
}
|
|
2938
4014
|
} catch (error) {
|
|
2939
|
-
spinner.stop(
|
|
4015
|
+
spinner.stop(import_picocolors8.default.red("Erro ao remover fnm"));
|
|
2940
4016
|
return false;
|
|
2941
4017
|
}
|
|
2942
4018
|
}
|
|
@@ -2950,59 +4026,59 @@ async function removeNvm(nvm) {
|
|
|
2950
4026
|
const wingetCheck = spawnSync2("winget", ["list", "--name", "nvm"], { encoding: "utf-8", shell: true });
|
|
2951
4027
|
if (wingetCheck.stdout?.toLowerCase().includes("nvm")) {
|
|
2952
4028
|
execSync2("winget uninstall nvm --silent", { stdio: "pipe" });
|
|
2953
|
-
console.log(
|
|
4029
|
+
console.log(import_picocolors8.default.dim(" Removido via winget"));
|
|
2954
4030
|
removed = true;
|
|
2955
4031
|
}
|
|
2956
4032
|
} catch {}
|
|
2957
4033
|
const nvmWinDirs = [
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
4034
|
+
join4(HOME, "AppData", "Roaming", "nvm"),
|
|
4035
|
+
join4("C:", "Program Files", "nvm"),
|
|
4036
|
+
join4("C:", "ProgramData", "nvm")
|
|
2961
4037
|
];
|
|
2962
4038
|
for (const dir of nvmWinDirs) {
|
|
2963
4039
|
if (existsSync2(dir)) {
|
|
2964
4040
|
try {
|
|
2965
4041
|
execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: "cmd.exe" });
|
|
2966
|
-
console.log(
|
|
4042
|
+
console.log(import_picocolors8.default.dim(` Removido ${dir}`));
|
|
2967
4043
|
removed = true;
|
|
2968
4044
|
} catch {}
|
|
2969
4045
|
}
|
|
2970
4046
|
}
|
|
2971
4047
|
for (const configFile of nvm.configFiles || []) {
|
|
2972
4048
|
if (removeNvmFromConfig(configFile)) {
|
|
2973
|
-
console.log(
|
|
4049
|
+
console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
|
|
2974
4050
|
removed = true;
|
|
2975
4051
|
}
|
|
2976
4052
|
}
|
|
2977
4053
|
if (!removed) {
|
|
2978
|
-
console.log(
|
|
4054
|
+
console.log(import_picocolors8.default.yellow(`
|
|
2979
4055
|
nvm-windows pode precisar de remocao manual:`));
|
|
2980
|
-
console.log(
|
|
2981
|
-
console.log(
|
|
2982
|
-
console.log(
|
|
4056
|
+
console.log(import_picocolors8.default.dim(" 1. Abra 'Adicionar ou remover programas'"));
|
|
4057
|
+
console.log(import_picocolors8.default.dim(" 2. Procure por 'NVM for Windows'"));
|
|
4058
|
+
console.log(import_picocolors8.default.dim(" 3. Clique em Desinstalar"));
|
|
2983
4059
|
}
|
|
2984
|
-
spinner.stop(removed ? "nvm removido!" :
|
|
4060
|
+
spinner.stop(removed ? "nvm removido!" : import_picocolors8.default.yellow("Verifique manualmente"));
|
|
2985
4061
|
return removed;
|
|
2986
4062
|
} else {
|
|
2987
4063
|
spinner.start("Removendo nvm...");
|
|
2988
4064
|
let removed = false;
|
|
2989
4065
|
for (const configFile of nvm.configFiles || []) {
|
|
2990
4066
|
if (removeNvmFromConfig(configFile)) {
|
|
2991
|
-
console.log(
|
|
4067
|
+
console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
|
|
2992
4068
|
removed = true;
|
|
2993
4069
|
}
|
|
2994
4070
|
}
|
|
2995
|
-
const nvmDir = process.env.NVM_DIR ||
|
|
4071
|
+
const nvmDir = process.env.NVM_DIR || join4(HOME, ".nvm");
|
|
2996
4072
|
if (existsSync2(nvmDir)) {
|
|
2997
4073
|
execSync2(`rm -rf "${nvmDir}"`, { stdio: "pipe" });
|
|
2998
|
-
console.log(
|
|
4074
|
+
console.log(import_picocolors8.default.dim(` Removido ${nvmDir}`));
|
|
2999
4075
|
removed = true;
|
|
3000
4076
|
}
|
|
3001
4077
|
spinner.stop(removed ? "nvm removido!" : "nvm nao encontrado");
|
|
3002
4078
|
return removed;
|
|
3003
4079
|
}
|
|
3004
4080
|
} catch (error) {
|
|
3005
|
-
spinner.stop(
|
|
4081
|
+
spinner.stop(import_picocolors8.default.red("Erro ao remover nvm"));
|
|
3006
4082
|
return false;
|
|
3007
4083
|
}
|
|
3008
4084
|
}
|
|
@@ -3021,14 +4097,14 @@ async function installVolta() {
|
|
|
3021
4097
|
timeout: 120000
|
|
3022
4098
|
});
|
|
3023
4099
|
spinner.stop("Volta instalado!");
|
|
3024
|
-
const voltaPath =
|
|
3025
|
-
console.log(
|
|
4100
|
+
const voltaPath = join4(HOME, ".volta", "bin");
|
|
4101
|
+
console.log(import_picocolors8.default.dim(` Adicionando ${voltaPath} ao PATH...`));
|
|
3026
4102
|
try {
|
|
3027
4103
|
execSync2(`setx PATH "%PATH%;${voltaPath}"`, { stdio: "pipe", shell: "cmd.exe" });
|
|
3028
4104
|
} catch {}
|
|
3029
4105
|
return true;
|
|
3030
4106
|
} catch (e2) {
|
|
3031
|
-
spinner.stop(
|
|
4107
|
+
spinner.stop(import_picocolors8.default.yellow("winget falhou, tentando outro metodo..."));
|
|
3032
4108
|
}
|
|
3033
4109
|
}
|
|
3034
4110
|
const chocoCheck = spawnSync2(CHECK_CMD, ["choco"], { encoding: "utf-8", shell: true });
|
|
@@ -3039,7 +4115,7 @@ async function installVolta() {
|
|
|
3039
4115
|
spinner.stop("Volta instalado!");
|
|
3040
4116
|
return true;
|
|
3041
4117
|
} catch {
|
|
3042
|
-
spinner.stop(
|
|
4118
|
+
spinner.stop(import_picocolors8.default.yellow("Chocolatey falhou"));
|
|
3043
4119
|
}
|
|
3044
4120
|
}
|
|
3045
4121
|
spinner.start("Baixando Volta diretamente...");
|
|
@@ -3063,17 +4139,17 @@ async function installVolta() {
|
|
|
3063
4139
|
spinner.stop("Volta instalado!");
|
|
3064
4140
|
return true;
|
|
3065
4141
|
} catch (e2) {
|
|
3066
|
-
spinner.stop(
|
|
4142
|
+
spinner.stop(import_picocolors8.default.yellow("Download direto falhou"));
|
|
3067
4143
|
}
|
|
3068
4144
|
console.log();
|
|
3069
|
-
console.log(
|
|
4145
|
+
console.log(import_picocolors8.default.bold(" Instale manualmente:"));
|
|
3070
4146
|
console.log();
|
|
3071
|
-
console.log(
|
|
3072
|
-
console.log(
|
|
4147
|
+
console.log(import_picocolors8.default.cyan(" 1. Baixe: https://github.com/volta-cli/volta/releases/latest"));
|
|
4148
|
+
console.log(import_picocolors8.default.dim(" (arquivo volta-windows.msi)"));
|
|
3073
4149
|
console.log();
|
|
3074
|
-
console.log(
|
|
4150
|
+
console.log(import_picocolors8.default.cyan(" 2. Execute o instalador"));
|
|
3075
4151
|
console.log();
|
|
3076
|
-
console.log(
|
|
4152
|
+
console.log(import_picocolors8.default.cyan(" 3. Reinicie o terminal"));
|
|
3077
4153
|
console.log();
|
|
3078
4154
|
return false;
|
|
3079
4155
|
} else {
|
|
@@ -3082,7 +4158,7 @@ async function installVolta() {
|
|
|
3082
4158
|
stdio: "pipe",
|
|
3083
4159
|
shell: "/bin/bash"
|
|
3084
4160
|
});
|
|
3085
|
-
const shellConfig = existsSync2(
|
|
4161
|
+
const shellConfig = existsSync2(join4(HOME, ".zshrc")) ? join4(HOME, ".zshrc") : join4(HOME, ".bashrc");
|
|
3086
4162
|
const voltaSetup = `
|
|
3087
4163
|
# Volta - Node.js version manager
|
|
3088
4164
|
export VOLTA_HOME="$HOME/.volta"
|
|
@@ -3092,28 +4168,28 @@ export PATH="$VOLTA_HOME/bin:$PATH"
|
|
|
3092
4168
|
const content = readFileSync2(shellConfig, "utf-8");
|
|
3093
4169
|
if (!content.includes("VOLTA_HOME")) {
|
|
3094
4170
|
writeFileSync(shellConfig, content + voltaSetup);
|
|
3095
|
-
console.log(
|
|
4171
|
+
console.log(import_picocolors8.default.dim(` Adicionado ao ${shellConfig}`));
|
|
3096
4172
|
}
|
|
3097
4173
|
}
|
|
3098
4174
|
spinner.stop("Volta instalado!");
|
|
3099
4175
|
return true;
|
|
3100
4176
|
}
|
|
3101
4177
|
} catch (error) {
|
|
3102
|
-
spinner.stop(
|
|
3103
|
-
console.log(
|
|
4178
|
+
spinner.stop(import_picocolors8.default.red("Erro ao instalar Volta"));
|
|
4179
|
+
console.log(import_picocolors8.default.dim(` ${error}`));
|
|
3104
4180
|
return false;
|
|
3105
4181
|
}
|
|
3106
4182
|
}
|
|
3107
4183
|
async function installNodeWithVolta() {
|
|
3108
4184
|
const spinner = Y2();
|
|
3109
4185
|
try {
|
|
3110
|
-
const voltaBin = IS_WINDOWS ? "volta" :
|
|
4186
|
+
const voltaBin = IS_WINDOWS ? "volta" : join4(HOME, ".volta", "bin", "volta");
|
|
3111
4187
|
spinner.start("Instalando Node.js LTS via Volta...");
|
|
3112
4188
|
execSync2(`"${voltaBin}" install node`, { stdio: "pipe" });
|
|
3113
4189
|
spinner.stop("Node.js instalado!");
|
|
3114
4190
|
return true;
|
|
3115
4191
|
} catch (error) {
|
|
3116
|
-
spinner.stop(
|
|
4192
|
+
spinner.stop(import_picocolors8.default.red("Erro ao instalar Node.js"));
|
|
3117
4193
|
return false;
|
|
3118
4194
|
}
|
|
3119
4195
|
}
|
|
@@ -3121,23 +4197,23 @@ async function reinstallGlobalPackages(packages) {
|
|
|
3121
4197
|
if (packages.length === 0)
|
|
3122
4198
|
return;
|
|
3123
4199
|
const spinner = Y2();
|
|
3124
|
-
const voltaBin = IS_WINDOWS ? "volta" :
|
|
4200
|
+
const voltaBin = IS_WINDOWS ? "volta" : join4(HOME, ".volta", "bin", "volta");
|
|
3125
4201
|
for (const pkg of packages) {
|
|
3126
4202
|
spinner.start(`Instalando ${pkg}...`);
|
|
3127
4203
|
try {
|
|
3128
4204
|
execSync2(`"${voltaBin}" install ${pkg}`, { stdio: "pipe" });
|
|
3129
4205
|
spinner.stop(`${pkg} instalado!`);
|
|
3130
4206
|
} catch {
|
|
3131
|
-
spinner.stop(
|
|
4207
|
+
spinner.stop(import_picocolors8.default.yellow(`${pkg} - falha (instale manualmente)`));
|
|
3132
4208
|
}
|
|
3133
4209
|
}
|
|
3134
4210
|
}
|
|
3135
4211
|
async function setupNode(args) {
|
|
3136
4212
|
const checkOnly = args.includes("--check") || args.includes("-c");
|
|
3137
4213
|
console.log();
|
|
3138
|
-
Ie(
|
|
4214
|
+
Ie(import_picocolors8.default.bgCyan(import_picocolors8.default.black(" nimbus setup node ")));
|
|
3139
4215
|
console.log();
|
|
3140
|
-
console.log(
|
|
4216
|
+
console.log(import_picocolors8.default.bold(" Detectando ambiente..."));
|
|
3141
4217
|
console.log();
|
|
3142
4218
|
const fnm = detectFnm();
|
|
3143
4219
|
const nvm = detectNvm();
|
|
@@ -3145,27 +4221,27 @@ async function setupNode(args) {
|
|
|
3145
4221
|
const node = detectNode();
|
|
3146
4222
|
const status = (installed, version) => {
|
|
3147
4223
|
if (!installed)
|
|
3148
|
-
return
|
|
3149
|
-
return
|
|
4224
|
+
return import_picocolors8.default.dim("nao instalado");
|
|
4225
|
+
return import_picocolors8.default.green(`instalado${version ? ` (${version})` : ""}`);
|
|
3150
4226
|
};
|
|
3151
|
-
console.log(` ${
|
|
3152
|
-
console.log(` ${
|
|
3153
|
-
console.log(` ${
|
|
4227
|
+
console.log(` ${import_picocolors8.default.bold("fnm:")} ${status(fnm.installed, fnm.version)}`);
|
|
4228
|
+
console.log(` ${import_picocolors8.default.bold("nvm:")} ${status(nvm.installed, nvm.version)}`);
|
|
4229
|
+
console.log(` ${import_picocolors8.default.bold("volta:")} ${status(volta.installed, volta.version)}`);
|
|
3154
4230
|
console.log();
|
|
3155
|
-
console.log(` ${
|
|
4231
|
+
console.log(` ${import_picocolors8.default.bold("node:")} ${node.version || import_picocolors8.default.dim("nao encontrado")}`);
|
|
3156
4232
|
if (node.manager) {
|
|
3157
|
-
console.log(` ${
|
|
4233
|
+
console.log(` ${import_picocolors8.default.dim(`gerenciado por: ${node.manager}`)}`);
|
|
3158
4234
|
}
|
|
3159
4235
|
console.log();
|
|
3160
4236
|
if (volta.installed && !fnm.installed && !nvm.installed) {
|
|
3161
4237
|
M2.success("Ambiente OK! Volta instalado e configurado.");
|
|
3162
|
-
Se(
|
|
4238
|
+
Se(import_picocolors8.default.green("Nada a fazer."));
|
|
3163
4239
|
return;
|
|
3164
4240
|
}
|
|
3165
4241
|
if (checkOnly) {
|
|
3166
4242
|
if (fnm.installed || nvm.installed) {
|
|
3167
|
-
console.log(
|
|
3168
|
-
console.log(
|
|
4243
|
+
console.log(import_picocolors8.default.yellow(" Recomendacao: migre para Volta"));
|
|
4244
|
+
console.log(import_picocolors8.default.dim(" Execute: nimbus setup node"));
|
|
3169
4245
|
}
|
|
3170
4246
|
Se("");
|
|
3171
4247
|
return;
|
|
@@ -3173,15 +4249,15 @@ async function setupNode(args) {
|
|
|
3173
4249
|
const hasOldManager = fnm.installed || nvm.installed;
|
|
3174
4250
|
const globalPackages = getGlobalPackages();
|
|
3175
4251
|
if (hasOldManager) {
|
|
3176
|
-
console.log(
|
|
4252
|
+
console.log(import_picocolors8.default.yellow(" Gerenciadores antigos detectados!"));
|
|
3177
4253
|
console.log();
|
|
3178
|
-
console.log(
|
|
3179
|
-
console.log(
|
|
4254
|
+
console.log(import_picocolors8.default.dim(" fnm e nvm causam problemas de cache do shell."));
|
|
4255
|
+
console.log(import_picocolors8.default.dim(" Volta resolve isso e funciona melhor no Windows."));
|
|
3180
4256
|
console.log();
|
|
3181
4257
|
if (globalPackages.length > 0) {
|
|
3182
|
-
console.log(
|
|
4258
|
+
console.log(import_picocolors8.default.bold(" Pacotes globais encontrados:"));
|
|
3183
4259
|
for (const pkg of globalPackages) {
|
|
3184
|
-
console.log(
|
|
4260
|
+
console.log(import_picocolors8.default.dim(` - ${pkg}`));
|
|
3185
4261
|
}
|
|
3186
4262
|
console.log();
|
|
3187
4263
|
}
|
|
@@ -3196,9 +4272,9 @@ async function setupNode(args) {
|
|
|
3196
4272
|
actions.push("Instalar Node.js via Volta");
|
|
3197
4273
|
if (globalPackages.length > 0)
|
|
3198
4274
|
actions.push(`Reinstalar ${globalPackages.length} pacotes globais`);
|
|
3199
|
-
console.log(
|
|
4275
|
+
console.log(import_picocolors8.default.bold(" O que sera feito:"));
|
|
3200
4276
|
for (const action of actions) {
|
|
3201
|
-
console.log(
|
|
4277
|
+
console.log(import_picocolors8.default.cyan(` -> ${action}`));
|
|
3202
4278
|
}
|
|
3203
4279
|
console.log();
|
|
3204
4280
|
const confirm = await ye({
|
|
@@ -3211,60 +4287,60 @@ async function setupNode(args) {
|
|
|
3211
4287
|
}
|
|
3212
4288
|
console.log();
|
|
3213
4289
|
if (fnm.installed) {
|
|
3214
|
-
console.log(
|
|
4290
|
+
console.log(import_picocolors8.default.bold(" Removendo fnm..."));
|
|
3215
4291
|
await removeFnm(fnm);
|
|
3216
4292
|
console.log();
|
|
3217
4293
|
}
|
|
3218
4294
|
if (nvm.installed) {
|
|
3219
|
-
console.log(
|
|
4295
|
+
console.log(import_picocolors8.default.bold(" Removendo nvm..."));
|
|
3220
4296
|
await removeNvm(nvm);
|
|
3221
4297
|
console.log();
|
|
3222
4298
|
}
|
|
3223
4299
|
if (!volta.installed) {
|
|
3224
|
-
console.log(
|
|
4300
|
+
console.log(import_picocolors8.default.bold(" Instalando Volta..."));
|
|
3225
4301
|
const installed = await installVolta();
|
|
3226
4302
|
if (!installed) {
|
|
3227
|
-
Se(
|
|
4303
|
+
Se(import_picocolors8.default.red("Falha na instalacao. Tente manualmente."));
|
|
3228
4304
|
return;
|
|
3229
4305
|
}
|
|
3230
4306
|
console.log();
|
|
3231
4307
|
}
|
|
3232
|
-
console.log(
|
|
4308
|
+
console.log(import_picocolors8.default.bold(" Instalando Node.js..."));
|
|
3233
4309
|
await installNodeWithVolta();
|
|
3234
4310
|
console.log();
|
|
3235
4311
|
if (globalPackages.length > 0) {
|
|
3236
|
-
console.log(
|
|
4312
|
+
console.log(import_picocolors8.default.bold(" Reinstalando pacotes globais..."));
|
|
3237
4313
|
await reinstallGlobalPackages(globalPackages);
|
|
3238
4314
|
console.log();
|
|
3239
4315
|
}
|
|
3240
|
-
console.log(
|
|
3241
|
-
console.log(
|
|
3242
|
-
console.log(
|
|
4316
|
+
console.log(import_picocolors8.default.green(" ====================================="));
|
|
4317
|
+
console.log(import_picocolors8.default.green(" Migracao concluida!"));
|
|
4318
|
+
console.log(import_picocolors8.default.green(" ====================================="));
|
|
3243
4319
|
console.log();
|
|
3244
4320
|
if (IS_WINDOWS) {
|
|
3245
|
-
console.log(
|
|
4321
|
+
console.log(import_picocolors8.default.yellow(" IMPORTANTE: Reinicie o terminal!"));
|
|
3246
4322
|
console.log();
|
|
3247
|
-
console.log(
|
|
3248
|
-
console.log(
|
|
4323
|
+
console.log(import_picocolors8.default.dim(" Feche todas as janelas do PowerShell/Terminal"));
|
|
4324
|
+
console.log(import_picocolors8.default.dim(" e abra novamente para aplicar as mudancas."));
|
|
3249
4325
|
} else {
|
|
3250
|
-
console.log(
|
|
4326
|
+
console.log(import_picocolors8.default.yellow(" IMPORTANTE: Reinicie o terminal ou execute:"));
|
|
3251
4327
|
console.log();
|
|
3252
|
-
console.log(
|
|
3253
|
-
console.log(
|
|
3254
|
-
console.log(
|
|
4328
|
+
console.log(import_picocolors8.default.cyan(" source ~/.zshrc"));
|
|
4329
|
+
console.log(import_picocolors8.default.dim(" # ou"));
|
|
4330
|
+
console.log(import_picocolors8.default.cyan(" source ~/.bashrc"));
|
|
3255
4331
|
}
|
|
3256
4332
|
console.log();
|
|
3257
|
-
console.log(
|
|
3258
|
-
console.log(
|
|
3259
|
-
console.log(
|
|
3260
|
-
console.log(
|
|
4333
|
+
console.log(import_picocolors8.default.bold(" Depois, verifique:"));
|
|
4334
|
+
console.log(import_picocolors8.default.dim(" volta --version"));
|
|
4335
|
+
console.log(import_picocolors8.default.dim(" node --version"));
|
|
4336
|
+
console.log(import_picocolors8.default.dim(" nimbus --version"));
|
|
3261
4337
|
console.log();
|
|
3262
|
-
Se(
|
|
4338
|
+
Se(import_picocolors8.default.green("Pronto! Volta configurado."));
|
|
3263
4339
|
}
|
|
3264
4340
|
|
|
3265
4341
|
// src/index.ts
|
|
3266
4342
|
var PACKAGE_NAME2 = "@nimbuslab/cli";
|
|
3267
|
-
var CURRENT_VERSION = "1.
|
|
4343
|
+
var CURRENT_VERSION = "1.2.0";
|
|
3268
4344
|
var LOGO = `
|
|
3269
4345
|
\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
|
|
3270
4346
|
\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
|
|
@@ -3300,18 +4376,18 @@ function showUpdateNotice(latestVersion) {
|
|
|
3300
4376
|
const line2 = ` Atualize com: ${command}`;
|
|
3301
4377
|
const maxLen = Math.max(line1.length, line2.length);
|
|
3302
4378
|
const border = "\u2500".repeat(maxLen + 2);
|
|
3303
|
-
console.log(
|
|
3304
|
-
console.log(
|
|
3305
|
-
console.log(
|
|
3306
|
-
console.log(
|
|
4379
|
+
console.log(import_picocolors9.default.yellow(` \u250C${border}\u2510`));
|
|
4380
|
+
console.log(import_picocolors9.default.yellow(` \u2502`) + import_picocolors9.default.white(line1.padEnd(maxLen + 2)) + import_picocolors9.default.yellow(`\u2502`));
|
|
4381
|
+
console.log(import_picocolors9.default.yellow(` \u2502`) + import_picocolors9.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors9.default.yellow(`\u2502`));
|
|
4382
|
+
console.log(import_picocolors9.default.yellow(` \u2514${border}\u2518`));
|
|
3307
4383
|
console.log();
|
|
3308
4384
|
}
|
|
3309
4385
|
async function main() {
|
|
3310
4386
|
const args = process.argv.slice(2);
|
|
3311
4387
|
const command = args[0];
|
|
3312
|
-
console.log(
|
|
3313
|
-
console.log(
|
|
3314
|
-
console.log(
|
|
4388
|
+
console.log(import_picocolors9.default.cyan(LOGO));
|
|
4389
|
+
console.log(import_picocolors9.default.white(" nimbuslab CLI"));
|
|
4390
|
+
console.log(import_picocolors9.default.dim(" Create awesome projects"));
|
|
3315
4391
|
console.log();
|
|
3316
4392
|
const latestVersion = await checkForUpdates();
|
|
3317
4393
|
if (latestVersion) {
|
|
@@ -3330,8 +4406,8 @@ async function main() {
|
|
|
3330
4406
|
if (subcommand === "node") {
|
|
3331
4407
|
await setupNode(args.slice(2));
|
|
3332
4408
|
} else {
|
|
3333
|
-
console.log(
|
|
3334
|
-
console.log(
|
|
4409
|
+
console.log(import_picocolors9.default.red(`Subcomando desconhecido: ${subcommand || "(vazio)"}`));
|
|
4410
|
+
console.log(import_picocolors9.default.dim(" Uso: nimbus setup node"));
|
|
3335
4411
|
process.exit(1);
|
|
3336
4412
|
}
|
|
3337
4413
|
} else if (command === "help" || command === "--help" || command === "-h") {
|
|
@@ -3339,16 +4415,16 @@ async function main() {
|
|
|
3339
4415
|
} else if (command === "version" || command === "--version" || command === "-v") {
|
|
3340
4416
|
showVersion();
|
|
3341
4417
|
} else {
|
|
3342
|
-
console.log(
|
|
4418
|
+
console.log(import_picocolors9.default.red(`Comando desconhecido: ${command}`));
|
|
3343
4419
|
showHelp();
|
|
3344
4420
|
process.exit(1);
|
|
3345
4421
|
}
|
|
3346
4422
|
}
|
|
3347
4423
|
function showHelp() {
|
|
3348
4424
|
console.log(`
|
|
3349
|
-
${
|
|
4425
|
+
${import_picocolors9.default.bold("Uso:")} nimbus [comando] [op\xE7\xF5es]
|
|
3350
4426
|
|
|
3351
|
-
${
|
|
4427
|
+
${import_picocolors9.default.bold("Comandos:")}
|
|
3352
4428
|
create [nome] Criar novo projeto
|
|
3353
4429
|
analyze [dir] Analisar stack do projeto
|
|
3354
4430
|
upgrade [alvo] Atualizar depend\xEAncias
|
|
@@ -3358,52 +4434,52 @@ ${import_picocolors8.default.bold("Comandos:")}
|
|
|
3358
4434
|
help Mostrar esta ajuda
|
|
3359
4435
|
version Mostrar vers\xE3o
|
|
3360
4436
|
|
|
3361
|
-
${
|
|
4437
|
+
${import_picocolors9.default.bold("Templates:")}
|
|
3362
4438
|
--landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
|
|
3363
4439
|
--app Web app (Landing + Better Auth + Drizzle)
|
|
3364
4440
|
--turborepo Monorepo (Turborepo + apps/packages)
|
|
3365
4441
|
|
|
3366
|
-
${
|
|
4442
|
+
${import_picocolors9.default.bold("Analyze & Upgrade:")}
|
|
3367
4443
|
analyze . Detectar stack e mostrar recomenda\xE7\xF5es
|
|
3368
4444
|
analyze --json Output em JSON
|
|
3369
4445
|
upgrade --plan Mostrar plano de upgrade
|
|
3370
4446
|
upgrade next Atualizar Next.js
|
|
3371
4447
|
upgrade tailwind Atualizar Tailwind CSS
|
|
3372
4448
|
|
|
3373
|
-
${
|
|
4449
|
+
${import_picocolors9.default.bold("Update (CLI):")}
|
|
3374
4450
|
update Atualizar para ultima versao
|
|
3375
4451
|
update 0.11.0 Instalar versao especifica
|
|
3376
4452
|
update --list Listar versoes disponiveis
|
|
3377
4453
|
update --force Forcar reinstalacao (limpa cache)
|
|
3378
4454
|
|
|
3379
|
-
${
|
|
4455
|
+
${import_picocolors9.default.bold("Setup (Ambiente):")}
|
|
3380
4456
|
setup node Migrar para Volta (remove fnm/nvm)
|
|
3381
4457
|
setup node --check Verificar ambiente atual
|
|
3382
4458
|
|
|
3383
|
-
${
|
|
4459
|
+
${import_picocolors9.default.bold("Op\xE7\xF5es:")}
|
|
3384
4460
|
-y, --yes Aceitar padr\xF5es
|
|
3385
4461
|
--no-git N\xE3o inicializar Git
|
|
3386
4462
|
--no-install N\xE3o instalar depend\xEAncias
|
|
3387
4463
|
--template <url> Usar template customizado
|
|
3388
4464
|
|
|
3389
|
-
${
|
|
4465
|
+
${import_picocolors9.default.bold("Lola (Code Agent):")}
|
|
3390
4466
|
lola install Instalar/atualizar Lola
|
|
3391
4467
|
lola suggest Sugerir melhoria (cria issue)
|
|
3392
4468
|
|
|
3393
|
-
${
|
|
3394
|
-
${
|
|
3395
|
-
${
|
|
3396
|
-
${
|
|
3397
|
-
${
|
|
3398
|
-
${
|
|
3399
|
-
${
|
|
3400
|
-
${
|
|
4469
|
+
${import_picocolors9.default.bold("Exemplos:")}
|
|
4470
|
+
${import_picocolors9.default.dim("$")} nimbus create my-landing --landing
|
|
4471
|
+
${import_picocolors9.default.dim("$")} nimbus create my-app --app
|
|
4472
|
+
${import_picocolors9.default.dim("$")} nimbus analyze ./my-project
|
|
4473
|
+
${import_picocolors9.default.dim("$")} nimbus upgrade --plan
|
|
4474
|
+
${import_picocolors9.default.dim("$")} nimbus update
|
|
4475
|
+
${import_picocolors9.default.dim("$")} nimbus setup node
|
|
4476
|
+
${import_picocolors9.default.dim("$")} nimbus lola install
|
|
3401
4477
|
`);
|
|
3402
4478
|
}
|
|
3403
4479
|
function showVersion() {
|
|
3404
4480
|
console.log(`${PACKAGE_NAME2} v${CURRENT_VERSION}`);
|
|
3405
4481
|
}
|
|
3406
4482
|
main().catch((err) => {
|
|
3407
|
-
console.error(
|
|
4483
|
+
console.error(import_picocolors9.default.red("Erro:"), err.message);
|
|
3408
4484
|
process.exit(1);
|
|
3409
4485
|
});
|