@nimbuslab/cli 0.17.3 → 1.1.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 +27 -0
- package/dist/index.js +944 -1116
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -865,10 +865,666 @@ 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 createCompatibilitySymlinks(projectPath);
|
|
881
|
+
}
|
|
882
|
+
async function generateAgentsFile(projectPath, config) {
|
|
883
|
+
const content = `# Project Context for AI Assistants
|
|
884
|
+
|
|
885
|
+
> This file is automatically loaded by Claude Code, Cursor, GitHub Copilot, and other AI coding assistants.
|
|
886
|
+
|
|
887
|
+
## Project Overview
|
|
888
|
+
|
|
889
|
+
**Name:** ${config.name}
|
|
890
|
+
**Type:** ${config.type}
|
|
891
|
+
**Description:** ${config.description}
|
|
892
|
+
|
|
893
|
+
## Quick Start
|
|
894
|
+
|
|
895
|
+
\`\`\`bash
|
|
896
|
+
bun install
|
|
897
|
+
bun dev # http://localhost:3000
|
|
898
|
+
bun build # Production build
|
|
899
|
+
bun lint # ESLint
|
|
900
|
+
bun typecheck # TypeScript check
|
|
901
|
+
\`\`\`
|
|
902
|
+
|
|
903
|
+
## Tech Stack
|
|
904
|
+
|
|
905
|
+
| Category | Technology | Why? |
|
|
906
|
+
|----------|-----------|------|
|
|
907
|
+
| Framework | ${config.stack.framework} | App Router, Turbopack, best DX |
|
|
908
|
+
| Styling | ${config.stack.styling} | Fast, composable, CSS-first |
|
|
909
|
+
| Components | ${config.stack.components} | Copy-paste, zero lock-in |
|
|
910
|
+
${config.stack.forms ? `| Forms | ${config.stack.forms} | Type-safe validation |
|
|
911
|
+
` : ""}${config.stack.email ? `| Email | ${config.stack.email} | Transactional emails |
|
|
912
|
+
` : ""}${config.stack.auth ? `| Auth | ${config.stack.auth} | Secure authentication |
|
|
913
|
+
` : ""}
|
|
914
|
+
## Architecture Decisions
|
|
915
|
+
|
|
916
|
+
### Server vs Client Components
|
|
917
|
+
|
|
918
|
+
**Default: Server Components**
|
|
919
|
+
- Better performance (less JS shipped)
|
|
920
|
+
- SEO-friendly
|
|
921
|
+
- Direct data access
|
|
922
|
+
|
|
923
|
+
**Use Client Components when:**
|
|
924
|
+
- Need \`useState\`/\`useEffect\`
|
|
925
|
+
- Browser APIs (\`localStorage\`, \`window\`)
|
|
926
|
+
- Event handlers (\`onClick\`, \`onChange\`)
|
|
927
|
+
- Third-party libraries that require \`'use client'\`
|
|
928
|
+
|
|
929
|
+
### File Structure
|
|
930
|
+
|
|
931
|
+
\`\`\`
|
|
932
|
+
app/
|
|
933
|
+
\u251C\u2500\u2500 layout.tsx # Root layout
|
|
934
|
+
\u251C\u2500\u2500 page.tsx # Home page
|
|
935
|
+
${config.features.contactForm ? `\u251C\u2500\u2500 api/
|
|
936
|
+
\u2502 \u2514\u2500\u2500 contact/ # Form API
|
|
937
|
+
` : ""}\u2514\u2500\u2500 ...
|
|
938
|
+
|
|
939
|
+
components/
|
|
940
|
+
\u251C\u2500\u2500 ui/ # shadcn/ui components (DON'T EDIT)
|
|
941
|
+
${config.type === "landing" ? `\u251C\u2500\u2500 sections/ # Landing sections
|
|
942
|
+
` : ""}${config.type === "app" ? `\u251C\u2500\u2500 dashboard/ # Dashboard components
|
|
943
|
+
` : ""}\u2514\u2500\u2500 forms/ # Form components
|
|
944
|
+
|
|
945
|
+
lib/
|
|
946
|
+
\u251C\u2500\u2500 utils.ts # Helpers (cn, etc)
|
|
947
|
+
${config.features.contactForm ? `\u251C\u2500\u2500 validations.ts # Zod schemas
|
|
948
|
+
` : ""}${config.stack.email ? `\u251C\u2500\u2500 email.ts # Email client
|
|
949
|
+
` : ""}${config.stack.auth ? `\u251C\u2500\u2500 auth.ts # Auth config
|
|
950
|
+
` : ""}\u2514\u2500\u2500 ...
|
|
951
|
+
\`\`\`
|
|
952
|
+
|
|
953
|
+
## Coding Conventions
|
|
954
|
+
|
|
955
|
+
### Naming
|
|
956
|
+
- Components: \`PascalCase\` (UserProfile.tsx)
|
|
957
|
+
- Files: \`kebab-case\` (user-profile.tsx)
|
|
958
|
+
- Hooks: \`useCamelCase\` (useAuth.ts)
|
|
959
|
+
- Utils: \`camelCase\` (formatDate)
|
|
960
|
+
- Constants: \`SCREAMING_SNAKE_CASE\`
|
|
961
|
+
|
|
962
|
+
### Imports Order
|
|
963
|
+
\`\`\`typescript
|
|
964
|
+
// 1. External
|
|
965
|
+
import { useState } from 'react'
|
|
966
|
+
import { cn } from '@/lib/utils'
|
|
967
|
+
|
|
968
|
+
// 2. Internal components
|
|
969
|
+
import { Button } from '@/components/ui/button'
|
|
970
|
+
|
|
971
|
+
// 3. Local
|
|
972
|
+
import { schema } from './validations'
|
|
973
|
+
|
|
974
|
+
// 4. Types
|
|
975
|
+
import type { User } from '@/types'
|
|
976
|
+
\`\`\`
|
|
977
|
+
|
|
978
|
+
### TypeScript
|
|
979
|
+
- Always use \`type\` for objects
|
|
980
|
+
- Use \`interface\` only for extendable contracts
|
|
981
|
+
- Prefer \`const\` over \`let\`
|
|
982
|
+
- Use arrow functions for components
|
|
983
|
+
- Explicit return types for exported functions
|
|
984
|
+
|
|
985
|
+
## Common Tasks
|
|
986
|
+
|
|
987
|
+
### Add a new section
|
|
988
|
+
\`\`\`bash
|
|
989
|
+
# 1. Create component
|
|
990
|
+
touch components/sections/pricing.tsx
|
|
991
|
+
|
|
992
|
+
# 2. Add to page
|
|
993
|
+
# app/page.tsx
|
|
994
|
+
import { Pricing } from '@/components/sections/pricing'
|
|
995
|
+
\`\`\`
|
|
996
|
+
|
|
997
|
+
${config.features.contactForm ? `### Add form validation
|
|
998
|
+
\`\`\`typescript
|
|
999
|
+
// lib/validations.ts
|
|
1000
|
+
export const contactSchema = z.object({
|
|
1001
|
+
email: z.string().email('Email inv\xE1lido'),
|
|
1002
|
+
message: z.string().min(10, 'M\xEDnimo 10 caracteres'),
|
|
1003
|
+
})
|
|
1004
|
+
|
|
1005
|
+
// components/forms/contact-form.tsx
|
|
1006
|
+
const form = useForm<z.infer<typeof contactSchema>>({
|
|
1007
|
+
resolver: zodResolver(contactSchema),
|
|
1008
|
+
})
|
|
1009
|
+
\`\`\`
|
|
1010
|
+
|
|
1011
|
+
` : ""}${config.stack.email ? `### Send email
|
|
1012
|
+
\`\`\`typescript
|
|
1013
|
+
// app/api/contact/route.ts
|
|
1014
|
+
import { resend } from '@/lib/email'
|
|
1015
|
+
|
|
1016
|
+
await resend.emails.send({
|
|
1017
|
+
from: 'noreply@example.com',
|
|
1018
|
+
to: 'contact@example.com',
|
|
1019
|
+
subject: 'Novo contato',
|
|
1020
|
+
react: ContactEmail({ name, email, message }),
|
|
1021
|
+
})
|
|
1022
|
+
\`\`\`
|
|
1023
|
+
|
|
1024
|
+
` : ""}## Performance Targets
|
|
1025
|
+
|
|
1026
|
+
| Metric | Target |
|
|
1027
|
+
|--------|--------|
|
|
1028
|
+
| Lighthouse Performance | 95+ |
|
|
1029
|
+
| LCP | < 2.0s |
|
|
1030
|
+
| CLS | < 0.05 |
|
|
1031
|
+
| Bundle Size | < 100KB |
|
|
1032
|
+
|
|
1033
|
+
## Environment Variables
|
|
1034
|
+
|
|
1035
|
+
\`\`\`env
|
|
1036
|
+
# Required
|
|
1037
|
+
${config.stack.email ? `RESEND_API_KEY=re_*** # Get: https://resend.com/api-keys
|
|
1038
|
+
` : ""}${config.stack.auth ? `NEXTAUTH_SECRET=*** # Generate: openssl rand -base64 32
|
|
1039
|
+
` : ""}
|
|
1040
|
+
# Optional
|
|
1041
|
+
NEXT_PUBLIC_GA_ID=G-*** # Google Analytics
|
|
1042
|
+
\`\`\`
|
|
1043
|
+
|
|
1044
|
+
## Testing
|
|
1045
|
+
|
|
1046
|
+
\`\`\`bash
|
|
1047
|
+
bun test # Unit tests
|
|
1048
|
+
bun test:e2e # E2E tests
|
|
1049
|
+
bun lint # ESLint
|
|
1050
|
+
bun typecheck # TypeScript
|
|
1051
|
+
\`\`\`
|
|
1052
|
+
|
|
1053
|
+
## Deployment
|
|
1054
|
+
|
|
1055
|
+
Auto-deploys to Vercel on push to \`main\`.
|
|
1056
|
+
|
|
1057
|
+
**Manual:**
|
|
1058
|
+
\`\`\`bash
|
|
1059
|
+
vercel --prod
|
|
1060
|
+
\`\`\`
|
|
1061
|
+
|
|
1062
|
+
## Troubleshooting
|
|
1063
|
+
|
|
1064
|
+
### Build errors
|
|
1065
|
+
- Clear \`.next\`: \`rm -rf .next\`
|
|
1066
|
+
- Clear cache: \`bun install --force\`
|
|
1067
|
+
|
|
1068
|
+
### Type errors
|
|
1069
|
+
- Restart TS server in IDE
|
|
1070
|
+
- Check \`tsconfig.json\` paths
|
|
1071
|
+
|
|
1072
|
+
## Resources
|
|
1073
|
+
|
|
1074
|
+
- [Next.js Docs](https://nextjs.org/docs)
|
|
1075
|
+
- [Tailwind Docs](https://tailwindcss.com/docs)
|
|
1076
|
+
- [shadcn/ui](https://ui.shadcn.com)
|
|
1077
|
+
${config.stack.email ? `- [Resend Docs](https://resend.com/docs)
|
|
1078
|
+
` : ""}${config.stack.auth ? `- [NextAuth Docs](https://authjs.dev)
|
|
1079
|
+
` : ""}
|
|
1080
|
+
---
|
|
1081
|
+
|
|
1082
|
+
*Generated by @nimbuslab/cli*
|
|
1083
|
+
*Last updated: ${new Date().toISOString().split("T")[0]}*
|
|
1084
|
+
`;
|
|
1085
|
+
await Bun.write(join(projectPath, "AGENTS.md"), content);
|
|
1086
|
+
}
|
|
1087
|
+
async function generateLLMsFile(projectPath, config) {
|
|
1088
|
+
const content = `# ${config.name}
|
|
1089
|
+
|
|
1090
|
+
> AI-friendly documentation index
|
|
1091
|
+
|
|
1092
|
+
## Navigation
|
|
1093
|
+
|
|
1094
|
+
- [Project Overview](./AGENTS.md)
|
|
1095
|
+
- [Architecture](./ARCHITECTURE.md)
|
|
1096
|
+
- [Examples](./EXAMPLES.md)
|
|
1097
|
+
- [Contributing](./CONTRIBUTING.md)
|
|
1098
|
+
|
|
1099
|
+
## Quick Context
|
|
1100
|
+
|
|
1101
|
+
${config.description}
|
|
1102
|
+
|
|
1103
|
+
**Stack:** ${config.stack.framework}, ${config.stack.styling}, ${config.stack.components}
|
|
1104
|
+
|
|
1105
|
+
## Common Questions
|
|
1106
|
+
|
|
1107
|
+
### How do I start development?
|
|
1108
|
+
\`\`\`bash
|
|
1109
|
+
bun install && bun dev
|
|
1110
|
+
\`\`\`
|
|
1111
|
+
|
|
1112
|
+
${config.features.contactForm ? `### How do I configure email?
|
|
1113
|
+
See [AGENTS.md#send-email](./AGENTS.md#send-email)
|
|
1114
|
+
|
|
1115
|
+
` : ""}${config.features.auth ? `### How do I set up authentication?
|
|
1116
|
+
See [AGENTS.md#environment-variables](./AGENTS.md#environment-variables)
|
|
1117
|
+
|
|
1118
|
+
` : ""}### How do I deploy?
|
|
1119
|
+
Push to \`main\` branch - auto-deploys to Vercel.
|
|
1120
|
+
|
|
1121
|
+
## File Structure
|
|
1122
|
+
|
|
1123
|
+
\`\`\`
|
|
1124
|
+
app/ # Next.js app router
|
|
1125
|
+
components/ # React components
|
|
1126
|
+
ui/ # shadcn/ui (auto-generated)
|
|
1127
|
+
lib/ # Utilities
|
|
1128
|
+
public/ # Static assets
|
|
1129
|
+
\`\`\`
|
|
1130
|
+
|
|
1131
|
+
---
|
|
1132
|
+
|
|
1133
|
+
*Auto-generated for LLM consumption*
|
|
1134
|
+
*Learn more: https://mintlify.com/blog/simplifying-docs-with-llms-txt*
|
|
1135
|
+
`;
|
|
1136
|
+
await Bun.write(join(projectPath, "llms.txt"), content);
|
|
1137
|
+
}
|
|
1138
|
+
async function generateArchitectureDoc(projectPath, config) {
|
|
1139
|
+
const content = `# Architecture
|
|
1140
|
+
|
|
1141
|
+
## Design Decisions
|
|
1142
|
+
|
|
1143
|
+
### 1. Next.js App Router
|
|
1144
|
+
|
|
1145
|
+
**Why:**
|
|
1146
|
+
- React Server Components by default
|
|
1147
|
+
- Better performance (less client JS)
|
|
1148
|
+
- Simplified data fetching
|
|
1149
|
+
- Native TypeScript support
|
|
1150
|
+
|
|
1151
|
+
**Trade-offs:**
|
|
1152
|
+
- Learning curve vs Pages Router
|
|
1153
|
+
- Some libraries require \`'use client'\`
|
|
1154
|
+
|
|
1155
|
+
### 2. ${config.stack.styling}
|
|
1156
|
+
|
|
1157
|
+
**Why:**
|
|
1158
|
+
- Zero runtime (pure CSS)
|
|
1159
|
+
- Better performance
|
|
1160
|
+
- Smaller bundle size
|
|
1161
|
+
- Familiar DX
|
|
1162
|
+
|
|
1163
|
+
${config.type === "landing" ? `### 3. Landing Page Structure
|
|
1164
|
+
|
|
1165
|
+
\`\`\`
|
|
1166
|
+
Hero
|
|
1167
|
+
\u2193
|
|
1168
|
+
Social Proof / Features
|
|
1169
|
+
\u2193
|
|
1170
|
+
How It Works
|
|
1171
|
+
\u2193
|
|
1172
|
+
Testimonials
|
|
1173
|
+
\u2193
|
|
1174
|
+
FAQ
|
|
1175
|
+
\u2193
|
|
1176
|
+
CTA
|
|
1177
|
+
\u2193
|
|
1178
|
+
Footer
|
|
1179
|
+
\`\`\`
|
|
1180
|
+
|
|
1181
|
+
` : ""}## Data Flow
|
|
1182
|
+
|
|
1183
|
+
\`\`\`
|
|
1184
|
+
User Action
|
|
1185
|
+
\u2193
|
|
1186
|
+
Client Component (onClick)
|
|
1187
|
+
\u2193
|
|
1188
|
+
${config.features.contactForm ? `Server Action / API Route
|
|
1189
|
+
\u2193
|
|
1190
|
+
Validation (Zod)
|
|
1191
|
+
\u2193
|
|
1192
|
+
` : ""}${config.stack.email ? `External API (Resend)
|
|
1193
|
+
\u2193
|
|
1194
|
+
` : ""}Response to client
|
|
1195
|
+
\`\`\`
|
|
1196
|
+
|
|
1197
|
+
## Performance Strategy
|
|
1198
|
+
|
|
1199
|
+
### 1. Server Components First
|
|
1200
|
+
- Default to Server Components
|
|
1201
|
+
- Only use Client when needed
|
|
1202
|
+
- Less JavaScript shipped
|
|
1203
|
+
|
|
1204
|
+
### 2. Image Optimization
|
|
1205
|
+
- Always use \`next/image\`
|
|
1206
|
+
- Lazy loading by default
|
|
1207
|
+
- Modern formats (WebP, AVIF)
|
|
1208
|
+
|
|
1209
|
+
### 3. Code Splitting
|
|
1210
|
+
- Dynamic imports for heavy components
|
|
1211
|
+
- Route-based splitting (automatic)
|
|
1212
|
+
|
|
1213
|
+
## Security
|
|
1214
|
+
|
|
1215
|
+
### 1. Environment Variables
|
|
1216
|
+
- Never commit \`.env\`
|
|
1217
|
+
- Use \`.env.example\` for templates
|
|
1218
|
+
- Validate on startup
|
|
1219
|
+
|
|
1220
|
+
${config.features.contactForm ? `### 2. Form Validation
|
|
1221
|
+
- Client + Server validation
|
|
1222
|
+
- Zod schemas shared
|
|
1223
|
+
- Sanitize inputs
|
|
1224
|
+
|
|
1225
|
+
` : ""}### 3. Rate Limiting
|
|
1226
|
+
- API routes protected
|
|
1227
|
+
- Per-IP limits
|
|
1228
|
+
|
|
1229
|
+
---
|
|
1230
|
+
|
|
1231
|
+
*This document explains WHY, not HOW.*
|
|
1232
|
+
*For HOW, see AGENTS.md*
|
|
1233
|
+
`;
|
|
1234
|
+
await Bun.write(join(projectPath, "ARCHITECTURE.md"), content);
|
|
1235
|
+
}
|
|
1236
|
+
async function generateExamplesDoc(projectPath, config) {
|
|
1237
|
+
const content = `# Examples
|
|
1238
|
+
|
|
1239
|
+
Common tasks with complete code examples.
|
|
1240
|
+
|
|
1241
|
+
## Adding a New Component
|
|
1242
|
+
|
|
1243
|
+
\`\`\`tsx
|
|
1244
|
+
// components/ui/card.tsx
|
|
1245
|
+
export function Card({ children, className }: {
|
|
1246
|
+
children: React.ReactNode
|
|
1247
|
+
className?: string
|
|
1248
|
+
}) {
|
|
1249
|
+
return (
|
|
1250
|
+
<div className={cn("rounded-lg border p-6", className)}>
|
|
1251
|
+
{children}
|
|
1252
|
+
</div>
|
|
1253
|
+
)
|
|
1254
|
+
}
|
|
1255
|
+
\`\`\`
|
|
1256
|
+
|
|
1257
|
+
${config.features.contactForm ? `## Form with Validation
|
|
1258
|
+
|
|
1259
|
+
\`\`\`tsx
|
|
1260
|
+
// lib/validations.ts
|
|
1261
|
+
export const contactSchema = z.object({
|
|
1262
|
+
name: z.string().min(2, 'Nome muito curto'),
|
|
1263
|
+
email: z.string().email('Email inv\xE1lido'),
|
|
1264
|
+
message: z.string().min(10, 'Mensagem muito curta'),
|
|
1265
|
+
})
|
|
1266
|
+
|
|
1267
|
+
// components/forms/contact.tsx
|
|
1268
|
+
'use client'
|
|
1269
|
+
|
|
1270
|
+
import { useForm } from 'react-hook-form'
|
|
1271
|
+
import { zodResolver } from '@hookform/resolvers/zod'
|
|
1272
|
+
|
|
1273
|
+
export function ContactForm() {
|
|
1274
|
+
const form = useForm({
|
|
1275
|
+
resolver: zodResolver(contactSchema),
|
|
1276
|
+
})
|
|
1277
|
+
|
|
1278
|
+
async function onSubmit(data) {
|
|
1279
|
+
const res = await fetch('/api/contact', {
|
|
1280
|
+
method: 'POST',
|
|
1281
|
+
body: JSON.stringify(data),
|
|
1282
|
+
})
|
|
1283
|
+
// Handle response
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
return <form onSubmit={form.handleSubmit(onSubmit)}>...</form>
|
|
1287
|
+
}
|
|
1288
|
+
\`\`\`
|
|
1289
|
+
|
|
1290
|
+
` : ""}## Adding Animation
|
|
1291
|
+
|
|
1292
|
+
\`\`\`tsx
|
|
1293
|
+
'use client'
|
|
1294
|
+
|
|
1295
|
+
import { motion } from 'framer-motion'
|
|
1296
|
+
|
|
1297
|
+
export function FadeIn({ children }: { children: React.ReactNode }) {
|
|
1298
|
+
return (
|
|
1299
|
+
<motion.div
|
|
1300
|
+
initial={{ opacity: 0, y: 20 }}
|
|
1301
|
+
animate={{ opacity: 1, y: 0 }}
|
|
1302
|
+
transition={{ duration: 0.5 }}
|
|
1303
|
+
>
|
|
1304
|
+
{children}
|
|
1305
|
+
</motion.div>
|
|
1306
|
+
)
|
|
1307
|
+
}
|
|
1308
|
+
\`\`\`
|
|
1309
|
+
|
|
1310
|
+
## Environment Variables
|
|
1311
|
+
|
|
1312
|
+
\`\`\`typescript
|
|
1313
|
+
// lib/env.ts
|
|
1314
|
+
import { z } from 'zod'
|
|
1315
|
+
|
|
1316
|
+
const envSchema = z.object({
|
|
1317
|
+
${config.stack.email ? `RESEND_API_KEY: z.string().min(1),
|
|
1318
|
+
` : ""}NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
1319
|
+
})
|
|
1320
|
+
|
|
1321
|
+
export const env = envSchema.parse(process.env)
|
|
1322
|
+
\`\`\`
|
|
1323
|
+
|
|
1324
|
+
---
|
|
1325
|
+
|
|
1326
|
+
*For more examples, see the component files*
|
|
1327
|
+
`;
|
|
1328
|
+
await Bun.write(join(projectPath, "EXAMPLES.md"), content);
|
|
1329
|
+
}
|
|
1330
|
+
async function createCompatibilitySymlinks(projectPath) {
|
|
1331
|
+
const agentsContent = await Bun.file(join(projectPath, "AGENTS.md")).text();
|
|
1332
|
+
await Bun.write(join(projectPath, ".cursorrules"), agentsContent);
|
|
1333
|
+
const githubDir = join(projectPath, ".github");
|
|
1334
|
+
await Bun.$`mkdir -p ${githubDir}`.quiet();
|
|
1335
|
+
await Bun.write(join(githubDir, "copilot-instructions.md"), agentsContent);
|
|
1336
|
+
}
|
|
1337
|
+
// src/lib/generators/interactive-setup.ts
|
|
1338
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
1339
|
+
var SERVICE_INFO = {
|
|
1340
|
+
resend: {
|
|
1341
|
+
name: "Resend",
|
|
1342
|
+
description: "Servi\xE7o de email transacional",
|
|
1343
|
+
pricing: "Gr\xE1tis: 3,000 emails/m\xEAs",
|
|
1344
|
+
signupUrl: "https://resend.com/signup",
|
|
1345
|
+
apiKeyUrl: "https://resend.com/api-keys",
|
|
1346
|
+
keyPrefix: "re_"
|
|
1347
|
+
},
|
|
1348
|
+
googleAnalytics: {
|
|
1349
|
+
name: "Google Analytics",
|
|
1350
|
+
description: "Analytics e m\xE9tricas do site",
|
|
1351
|
+
pricing: "Gr\xE1tis",
|
|
1352
|
+
setupUrl: "https://analytics.google.com",
|
|
1353
|
+
keyFormat: "G-XXXXXXXXXX"
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
async function interactiveSetup(templateType) {
|
|
1357
|
+
console.log();
|
|
1358
|
+
console.log(import_picocolors3.default.cyan(" Configura\xE7\xE3o Interativa"));
|
|
1359
|
+
console.log(import_picocolors3.default.dim(" ======================="));
|
|
1360
|
+
console.log();
|
|
1361
|
+
const skipSetup = await ye({
|
|
1362
|
+
message: "Deseja configurar integra\xE7\xF5es agora?",
|
|
1363
|
+
initialValue: true
|
|
1364
|
+
});
|
|
1365
|
+
if (pD(skipSetup) || !skipSetup) {
|
|
1366
|
+
return {
|
|
1367
|
+
features: {
|
|
1368
|
+
contactForm: false,
|
|
1369
|
+
newsletter: false,
|
|
1370
|
+
analytics: false
|
|
1371
|
+
},
|
|
1372
|
+
apiKeys: {},
|
|
1373
|
+
skipSetup: true
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
const result = {
|
|
1377
|
+
features: {
|
|
1378
|
+
contactForm: false,
|
|
1379
|
+
newsletter: false,
|
|
1380
|
+
analytics: false
|
|
1381
|
+
},
|
|
1382
|
+
apiKeys: {},
|
|
1383
|
+
skipSetup: false
|
|
1384
|
+
};
|
|
1385
|
+
if (templateType === "landing" || templateType === "app") {
|
|
1386
|
+
const contactFormSetup = await setupContactForm();
|
|
1387
|
+
if (!pD(contactFormSetup)) {
|
|
1388
|
+
result.features.contactForm = contactFormSetup.enabled;
|
|
1389
|
+
if (contactFormSetup.apiKey) {
|
|
1390
|
+
result.apiKeys.resend = contactFormSetup.apiKey;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
const analyticsSetup = await setupAnalytics();
|
|
1395
|
+
if (!pD(analyticsSetup)) {
|
|
1396
|
+
result.features.analytics = analyticsSetup.enabled;
|
|
1397
|
+
if (analyticsSetup.trackingId) {
|
|
1398
|
+
result.apiKeys.ga = analyticsSetup.trackingId;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
return result;
|
|
1402
|
+
}
|
|
1403
|
+
async function setupContactForm() {
|
|
1404
|
+
console.log();
|
|
1405
|
+
console.log(import_picocolors3.default.cyan(" \uD83D\uDCE7 Formul\xE1rio de Contato"));
|
|
1406
|
+
console.log();
|
|
1407
|
+
const needsForm = await ve({
|
|
1408
|
+
message: "Incluir formul\xE1rio de contato?",
|
|
1409
|
+
options: [
|
|
1410
|
+
{ value: "now", label: "Sim, configurar agora" },
|
|
1411
|
+
{ value: "later", label: "Sim, mas configurar depois" },
|
|
1412
|
+
{ value: "no", label: "N\xE3o incluir" }
|
|
1413
|
+
]
|
|
1414
|
+
});
|
|
1415
|
+
if (pD(needsForm) || needsForm === "no") {
|
|
1416
|
+
return { enabled: false };
|
|
1417
|
+
}
|
|
1418
|
+
if (needsForm === "later") {
|
|
1419
|
+
return { enabled: true };
|
|
1420
|
+
}
|
|
1421
|
+
showServiceInfo("resend");
|
|
1422
|
+
const apiKey = await he({
|
|
1423
|
+
message: "Resend API Key (deixe vazio para configurar depois):",
|
|
1424
|
+
placeholder: "re_...",
|
|
1425
|
+
validate: (v2) => {
|
|
1426
|
+
if (!v2)
|
|
1427
|
+
return;
|
|
1428
|
+
if (!v2.startsWith(SERVICE_INFO.resend.keyPrefix)) {
|
|
1429
|
+
return `Key inv\xE1lida (deve come\xE7ar com ${SERVICE_INFO.resend.keyPrefix})`;
|
|
1430
|
+
}
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
});
|
|
1434
|
+
if (pD(apiKey)) {
|
|
1435
|
+
return { enabled: true };
|
|
1436
|
+
}
|
|
1437
|
+
return {
|
|
1438
|
+
enabled: true,
|
|
1439
|
+
apiKey: apiKey || undefined
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
async function setupAnalytics() {
|
|
1443
|
+
console.log();
|
|
1444
|
+
console.log(import_picocolors3.default.cyan(" \uD83D\uDCCA Analytics"));
|
|
1445
|
+
console.log();
|
|
1446
|
+
const needsAnalytics = await ye({
|
|
1447
|
+
message: "Incluir Google Analytics?",
|
|
1448
|
+
initialValue: false
|
|
1449
|
+
});
|
|
1450
|
+
if (pD(needsAnalytics) || !needsAnalytics) {
|
|
1451
|
+
return { enabled: false };
|
|
1452
|
+
}
|
|
1453
|
+
showServiceInfo("googleAnalytics");
|
|
1454
|
+
const trackingId = await he({
|
|
1455
|
+
message: "Google Analytics Tracking ID (deixe vazio para configurar depois):",
|
|
1456
|
+
placeholder: "G-XXXXXXXXXX",
|
|
1457
|
+
validate: (v2) => {
|
|
1458
|
+
if (!v2)
|
|
1459
|
+
return;
|
|
1460
|
+
if (!v2.startsWith("G-")) {
|
|
1461
|
+
return "ID inv\xE1lido (deve come\xE7ar com G-)";
|
|
1462
|
+
}
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
if (pD(trackingId)) {
|
|
1467
|
+
return { enabled: false };
|
|
1468
|
+
}
|
|
1469
|
+
return {
|
|
1470
|
+
enabled: true,
|
|
1471
|
+
trackingId: trackingId || undefined
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
function showServiceInfo(service) {
|
|
1475
|
+
const info = SERVICE_INFO[service];
|
|
1476
|
+
console.log();
|
|
1477
|
+
console.log(import_picocolors3.default.bold(` ${info.name}`));
|
|
1478
|
+
console.log(import_picocolors3.default.dim(` ${info.description}`));
|
|
1479
|
+
console.log(import_picocolors3.default.dim(` ${info.pricing}`));
|
|
1480
|
+
if ("apiKeyUrl" in info) {
|
|
1481
|
+
console.log(import_picocolors3.default.cyan(` ${info.apiKeyUrl}`));
|
|
1482
|
+
} else if ("setupUrl" in info) {
|
|
1483
|
+
console.log(import_picocolors3.default.cyan(` ${info.setupUrl}`));
|
|
1484
|
+
}
|
|
1485
|
+
console.log();
|
|
1486
|
+
}
|
|
1487
|
+
async function generateEnvFile(projectPath, apiKeys, features) {
|
|
1488
|
+
const lines = [
|
|
1489
|
+
"# ====================================",
|
|
1490
|
+
"# Environment Variables",
|
|
1491
|
+
"# ====================================",
|
|
1492
|
+
"",
|
|
1493
|
+
"# IMPORTANT: Add this file to .gitignore",
|
|
1494
|
+
"# Never commit API keys to version control!",
|
|
1495
|
+
""
|
|
1496
|
+
];
|
|
1497
|
+
if (features.contactForm) {
|
|
1498
|
+
lines.push("# Email (Resend)");
|
|
1499
|
+
lines.push("# Get your key: https://resend.com/api-keys");
|
|
1500
|
+
lines.push(`RESEND_API_KEY=${apiKeys.resend || "your_api_key_here"}`);
|
|
1501
|
+
lines.push("");
|
|
1502
|
+
}
|
|
1503
|
+
if (features.analytics) {
|
|
1504
|
+
lines.push("# Analytics (Google Analytics)");
|
|
1505
|
+
lines.push("# Get your ID: https://analytics.google.com");
|
|
1506
|
+
lines.push(`NEXT_PUBLIC_GA_ID=${apiKeys.ga || "G-XXXXXXXXXX"}`);
|
|
1507
|
+
lines.push("");
|
|
1508
|
+
}
|
|
1509
|
+
lines.push("# ====================================");
|
|
1510
|
+
lines.push("# Docs completa em README.md");
|
|
1511
|
+
lines.push("# ====================================");
|
|
1512
|
+
const content = lines.join(`
|
|
1513
|
+
`);
|
|
1514
|
+
await Bun.write(`${projectPath}/.env`, content);
|
|
1515
|
+
const exampleLines = lines.map((line) => {
|
|
1516
|
+
if (line.includes("RESEND_API_KEY=") && !line.startsWith("#")) {
|
|
1517
|
+
return "RESEND_API_KEY=re_your_key_here";
|
|
1518
|
+
}
|
|
1519
|
+
if (line.includes("NEXT_PUBLIC_GA_ID=") && !line.startsWith("#")) {
|
|
1520
|
+
return "NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX";
|
|
1521
|
+
}
|
|
1522
|
+
return line;
|
|
1523
|
+
});
|
|
1524
|
+
await Bun.write(`${projectPath}/.env.example`, exampleLines.join(`
|
|
1525
|
+
`));
|
|
1526
|
+
}
|
|
1527
|
+
// src/commands/create.ts
|
|
872
1528
|
var AI_CONFIGS = {
|
|
873
1529
|
claude: {
|
|
874
1530
|
filename: "CLAUDE.md",
|
|
@@ -1068,7 +1724,7 @@ async function ensureRailwayCli() {
|
|
|
1068
1724
|
const hasRailway = await $2`${checkCmd} railway`.quiet().then(() => true).catch(() => false);
|
|
1069
1725
|
if (hasRailway)
|
|
1070
1726
|
return true;
|
|
1071
|
-
console.log(
|
|
1727
|
+
console.log(import_picocolors4.default.yellow("Railway CLI not found. Installing..."));
|
|
1072
1728
|
console.log();
|
|
1073
1729
|
try {
|
|
1074
1730
|
if (process.platform === "win32") {
|
|
@@ -1076,11 +1732,11 @@ async function ensureRailwayCli() {
|
|
|
1076
1732
|
} else {
|
|
1077
1733
|
await $2`curl -fsSL https://railway.app/install.sh | sh`.quiet();
|
|
1078
1734
|
}
|
|
1079
|
-
console.log(
|
|
1735
|
+
console.log(import_picocolors4.default.green("Railway CLI installed successfully!"));
|
|
1080
1736
|
return true;
|
|
1081
1737
|
} catch (error) {
|
|
1082
|
-
console.log(
|
|
1083
|
-
console.log(
|
|
1738
|
+
console.log(import_picocolors4.default.red("Error installing Railway CLI."));
|
|
1739
|
+
console.log(import_picocolors4.default.dim("Install manually: https://docs.railway.app/guides/cli"));
|
|
1084
1740
|
return false;
|
|
1085
1741
|
}
|
|
1086
1742
|
}
|
|
@@ -1108,38 +1764,38 @@ async function create(args) {
|
|
|
1108
1764
|
const hasGit = await $2`${checkCmd} git`.quiet().then(() => true).catch(() => false);
|
|
1109
1765
|
const hasGh = await $2`${checkCmd} gh`.quiet().then(() => true).catch(() => false);
|
|
1110
1766
|
if (!hasBun) {
|
|
1111
|
-
console.log(
|
|
1112
|
-
console.log(
|
|
1767
|
+
console.log(import_picocolors4.default.red("Error: Bun not found."));
|
|
1768
|
+
console.log(import_picocolors4.default.dim("Install from: https://bun.sh"));
|
|
1113
1769
|
console.log();
|
|
1114
1770
|
if (process.platform === "win32") {
|
|
1115
|
-
console.log(
|
|
1771
|
+
console.log(import_picocolors4.default.cyan('powershell -c "irm bun.sh/install.ps1 | iex"'));
|
|
1116
1772
|
} else {
|
|
1117
|
-
console.log(
|
|
1773
|
+
console.log(import_picocolors4.default.cyan("curl -fsSL https://bun.sh/install | bash"));
|
|
1118
1774
|
}
|
|
1119
1775
|
console.log();
|
|
1120
1776
|
process.exit(1);
|
|
1121
1777
|
}
|
|
1122
1778
|
if (!hasGit) {
|
|
1123
|
-
console.log(
|
|
1124
|
-
console.log(
|
|
1779
|
+
console.log(import_picocolors4.default.red("Error: Git not found."));
|
|
1780
|
+
console.log(import_picocolors4.default.dim("Install git to continue."));
|
|
1125
1781
|
process.exit(1);
|
|
1126
1782
|
}
|
|
1127
1783
|
if (!hasGh) {
|
|
1128
|
-
console.log(
|
|
1129
|
-
console.log(
|
|
1784
|
+
console.log(import_picocolors4.default.dim(" GitHub CLI not found (repo creation will be skipped)"));
|
|
1785
|
+
console.log(import_picocolors4.default.dim(" Install from: https://cli.github.com"));
|
|
1130
1786
|
console.log();
|
|
1131
1787
|
}
|
|
1132
1788
|
const hasRailway = await ensureRailwayCli();
|
|
1133
1789
|
if (hasRailway) {
|
|
1134
1790
|
const railwayAuth = await isRailwayAuthenticated();
|
|
1135
1791
|
if (!railwayAuth) {
|
|
1136
|
-
console.log(
|
|
1137
|
-
console.log(
|
|
1792
|
+
console.log(import_picocolors4.default.yellow("Railway CLI not authenticated."));
|
|
1793
|
+
console.log(import_picocolors4.default.dim("Run: railway login"));
|
|
1138
1794
|
console.log();
|
|
1139
1795
|
}
|
|
1140
1796
|
}
|
|
1141
1797
|
const { flags, projectName } = parseFlags(args);
|
|
1142
|
-
Ie(
|
|
1798
|
+
Ie(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" New nimbuslab Project ")));
|
|
1143
1799
|
let config;
|
|
1144
1800
|
const hasTypeFlag = flags.landing || flags.app || flags.turborepo || flags.fast || flags.fastPlus || flags.fastTurborepo || flags.core;
|
|
1145
1801
|
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 +1824,14 @@ async function create(args) {
|
|
|
1168
1824
|
customTemplate: flags.template
|
|
1169
1825
|
};
|
|
1170
1826
|
const typeLabel = flags.turborepo ? "fast+ (monorepo)" : config.type;
|
|
1171
|
-
console.log(
|
|
1172
|
-
console.log(
|
|
1173
|
-
console.log(
|
|
1174
|
-
console.log(
|
|
1827
|
+
console.log(import_picocolors4.default.dim(` Project: ${projectName}`));
|
|
1828
|
+
console.log(import_picocolors4.default.dim(` Type: ${typeLabel}`));
|
|
1829
|
+
console.log(import_picocolors4.default.dim(` Git: ${config.git ? "yes" : "no"}`));
|
|
1830
|
+
console.log(import_picocolors4.default.dim(` Install: ${config.install ? "yes" : "no"}`));
|
|
1175
1831
|
if (flags.railway)
|
|
1176
|
-
console.log(
|
|
1832
|
+
console.log(import_picocolors4.default.dim(` Railway: configurar`));
|
|
1177
1833
|
if (flags.template)
|
|
1178
|
-
console.log(
|
|
1834
|
+
console.log(import_picocolors4.default.dim(` Template: ${flags.template}`));
|
|
1179
1835
|
console.log();
|
|
1180
1836
|
if (flags.railway) {
|
|
1181
1837
|
const railwayAuthenticated = await isRailwayAuthenticated();
|
|
@@ -1185,21 +1841,21 @@ async function create(args) {
|
|
|
1185
1841
|
const fastProject = projects.find((p2) => p2.toLowerCase().includes("fast by nimbuslab"));
|
|
1186
1842
|
if (fastProject) {
|
|
1187
1843
|
config.railwayProject = fastProject;
|
|
1188
|
-
console.log(
|
|
1844
|
+
console.log(import_picocolors4.default.green(` Railway: ${fastProject}`));
|
|
1189
1845
|
}
|
|
1190
1846
|
} else {
|
|
1191
|
-
console.log(
|
|
1847
|
+
console.log(import_picocolors4.default.dim(` Creating project Railway: ${projectName}...`));
|
|
1192
1848
|
try {
|
|
1193
1849
|
const result = await $2`echo "" | railway init -n ${projectName} -w nimbuslab --json`.text();
|
|
1194
1850
|
const newProject = JSON.parse(result);
|
|
1195
1851
|
config.railwayProject = newProject.name || projectName;
|
|
1196
|
-
console.log(
|
|
1852
|
+
console.log(import_picocolors4.default.green(` Railway: ${config.railwayProject} criado`));
|
|
1197
1853
|
} catch {
|
|
1198
|
-
console.log(
|
|
1854
|
+
console.log(import_picocolors4.default.yellow(` Railway: erro ao criar projeto`));
|
|
1199
1855
|
}
|
|
1200
1856
|
}
|
|
1201
1857
|
} else {
|
|
1202
|
-
console.log(
|
|
1858
|
+
console.log(import_picocolors4.default.yellow(` Railway: not authenticated (railway login)`));
|
|
1203
1859
|
}
|
|
1204
1860
|
console.log();
|
|
1205
1861
|
}
|
|
@@ -1211,13 +1867,58 @@ async function create(args) {
|
|
|
1211
1867
|
process.exit(0);
|
|
1212
1868
|
}
|
|
1213
1869
|
await createProject(config);
|
|
1214
|
-
|
|
1870
|
+
const finalConfig = config;
|
|
1871
|
+
const isPublicTemplate = ["landing", "app", "turborepo"].includes(finalConfig.type);
|
|
1872
|
+
if (isPublicTemplate) {
|
|
1873
|
+
const s = Y2();
|
|
1874
|
+
s.start("Configura\xE7\xE3o de servi\xE7os...");
|
|
1875
|
+
const setupResult = await interactiveSetup(finalConfig.type);
|
|
1876
|
+
s.stop("Configura\xE7\xE3o conclu\xEDda");
|
|
1877
|
+
s.start("Gerando documenta\xE7\xE3o AI-friendly...");
|
|
1878
|
+
try {
|
|
1879
|
+
const generatorConfig = {
|
|
1880
|
+
name: finalConfig.name,
|
|
1881
|
+
type: finalConfig.type,
|
|
1882
|
+
description: finalConfig.githubDescription || `${finalConfig.type} criado com nimbus-cli`,
|
|
1883
|
+
stack: {
|
|
1884
|
+
framework: "Next.js 16 (App Router)",
|
|
1885
|
+
styling: "Tailwind CSS 4",
|
|
1886
|
+
components: "shadcn/ui (default)",
|
|
1887
|
+
forms: setupResult.features.contactForm ? "React Hook Form + Zod" : undefined,
|
|
1888
|
+
email: setupResult.features.contactForm ? "Resend" : undefined,
|
|
1889
|
+
auth: finalConfig.type === "app" ? "Better Auth" : undefined
|
|
1890
|
+
},
|
|
1891
|
+
features: {
|
|
1892
|
+
contactForm: setupResult.features.contactForm,
|
|
1893
|
+
newsletter: setupResult.features.newsletter,
|
|
1894
|
+
analytics: setupResult.features.analytics,
|
|
1895
|
+
auth: finalConfig.type === "app"
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
await generateAIFriendlyDocs(finalConfig.name, generatorConfig);
|
|
1899
|
+
s.stop("Documenta\xE7\xE3o AI-friendly gerada");
|
|
1900
|
+
} catch (error) {
|
|
1901
|
+
s.stop("Erro ao gerar documenta\xE7\xE3o AI-friendly");
|
|
1902
|
+
console.log(import_picocolors4.default.dim(" Voc\xEA pode gerar manualmente depois"));
|
|
1903
|
+
}
|
|
1904
|
+
if (!setupResult.skipSetup && (setupResult.apiKeys.resend || setupResult.apiKeys.ga)) {
|
|
1905
|
+
s.start("Gerando arquivos .env...");
|
|
1906
|
+
try {
|
|
1907
|
+
await generateEnvFile(finalConfig.name, setupResult.apiKeys, setupResult.features);
|
|
1908
|
+
s.stop("Arquivos .env gerados (.env e .env.example)");
|
|
1909
|
+
} catch (error) {
|
|
1910
|
+
s.stop("Erro ao gerar .env");
|
|
1911
|
+
console.log(import_picocolors4.default.dim(" Voc\xEA pode criar manualmente depois"));
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
Se(import_picocolors4.default.green("Project created successfully!"));
|
|
1215
1916
|
showNextSteps(config);
|
|
1216
1917
|
}
|
|
1217
1918
|
async function promptConfig(initialName, flags) {
|
|
1218
1919
|
const { isMember, user } = await isNimbuslabMember();
|
|
1219
1920
|
const greeting = user ? `Hello, ${user}!` : "Hello!";
|
|
1220
|
-
console.log(
|
|
1921
|
+
console.log(import_picocolors4.default.dim(` ${greeting}`));
|
|
1221
1922
|
console.log();
|
|
1222
1923
|
const name = await he({
|
|
1223
1924
|
message: "Project name:",
|
|
@@ -1276,12 +1977,12 @@ async function promptConfig(initialName, flags) {
|
|
|
1276
1977
|
return type;
|
|
1277
1978
|
const isPublicTemplate = ["landing", "app", "turborepo"].includes(type);
|
|
1278
1979
|
if (!isMember && !isPublicTemplate) {
|
|
1279
|
-
console.log(
|
|
1980
|
+
console.log(import_picocolors4.default.red("Error: Template available only for nimbuslab members"));
|
|
1280
1981
|
process.exit(1);
|
|
1281
1982
|
}
|
|
1282
1983
|
if (type === "nimbus-core") {
|
|
1283
1984
|
console.log();
|
|
1284
|
-
console.log(
|
|
1985
|
+
console.log(import_picocolors4.default.dim(" nimbus-core: Motor para projetos externos (stealth mode)"));
|
|
1285
1986
|
console.log();
|
|
1286
1987
|
const repoOption = await ve({
|
|
1287
1988
|
message: "Create repository for this project?",
|
|
@@ -1496,7 +2197,7 @@ async function promptConfig(initialName, flags) {
|
|
|
1496
2197
|
const configItems = infraOptions;
|
|
1497
2198
|
if (configItems.includes("urls")) {
|
|
1498
2199
|
console.log();
|
|
1499
|
-
console.log(
|
|
2200
|
+
console.log(import_picocolors4.default.dim(" Project URLs"));
|
|
1500
2201
|
const staging = await he({
|
|
1501
2202
|
message: "Staging URL:",
|
|
1502
2203
|
placeholder: defaultStagingUrl,
|
|
@@ -1516,7 +2217,7 @@ async function promptConfig(initialName, flags) {
|
|
|
1516
2217
|
}
|
|
1517
2218
|
if (configItems.includes("resend")) {
|
|
1518
2219
|
console.log();
|
|
1519
|
-
console.log(
|
|
2220
|
+
console.log(import_picocolors4.default.dim(" Resend (Email)"));
|
|
1520
2221
|
const resendKey = await he({
|
|
1521
2222
|
message: "RESEND_API_KEY:",
|
|
1522
2223
|
placeholder: "re_xxxxxxxxxxxx"
|
|
@@ -1545,16 +2246,16 @@ async function promptConfig(initialName, flags) {
|
|
|
1545
2246
|
const railwayAuthenticated = await isRailwayAuthenticated();
|
|
1546
2247
|
if (railwayAuthenticated) {
|
|
1547
2248
|
console.log();
|
|
1548
|
-
console.log(
|
|
2249
|
+
console.log(import_picocolors4.default.dim(" Railway"));
|
|
1549
2250
|
const projects = await listRailwayProjects();
|
|
1550
2251
|
if (type === "fast") {
|
|
1551
2252
|
const fastProject = projects.find((p2) => p2.toLowerCase().includes("fast by nimbuslab"));
|
|
1552
2253
|
if (fastProject) {
|
|
1553
2254
|
railwayProject = fastProject;
|
|
1554
|
-
console.log(
|
|
2255
|
+
console.log(import_picocolors4.default.green(` Project: ${fastProject} (automatico)`));
|
|
1555
2256
|
} else {
|
|
1556
|
-
console.log(
|
|
1557
|
-
console.log(
|
|
2257
|
+
console.log(import_picocolors4.default.yellow(" Project 'Fast by nimbuslab' not found."));
|
|
2258
|
+
console.log(import_picocolors4.default.dim(" Configure manually in .env"));
|
|
1558
2259
|
}
|
|
1559
2260
|
} else {
|
|
1560
2261
|
const projectOptions = [
|
|
@@ -1570,26 +2271,26 @@ async function promptConfig(initialName, flags) {
|
|
|
1570
2271
|
return selectedProject;
|
|
1571
2272
|
if (selectedProject === "__new__") {
|
|
1572
2273
|
const projectNameForRailway = name;
|
|
1573
|
-
console.log(
|
|
2274
|
+
console.log(import_picocolors4.default.dim(` Creating project "${projectNameForRailway}" on Railway...`));
|
|
1574
2275
|
try {
|
|
1575
2276
|
const result = await $2`echo "" | railway init -n ${projectNameForRailway} -w nimbuslab --json`.text();
|
|
1576
2277
|
const newProject = JSON.parse(result);
|
|
1577
2278
|
railwayProject = newProject.name || projectNameForRailway;
|
|
1578
|
-
console.log(
|
|
1579
|
-
console.log(
|
|
2279
|
+
console.log(import_picocolors4.default.green(` Projeto "${railwayProject}" created successfully!`));
|
|
2280
|
+
console.log(import_picocolors4.default.dim(` ID: ${newProject.id || "N/A"}`));
|
|
1580
2281
|
} catch (error) {
|
|
1581
|
-
console.log(
|
|
1582
|
-
console.log(
|
|
2282
|
+
console.log(import_picocolors4.default.yellow(" Error creating project via CLI."));
|
|
2283
|
+
console.log(import_picocolors4.default.dim(" Create manually at: https://railway.app/new"));
|
|
1583
2284
|
}
|
|
1584
2285
|
} else if (selectedProject !== "__skip__") {
|
|
1585
2286
|
railwayProject = selectedProject;
|
|
1586
|
-
console.log(
|
|
2287
|
+
console.log(import_picocolors4.default.green(` Project selected: ${railwayProject}`));
|
|
1587
2288
|
}
|
|
1588
2289
|
}
|
|
1589
2290
|
} else {
|
|
1590
2291
|
console.log();
|
|
1591
|
-
console.log(
|
|
1592
|
-
console.log(
|
|
2292
|
+
console.log(import_picocolors4.default.yellow(" Railway: not authenticated (railway login)"));
|
|
2293
|
+
console.log(import_picocolors4.default.dim(" Configure manually in .env"));
|
|
1593
2294
|
}
|
|
1594
2295
|
}
|
|
1595
2296
|
const install = await ye({
|
|
@@ -1641,7 +2342,7 @@ async function createProject(config) {
|
|
|
1641
2342
|
} else {
|
|
1642
2343
|
await $2`gh repo clone ${templateRepo} ${config.name} -- --depth 1`.quiet();
|
|
1643
2344
|
}
|
|
1644
|
-
await rm(
|
|
2345
|
+
await rm(join2(config.name, ".git"), { recursive: true, force: true });
|
|
1645
2346
|
s.stop(`Template cloned`);
|
|
1646
2347
|
} catch (error) {
|
|
1647
2348
|
s.stop("Error cloning template");
|
|
@@ -1662,7 +2363,7 @@ async function createProject(config) {
|
|
|
1662
2363
|
s.stop(`Client repo cloned: workspace/${projectName}`);
|
|
1663
2364
|
} catch (error) {
|
|
1664
2365
|
s.stop("Error cloning client repo");
|
|
1665
|
-
console.log(
|
|
2366
|
+
console.log(import_picocolors4.default.dim(" You can clone manually: cd workspace && git clone <url>"));
|
|
1666
2367
|
}
|
|
1667
2368
|
}
|
|
1668
2369
|
if (config.type !== "nimbus-core") {
|
|
@@ -1751,7 +2452,7 @@ async function createProject(config) {
|
|
|
1751
2452
|
s.stop(`GitHub: ${repoName}`);
|
|
1752
2453
|
} catch (error) {
|
|
1753
2454
|
s.stop("Error creating GitHub repository");
|
|
1754
|
-
console.log(
|
|
2455
|
+
console.log(import_picocolors4.default.dim(" You can create manually with: gh repo create"));
|
|
1755
2456
|
}
|
|
1756
2457
|
}
|
|
1757
2458
|
}
|
|
@@ -1762,13 +2463,13 @@ async function createProject(config) {
|
|
|
1762
2463
|
s.stop(`Railway linkado: ${config.railwayProject}`);
|
|
1763
2464
|
} catch (error) {
|
|
1764
2465
|
s.stop("Error linking Railway");
|
|
1765
|
-
console.log(
|
|
2466
|
+
console.log(import_picocolors4.default.dim(" Run manually: railway link"));
|
|
1766
2467
|
}
|
|
1767
2468
|
}
|
|
1768
2469
|
if (config.resendApiKey || config.stagingUrl) {
|
|
1769
2470
|
s.start("Gerando arquivo .env...");
|
|
1770
2471
|
try {
|
|
1771
|
-
const envContent =
|
|
2472
|
+
const envContent = generateEnvFile2(config);
|
|
1772
2473
|
await Bun.write(`${config.name}/.env`, envContent);
|
|
1773
2474
|
s.stop("Arquivo .env criado");
|
|
1774
2475
|
} catch (error) {
|
|
@@ -1785,7 +2486,7 @@ async function createProject(config) {
|
|
|
1785
2486
|
}
|
|
1786
2487
|
}
|
|
1787
2488
|
}
|
|
1788
|
-
function
|
|
2489
|
+
function generateEnvFile2(config) {
|
|
1789
2490
|
const lines = [
|
|
1790
2491
|
"# Gerado automaticamente pelo nimbus-cli",
|
|
1791
2492
|
"# Nao commitar este arquivo!",
|
|
@@ -1828,58 +2529,58 @@ function showNextSteps(config) {
|
|
|
1828
2529
|
const isPublicTemplate = ["landing", "app", "turborepo"].includes(config.type);
|
|
1829
2530
|
const needsSetup = config.type === "app";
|
|
1830
2531
|
console.log();
|
|
1831
|
-
console.log(
|
|
2532
|
+
console.log(import_picocolors4.default.bold("Next steps:"));
|
|
1832
2533
|
console.log();
|
|
1833
|
-
console.log(` ${
|
|
2534
|
+
console.log(` ${import_picocolors4.default.cyan("cd")} ${config.name}`);
|
|
1834
2535
|
if (config.type === "nimbus-core") {
|
|
1835
2536
|
console.log();
|
|
1836
|
-
console.log(
|
|
2537
|
+
console.log(import_picocolors4.default.dim(" nimbus-core: Motor para projetos externos"));
|
|
1837
2538
|
console.log();
|
|
1838
|
-
console.log(
|
|
1839
|
-
console.log(` ${
|
|
2539
|
+
console.log(import_picocolors4.default.dim(" Para usar a Lola:"));
|
|
2540
|
+
console.log(` ${import_picocolors4.default.cyan("lola")}`);
|
|
1840
2541
|
console.log();
|
|
1841
|
-
console.log(
|
|
2542
|
+
console.log(import_picocolors4.default.yellow(" STEALTH MODE: Commits sem mencao a nimbuslab/Lola/IA"));
|
|
1842
2543
|
console.log();
|
|
1843
2544
|
if (config.github) {
|
|
1844
2545
|
const repoUrl = `https://github.com/nimbuslab/${config.name}`;
|
|
1845
|
-
console.log(
|
|
2546
|
+
console.log(import_picocolors4.default.green(` GitHub (private): ${repoUrl}`));
|
|
1846
2547
|
console.log();
|
|
1847
2548
|
}
|
|
1848
|
-
console.log(
|
|
2549
|
+
console.log(import_picocolors4.default.dim(" Docs: See README.md for full instructions"));
|
|
1849
2550
|
console.log();
|
|
1850
2551
|
return;
|
|
1851
2552
|
}
|
|
1852
2553
|
if (!config.install) {
|
|
1853
|
-
console.log(` ${
|
|
2554
|
+
console.log(` ${import_picocolors4.default.cyan("bun")} install`);
|
|
1854
2555
|
}
|
|
1855
2556
|
if (!isPublicTemplate || needsSetup) {
|
|
1856
|
-
console.log(` ${
|
|
2557
|
+
console.log(` ${import_picocolors4.default.cyan("bun")} setup`);
|
|
1857
2558
|
}
|
|
1858
|
-
console.log(` ${
|
|
2559
|
+
console.log(` ${import_picocolors4.default.cyan("bun")} dev`);
|
|
1859
2560
|
console.log();
|
|
1860
2561
|
if (needsSetup && isPublicTemplate) {
|
|
1861
|
-
console.log(
|
|
1862
|
-
console.log(
|
|
1863
|
-
console.log(
|
|
1864
|
-
console.log(
|
|
2562
|
+
console.log(import_picocolors4.default.dim(" bun setup will:"));
|
|
2563
|
+
console.log(import_picocolors4.default.dim(" - Start PostgreSQL with Docker"));
|
|
2564
|
+
console.log(import_picocolors4.default.dim(" - Run database migrations"));
|
|
2565
|
+
console.log(import_picocolors4.default.dim(" - Create demo user (demo@example.com / demo1234)"));
|
|
1865
2566
|
console.log();
|
|
1866
2567
|
}
|
|
1867
2568
|
if (config.git) {
|
|
1868
|
-
console.log(
|
|
2569
|
+
console.log(import_picocolors4.default.dim(" Git: main -> staging -> develop (current branch)"));
|
|
1869
2570
|
if (config.github) {
|
|
1870
2571
|
const repoUrl = config.githubOrg ? `https://github.com/${config.githubOrg}/${config.name}` : `https://github.com/${config.name}`;
|
|
1871
|
-
console.log(
|
|
2572
|
+
console.log(import_picocolors4.default.green(` GitHub: ${repoUrl}`));
|
|
1872
2573
|
}
|
|
1873
2574
|
console.log();
|
|
1874
2575
|
}
|
|
1875
2576
|
if (isPublicTemplate) {
|
|
1876
2577
|
if (config.theme !== "dark") {
|
|
1877
|
-
console.log(
|
|
2578
|
+
console.log(import_picocolors4.default.dim(` Theme: ${config.theme}`));
|
|
1878
2579
|
}
|
|
1879
2580
|
if (config.aiAssistant) {
|
|
1880
2581
|
const aiConfig = AI_CONFIGS[config.aiAssistant];
|
|
1881
2582
|
if (aiConfig) {
|
|
1882
|
-
console.log(
|
|
2583
|
+
console.log(import_picocolors4.default.dim(` AI config: ${aiConfig.filename}`));
|
|
1883
2584
|
}
|
|
1884
2585
|
}
|
|
1885
2586
|
if (config.theme !== "dark" || config.aiAssistant) {
|
|
@@ -1887,56 +2588,56 @@ function showNextSteps(config) {
|
|
|
1887
2588
|
}
|
|
1888
2589
|
}
|
|
1889
2590
|
if (config.type === "fast+") {
|
|
1890
|
-
console.log(
|
|
1891
|
-
console.log(
|
|
1892
|
-
console.log(
|
|
1893
|
-
console.log(
|
|
2591
|
+
console.log(import_picocolors4.default.dim(" bun setup will:"));
|
|
2592
|
+
console.log(import_picocolors4.default.dim(" - Start PostgreSQL with Docker"));
|
|
2593
|
+
console.log(import_picocolors4.default.dim(" - Run database migrations"));
|
|
2594
|
+
console.log(import_picocolors4.default.dim(" - Create demo user (demo@example.com / demo1234)"));
|
|
1894
2595
|
console.log();
|
|
1895
|
-
console.log(
|
|
2596
|
+
console.log(import_picocolors4.default.dim(" Tip: Configure DATABASE_URL and BETTER_AUTH_SECRET in .env"));
|
|
1896
2597
|
if (!config.railwayToken) {
|
|
1897
|
-
console.log(
|
|
2598
|
+
console.log(import_picocolors4.default.dim(" Railway: Create a project at https://railway.app/new"));
|
|
1898
2599
|
}
|
|
1899
2600
|
console.log();
|
|
1900
2601
|
}
|
|
1901
2602
|
if (!isPublicTemplate) {
|
|
1902
2603
|
if (config.resendApiKey || config.stagingUrl) {
|
|
1903
|
-
console.log(
|
|
2604
|
+
console.log(import_picocolors4.default.green(" .env configured!"));
|
|
1904
2605
|
console.log();
|
|
1905
2606
|
} else {
|
|
1906
|
-
console.log(
|
|
2607
|
+
console.log(import_picocolors4.default.yellow(" Tip: Configure .env manually or use 'bun setup'."));
|
|
1907
2608
|
console.log();
|
|
1908
2609
|
}
|
|
1909
2610
|
}
|
|
1910
2611
|
if (isPublicTemplate) {
|
|
1911
|
-
console.log(
|
|
1912
|
-
console.log(
|
|
2612
|
+
console.log(import_picocolors4.default.dim(" Open source template (MIT) by nimbuslab"));
|
|
2613
|
+
console.log(import_picocolors4.default.dim(` https://github.com/nimbuslab/create-next-${config.type === "turborepo" ? "turborepo" : config.type}`));
|
|
1913
2614
|
} else {
|
|
1914
|
-
console.log(
|
|
2615
|
+
console.log(import_picocolors4.default.dim(" https://github.com/nimbuslab-templates"));
|
|
1915
2616
|
}
|
|
1916
2617
|
console.log();
|
|
1917
2618
|
}
|
|
1918
2619
|
|
|
1919
2620
|
// src/commands/analyze.ts
|
|
1920
|
-
var
|
|
2621
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
1921
2622
|
import { existsSync, readFileSync } from "fs";
|
|
1922
|
-
import { join as
|
|
2623
|
+
import { join as join3 } from "path";
|
|
1923
2624
|
function detectPackageManager(dir) {
|
|
1924
|
-
if (existsSync(
|
|
2625
|
+
if (existsSync(join3(dir, "bun.lockb")))
|
|
1925
2626
|
return "bun";
|
|
1926
|
-
if (existsSync(
|
|
2627
|
+
if (existsSync(join3(dir, "pnpm-lock.yaml")))
|
|
1927
2628
|
return "pnpm";
|
|
1928
|
-
if (existsSync(
|
|
2629
|
+
if (existsSync(join3(dir, "yarn.lock")))
|
|
1929
2630
|
return "yarn";
|
|
1930
|
-
if (existsSync(
|
|
2631
|
+
if (existsSync(join3(dir, "package-lock.json")))
|
|
1931
2632
|
return "npm";
|
|
1932
2633
|
return "unknown";
|
|
1933
2634
|
}
|
|
1934
2635
|
function detectMonorepo(dir, pkg) {
|
|
1935
|
-
if (existsSync(
|
|
2636
|
+
if (existsSync(join3(dir, "turbo.json")))
|
|
1936
2637
|
return "turborepo";
|
|
1937
|
-
if (existsSync(
|
|
2638
|
+
if (existsSync(join3(dir, "nx.json")))
|
|
1938
2639
|
return "nx";
|
|
1939
|
-
if (existsSync(
|
|
2640
|
+
if (existsSync(join3(dir, "lerna.json")))
|
|
1940
2641
|
return "lerna";
|
|
1941
2642
|
if (pkg.workspaces)
|
|
1942
2643
|
return "workspaces";
|
|
@@ -2041,14 +2742,14 @@ function generateRecommendations(result) {
|
|
|
2041
2742
|
}
|
|
2042
2743
|
async function analyze(args) {
|
|
2043
2744
|
const targetDir = args[0] || ".";
|
|
2044
|
-
const absoluteDir = targetDir.startsWith("/") ? targetDir :
|
|
2745
|
+
const absoluteDir = targetDir.startsWith("/") ? targetDir : join3(process.cwd(), targetDir);
|
|
2045
2746
|
console.log();
|
|
2046
|
-
console.log(
|
|
2747
|
+
console.log(import_picocolors5.default.cyan(" Analisando projeto..."));
|
|
2047
2748
|
console.log();
|
|
2048
|
-
const pkgPath =
|
|
2749
|
+
const pkgPath = join3(absoluteDir, "package.json");
|
|
2049
2750
|
if (!existsSync(pkgPath)) {
|
|
2050
|
-
console.log(
|
|
2051
|
-
console.log(
|
|
2751
|
+
console.log(import_picocolors5.default.red(" Erro: package.json nao encontrado"));
|
|
2752
|
+
console.log(import_picocolors5.default.dim(` Diretorio: ${absoluteDir}`));
|
|
2052
2753
|
process.exit(1);
|
|
2053
2754
|
}
|
|
2054
2755
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -2065,42 +2766,42 @@ async function analyze(args) {
|
|
|
2065
2766
|
monorepo: detectMonorepo(absoluteDir, pkg),
|
|
2066
2767
|
auth: detectAuth(deps),
|
|
2067
2768
|
database: detectDatabase(deps),
|
|
2068
|
-
typescript: existsSync(
|
|
2769
|
+
typescript: existsSync(join3(absoluteDir, "tsconfig.json")),
|
|
2069
2770
|
dependencies: deps,
|
|
2070
2771
|
devDependencies: devDeps,
|
|
2071
2772
|
recommendations: []
|
|
2072
2773
|
};
|
|
2073
2774
|
result.recommendations = generateRecommendations(result);
|
|
2074
|
-
console.log(
|
|
2775
|
+
console.log(import_picocolors5.default.bold(" Projeto: ") + import_picocolors5.default.cyan(result.name) + import_picocolors5.default.dim(` v${result.version}`));
|
|
2075
2776
|
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 ?
|
|
2777
|
+
console.log(import_picocolors5.default.bold(" Stack Detectada:"));
|
|
2778
|
+
console.log(` Framework: ${result.framework ? import_picocolors5.default.green(result.framework + "@" + result.frameworkVersion) : import_picocolors5.default.dim("nenhum")}`);
|
|
2779
|
+
console.log(` Styling: ${result.styling.map((s) => import_picocolors5.default.green(s)).join(", ")}`);
|
|
2780
|
+
console.log(` Package Manager: ${result.packageManager === "bun" ? import_picocolors5.default.green(result.packageManager) : import_picocolors5.default.yellow(result.packageManager)}`);
|
|
2781
|
+
console.log(` TypeScript: ${result.typescript ? import_picocolors5.default.green("sim") : import_picocolors5.default.dim("nao")}`);
|
|
2782
|
+
console.log(` Monorepo: ${result.monorepo ? import_picocolors5.default.green(result.monorepo) : import_picocolors5.default.dim("nao")}`);
|
|
2783
|
+
console.log(` Auth: ${result.auth ? import_picocolors5.default.green(result.auth) : import_picocolors5.default.dim("nenhum")}`);
|
|
2784
|
+
console.log(` Database: ${result.database ? import_picocolors5.default.green(result.database) : import_picocolors5.default.dim("nenhum")}`);
|
|
2084
2785
|
console.log();
|
|
2085
2786
|
if (result.recommendations.length > 0) {
|
|
2086
|
-
console.log(
|
|
2787
|
+
console.log(import_picocolors5.default.bold(" Recomendacoes:"));
|
|
2087
2788
|
result.recommendations.forEach((rec, i) => {
|
|
2088
|
-
console.log(
|
|
2789
|
+
console.log(import_picocolors5.default.yellow(` ${i + 1}. ${rec}`));
|
|
2089
2790
|
});
|
|
2090
2791
|
console.log();
|
|
2091
2792
|
} else {
|
|
2092
|
-
console.log(
|
|
2793
|
+
console.log(import_picocolors5.default.green(" Projeto ja esta na stack recomendada!"));
|
|
2093
2794
|
console.log();
|
|
2094
2795
|
}
|
|
2095
2796
|
if (args.includes("--json")) {
|
|
2096
|
-
console.log(
|
|
2797
|
+
console.log(import_picocolors5.default.dim(" JSON:"));
|
|
2097
2798
|
console.log(JSON.stringify(result, null, 2));
|
|
2098
2799
|
}
|
|
2099
2800
|
return result;
|
|
2100
2801
|
}
|
|
2101
2802
|
|
|
2102
2803
|
// src/commands/upgrade.ts
|
|
2103
|
-
var
|
|
2804
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
2104
2805
|
var UPGRADE_PLANS = {
|
|
2105
2806
|
next: (current) => {
|
|
2106
2807
|
const major = parseInt(current.replace(/[^0-9]/g, "").slice(0, 2));
|
|
@@ -2217,10 +2918,10 @@ async function upgrade(args) {
|
|
|
2217
2918
|
const target = args.find((a) => !a.startsWith("-"));
|
|
2218
2919
|
console.log();
|
|
2219
2920
|
if (showPlan || !target) {
|
|
2220
|
-
console.log(
|
|
2921
|
+
console.log(import_picocolors6.default.cyan(" Analisando projeto para plano de upgrade..."));
|
|
2221
2922
|
console.log();
|
|
2222
2923
|
const analysis = await analyze([".", "--quiet"]);
|
|
2223
|
-
console.log(
|
|
2924
|
+
console.log(import_picocolors6.default.bold(" Upgrades Disponiveis:"));
|
|
2224
2925
|
console.log();
|
|
2225
2926
|
let hasUpgrades = false;
|
|
2226
2927
|
if (analysis.frameworkVersion && analysis.framework === "nextjs") {
|
|
@@ -2275,44 +2976,44 @@ async function upgrade(args) {
|
|
|
2275
2976
|
}
|
|
2276
2977
|
}
|
|
2277
2978
|
if (!hasUpgrades) {
|
|
2278
|
-
console.log(
|
|
2979
|
+
console.log(import_picocolors6.default.green(" Projeto ja esta atualizado!"));
|
|
2279
2980
|
}
|
|
2280
2981
|
console.log();
|
|
2281
|
-
console.log(
|
|
2282
|
-
console.log(
|
|
2283
|
-
console.log(
|
|
2284
|
-
console.log(
|
|
2982
|
+
console.log(import_picocolors6.default.dim(" Para executar um upgrade especifico:"));
|
|
2983
|
+
console.log(import_picocolors6.default.dim(" nimbus upgrade next"));
|
|
2984
|
+
console.log(import_picocolors6.default.dim(" nimbus upgrade tailwind"));
|
|
2985
|
+
console.log(import_picocolors6.default.dim(" nimbus upgrade bun"));
|
|
2285
2986
|
console.log();
|
|
2286
2987
|
return;
|
|
2287
2988
|
}
|
|
2288
|
-
console.log(
|
|
2289
|
-
console.log(
|
|
2989
|
+
console.log(import_picocolors6.default.yellow(` Upgrade ${target} ainda nao implementado.`));
|
|
2990
|
+
console.log(import_picocolors6.default.dim(" Por enquanto, siga os passos do --plan manualmente."));
|
|
2290
2991
|
console.log();
|
|
2291
2992
|
}
|
|
2292
2993
|
function printUpgradePlan(name, plan) {
|
|
2293
2994
|
const complexityColor = {
|
|
2294
|
-
low:
|
|
2295
|
-
medium:
|
|
2296
|
-
high:
|
|
2995
|
+
low: import_picocolors6.default.green,
|
|
2996
|
+
medium: import_picocolors6.default.yellow,
|
|
2997
|
+
high: import_picocolors6.default.red
|
|
2297
2998
|
};
|
|
2298
|
-
console.log(` ${
|
|
2299
|
-
console.log(` ${
|
|
2300
|
-
console.log(` ${
|
|
2999
|
+
console.log(` ${import_picocolors6.default.bold(name)}`);
|
|
3000
|
+
console.log(` ${import_picocolors6.default.dim("Atual:")} ${plan.current} ${import_picocolors6.default.dim("->")} ${import_picocolors6.default.cyan(plan.target)}`);
|
|
3001
|
+
console.log(` ${import_picocolors6.default.dim("Complexidade:")} ${complexityColor[plan.complexity](plan.complexity)}`);
|
|
2301
3002
|
console.log();
|
|
2302
|
-
console.log(` ${
|
|
3003
|
+
console.log(` ${import_picocolors6.default.dim("Breaking Changes:")}`);
|
|
2303
3004
|
plan.breakingChanges.forEach((bc) => {
|
|
2304
|
-
console.log(` ${
|
|
3005
|
+
console.log(` ${import_picocolors6.default.yellow("!")} ${bc}`);
|
|
2305
3006
|
});
|
|
2306
3007
|
console.log();
|
|
2307
|
-
console.log(` ${
|
|
3008
|
+
console.log(` ${import_picocolors6.default.dim("Passos:")}`);
|
|
2308
3009
|
plan.steps.forEach((step, i) => {
|
|
2309
|
-
console.log(` ${
|
|
3010
|
+
console.log(` ${import_picocolors6.default.dim(`${i + 1}.`)} ${step}`);
|
|
2310
3011
|
});
|
|
2311
3012
|
console.log();
|
|
2312
3013
|
}
|
|
2313
3014
|
|
|
2314
3015
|
// src/commands/update.ts
|
|
2315
|
-
var
|
|
3016
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
2316
3017
|
import { execSync, spawnSync } from "child_process";
|
|
2317
3018
|
var PACKAGE_NAME = "@nimbuslab/cli";
|
|
2318
3019
|
function hasBunInstall() {
|
|
@@ -2448,7 +3149,7 @@ async function update(args) {
|
|
|
2448
3149
|
const filteredArgs = args.filter((a) => a !== "--force" && a !== "-f");
|
|
2449
3150
|
const flag = filteredArgs[0];
|
|
2450
3151
|
if (flag === "--list" || flag === "-l") {
|
|
2451
|
-
Ie(
|
|
3152
|
+
Ie(import_picocolors7.default.cyan("Versoes disponiveis"));
|
|
2452
3153
|
const spinner2 = Y2();
|
|
2453
3154
|
spinner2.start("Buscando versoes...");
|
|
2454
3155
|
const versions = await getAvailableVersions();
|
|
@@ -2460,29 +3161,29 @@ async function update(args) {
|
|
|
2460
3161
|
const current = getCurrentVersion();
|
|
2461
3162
|
const pm2 = detectPackageManager2();
|
|
2462
3163
|
console.log();
|
|
2463
|
-
console.log(
|
|
3164
|
+
console.log(import_picocolors7.default.bold("Ultimas 10 versoes:"));
|
|
2464
3165
|
versions.slice(0, 10).forEach((v2, i) => {
|
|
2465
3166
|
const isCurrent = v2 === current;
|
|
2466
|
-
const prefix = isCurrent ?
|
|
2467
|
-
const suffix = isCurrent ?
|
|
2468
|
-
const isLatest = i === 0 ?
|
|
3167
|
+
const prefix = isCurrent ? import_picocolors7.default.green("-> ") : " ";
|
|
3168
|
+
const suffix = isCurrent ? import_picocolors7.default.dim(" (instalada)") : "";
|
|
3169
|
+
const isLatest = i === 0 ? import_picocolors7.default.yellow(" (latest)") : "";
|
|
2469
3170
|
console.log(`${prefix}${v2}${suffix}${isLatest}`);
|
|
2470
3171
|
});
|
|
2471
3172
|
console.log();
|
|
2472
|
-
console.log(
|
|
2473
|
-
console.log(
|
|
2474
|
-
console.log(
|
|
2475
|
-
console.log(
|
|
3173
|
+
console.log(import_picocolors7.default.dim(`Total: ${versions.length} versoes`));
|
|
3174
|
+
console.log(import_picocolors7.default.dim(`Package manager detectado: ${pm2 === "unknown" ? "nenhum" : pm2}`));
|
|
3175
|
+
console.log(import_picocolors7.default.dim(`Instalar versao especifica: nimbus update <versao>`));
|
|
3176
|
+
console.log(import_picocolors7.default.dim(`Forcar reinstalacao: nimbus update --force`));
|
|
2476
3177
|
return;
|
|
2477
3178
|
}
|
|
2478
3179
|
const targetVersion = flag || "latest";
|
|
2479
3180
|
const isSpecificVersion = flag && flag !== "latest" && !flag.startsWith("-");
|
|
2480
|
-
Ie(
|
|
3181
|
+
Ie(import_picocolors7.default.cyan(`Atualizando ${PACKAGE_NAME}`));
|
|
2481
3182
|
const spinner = Y2();
|
|
2482
3183
|
spinner.start("Verificando instalacoes...");
|
|
2483
3184
|
const cleanup = cleanupDuplicateInstalls();
|
|
2484
3185
|
if (cleanup.cleaned) {
|
|
2485
|
-
spinner.stop(
|
|
3186
|
+
spinner.stop(import_picocolors7.default.yellow(cleanup.message));
|
|
2486
3187
|
} else {
|
|
2487
3188
|
spinner.stop("OK");
|
|
2488
3189
|
}
|
|
@@ -2500,7 +3201,7 @@ async function update(args) {
|
|
|
2500
3201
|
spinner.stop(`Ultima versao: ${latestVersion || "desconhecida"}`);
|
|
2501
3202
|
if (!forceFlag && latestVersion && latestVersion === currentVersion) {
|
|
2502
3203
|
M2.success("Voce ja esta na ultima versao!");
|
|
2503
|
-
console.log(
|
|
3204
|
+
console.log(import_picocolors7.default.dim(" Use --force para reinstalar"));
|
|
2504
3205
|
return;
|
|
2505
3206
|
}
|
|
2506
3207
|
}
|
|
@@ -2538,953 +3239,82 @@ async function update(args) {
|
|
|
2538
3239
|
const isWindows = process.platform === "win32";
|
|
2539
3240
|
if (isWindows) {
|
|
2540
3241
|
console.log();
|
|
2541
|
-
console.log(
|
|
3242
|
+
console.log(import_picocolors7.default.yellow(" Reinicie o terminal para aplicar a atualizacao."));
|
|
2542
3243
|
} else if (isUsingFnm()) {
|
|
2543
3244
|
console.log();
|
|
2544
|
-
console.log(
|
|
2545
|
-
console.log(
|
|
2546
|
-
console.log(
|
|
3245
|
+
console.log(import_picocolors7.default.yellow(" fnm detectado - execute para aplicar:"));
|
|
3246
|
+
console.log(import_picocolors7.default.cyan(" hash -r"));
|
|
3247
|
+
console.log(import_picocolors7.default.dim(" Ou abra um novo terminal."));
|
|
2547
3248
|
}
|
|
2548
|
-
Se(
|
|
3249
|
+
Se(import_picocolors7.default.green("Pronto!"));
|
|
2549
3250
|
} catch (error) {
|
|
2550
3251
|
spinner.stop("Erro na atualizacao");
|
|
2551
3252
|
const err = error;
|
|
2552
3253
|
M2.error("Falha ao atualizar");
|
|
2553
3254
|
if (err.stderr) {
|
|
2554
|
-
console.log(
|
|
3255
|
+
console.log(import_picocolors7.default.dim(err.stderr));
|
|
2555
3256
|
}
|
|
2556
3257
|
console.log();
|
|
2557
|
-
console.log(
|
|
3258
|
+
console.log(import_picocolors7.default.yellow("Tente manualmente:"));
|
|
2558
3259
|
if (pm === "bun") {
|
|
2559
|
-
console.log(
|
|
3260
|
+
console.log(import_picocolors7.default.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
|
|
2560
3261
|
} else {
|
|
2561
|
-
console.log(
|
|
3262
|
+
console.log(import_picocolors7.default.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
|
|
2562
3263
|
}
|
|
2563
3264
|
}
|
|
2564
3265
|
}
|
|
2565
3266
|
|
|
2566
|
-
// src/commands/lola.ts
|
|
2567
|
-
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
2568
|
-
import { existsSync as existsSync2 } from "fs";
|
|
2569
|
-
import { join as join3 } from "path";
|
|
2570
|
-
import { homedir } from "os";
|
|
2571
|
-
var HOME = homedir();
|
|
2572
|
-
var LOLA_DIR = join3(HOME, ".lola");
|
|
2573
|
-
var LOLA_REPO = "git@github.com:nimbuslab/lola.git";
|
|
2574
|
-
var USER_MEMORY = join3(HOME, ".claude", "USER_MEMORY.md");
|
|
2575
|
-
var CLAUDE_COMMANDS_DIR = join3(HOME, ".claude", "commands");
|
|
2576
|
-
var LOLA_COMMANDS_DIR = join3(LOLA_DIR, "commands");
|
|
2577
|
-
var LOLA_MEMORY_URL = "https://lola.nimbuslab.com.br/sse";
|
|
2578
|
-
var LOLA_MEMORY_NAME = "lola-memory";
|
|
2579
|
-
var GEMINI_DIR = join3(HOME, ".gemini");
|
|
2580
|
-
var GEMINI_SETTINGS = join3(GEMINI_DIR, "GEMINI.md");
|
|
2581
|
-
var CHECK_CMD = process.platform === "win32" ? "where" : "which";
|
|
2582
|
-
function hasClaudeCLI() {
|
|
2583
|
-
const result = Bun.spawnSync([CHECK_CMD, "claude"], { stdout: "pipe", stderr: "pipe" });
|
|
2584
|
-
return result.exitCode === 0;
|
|
2585
|
-
}
|
|
2586
|
-
function hasGeminiCLI() {
|
|
2587
|
-
const result = Bun.spawnSync([CHECK_CMD, "gemini"], { stdout: "pipe", stderr: "pipe" });
|
|
2588
|
-
return result.exitCode === 0;
|
|
2589
|
-
}
|
|
2590
|
-
async function installLolaMemoryMCP() {
|
|
2591
|
-
console.log();
|
|
2592
|
-
console.log(import_picocolors7.default.cyan(" Configurando lola-memory MCP..."));
|
|
2593
|
-
const claudeCheck = Bun.spawnSync([CHECK_CMD, "claude"], { stdout: "pipe", stderr: "pipe" });
|
|
2594
|
-
if (claudeCheck.exitCode !== 0) {
|
|
2595
|
-
console.log(import_picocolors7.default.yellow(" Claude CLI nao encontrado, pulando MCP"));
|
|
2596
|
-
console.log(import_picocolors7.default.dim(" Instale o Claude CLI e rode 'nimbus lola install' novamente"));
|
|
2597
|
-
return;
|
|
2598
|
-
}
|
|
2599
|
-
const mcpList = Bun.spawnSync(["claude", "mcp", "list"], { stdout: "pipe", stderr: "pipe" });
|
|
2600
|
-
const mcpOutput = mcpList.stdout.toString();
|
|
2601
|
-
if (mcpOutput.includes(LOLA_MEMORY_NAME)) {
|
|
2602
|
-
console.log(import_picocolors7.default.green(" MCP lola-memory ja configurado"));
|
|
2603
|
-
return;
|
|
2604
|
-
}
|
|
2605
|
-
console.log(import_picocolors7.default.dim(" Adicionando MCP lola-memory..."));
|
|
2606
|
-
const result = Bun.spawnSync([
|
|
2607
|
-
"claude",
|
|
2608
|
-
"mcp",
|
|
2609
|
-
"add",
|
|
2610
|
-
"-s",
|
|
2611
|
-
"user",
|
|
2612
|
-
LOLA_MEMORY_NAME,
|
|
2613
|
-
"--",
|
|
2614
|
-
"bunx",
|
|
2615
|
-
"mcp-remote",
|
|
2616
|
-
LOLA_MEMORY_URL
|
|
2617
|
-
], {
|
|
2618
|
-
stdout: "inherit",
|
|
2619
|
-
stderr: "inherit"
|
|
2620
|
-
});
|
|
2621
|
-
if (result.exitCode !== 0) {
|
|
2622
|
-
console.log(import_picocolors7.default.yellow(" Erro ao adicionar MCP, pode ser adicionado manualmente:"));
|
|
2623
|
-
console.log(import_picocolors7.default.dim(` claude mcp add -s user ${LOLA_MEMORY_NAME} -- bunx mcp-remote ${LOLA_MEMORY_URL}`));
|
|
2624
|
-
return;
|
|
2625
|
-
}
|
|
2626
|
-
console.log(import_picocolors7.default.green(" MCP lola-memory instalado!"));
|
|
2627
|
-
console.log();
|
|
2628
|
-
console.log(import_picocolors7.default.dim(" Comandos disponiveis:"));
|
|
2629
|
-
console.log(import_picocolors7.default.dim(' remember "query" - Buscar conhecimento'));
|
|
2630
|
-
console.log(import_picocolors7.default.dim(' learn "content" - Salvar conhecimento'));
|
|
2631
|
-
console.log(import_picocolors7.default.dim(" memory_stats - Ver estatisticas"));
|
|
2632
|
-
}
|
|
2633
|
-
async function installLolaCommands() {
|
|
2634
|
-
console.log();
|
|
2635
|
-
console.log(import_picocolors7.default.cyan(" Instalando comandos da Lola..."));
|
|
2636
|
-
if (!existsSync2(LOLA_COMMANDS_DIR)) {
|
|
2637
|
-
console.log(import_picocolors7.default.dim(" Pasta de comandos nao encontrada em ~/.lola/commands"));
|
|
2638
|
-
return;
|
|
2639
|
-
}
|
|
2640
|
-
if (!existsSync2(CLAUDE_COMMANDS_DIR)) {
|
|
2641
|
-
await Bun.$`mkdir -p ${CLAUDE_COMMANDS_DIR}`;
|
|
2642
|
-
}
|
|
2643
|
-
const glob = new Bun.Glob("*.md");
|
|
2644
|
-
const files = Array.from(glob.scanSync({ cwd: LOLA_COMMANDS_DIR }));
|
|
2645
|
-
if (files.length === 0) {
|
|
2646
|
-
console.log(import_picocolors7.default.dim(" Nenhum comando encontrado"));
|
|
2647
|
-
return;
|
|
2648
|
-
}
|
|
2649
|
-
let installed = 0;
|
|
2650
|
-
for (const file of files) {
|
|
2651
|
-
const src = join3(LOLA_COMMANDS_DIR, file);
|
|
2652
|
-
const dest = join3(CLAUDE_COMMANDS_DIR, file);
|
|
2653
|
-
const content = await Bun.file(src).text();
|
|
2654
|
-
await Bun.write(dest, content);
|
|
2655
|
-
installed++;
|
|
2656
|
-
}
|
|
2657
|
-
console.log(import_picocolors7.default.green(` ${installed} comandos instalados!`));
|
|
2658
|
-
console.log(import_picocolors7.default.dim(" Comandos: /inbox, /sent, /msg, /conversation"));
|
|
2659
|
-
}
|
|
2660
|
-
async function installGeminiCLI() {
|
|
2661
|
-
console.log();
|
|
2662
|
-
console.log(import_picocolors7.default.cyan(" Instalando Gemini CLI..."));
|
|
2663
|
-
const result = Bun.spawnSync(["npm", "install", "-g", "@google/gemini-cli"], {
|
|
2664
|
-
stdout: "inherit",
|
|
2665
|
-
stderr: "inherit"
|
|
2666
|
-
});
|
|
2667
|
-
if (result.exitCode !== 0) {
|
|
2668
|
-
console.log(import_picocolors7.default.red(" Erro ao instalar Gemini CLI"));
|
|
2669
|
-
console.log(import_picocolors7.default.dim(" Tente manualmente: npm install -g @google/gemini-cli"));
|
|
2670
|
-
return false;
|
|
2671
|
-
}
|
|
2672
|
-
console.log(import_picocolors7.default.green(" Gemini CLI instalado!"));
|
|
2673
|
-
return true;
|
|
2674
|
-
}
|
|
2675
|
-
async function installGeminiMCP() {
|
|
2676
|
-
console.log();
|
|
2677
|
-
console.log(import_picocolors7.default.cyan(" Configurando MCP no Gemini..."));
|
|
2678
|
-
const settingsPath = join3(GEMINI_DIR, "settings.json");
|
|
2679
|
-
if (!existsSync2(GEMINI_DIR)) {
|
|
2680
|
-
await Bun.$`mkdir -p ${GEMINI_DIR}`;
|
|
2681
|
-
}
|
|
2682
|
-
let settings = {};
|
|
2683
|
-
if (existsSync2(settingsPath)) {
|
|
2684
|
-
try {
|
|
2685
|
-
const content = await Bun.file(settingsPath).text();
|
|
2686
|
-
settings = JSON.parse(content);
|
|
2687
|
-
} catch {}
|
|
2688
|
-
}
|
|
2689
|
-
const mcpServers = settings.mcpServers || {};
|
|
2690
|
-
if (mcpServers[LOLA_MEMORY_NAME]) {
|
|
2691
|
-
console.log(import_picocolors7.default.green(" MCP lola-memory ja configurado no Gemini"));
|
|
2692
|
-
return;
|
|
2693
|
-
}
|
|
2694
|
-
mcpServers[LOLA_MEMORY_NAME] = {
|
|
2695
|
-
url: LOLA_MEMORY_URL
|
|
2696
|
-
};
|
|
2697
|
-
settings.mcpServers = mcpServers;
|
|
2698
|
-
await Bun.write(settingsPath, JSON.stringify(settings, null, 2));
|
|
2699
|
-
console.log(import_picocolors7.default.green(" MCP lola-memory adicionado ao Gemini!"));
|
|
2700
|
-
}
|
|
2701
|
-
async function installGeminiSystemPrompt() {
|
|
2702
|
-
console.log();
|
|
2703
|
-
console.log(import_picocolors7.default.cyan(" Configurando GEMINI.md..."));
|
|
2704
|
-
if (!existsSync2(GEMINI_DIR)) {
|
|
2705
|
-
await Bun.$`mkdir -p ${GEMINI_DIR}`;
|
|
2706
|
-
}
|
|
2707
|
-
const lolaAgent = join3(LOLA_DIR, "agents", "claude.md");
|
|
2708
|
-
if (!existsSync2(lolaAgent)) {
|
|
2709
|
-
console.log(import_picocolors7.default.yellow(" Agent Lola nao encontrado"));
|
|
2710
|
-
console.log(import_picocolors7.default.dim(" Rode 'nimbus lola install' primeiro"));
|
|
2711
|
-
return;
|
|
2712
|
-
}
|
|
2713
|
-
let content = await Bun.file(lolaAgent).text();
|
|
2714
|
-
content = content.replace(/^---[\s\S]*?---\n/, "");
|
|
2715
|
-
content = content.replace(/Claude Code/g, "Gemini CLI");
|
|
2716
|
-
content = content.replace(/Claude CLI/g, "Gemini CLI");
|
|
2717
|
-
const geminiContent = `# Lola - Code Agent (Gemini)
|
|
2718
|
-
|
|
2719
|
-
> Este arquivo configura a Lola para o Gemini CLI
|
|
2720
|
-
> Gerado automaticamente por: nimbus lola install
|
|
2721
|
-
|
|
2722
|
-
---
|
|
2723
|
-
|
|
2724
|
-
${content}`;
|
|
2725
|
-
await Bun.write(GEMINI_SETTINGS, geminiContent);
|
|
2726
|
-
console.log(import_picocolors7.default.green(" GEMINI.md criado!"));
|
|
2727
|
-
}
|
|
2728
|
-
async function createGeminiCommand() {
|
|
2729
|
-
const isWindows = process.platform === "win32";
|
|
2730
|
-
const lolaAgent = GEMINI_SETTINGS;
|
|
2731
|
-
console.log();
|
|
2732
|
-
console.log(import_picocolors7.default.cyan(" Configurando comando lola-gemini..."));
|
|
2733
|
-
if (isWindows) {
|
|
2734
|
-
const ps7ProfileDir = join3(HOME, "Documents", "PowerShell");
|
|
2735
|
-
const profileName = "Microsoft.PowerShell_profile.ps1";
|
|
2736
|
-
const profilePath = join3(ps7ProfileDir, profileName);
|
|
2737
|
-
const lolaGeminiFunction = `
|
|
2738
|
-
# Lola (Gemini) - Code Agent da nimbuslab
|
|
2739
|
-
function lola-gemini {
|
|
2740
|
-
param([Parameter(ValueFromRemainingArguments=$true)]$args)
|
|
2741
|
-
gemini @args
|
|
2742
|
-
}
|
|
2743
|
-
`;
|
|
2744
|
-
if (!existsSync2(ps7ProfileDir)) {
|
|
2745
|
-
await Bun.$`mkdir -p ${ps7ProfileDir}`;
|
|
2746
|
-
}
|
|
2747
|
-
let profileContent = "";
|
|
2748
|
-
if (existsSync2(profilePath)) {
|
|
2749
|
-
profileContent = await Bun.file(profilePath).text();
|
|
2750
|
-
}
|
|
2751
|
-
if (!profileContent.includes("function lola-gemini")) {
|
|
2752
|
-
await Bun.write(profilePath, profileContent + lolaGeminiFunction);
|
|
2753
|
-
console.log(import_picocolors7.default.green(" Funcao lola-gemini adicionada ao PowerShell"));
|
|
2754
|
-
} else {
|
|
2755
|
-
console.log(import_picocolors7.default.green(" Funcao lola-gemini ja existe"));
|
|
2756
|
-
}
|
|
2757
|
-
} else {
|
|
2758
|
-
const binDir = join3(HOME, ".local", "bin");
|
|
2759
|
-
const lolaGeminiScript = join3(binDir, "lola-gemini");
|
|
2760
|
-
if (!existsSync2(lolaGeminiScript)) {
|
|
2761
|
-
await Bun.$`mkdir -p ${binDir}`;
|
|
2762
|
-
const unixScript = `#!/bin/bash
|
|
2763
|
-
# lola-gemini - Code Agent da nimbuslab (Gemini)
|
|
2764
|
-
|
|
2765
|
-
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
|
2766
|
-
echo "lola-gemini - Code Agent da nimbuslab (Gemini)"
|
|
2767
|
-
echo "Uso: lola-gemini [args]"
|
|
2768
|
-
echo " lola-gemini Abre Gemini CLI com a Lola"
|
|
2769
|
-
exit 0
|
|
2770
|
-
fi
|
|
2771
|
-
|
|
2772
|
-
exec gemini "$@"
|
|
2773
|
-
`;
|
|
2774
|
-
await Bun.write(lolaGeminiScript, unixScript);
|
|
2775
|
-
await Bun.$`chmod +x ${lolaGeminiScript}`;
|
|
2776
|
-
console.log(import_picocolors7.default.green(` Script lola-gemini criado em ${lolaGeminiScript}`));
|
|
2777
|
-
} else {
|
|
2778
|
-
console.log(import_picocolors7.default.green(" Script lola-gemini ja existe"));
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
async function setupGemini() {
|
|
2783
|
-
if (!hasGeminiCLI()) {
|
|
2784
|
-
const installed = await installGeminiCLI();
|
|
2785
|
-
if (!installed)
|
|
2786
|
-
return;
|
|
2787
|
-
} else {
|
|
2788
|
-
console.log(import_picocolors7.default.green(" Gemini CLI ja instalado"));
|
|
2789
|
-
}
|
|
2790
|
-
await installGeminiMCP();
|
|
2791
|
-
await installGeminiSystemPrompt();
|
|
2792
|
-
await createGeminiCommand();
|
|
2793
|
-
console.log();
|
|
2794
|
-
console.log(import_picocolors7.default.green(" Gemini configurado!"));
|
|
2795
|
-
console.log();
|
|
2796
|
-
console.log(import_picocolors7.default.bold(" Para usar:"));
|
|
2797
|
-
console.log(import_picocolors7.default.dim(" lola-gemini ") + import_picocolors7.default.white("# Iniciar sessao com Gemini"));
|
|
2798
|
-
console.log(import_picocolors7.default.dim(" gemini ") + import_picocolors7.default.white("# Gemini puro (sem Lola)"));
|
|
2799
|
-
console.log();
|
|
2800
|
-
console.log(import_picocolors7.default.dim(" Na primeira execucao, faca login com sua conta Google."));
|
|
2801
|
-
}
|
|
2802
|
-
async function suggestImprovement(message) {
|
|
2803
|
-
if (!message) {
|
|
2804
|
-
console.log(import_picocolors7.default.red(" Erro: forne\xE7a uma mensagem"));
|
|
2805
|
-
console.log(import_picocolors7.default.dim(' Uso: nimbus lola suggest "sua sugestao aqui"'));
|
|
2806
|
-
process.exit(1);
|
|
2807
|
-
}
|
|
2808
|
-
const ghCheck = Bun.spawnSync([CHECK_CMD, "gh"], { stderr: "pipe" });
|
|
2809
|
-
if (ghCheck.exitCode !== 0) {
|
|
2810
|
-
console.log(import_picocolors7.default.red(" Erro: GitHub CLI (gh) nao encontrado"));
|
|
2811
|
-
console.log(import_picocolors7.default.dim(" Instale: https://cli.github.com"));
|
|
2812
|
-
process.exit(1);
|
|
2813
|
-
}
|
|
2814
|
-
const authCheck = Bun.spawnSync(["gh", "auth", "status"], {
|
|
2815
|
-
stdout: "pipe",
|
|
2816
|
-
stderr: "pipe"
|
|
2817
|
-
});
|
|
2818
|
-
if (authCheck.exitCode !== 0) {
|
|
2819
|
-
console.log(import_picocolors7.default.red(" Erro: GitHub CLI nao autenticado"));
|
|
2820
|
-
console.log(import_picocolors7.default.dim(" Execute: gh auth login"));
|
|
2821
|
-
process.exit(1);
|
|
2822
|
-
}
|
|
2823
|
-
const gitUser = Bun.spawnSync(["git", "config", "user.name"], { stdout: "pipe" });
|
|
2824
|
-
const gitEmail = Bun.spawnSync(["git", "config", "user.email"], { stdout: "pipe" });
|
|
2825
|
-
const userName = gitUser.stdout.toString().trim() || "Dev";
|
|
2826
|
-
const userEmail = gitEmail.stdout.toString().trim() || "";
|
|
2827
|
-
console.log();
|
|
2828
|
-
console.log(import_picocolors7.default.cyan(" Criando sugestao..."));
|
|
2829
|
-
const date = new Date().toISOString().split("T")[0];
|
|
2830
|
-
const body = `## Sugestao
|
|
2831
|
-
|
|
2832
|
-
${message}
|
|
2833
|
-
|
|
2834
|
-
---
|
|
2835
|
-
|
|
2836
|
-
**Enviado por:** ${userName}
|
|
2837
|
-
**Email:** ${userEmail}
|
|
2838
|
-
**Data:** ${date}
|
|
2839
|
-
|
|
2840
|
-
---
|
|
2841
|
-
*Criado via \`nimbus lola suggest\`*`;
|
|
2842
|
-
const title = `Sugestao: ${message.slice(0, 50)}${message.length > 50 ? "..." : ""}`;
|
|
2843
|
-
const result = Bun.spawnSync([
|
|
2844
|
-
"gh",
|
|
2845
|
-
"issue",
|
|
2846
|
-
"create",
|
|
2847
|
-
"--repo",
|
|
2848
|
-
"nimbuslab/lola",
|
|
2849
|
-
"--title",
|
|
2850
|
-
title,
|
|
2851
|
-
"--body",
|
|
2852
|
-
body,
|
|
2853
|
-
"--label",
|
|
2854
|
-
"sugestao"
|
|
2855
|
-
], {
|
|
2856
|
-
stdout: "inherit",
|
|
2857
|
-
stderr: "inherit"
|
|
2858
|
-
});
|
|
2859
|
-
if (result.exitCode !== 0) {
|
|
2860
|
-
console.log(import_picocolors7.default.red(" Erro ao criar issue"));
|
|
2861
|
-
process.exit(1);
|
|
2862
|
-
}
|
|
2863
|
-
console.log();
|
|
2864
|
-
console.log(import_picocolors7.default.green(" Sugestao enviada! Hugo vai revisar."));
|
|
2865
|
-
console.log();
|
|
2866
|
-
}
|
|
2867
|
-
var PROFILES = {
|
|
2868
|
-
millennial: {
|
|
2869
|
-
label: "Millennial",
|
|
2870
|
-
hint: "Nerd 90s/2000s, DBZ, Matrix, MSN",
|
|
2871
|
-
emoji: ""
|
|
2872
|
-
},
|
|
2873
|
-
genz: {
|
|
2874
|
-
label: "Gen Z",
|
|
2875
|
-
hint: "Direto, girias atuais, slay",
|
|
2876
|
-
emoji: ""
|
|
2877
|
-
},
|
|
2878
|
-
profissional: {
|
|
2879
|
-
label: "Profissional",
|
|
2880
|
-
hint: "100% tecnico, sem referencias",
|
|
2881
|
-
emoji: ""
|
|
2882
|
-
},
|
|
2883
|
-
nerd: {
|
|
2884
|
-
label: "Nerd",
|
|
2885
|
-
hint: "Star Trek, vim jokes, deep tech",
|
|
2886
|
-
emoji: ""
|
|
2887
|
-
},
|
|
2888
|
-
chill: {
|
|
2889
|
-
label: "Chill",
|
|
2890
|
-
hint: "Relaxado, vibes cafe, positivo",
|
|
2891
|
-
emoji: ""
|
|
2892
|
-
}
|
|
2893
|
-
};
|
|
2894
|
-
async function onboardDev() {
|
|
2895
|
-
console.log();
|
|
2896
|
-
console.log(import_picocolors7.default.cyan(" Lola - Onboarding"));
|
|
2897
|
-
console.log(import_picocolors7.default.dim(" ================="));
|
|
2898
|
-
console.log();
|
|
2899
|
-
if (!existsSync2(LOLA_DIR)) {
|
|
2900
|
-
console.log(import_picocolors7.default.yellow(" Lola nao instalada. Instalando primeiro..."));
|
|
2901
|
-
console.log();
|
|
2902
|
-
await installLolaBase();
|
|
2903
|
-
console.log();
|
|
2904
|
-
}
|
|
2905
|
-
const gitUser = Bun.spawnSync(["git", "config", "user.name"], { stdout: "pipe" });
|
|
2906
|
-
const defaultName = gitUser.stdout.toString().trim() || "";
|
|
2907
|
-
Ie(import_picocolors7.default.bgCyan(import_picocolors7.default.black(" Bem-vindo a nimbuslab! ")));
|
|
2908
|
-
const devName = await he({
|
|
2909
|
-
message: "Qual seu nome?",
|
|
2910
|
-
placeholder: "Seu nome",
|
|
2911
|
-
initialValue: defaultName,
|
|
2912
|
-
validate: (v2) => v2 ? undefined : "Nome e obrigatorio"
|
|
2913
|
-
});
|
|
2914
|
-
if (pD(devName)) {
|
|
2915
|
-
xe("Onboarding cancelado");
|
|
2916
|
-
process.exit(0);
|
|
2917
|
-
}
|
|
2918
|
-
const profile = await ve({
|
|
2919
|
-
message: "Qual perfil da Lola voce prefere?",
|
|
2920
|
-
options: Object.entries(PROFILES).map(([value, { label, hint }]) => ({
|
|
2921
|
-
value,
|
|
2922
|
-
label,
|
|
2923
|
-
hint
|
|
2924
|
-
}))
|
|
2925
|
-
});
|
|
2926
|
-
if (pD(profile)) {
|
|
2927
|
-
xe("Onboarding cancelado");
|
|
2928
|
-
process.exit(0);
|
|
2929
|
-
}
|
|
2930
|
-
const claudeDir = join3(HOME, ".claude");
|
|
2931
|
-
await Bun.$`mkdir -p ${claudeDir}`;
|
|
2932
|
-
const content = `# User Memory
|
|
2933
|
-
|
|
2934
|
-
Memoria persistente para sessoes Claude Code
|
|
2935
|
-
|
|
2936
|
-
---
|
|
2937
|
-
|
|
2938
|
-
## Dev
|
|
2939
|
-
|
|
2940
|
-
**Nome:** ${devName}
|
|
2941
|
-
**Maquina:** ${process.env.HOSTNAME || "local"}
|
|
2942
|
-
**Onboarding:** ${new Date().toISOString().split("T")[0]}
|
|
2943
|
-
|
|
2944
|
-
---
|
|
2945
|
-
|
|
2946
|
-
## Configuracoes da Lola
|
|
2947
|
-
|
|
2948
|
-
\`\`\`
|
|
2949
|
-
lola_profile: ${profile}
|
|
2950
|
-
\`\`\`
|
|
2951
|
-
|
|
2952
|
-
---
|
|
2953
|
-
|
|
2954
|
-
## Ultima Sessao
|
|
2955
|
-
|
|
2956
|
-
(sera preenchido automaticamente)
|
|
2957
|
-
|
|
2958
|
-
---
|
|
2959
|
-
`;
|
|
2960
|
-
await Bun.write(USER_MEMORY, content);
|
|
2961
|
-
Se(import_picocolors7.default.green("Onboarding concluido!"));
|
|
2962
|
-
console.log();
|
|
2963
|
-
console.log(import_picocolors7.default.bold(" Resumo:"));
|
|
2964
|
-
console.log(import_picocolors7.default.dim(" Nome: ") + import_picocolors7.default.white(devName));
|
|
2965
|
-
console.log(import_picocolors7.default.dim(" Perfil: ") + import_picocolors7.default.white(PROFILES[profile].label));
|
|
2966
|
-
console.log();
|
|
2967
|
-
console.log(import_picocolors7.default.bold(" Proximos passos:"));
|
|
2968
|
-
console.log(import_picocolors7.default.dim(" 1. ") + import_picocolors7.default.white("lola") + import_picocolors7.default.dim(" - Iniciar sessao com a Lola"));
|
|
2969
|
-
console.log(import_picocolors7.default.dim(" 2. ") + import_picocolors7.default.white("nimbus create meu-projeto --fast") + import_picocolors7.default.dim(" - Criar projeto"));
|
|
2970
|
-
console.log(import_picocolors7.default.dim(" 3. ") + import_picocolors7.default.white('lola suggest "sua ideia"') + import_picocolors7.default.dim(" - Sugerir melhoria"));
|
|
2971
|
-
console.log();
|
|
2972
|
-
console.log(import_picocolors7.default.dim(" Docs: ~/.lola/README.md"));
|
|
2973
|
-
console.log();
|
|
2974
|
-
}
|
|
2975
|
-
var QUIZ_QUESTIONS = [
|
|
2976
|
-
{
|
|
2977
|
-
question: "Quais sao os 4 valores da nimbuslab?",
|
|
2978
|
-
options: [
|
|
2979
|
-
{ value: "a", label: "Velocidade, Qualidade, Preco, Entrega" },
|
|
2980
|
-
{ value: "b", label: "Cocriacao, Inovacao, Evolucao, Humanizacao" },
|
|
2981
|
-
{ value: "c", label: "Codigo, Design, Marketing, Vendas" },
|
|
2982
|
-
{ value: "d", label: "Agil, Lean, Scrum, Kanban" }
|
|
2983
|
-
],
|
|
2984
|
-
correct: "b",
|
|
2985
|
-
explanation: "Cocriacao (construimos junto), Inovacao (buscamos o novo), Evolucao (aprendizado continuo), Humanizacao (tecnologia a servico das pessoas)."
|
|
2986
|
-
},
|
|
2987
|
-
{
|
|
2988
|
-
question: "Quais sao os 4 pilares da filosofia fast?",
|
|
2989
|
-
options: [
|
|
2990
|
-
{ value: "a", label: "Analise, Planejamento, Execucao, Documentacao" },
|
|
2991
|
-
{ value: "b", label: "Design, Codigo, Teste, Deploy" },
|
|
2992
|
-
{ value: "c", label: "Briefing, Prototipo, Desenvolvimento, Lancamento" },
|
|
2993
|
-
{ value: "d", label: "Discovery, Definition, Development, Delivery" }
|
|
2994
|
-
],
|
|
2995
|
-
correct: "a",
|
|
2996
|
-
explanation: "Filosofia fast: 1. Analise (entender), 2. Planejamento (definir caminho), 3. Execucao (implementar), 4. Documentacao (registrar)."
|
|
2997
|
-
},
|
|
2998
|
-
{
|
|
2999
|
-
question: "Qual package manager a nimbuslab usa como padrao?",
|
|
3000
|
-
options: [
|
|
3001
|
-
{ value: "a", label: "npm" },
|
|
3002
|
-
{ value: "b", label: "yarn" },
|
|
3003
|
-
{ value: "c", label: "pnpm" },
|
|
3004
|
-
{ value: "d", label: "bun" }
|
|
3005
|
-
],
|
|
3006
|
-
correct: "d",
|
|
3007
|
-
explanation: "Bun e o package manager padrao. Mais rapido e com menos dependencias."
|
|
3008
|
-
},
|
|
3009
|
-
{
|
|
3010
|
-
question: "Qual o estilo padrao do shadcn/ui na nimbuslab?",
|
|
3011
|
-
options: [
|
|
3012
|
-
{ value: "a", label: "new-york" },
|
|
3013
|
-
{ value: "b", label: "default" },
|
|
3014
|
-
{ value: "c", label: "minimal" },
|
|
3015
|
-
{ value: "d", label: "custom" }
|
|
3016
|
-
],
|
|
3017
|
-
correct: "b",
|
|
3018
|
-
explanation: "Usamos o estilo 'default' do shadcn/ui. Nunca 'new-york'."
|
|
3019
|
-
},
|
|
3020
|
-
{
|
|
3021
|
-
question: "Em projetos externos (stealth mode), a Lola deve:",
|
|
3022
|
-
options: [
|
|
3023
|
-
{ value: "a", label: "Sempre mencionar a nimbuslab nos commits" },
|
|
3024
|
-
{ value: "b", label: "Usar assinatura 'Co-authored-by: Lola'" },
|
|
3025
|
-
{ value: "c", label: "Nunca mencionar nimbuslab, Lola ou IA" },
|
|
3026
|
-
{ value: "d", label: "Adicionar badge da nimbuslab no README" }
|
|
3027
|
-
],
|
|
3028
|
-
correct: "c",
|
|
3029
|
-
explanation: "Stealth mode: commits sem mencao a nimbuslab/Lola/IA. O cliente nao precisa saber dos bastidores."
|
|
3030
|
-
},
|
|
3031
|
-
{
|
|
3032
|
-
question: "Qual a versao minima do Next.js usada na stack nimbuslab?",
|
|
3033
|
-
options: [
|
|
3034
|
-
{ value: "a", label: "Next.js 13" },
|
|
3035
|
-
{ value: "b", label: "Next.js 14" },
|
|
3036
|
-
{ value: "c", label: "Next.js 15" },
|
|
3037
|
-
{ value: "d", label: "Next.js 16" }
|
|
3038
|
-
],
|
|
3039
|
-
correct: "d",
|
|
3040
|
-
explanation: "Stack atual: Next.js 16+ com App Router e Turbopack."
|
|
3041
|
-
},
|
|
3042
|
-
{
|
|
3043
|
-
question: "Quem pode aprovar e mergear mudancas no repositorio da Lola?",
|
|
3044
|
-
options: [
|
|
3045
|
-
{ value: "a", label: "Qualquer dev da nimbuslab" },
|
|
3046
|
-
{ value: "b", label: "Apenas o Hugo" },
|
|
3047
|
-
{ value: "c", label: "Qualquer pessoa com acesso ao repo" },
|
|
3048
|
-
{ value: "d", label: "A propria Lola via automacao" }
|
|
3049
|
-
],
|
|
3050
|
-
correct: "b",
|
|
3051
|
-
explanation: "Apenas o Hugo pode aprovar e mergear. Devs sugerem via 'lola suggest', Hugo revisa."
|
|
3052
|
-
},
|
|
3053
|
-
{
|
|
3054
|
-
question: "Em commits da nimbuslab, qual o idioma correto?",
|
|
3055
|
-
options: [
|
|
3056
|
-
{ value: "a", label: "Ingles" },
|
|
3057
|
-
{ value: "b", label: "Portugues (BR)" },
|
|
3058
|
-
{ value: "c", label: "Depende do projeto" },
|
|
3059
|
-
{ value: "d", label: "Spanglish" }
|
|
3060
|
-
],
|
|
3061
|
-
correct: "b",
|
|
3062
|
-
explanation: "Commits e PRs em Portugues (BR). Codigo e comentarios em Ingles."
|
|
3063
|
-
}
|
|
3064
|
-
];
|
|
3065
|
-
async function runQuiz() {
|
|
3066
|
-
console.log();
|
|
3067
|
-
console.log(import_picocolors7.default.cyan(" Quiz nimbuslab"));
|
|
3068
|
-
console.log(import_picocolors7.default.dim(" =============="));
|
|
3069
|
-
console.log();
|
|
3070
|
-
console.log(import_picocolors7.default.dim(" Teste seus conhecimentos sobre a nimbuslab!"));
|
|
3071
|
-
console.log(import_picocolors7.default.dim(" 8 perguntas sobre valores, filosofia e stack."));
|
|
3072
|
-
console.log();
|
|
3073
|
-
let score = 0;
|
|
3074
|
-
const results = [];
|
|
3075
|
-
for (let i = 0;i < QUIZ_QUESTIONS.length; i++) {
|
|
3076
|
-
const q2 = QUIZ_QUESTIONS[i];
|
|
3077
|
-
const answer = await ve({
|
|
3078
|
-
message: `${i + 1}. ${q2.question}`,
|
|
3079
|
-
options: q2.options
|
|
3080
|
-
});
|
|
3081
|
-
if (pD(answer)) {
|
|
3082
|
-
xe("Quiz cancelado");
|
|
3083
|
-
process.exit(0);
|
|
3084
|
-
}
|
|
3085
|
-
const isCorrect = answer === q2.correct;
|
|
3086
|
-
if (isCorrect) {
|
|
3087
|
-
score++;
|
|
3088
|
-
console.log(import_picocolors7.default.green(" Correto!"));
|
|
3089
|
-
} else {
|
|
3090
|
-
console.log(import_picocolors7.default.red(" Incorreto."));
|
|
3091
|
-
}
|
|
3092
|
-
console.log(import_picocolors7.default.dim(` ${q2.explanation}`));
|
|
3093
|
-
console.log();
|
|
3094
|
-
results.push({
|
|
3095
|
-
question: q2.question,
|
|
3096
|
-
correct: isCorrect,
|
|
3097
|
-
explanation: q2.explanation
|
|
3098
|
-
});
|
|
3099
|
-
}
|
|
3100
|
-
const percentage = Math.round(score / QUIZ_QUESTIONS.length * 100);
|
|
3101
|
-
const passed = percentage >= 75;
|
|
3102
|
-
console.log(import_picocolors7.default.bold(" Resultado:"));
|
|
3103
|
-
console.log();
|
|
3104
|
-
if (passed) {
|
|
3105
|
-
console.log(import_picocolors7.default.green(` ${score}/${QUIZ_QUESTIONS.length} (${percentage}%) - Aprovado!`));
|
|
3106
|
-
console.log();
|
|
3107
|
-
if (percentage === 100) {
|
|
3108
|
-
console.log(import_picocolors7.default.cyan(" Perfeito! Voce conhece bem a nimbuslab."));
|
|
3109
|
-
} else {
|
|
3110
|
-
console.log(import_picocolors7.default.cyan(" Muito bem! Voce esta pronto para trabalhar."));
|
|
3111
|
-
}
|
|
3112
|
-
} else {
|
|
3113
|
-
console.log(import_picocolors7.default.yellow(` ${score}/${QUIZ_QUESTIONS.length} (${percentage}%) - Precisa revisar`));
|
|
3114
|
-
console.log();
|
|
3115
|
-
console.log(import_picocolors7.default.dim(" Revise os conceitos em:"));
|
|
3116
|
-
console.log(import_picocolors7.default.dim(" ~/.lola/core/values.md"));
|
|
3117
|
-
console.log(import_picocolors7.default.dim(" ~/.lola/core/philosophy.md"));
|
|
3118
|
-
console.log(import_picocolors7.default.dim(" ~/.lola/modules/stack.md"));
|
|
3119
|
-
}
|
|
3120
|
-
console.log();
|
|
3121
|
-
}
|
|
3122
|
-
async function installInteractive() {
|
|
3123
|
-
console.log();
|
|
3124
|
-
console.log(import_picocolors7.default.cyan(" Lola - Code Agent da nimbuslab"));
|
|
3125
|
-
console.log(import_picocolors7.default.dim(" ==============================="));
|
|
3126
|
-
console.log();
|
|
3127
|
-
const hasClaude = hasClaudeCLI();
|
|
3128
|
-
const hasGemini = hasGeminiCLI();
|
|
3129
|
-
console.log(import_picocolors7.default.dim(" Detectando agents..."));
|
|
3130
|
-
console.log(import_picocolors7.default.dim(` Claude CLI: ${hasClaude ? import_picocolors7.default.green("instalado") : import_picocolors7.default.yellow("nao encontrado")}`));
|
|
3131
|
-
console.log(import_picocolors7.default.dim(` Gemini CLI: ${hasGemini ? import_picocolors7.default.green("instalado") : import_picocolors7.default.yellow("nao encontrado")}`));
|
|
3132
|
-
console.log();
|
|
3133
|
-
const agentChoice = await ve({
|
|
3134
|
-
message: "Qual agent deseja configurar?",
|
|
3135
|
-
options: [
|
|
3136
|
-
{
|
|
3137
|
-
value: "all",
|
|
3138
|
-
label: "Todos (Recomendado)",
|
|
3139
|
-
hint: "Configura Claude e Gemini"
|
|
3140
|
-
},
|
|
3141
|
-
{
|
|
3142
|
-
value: "claude",
|
|
3143
|
-
label: "Apenas Claude",
|
|
3144
|
-
hint: hasClaude ? "Ja instalado" : "Sera instalado"
|
|
3145
|
-
},
|
|
3146
|
-
{
|
|
3147
|
-
value: "gemini",
|
|
3148
|
-
label: "Apenas Gemini",
|
|
3149
|
-
hint: hasGemini ? "Ja instalado" : "Sera instalado"
|
|
3150
|
-
}
|
|
3151
|
-
]
|
|
3152
|
-
});
|
|
3153
|
-
if (pD(agentChoice)) {
|
|
3154
|
-
xe("Instalacao cancelada");
|
|
3155
|
-
process.exit(0);
|
|
3156
|
-
}
|
|
3157
|
-
const choice = agentChoice;
|
|
3158
|
-
await installLolaBase();
|
|
3159
|
-
if (choice === "claude" || choice === "all") {
|
|
3160
|
-
console.log();
|
|
3161
|
-
console.log(import_picocolors7.default.bgBlue(import_picocolors7.default.white(" CLAUDE ")));
|
|
3162
|
-
await setupClaude();
|
|
3163
|
-
}
|
|
3164
|
-
if (choice === "gemini" || choice === "all") {
|
|
3165
|
-
console.log();
|
|
3166
|
-
console.log(import_picocolors7.default.bgMagenta(import_picocolors7.default.white(" GEMINI ")));
|
|
3167
|
-
await setupGemini();
|
|
3168
|
-
}
|
|
3169
|
-
console.log();
|
|
3170
|
-
console.log(import_picocolors7.default.green(" ==============================="));
|
|
3171
|
-
console.log(import_picocolors7.default.green(" Instalacao concluida!"));
|
|
3172
|
-
console.log(import_picocolors7.default.green(" ==============================="));
|
|
3173
|
-
console.log();
|
|
3174
|
-
if (choice === "claude" || choice === "all") {
|
|
3175
|
-
console.log(import_picocolors7.default.dim(" lola ") + import_picocolors7.default.white("# Claude com Lola"));
|
|
3176
|
-
}
|
|
3177
|
-
if (choice === "gemini" || choice === "all") {
|
|
3178
|
-
console.log(import_picocolors7.default.dim(" lola-gemini ") + import_picocolors7.default.white("# Gemini com Lola"));
|
|
3179
|
-
}
|
|
3180
|
-
console.log();
|
|
3181
|
-
console.log(import_picocolors7.default.bold(" lola-memory (compartilhado entre agents):"));
|
|
3182
|
-
console.log(import_picocolors7.default.dim(" remember, learn, memory_stats"));
|
|
3183
|
-
console.log();
|
|
3184
|
-
}
|
|
3185
|
-
async function installLolaBase() {
|
|
3186
|
-
console.log();
|
|
3187
|
-
console.log(import_picocolors7.default.cyan(" Instalando base Lola (~/.lola)..."));
|
|
3188
|
-
const isUpdate = existsSync2(LOLA_DIR);
|
|
3189
|
-
if (isUpdate) {
|
|
3190
|
-
console.log(import_picocolors7.default.dim(` Lola ja instalada em ${LOLA_DIR}`));
|
|
3191
|
-
console.log(import_picocolors7.default.dim(" Atualizando..."));
|
|
3192
|
-
const statusCheck = Bun.spawnSync(["git", "status", "--porcelain"], {
|
|
3193
|
-
cwd: LOLA_DIR,
|
|
3194
|
-
stdout: "pipe"
|
|
3195
|
-
});
|
|
3196
|
-
const hasLocalChanges = statusCheck.stdout.toString().trim().length > 0;
|
|
3197
|
-
if (hasLocalChanges) {
|
|
3198
|
-
console.log(import_picocolors7.default.dim(" Salvando mudancas locais..."));
|
|
3199
|
-
Bun.spawnSync(["git", "stash", "--quiet"], {
|
|
3200
|
-
cwd: LOLA_DIR,
|
|
3201
|
-
stdout: "pipe",
|
|
3202
|
-
stderr: "pipe"
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3205
|
-
const result = Bun.spawnSync(["git", "pull", "--quiet"], {
|
|
3206
|
-
cwd: LOLA_DIR,
|
|
3207
|
-
stdout: "inherit",
|
|
3208
|
-
stderr: "inherit"
|
|
3209
|
-
});
|
|
3210
|
-
if (hasLocalChanges) {
|
|
3211
|
-
console.log(import_picocolors7.default.dim(" Restaurando mudancas locais..."));
|
|
3212
|
-
const stashPop = Bun.spawnSync(["git", "stash", "pop", "--quiet"], {
|
|
3213
|
-
cwd: LOLA_DIR,
|
|
3214
|
-
stdout: "pipe",
|
|
3215
|
-
stderr: "pipe"
|
|
3216
|
-
});
|
|
3217
|
-
if (stashPop.exitCode !== 0) {
|
|
3218
|
-
console.log(import_picocolors7.default.yellow(" Aviso: conflito ao restaurar mudancas locais"));
|
|
3219
|
-
console.log(import_picocolors7.default.dim(" Verifique ~/.lola e resolva manualmente: git stash pop"));
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
if (result.exitCode !== 0) {
|
|
3223
|
-
console.log(import_picocolors7.default.red(" Erro ao atualizar Lola"));
|
|
3224
|
-
process.exit(1);
|
|
3225
|
-
}
|
|
3226
|
-
console.log(import_picocolors7.default.green(" Atualizado!"));
|
|
3227
|
-
} else {
|
|
3228
|
-
console.log(import_picocolors7.default.dim(` Clonando em ${LOLA_DIR}...`));
|
|
3229
|
-
const result = Bun.spawnSync(["git", "clone", "--quiet", LOLA_REPO, LOLA_DIR], {
|
|
3230
|
-
stdout: "inherit",
|
|
3231
|
-
stderr: "inherit"
|
|
3232
|
-
});
|
|
3233
|
-
if (result.exitCode !== 0) {
|
|
3234
|
-
console.log(import_picocolors7.default.red(" Erro ao clonar repositorio"));
|
|
3235
|
-
console.log(import_picocolors7.default.dim(" Verifique se tem acesso ao repo nimbuslab/lola"));
|
|
3236
|
-
process.exit(1);
|
|
3237
|
-
}
|
|
3238
|
-
console.log(import_picocolors7.default.green(" Instalado!"));
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
async function setupClaude() {
|
|
3242
|
-
if (!hasClaudeCLI()) {
|
|
3243
|
-
console.log(import_picocolors7.default.yellow(" Claude CLI nao encontrado"));
|
|
3244
|
-
console.log(import_picocolors7.default.dim(" Instale: https://claude.ai/download"));
|
|
3245
|
-
console.log(import_picocolors7.default.dim(" Depois rode 'nimbus lola install' novamente"));
|
|
3246
|
-
return;
|
|
3247
|
-
}
|
|
3248
|
-
console.log(import_picocolors7.default.green(" Claude CLI encontrado"));
|
|
3249
|
-
const isWindows = process.platform === "win32";
|
|
3250
|
-
const lolaAgent = join3(LOLA_DIR, "agents", "claude.md");
|
|
3251
|
-
console.log();
|
|
3252
|
-
console.log(import_picocolors7.default.cyan(" Configurando comando lola..."));
|
|
3253
|
-
if (isWindows) {
|
|
3254
|
-
const ps5ProfileDir = join3(HOME, "Documents", "WindowsPowerShell");
|
|
3255
|
-
const ps7ProfileDir = join3(HOME, "Documents", "PowerShell");
|
|
3256
|
-
const profileName = "Microsoft.PowerShell_profile.ps1";
|
|
3257
|
-
const lolaFunction = `
|
|
3258
|
-
# Lola - Code Agent da nimbuslab
|
|
3259
|
-
function lola {
|
|
3260
|
-
param([Parameter(ValueFromRemainingArguments=$true)]$args)
|
|
3261
|
-
$agent = "$env:USERPROFILE\\.lola\\agents\\claude.md"
|
|
3262
|
-
if (Test-Path $agent) {
|
|
3263
|
-
claude --append-system-prompt-file $agent @args
|
|
3264
|
-
} else {
|
|
3265
|
-
Write-Host "Agente Lola nao encontrado. Rode: nimbus lola install"
|
|
3266
|
-
}
|
|
3267
|
-
}
|
|
3268
|
-
`;
|
|
3269
|
-
const profiles = [
|
|
3270
|
-
{ dir: ps5ProfileDir, name: "PowerShell 5.x" },
|
|
3271
|
-
{ dir: ps7ProfileDir, name: "PowerShell 7+" }
|
|
3272
|
-
];
|
|
3273
|
-
let addedToAny = false;
|
|
3274
|
-
for (const { dir, name } of profiles) {
|
|
3275
|
-
const profilePath = join3(dir, profileName);
|
|
3276
|
-
if (!existsSync2(dir)) {
|
|
3277
|
-
await Bun.$`mkdir -p ${dir}`;
|
|
3278
|
-
}
|
|
3279
|
-
let profileContent = "";
|
|
3280
|
-
if (existsSync2(profilePath)) {
|
|
3281
|
-
profileContent = await Bun.file(profilePath).text();
|
|
3282
|
-
}
|
|
3283
|
-
if (!profileContent.includes("function lola")) {
|
|
3284
|
-
await Bun.write(profilePath, profileContent + lolaFunction);
|
|
3285
|
-
console.log(import_picocolors7.default.green(` Funcao lola adicionada ao ${name} profile`));
|
|
3286
|
-
addedToAny = true;
|
|
3287
|
-
}
|
|
3288
|
-
}
|
|
3289
|
-
if (addedToAny) {
|
|
3290
|
-
console.log(import_picocolors7.default.yellow(" Reinicie o PowerShell para usar o comando 'lola'"));
|
|
3291
|
-
} else {
|
|
3292
|
-
console.log(import_picocolors7.default.green(" Funcao lola ja existe"));
|
|
3293
|
-
}
|
|
3294
|
-
} else {
|
|
3295
|
-
const binDir = join3(HOME, ".local", "bin");
|
|
3296
|
-
const lolaScript = join3(binDir, "lola");
|
|
3297
|
-
if (!existsSync2(lolaScript)) {
|
|
3298
|
-
await Bun.$`mkdir -p ${binDir}`;
|
|
3299
|
-
const unixScript = `#!/bin/bash
|
|
3300
|
-
# lola - Code Agent da nimbuslab
|
|
3301
|
-
LOLA_AGENT="${lolaAgent}"
|
|
3302
|
-
|
|
3303
|
-
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
|
3304
|
-
echo "lola - Code Agent da nimbuslab"
|
|
3305
|
-
echo "Uso: lola [args]"
|
|
3306
|
-
echo " lola Abre Claude CLI com a Lola"
|
|
3307
|
-
echo " lola --resume Resume sessao anterior"
|
|
3308
|
-
exit 0
|
|
3309
|
-
fi
|
|
3310
|
-
|
|
3311
|
-
if [[ -f "$LOLA_AGENT" ]]; then
|
|
3312
|
-
exec claude --append-system-prompt-file "$LOLA_AGENT" "$@"
|
|
3313
|
-
else
|
|
3314
|
-
echo "Agente Lola nao encontrado: $LOLA_AGENT"
|
|
3315
|
-
echo "Rode: nimbus lola install"
|
|
3316
|
-
exit 1
|
|
3317
|
-
fi
|
|
3318
|
-
`;
|
|
3319
|
-
await Bun.write(lolaScript, unixScript);
|
|
3320
|
-
await Bun.$`chmod +x ${lolaScript}`;
|
|
3321
|
-
console.log(import_picocolors7.default.green(` Script lola criado em ${lolaScript}`));
|
|
3322
|
-
const pathEnv = process.env.PATH || "";
|
|
3323
|
-
if (!pathEnv.includes(".local/bin")) {
|
|
3324
|
-
console.log();
|
|
3325
|
-
console.log(import_picocolors7.default.yellow(" IMPORTANTE: Adicione ~/.local/bin ao seu PATH"));
|
|
3326
|
-
console.log(import_picocolors7.default.dim(' export PATH="$HOME/.local/bin:$PATH"'));
|
|
3327
|
-
}
|
|
3328
|
-
} else {
|
|
3329
|
-
console.log(import_picocolors7.default.green(" Script lola ja existe"));
|
|
3330
|
-
}
|
|
3331
|
-
}
|
|
3332
|
-
await installLolaMemoryMCP();
|
|
3333
|
-
await installLolaCommands();
|
|
3334
|
-
const claudeDir = join3(HOME, ".claude");
|
|
3335
|
-
if (!existsSync2(USER_MEMORY)) {
|
|
3336
|
-
console.log();
|
|
3337
|
-
console.log(import_picocolors7.default.cyan(" Configurando USER_MEMORY.md..."));
|
|
3338
|
-
const gitUserResult = Bun.spawnSync(["git", "config", "user.name"], { stdout: "pipe" });
|
|
3339
|
-
const gitEmailResult = Bun.spawnSync(["git", "config", "user.email"], { stdout: "pipe" });
|
|
3340
|
-
const gitUser = gitUserResult.stdout.toString().trim() || "Dev";
|
|
3341
|
-
const gitEmail = gitEmailResult.stdout.toString().trim() || "";
|
|
3342
|
-
const hostname = process.env.HOSTNAME || process.env.COMPUTERNAME || "local";
|
|
3343
|
-
const today = new Date().toISOString().split("T")[0];
|
|
3344
|
-
await Bun.$`mkdir -p ${claudeDir}`;
|
|
3345
|
-
const content = `# User Memory
|
|
3346
|
-
|
|
3347
|
-
Memoria persistente para sessoes Claude Code
|
|
3348
|
-
|
|
3349
|
-
---
|
|
3350
|
-
|
|
3351
|
-
## Dev
|
|
3352
|
-
|
|
3353
|
-
**Nome:** ${gitUser}
|
|
3354
|
-
**Email:** ${gitEmail}
|
|
3355
|
-
**Maquina:** ${hostname}
|
|
3356
|
-
**Instalacao:** ${today}
|
|
3357
|
-
|
|
3358
|
-
---
|
|
3359
|
-
|
|
3360
|
-
## Configuracoes da Lola
|
|
3361
|
-
|
|
3362
|
-
\`\`\`
|
|
3363
|
-
lola_profile: millennial
|
|
3364
|
-
\`\`\`
|
|
3365
|
-
|
|
3366
|
-
---
|
|
3367
|
-
|
|
3368
|
-
## Ultima Sessao
|
|
3369
|
-
|
|
3370
|
-
(sera preenchido automaticamente)
|
|
3371
|
-
|
|
3372
|
-
---
|
|
3373
|
-
`;
|
|
3374
|
-
await Bun.write(USER_MEMORY, content);
|
|
3375
|
-
console.log(import_picocolors7.default.green(` USER_MEMORY.md criado para ${gitUser}!`));
|
|
3376
|
-
}
|
|
3377
|
-
console.log();
|
|
3378
|
-
console.log(import_picocolors7.default.green(" Claude configurado!"));
|
|
3379
|
-
}
|
|
3380
|
-
var SUBCOMMAND_ALIASES = {
|
|
3381
|
-
i: "install",
|
|
3382
|
-
s: "suggest",
|
|
3383
|
-
o: "onboard",
|
|
3384
|
-
q: "quiz",
|
|
3385
|
-
h: "help",
|
|
3386
|
-
sync: "install",
|
|
3387
|
-
"--help": "help",
|
|
3388
|
-
"-h": "help"
|
|
3389
|
-
};
|
|
3390
|
-
async function lola(args) {
|
|
3391
|
-
const rawSubcommand = args[0];
|
|
3392
|
-
const subcommand = rawSubcommand ? SUBCOMMAND_ALIASES[rawSubcommand] || rawSubcommand : null;
|
|
3393
|
-
if (!subcommand || subcommand === "install") {
|
|
3394
|
-
await installInteractive();
|
|
3395
|
-
} else if (subcommand === "onboard") {
|
|
3396
|
-
await onboardDev();
|
|
3397
|
-
} else if (subcommand === "quiz") {
|
|
3398
|
-
await runQuiz();
|
|
3399
|
-
} else if (subcommand === "suggest") {
|
|
3400
|
-
const message = args.slice(1).join(" ");
|
|
3401
|
-
await suggestImprovement(message);
|
|
3402
|
-
} else if (subcommand === "help") {
|
|
3403
|
-
showLolaHelp();
|
|
3404
|
-
} else {
|
|
3405
|
-
console.log(import_picocolors7.default.red(` Subcomando desconhecido: ${rawSubcommand}`));
|
|
3406
|
-
showLolaHelp();
|
|
3407
|
-
process.exit(1);
|
|
3408
|
-
}
|
|
3409
|
-
}
|
|
3410
|
-
function showLolaHelp() {
|
|
3411
|
-
console.log();
|
|
3412
|
-
console.log(import_picocolors7.default.bold(" Lola - Code Agent da nimbuslab"));
|
|
3413
|
-
console.log();
|
|
3414
|
-
console.log(import_picocolors7.default.bold(" Uso:") + " nimbus lola [subcomando]");
|
|
3415
|
-
console.log();
|
|
3416
|
-
console.log(import_picocolors7.default.bold(" Subcomandos:"));
|
|
3417
|
-
console.log(import_picocolors7.default.dim(" install, i ") + import_picocolors7.default.white("Instalar/atualizar Lola + MCP"));
|
|
3418
|
-
console.log(import_picocolors7.default.dim(" onboard, o ") + import_picocolors7.default.white("Configurar perfil (novos devs)"));
|
|
3419
|
-
console.log(import_picocolors7.default.dim(" quiz, q ") + import_picocolors7.default.white("Quiz sobre a nimbuslab"));
|
|
3420
|
-
console.log(import_picocolors7.default.dim(" suggest, s ") + import_picocolors7.default.white("Sugerir melhoria (cria issue)"));
|
|
3421
|
-
console.log(import_picocolors7.default.dim(" help, h ") + import_picocolors7.default.white("Mostrar esta ajuda"));
|
|
3422
|
-
console.log();
|
|
3423
|
-
console.log(import_picocolors7.default.bold(" Exemplos:"));
|
|
3424
|
-
console.log(import_picocolors7.default.dim(" $ nimbus lola i"));
|
|
3425
|
-
console.log(import_picocolors7.default.dim(" $ nimbus lola o"));
|
|
3426
|
-
console.log(import_picocolors7.default.dim(" $ nimbus lola q"));
|
|
3427
|
-
console.log(import_picocolors7.default.dim(' $ nimbus lola s "adicionar suporte a X"'));
|
|
3428
|
-
console.log();
|
|
3429
|
-
console.log(import_picocolors7.default.bold(" lola-memory (dentro do Claude):"));
|
|
3430
|
-
console.log(import_picocolors7.default.dim(' remember "query" ') + import_picocolors7.default.white("Buscar conhecimento"));
|
|
3431
|
-
console.log(import_picocolors7.default.dim(' learn "content" ') + import_picocolors7.default.white("Salvar conhecimento"));
|
|
3432
|
-
console.log(import_picocolors7.default.dim(" memory_stats ") + import_picocolors7.default.white("Ver estatisticas"));
|
|
3433
|
-
console.log(import_picocolors7.default.dim(" get_context ") + import_picocolors7.default.white("Perfil + memorias recentes"));
|
|
3434
|
-
console.log();
|
|
3435
|
-
}
|
|
3436
|
-
|
|
3437
3267
|
// src/commands/setup-node.ts
|
|
3438
3268
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
3439
3269
|
import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
|
|
3440
|
-
import { existsSync as
|
|
3441
|
-
import { homedir
|
|
3270
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
3271
|
+
import { homedir } from "os";
|
|
3442
3272
|
import { join as join4 } from "path";
|
|
3443
|
-
var
|
|
3273
|
+
var HOME = homedir();
|
|
3444
3274
|
var IS_WINDOWS = process.platform === "win32";
|
|
3445
|
-
var
|
|
3275
|
+
var CHECK_CMD = IS_WINDOWS ? "where" : "which";
|
|
3446
3276
|
function detectFnm() {
|
|
3447
3277
|
const result = { name: "fnm", installed: false };
|
|
3448
|
-
const check = spawnSync2(
|
|
3278
|
+
const check = spawnSync2(CHECK_CMD, ["fnm"], { encoding: "utf-8", shell: true });
|
|
3449
3279
|
const fnmLocations = IS_WINDOWS ? [
|
|
3450
|
-
join4(
|
|
3451
|
-
join4(
|
|
3280
|
+
join4(HOME, "scoop", "shims", "fnm.exe"),
|
|
3281
|
+
join4(HOME, "scoop", "apps", "fnm", "current", "fnm.exe"),
|
|
3452
3282
|
"C:\\ProgramData\\chocolatey\\bin\\fnm.exe",
|
|
3453
|
-
join4(
|
|
3454
|
-
join4(
|
|
3455
|
-
join4(
|
|
3456
|
-
join4(
|
|
3457
|
-
join4(
|
|
3458
|
-
join4(
|
|
3459
|
-
join4(
|
|
3283
|
+
join4(HOME, ".cargo", "bin", "fnm.exe"),
|
|
3284
|
+
join4(HOME, ".fnm", "fnm.exe"),
|
|
3285
|
+
join4(HOME, "AppData", "Local", "fnm", "fnm.exe"),
|
|
3286
|
+
join4(HOME, "AppData", "Roaming", "fnm", "fnm.exe"),
|
|
3287
|
+
join4(HOME, "AppData", "Local", "Microsoft", "fnm", "fnm.exe"),
|
|
3288
|
+
join4(HOME, "AppData", "Roaming", "fnm"),
|
|
3289
|
+
join4(HOME, "AppData", "Local", "fnm_multishells")
|
|
3460
3290
|
] : [
|
|
3461
|
-
join4(
|
|
3462
|
-
join4(
|
|
3463
|
-
join4(
|
|
3291
|
+
join4(HOME, ".local", "share", "fnm", "fnm"),
|
|
3292
|
+
join4(HOME, ".fnm", "fnm"),
|
|
3293
|
+
join4(HOME, ".local", "bin", "fnm"),
|
|
3464
3294
|
"/opt/homebrew/bin/fnm",
|
|
3465
3295
|
"/usr/local/bin/fnm",
|
|
3466
|
-
join4(
|
|
3296
|
+
join4(HOME, ".cargo", "bin", "fnm")
|
|
3467
3297
|
];
|
|
3468
3298
|
let fnmPath = null;
|
|
3469
|
-
if (check.
|
|
3299
|
+
if (check.status === 0) {
|
|
3470
3300
|
fnmPath = check.stdout?.trim().split(`
|
|
3471
3301
|
`)[0] || null;
|
|
3472
3302
|
} else {
|
|
3473
3303
|
for (const loc of fnmLocations) {
|
|
3474
|
-
if (
|
|
3304
|
+
if (existsSync2(loc)) {
|
|
3475
3305
|
fnmPath = loc;
|
|
3476
3306
|
break;
|
|
3477
3307
|
}
|
|
3478
3308
|
}
|
|
3479
3309
|
}
|
|
3480
3310
|
if (!fnmPath && process.env.FNM_DIR) {
|
|
3481
|
-
if (
|
|
3311
|
+
if (existsSync2(process.env.FNM_DIR)) {
|
|
3482
3312
|
fnmPath = process.env.FNM_DIR;
|
|
3483
3313
|
}
|
|
3484
3314
|
}
|
|
3485
3315
|
if (!fnmPath && IS_WINDOWS) {
|
|
3486
|
-
const fnmMultishells = join4(
|
|
3487
|
-
if (
|
|
3316
|
+
const fnmMultishells = join4(HOME, "AppData", "Local", "fnm_multishells");
|
|
3317
|
+
if (existsSync2(fnmMultishells)) {
|
|
3488
3318
|
fnmPath = fnmMultishells;
|
|
3489
3319
|
}
|
|
3490
3320
|
}
|
|
@@ -3499,26 +3329,26 @@ function detectFnm() {
|
|
|
3499
3329
|
} catch {}
|
|
3500
3330
|
result.configFiles = [];
|
|
3501
3331
|
if (IS_WINDOWS) {
|
|
3502
|
-
const ps5Profile = join4(
|
|
3503
|
-
const ps7Profile = join4(
|
|
3504
|
-
const psProfile = join4(
|
|
3505
|
-
if (
|
|
3332
|
+
const ps5Profile = join4(HOME, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
3333
|
+
const ps7Profile = join4(HOME, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
3334
|
+
const psProfile = join4(HOME, "Documents", "PowerShell", "profile.ps1");
|
|
3335
|
+
if (existsSync2(ps5Profile))
|
|
3506
3336
|
result.configFiles.push(ps5Profile);
|
|
3507
|
-
if (
|
|
3337
|
+
if (existsSync2(ps7Profile))
|
|
3508
3338
|
result.configFiles.push(ps7Profile);
|
|
3509
|
-
if (
|
|
3339
|
+
if (existsSync2(psProfile))
|
|
3510
3340
|
result.configFiles.push(psProfile);
|
|
3511
3341
|
} else {
|
|
3512
3342
|
const configs = [
|
|
3513
|
-
join4(
|
|
3514
|
-
join4(
|
|
3515
|
-
join4(
|
|
3516
|
-
join4(
|
|
3517
|
-
join4(
|
|
3518
|
-
join4(
|
|
3343
|
+
join4(HOME, ".bashrc"),
|
|
3344
|
+
join4(HOME, ".bash_profile"),
|
|
3345
|
+
join4(HOME, ".profile"),
|
|
3346
|
+
join4(HOME, ".zshrc"),
|
|
3347
|
+
join4(HOME, ".zprofile"),
|
|
3348
|
+
join4(HOME, ".config", "fish", "config.fish")
|
|
3519
3349
|
];
|
|
3520
3350
|
for (const cfg of configs) {
|
|
3521
|
-
if (
|
|
3351
|
+
if (existsSync2(cfg))
|
|
3522
3352
|
result.configFiles.push(cfg);
|
|
3523
3353
|
}
|
|
3524
3354
|
}
|
|
@@ -3527,20 +3357,20 @@ function detectFnm() {
|
|
|
3527
3357
|
function detectNvm() {
|
|
3528
3358
|
const result = { name: "nvm", installed: false };
|
|
3529
3359
|
if (IS_WINDOWS) {
|
|
3530
|
-
const check = spawnSync2(
|
|
3360
|
+
const check = spawnSync2(CHECK_CMD, ["nvm"], { encoding: "utf-8", shell: true });
|
|
3531
3361
|
const nvmWinLocations = [
|
|
3532
|
-
join4(
|
|
3362
|
+
join4(HOME, "AppData", "Roaming", "nvm", "nvm.exe"),
|
|
3533
3363
|
"C:\\Program Files\\nvm\\nvm.exe",
|
|
3534
3364
|
"C:\\ProgramData\\nvm\\nvm.exe",
|
|
3535
|
-
join4(
|
|
3365
|
+
join4(HOME, "nvm", "nvm.exe")
|
|
3536
3366
|
];
|
|
3537
3367
|
let nvmPath = null;
|
|
3538
|
-
if (check.
|
|
3368
|
+
if (check.status === 0) {
|
|
3539
3369
|
nvmPath = check.stdout?.trim().split(`
|
|
3540
3370
|
`)[0] || null;
|
|
3541
3371
|
} else {
|
|
3542
3372
|
for (const loc of nvmWinLocations) {
|
|
3543
|
-
if (
|
|
3373
|
+
if (existsSync2(loc)) {
|
|
3544
3374
|
nvmPath = loc;
|
|
3545
3375
|
break;
|
|
3546
3376
|
}
|
|
@@ -3556,31 +3386,31 @@ function detectNvm() {
|
|
|
3556
3386
|
} catch {}
|
|
3557
3387
|
result.configFiles = [];
|
|
3558
3388
|
const configs = [
|
|
3559
|
-
join4(
|
|
3560
|
-
join4(
|
|
3561
|
-
join4(
|
|
3389
|
+
join4(HOME, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1"),
|
|
3390
|
+
join4(HOME, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1"),
|
|
3391
|
+
join4(HOME, "Documents", "PowerShell", "profile.ps1")
|
|
3562
3392
|
];
|
|
3563
3393
|
for (const cfg of configs) {
|
|
3564
|
-
if (
|
|
3394
|
+
if (existsSync2(cfg))
|
|
3565
3395
|
result.configFiles.push(cfg);
|
|
3566
3396
|
}
|
|
3567
3397
|
} else {
|
|
3568
|
-
const nvmDir = process.env.NVM_DIR || join4(
|
|
3569
|
-
if (!
|
|
3398
|
+
const nvmDir = process.env.NVM_DIR || join4(HOME, ".nvm");
|
|
3399
|
+
if (!existsSync2(nvmDir))
|
|
3570
3400
|
return result;
|
|
3571
3401
|
result.installed = true;
|
|
3572
3402
|
result.path = nvmDir;
|
|
3573
3403
|
result.configFiles = [];
|
|
3574
3404
|
const configs = [
|
|
3575
|
-
join4(
|
|
3576
|
-
join4(
|
|
3577
|
-
join4(
|
|
3578
|
-
join4(
|
|
3579
|
-
join4(
|
|
3580
|
-
join4(
|
|
3405
|
+
join4(HOME, ".bashrc"),
|
|
3406
|
+
join4(HOME, ".bash_profile"),
|
|
3407
|
+
join4(HOME, ".profile"),
|
|
3408
|
+
join4(HOME, ".zshrc"),
|
|
3409
|
+
join4(HOME, ".zprofile"),
|
|
3410
|
+
join4(HOME, ".config", "fish", "config.fish")
|
|
3581
3411
|
];
|
|
3582
3412
|
for (const cfg of configs) {
|
|
3583
|
-
if (
|
|
3413
|
+
if (existsSync2(cfg))
|
|
3584
3414
|
result.configFiles.push(cfg);
|
|
3585
3415
|
}
|
|
3586
3416
|
}
|
|
@@ -3588,8 +3418,8 @@ function detectNvm() {
|
|
|
3588
3418
|
}
|
|
3589
3419
|
function detectVolta() {
|
|
3590
3420
|
const result = { name: "volta", installed: false };
|
|
3591
|
-
const check = spawnSync2(
|
|
3592
|
-
if (check.
|
|
3421
|
+
const check = spawnSync2(CHECK_CMD, ["volta"], { encoding: "utf-8", shell: true });
|
|
3422
|
+
if (check.status !== 0)
|
|
3593
3423
|
return result;
|
|
3594
3424
|
result.installed = true;
|
|
3595
3425
|
result.path = check.stdout?.trim().split(`
|
|
@@ -3601,8 +3431,8 @@ function detectVolta() {
|
|
|
3601
3431
|
return result;
|
|
3602
3432
|
}
|
|
3603
3433
|
function detectNode() {
|
|
3604
|
-
const check = spawnSync2(
|
|
3605
|
-
if (check.
|
|
3434
|
+
const check = spawnSync2(CHECK_CMD, ["node"], { encoding: "utf-8", shell: true });
|
|
3435
|
+
if (check.status !== 0)
|
|
3606
3436
|
return { version: null, manager: null };
|
|
3607
3437
|
const nodePath = check.stdout?.trim().split(`
|
|
3608
3438
|
`)[0] || "";
|
|
@@ -3643,7 +3473,7 @@ function getGlobalPackages() {
|
|
|
3643
3473
|
return packages;
|
|
3644
3474
|
}
|
|
3645
3475
|
function removeFnmFromConfig(configFile) {
|
|
3646
|
-
if (!
|
|
3476
|
+
if (!existsSync2(configFile))
|
|
3647
3477
|
return false;
|
|
3648
3478
|
try {
|
|
3649
3479
|
let content = readFileSync2(configFile, "utf-8");
|
|
@@ -3668,7 +3498,7 @@ function removeFnmFromConfig(configFile) {
|
|
|
3668
3498
|
return false;
|
|
3669
3499
|
}
|
|
3670
3500
|
function removeNvmFromConfig(configFile) {
|
|
3671
|
-
if (!
|
|
3501
|
+
if (!existsSync2(configFile))
|
|
3672
3502
|
return false;
|
|
3673
3503
|
try {
|
|
3674
3504
|
let content = readFileSync2(configFile, "utf-8");
|
|
@@ -3729,16 +3559,16 @@ async function removeFnm(fnm) {
|
|
|
3729
3559
|
} catch {}
|
|
3730
3560
|
}
|
|
3731
3561
|
const winFnmDirs = [
|
|
3732
|
-
join4(
|
|
3733
|
-
join4(
|
|
3734
|
-
join4(
|
|
3735
|
-
join4(
|
|
3736
|
-
join4(
|
|
3562
|
+
join4(HOME, ".fnm"),
|
|
3563
|
+
join4(HOME, "AppData", "Local", "fnm"),
|
|
3564
|
+
join4(HOME, "AppData", "Roaming", "fnm"),
|
|
3565
|
+
join4(HOME, "AppData", "Local", "fnm_multishells"),
|
|
3566
|
+
join4(HOME, "AppData", "Local", "Microsoft", "fnm")
|
|
3737
3567
|
];
|
|
3738
3568
|
for (const dir of winFnmDirs) {
|
|
3739
|
-
if (
|
|
3569
|
+
if (existsSync2(dir)) {
|
|
3740
3570
|
try {
|
|
3741
|
-
execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell:
|
|
3571
|
+
execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: "cmd.exe" });
|
|
3742
3572
|
console.log(import_picocolors8.default.dim(` Removido ${dir}`));
|
|
3743
3573
|
removed = true;
|
|
3744
3574
|
} catch {
|
|
@@ -3769,7 +3599,7 @@ async function removeFnm(fnm) {
|
|
|
3769
3599
|
let removed = false;
|
|
3770
3600
|
try {
|
|
3771
3601
|
const brewCheck = spawnSync2("brew", ["list", "fnm"], { encoding: "utf-8", shell: true });
|
|
3772
|
-
if (brewCheck.
|
|
3602
|
+
if (brewCheck.status === 0) {
|
|
3773
3603
|
execSync2("brew uninstall fnm", { stdio: "pipe" });
|
|
3774
3604
|
console.log(import_picocolors8.default.dim(" Removido via Homebrew"));
|
|
3775
3605
|
removed = true;
|
|
@@ -3782,22 +3612,22 @@ async function removeFnm(fnm) {
|
|
|
3782
3612
|
}
|
|
3783
3613
|
}
|
|
3784
3614
|
const fnmDirs = [
|
|
3785
|
-
join4(
|
|
3786
|
-
join4(
|
|
3615
|
+
join4(HOME, ".fnm"),
|
|
3616
|
+
join4(HOME, ".local", "share", "fnm")
|
|
3787
3617
|
];
|
|
3788
3618
|
for (const fnmDir of fnmDirs) {
|
|
3789
|
-
if (
|
|
3619
|
+
if (existsSync2(fnmDir)) {
|
|
3790
3620
|
execSync2(`rm -rf "${fnmDir}"`, { stdio: "pipe" });
|
|
3791
3621
|
console.log(import_picocolors8.default.dim(` Removido ${fnmDir}`));
|
|
3792
3622
|
removed = true;
|
|
3793
3623
|
}
|
|
3794
3624
|
}
|
|
3795
3625
|
const fnmBins = [
|
|
3796
|
-
join4(
|
|
3797
|
-
join4(
|
|
3626
|
+
join4(HOME, ".local", "bin", "fnm"),
|
|
3627
|
+
join4(HOME, ".cargo", "bin", "fnm")
|
|
3798
3628
|
];
|
|
3799
3629
|
for (const bin of fnmBins) {
|
|
3800
|
-
if (
|
|
3630
|
+
if (existsSync2(bin)) {
|
|
3801
3631
|
execSync2(`rm -f "${bin}"`, { stdio: "pipe" });
|
|
3802
3632
|
console.log(import_picocolors8.default.dim(` Removido ${bin}`));
|
|
3803
3633
|
removed = true;
|
|
@@ -3826,14 +3656,14 @@ async function removeNvm(nvm) {
|
|
|
3826
3656
|
}
|
|
3827
3657
|
} catch {}
|
|
3828
3658
|
const nvmWinDirs = [
|
|
3829
|
-
join4(
|
|
3659
|
+
join4(HOME, "AppData", "Roaming", "nvm"),
|
|
3830
3660
|
join4("C:", "Program Files", "nvm"),
|
|
3831
3661
|
join4("C:", "ProgramData", "nvm")
|
|
3832
3662
|
];
|
|
3833
3663
|
for (const dir of nvmWinDirs) {
|
|
3834
|
-
if (
|
|
3664
|
+
if (existsSync2(dir)) {
|
|
3835
3665
|
try {
|
|
3836
|
-
execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell:
|
|
3666
|
+
execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: "cmd.exe" });
|
|
3837
3667
|
console.log(import_picocolors8.default.dim(` Removido ${dir}`));
|
|
3838
3668
|
removed = true;
|
|
3839
3669
|
} catch {}
|
|
@@ -3863,8 +3693,8 @@ async function removeNvm(nvm) {
|
|
|
3863
3693
|
removed = true;
|
|
3864
3694
|
}
|
|
3865
3695
|
}
|
|
3866
|
-
const nvmDir = process.env.NVM_DIR || join4(
|
|
3867
|
-
if (
|
|
3696
|
+
const nvmDir = process.env.NVM_DIR || join4(HOME, ".nvm");
|
|
3697
|
+
if (existsSync2(nvmDir)) {
|
|
3868
3698
|
execSync2(`rm -rf "${nvmDir}"`, { stdio: "pipe" });
|
|
3869
3699
|
console.log(import_picocolors8.default.dim(` Removido ${nvmDir}`));
|
|
3870
3700
|
removed = true;
|
|
@@ -3882,8 +3712,8 @@ async function installVolta() {
|
|
|
3882
3712
|
try {
|
|
3883
3713
|
if (IS_WINDOWS) {
|
|
3884
3714
|
spinner.start("Verificando metodo de instalacao...");
|
|
3885
|
-
const wingetCheck = spawnSync2(
|
|
3886
|
-
if (wingetCheck.
|
|
3715
|
+
const wingetCheck = spawnSync2(CHECK_CMD, ["winget"], { encoding: "utf-8", shell: true });
|
|
3716
|
+
if (wingetCheck.status === 0) {
|
|
3887
3717
|
spinner.stop("winget detectado");
|
|
3888
3718
|
spinner.start("Instalando Volta via winget...");
|
|
3889
3719
|
try {
|
|
@@ -3892,18 +3722,18 @@ async function installVolta() {
|
|
|
3892
3722
|
timeout: 120000
|
|
3893
3723
|
});
|
|
3894
3724
|
spinner.stop("Volta instalado!");
|
|
3895
|
-
const voltaPath = join4(
|
|
3725
|
+
const voltaPath = join4(HOME, ".volta", "bin");
|
|
3896
3726
|
console.log(import_picocolors8.default.dim(` Adicionando ${voltaPath} ao PATH...`));
|
|
3897
3727
|
try {
|
|
3898
|
-
execSync2(`setx PATH "%PATH%;${voltaPath}"`, { stdio: "pipe", shell:
|
|
3728
|
+
execSync2(`setx PATH "%PATH%;${voltaPath}"`, { stdio: "pipe", shell: "cmd.exe" });
|
|
3899
3729
|
} catch {}
|
|
3900
3730
|
return true;
|
|
3901
3731
|
} catch (e2) {
|
|
3902
3732
|
spinner.stop(import_picocolors8.default.yellow("winget falhou, tentando outro metodo..."));
|
|
3903
3733
|
}
|
|
3904
3734
|
}
|
|
3905
|
-
const chocoCheck = spawnSync2(
|
|
3906
|
-
if (chocoCheck.
|
|
3735
|
+
const chocoCheck = spawnSync2(CHECK_CMD, ["choco"], { encoding: "utf-8", shell: true });
|
|
3736
|
+
if (chocoCheck.status === 0) {
|
|
3907
3737
|
spinner.start("Instalando Volta via Chocolatey...");
|
|
3908
3738
|
try {
|
|
3909
3739
|
execSync2("choco install volta -y", { stdio: "pipe", timeout: 120000 });
|
|
@@ -3953,13 +3783,13 @@ async function installVolta() {
|
|
|
3953
3783
|
stdio: "pipe",
|
|
3954
3784
|
shell: "/bin/bash"
|
|
3955
3785
|
});
|
|
3956
|
-
const shellConfig =
|
|
3786
|
+
const shellConfig = existsSync2(join4(HOME, ".zshrc")) ? join4(HOME, ".zshrc") : join4(HOME, ".bashrc");
|
|
3957
3787
|
const voltaSetup = `
|
|
3958
3788
|
# Volta - Node.js version manager
|
|
3959
3789
|
export VOLTA_HOME="$HOME/.volta"
|
|
3960
3790
|
export PATH="$VOLTA_HOME/bin:$PATH"
|
|
3961
3791
|
`;
|
|
3962
|
-
if (
|
|
3792
|
+
if (existsSync2(shellConfig)) {
|
|
3963
3793
|
const content = readFileSync2(shellConfig, "utf-8");
|
|
3964
3794
|
if (!content.includes("VOLTA_HOME")) {
|
|
3965
3795
|
writeFileSync(shellConfig, content + voltaSetup);
|
|
@@ -3978,9 +3808,9 @@ export PATH="$VOLTA_HOME/bin:$PATH"
|
|
|
3978
3808
|
async function installNodeWithVolta() {
|
|
3979
3809
|
const spinner = Y2();
|
|
3980
3810
|
try {
|
|
3981
|
-
const voltaBin = IS_WINDOWS ? "volta" : join4(
|
|
3811
|
+
const voltaBin = IS_WINDOWS ? "volta" : join4(HOME, ".volta", "bin", "volta");
|
|
3982
3812
|
spinner.start("Instalando Node.js LTS via Volta...");
|
|
3983
|
-
execSync2(`"${voltaBin}" install node`, { stdio: "pipe"
|
|
3813
|
+
execSync2(`"${voltaBin}" install node`, { stdio: "pipe" });
|
|
3984
3814
|
spinner.stop("Node.js instalado!");
|
|
3985
3815
|
return true;
|
|
3986
3816
|
} catch (error) {
|
|
@@ -3992,11 +3822,11 @@ async function reinstallGlobalPackages(packages) {
|
|
|
3992
3822
|
if (packages.length === 0)
|
|
3993
3823
|
return;
|
|
3994
3824
|
const spinner = Y2();
|
|
3995
|
-
const voltaBin = IS_WINDOWS ? "volta" : join4(
|
|
3825
|
+
const voltaBin = IS_WINDOWS ? "volta" : join4(HOME, ".volta", "bin", "volta");
|
|
3996
3826
|
for (const pkg of packages) {
|
|
3997
3827
|
spinner.start(`Instalando ${pkg}...`);
|
|
3998
3828
|
try {
|
|
3999
|
-
execSync2(`"${voltaBin}" install ${pkg}`, { stdio: "pipe"
|
|
3829
|
+
execSync2(`"${voltaBin}" install ${pkg}`, { stdio: "pipe" });
|
|
4000
3830
|
spinner.stop(`${pkg} instalado!`);
|
|
4001
3831
|
} catch {
|
|
4002
3832
|
spinner.stop(import_picocolors8.default.yellow(`${pkg} - falha (instale manualmente)`));
|
|
@@ -4135,7 +3965,7 @@ async function setupNode(args) {
|
|
|
4135
3965
|
|
|
4136
3966
|
// src/index.ts
|
|
4137
3967
|
var PACKAGE_NAME2 = "@nimbuslab/cli";
|
|
4138
|
-
var CURRENT_VERSION = "
|
|
3968
|
+
var CURRENT_VERSION = "1.1.0";
|
|
4139
3969
|
var LOGO = `
|
|
4140
3970
|
\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
|
|
4141
3971
|
\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
|
|
@@ -4196,8 +4026,6 @@ async function main() {
|
|
|
4196
4026
|
await upgrade(args.slice(1));
|
|
4197
4027
|
} else if (command === "update") {
|
|
4198
4028
|
await update(args.slice(1));
|
|
4199
|
-
} else if (command === "lola") {
|
|
4200
|
-
await lola(args.slice(1));
|
|
4201
4029
|
} else if (command === "setup") {
|
|
4202
4030
|
const subcommand = args[1];
|
|
4203
4031
|
if (subcommand === "node") {
|