@nimbuslab/cli 1.1.0 → 1.2.1

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.
Files changed (3) hide show
  1. package/README.md +167 -75
  2. package/dist/index.js +745 -1301
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -147,7 +147,7 @@ var require_src = __commonJS((exports, module) => {
147
147
  });
148
148
 
149
149
  // src/index.ts
150
- var import_picocolors9 = __toESM(require_picocolors(), 1);
150
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
151
151
 
152
152
  // node_modules/@clack/core/dist/index.mjs
153
153
  var import_sisteransi = __toESM(require_src(), 1);
@@ -526,41 +526,6 @@ class dD extends x {
526
526
  }
527
527
  var A;
528
528
  A = new WeakMap;
529
- var kD = Object.defineProperty;
530
- var $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
531
- var H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t);
532
- var SD = class extends x {
533
- constructor(u) {
534
- super(u, false), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
535
- t === "a" && this.toggleAll();
536
- }), this.on("cursor", (t) => {
537
- switch (t) {
538
- case "left":
539
- case "up":
540
- this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
541
- break;
542
- case "down":
543
- case "right":
544
- this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
545
- break;
546
- case "space":
547
- this.toggleValue();
548
- break;
549
- }
550
- });
551
- }
552
- get _value() {
553
- return this.options[this.cursor].value;
554
- }
555
- toggleAll() {
556
- const u = this.value.length === this.options.length;
557
- this.value = u ? [] : this.options.map((t) => t.value);
558
- }
559
- toggleValue() {
560
- const u = this.value.includes(this._value);
561
- this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
562
- }
563
- };
564
529
  var OD = Object.defineProperty;
565
530
  var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
566
531
  var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
@@ -732,47 +697,6 @@ ${import_picocolors2.default.cyan(d2)}
732
697
  }
733
698
  } }).prompt();
734
699
  };
735
- var fe = (t) => {
736
- const n = (r2, i) => {
737
- const s = r2.label ?? String(r2.value);
738
- return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
739
- };
740
- return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
741
- if (this.required && r2.length === 0)
742
- return `Please select at least one option.
743
- ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
744
- }, render() {
745
- const r2 = `${import_picocolors2.default.gray(o)}
746
- ${b2(this.state)} ${t.message}
747
- `, i = (s, c) => {
748
- const a = this.value.includes(s.value);
749
- return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
750
- };
751
- switch (this.state) {
752
- case "submit":
753
- return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
754
- case "cancel": {
755
- const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
756
- return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
757
- ${import_picocolors2.default.gray(o)}` : ""}`;
758
- }
759
- case "error": {
760
- const s = this.error.split(`
761
- `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
762
- `);
763
- return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
764
- ${import_picocolors2.default.yellow(o)} `)}
765
- ${s}
766
- `;
767
- }
768
- default:
769
- return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
770
- ${import_picocolors2.default.cyan(o)} `)}
771
- ${import_picocolors2.default.cyan(d2)}
772
- `;
773
- }
774
- } }).prompt();
775
- };
776
700
  var xe = (t = "") => {
777
701
  process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
778
702
 
@@ -833,7 +757,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
833
757
  }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
834
758
  const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
835
759
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
836
- }, H2 = (m2 = "") => {
760
+ }, H = (m2 = "") => {
837
761
  a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
838
762
  `);
839
763
  let h2 = 0, w2 = 0;
@@ -859,13 +783,13 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
859
783
  `) : process.stdout.write(`${w2} ${l2}
860
784
  `), E(), s();
861
785
  };
862
- return { start: H2, stop: N2, message: (m2 = "") => {
786
+ return { start: H, stop: N2, message: (m2 = "") => {
863
787
  l2 = R2(m2 ?? l2);
864
788
  } };
865
789
  };
866
790
 
867
791
  // src/commands/create.ts
868
- var import_picocolors4 = __toESM(require_picocolors(), 1);
792
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
869
793
  var {$: $2 } = globalThis.Bun;
870
794
  import { rm, mkdir } from "fs/promises";
871
795
  import { join as join2 } from "path";
@@ -877,6 +801,7 @@ async function generateAIFriendlyDocs(projectPath, config) {
877
801
  await generateLLMsFile(projectPath, config);
878
802
  await generateArchitectureDoc(projectPath, config);
879
803
  await generateExamplesDoc(projectPath, config);
804
+ await generateModificationsDoc(projectPath, config);
880
805
  await createCompatibilitySymlinks(projectPath);
881
806
  }
882
807
  async function generateAgentsFile(projectPath, config) {
@@ -982,6 +907,14 @@ import type { User } from '@/types'
982
907
  - Use arrow functions for components
983
908
  - Explicit return types for exported functions
984
909
 
910
+ ## Project Inventory
911
+
912
+ ${generateProjectInventory(config)}
913
+
914
+ ## Feature Dependencies
915
+
916
+ ${generateFeatureDependencies(config)}
917
+
985
918
  ## Common Tasks
986
919
 
987
920
  ### Add a new section
@@ -998,8 +931,8 @@ ${config.features.contactForm ? `### Add form validation
998
931
  \`\`\`typescript
999
932
  // lib/validations.ts
1000
933
  export const contactSchema = z.object({
1001
- email: z.string().email('Email inv\xE1lido'),
1002
- message: z.string().min(10, 'M\xEDnimo 10 caracteres'),
934
+ email: z.string().email('Invalid email'),
935
+ message: z.string().min(10, 'Minimum 10 characters'),
1003
936
  })
1004
937
 
1005
938
  // components/forms/contact-form.tsx
@@ -1094,6 +1027,7 @@ async function generateLLMsFile(projectPath, config) {
1094
1027
  - [Project Overview](./AGENTS.md)
1095
1028
  - [Architecture](./ARCHITECTURE.md)
1096
1029
  - [Examples](./EXAMPLES.md)
1030
+ - [How to Modify](./MODIFICATIONS.md)
1097
1031
  - [Contributing](./CONTRIBUTING.md)
1098
1032
 
1099
1033
  ## Quick Context
@@ -1160,7 +1094,20 @@ async function generateArchitectureDoc(projectPath, config) {
1160
1094
  - Smaller bundle size
1161
1095
  - Familiar DX
1162
1096
 
1163
- ${config.type === "landing" ? `### 3. Landing Page Structure
1097
+ ### 3. ${config.stack.components}
1098
+
1099
+ **Why:**
1100
+ - Copy-paste workflow (no lock-in)
1101
+ - Full control over components
1102
+ - Customizable without ejecting
1103
+ - Built on Radix UI (accessibility)
1104
+
1105
+ **Trade-offs:**
1106
+ - Manual updates (not auto-updated via npm)
1107
+ - More files in your repo
1108
+ - Worth it for flexibility
1109
+
1110
+ ${config.type === "landing" ? `### 4. Landing Page Structure
1164
1111
 
1165
1112
  \`\`\`
1166
1113
  Hero
@@ -1178,7 +1125,17 @@ CTA
1178
1125
  Footer
1179
1126
  \`\`\`
1180
1127
 
1181
- ` : ""}## Data Flow
1128
+ **Why this order:**
1129
+ - Hero grabs attention first
1130
+ - Features build interest
1131
+ - FAQ reduces friction
1132
+ - CTA when ready to convert
1133
+
1134
+ ` : ""}## This Project's Specific Decisions
1135
+
1136
+ ${generateProjectDecisions(config)}
1137
+
1138
+ ## Data Flow
1182
1139
 
1183
1140
  \`\`\`
1184
1141
  User Action
@@ -1260,7 +1217,7 @@ ${config.features.contactForm ? `## Form with Validation
1260
1217
  // lib/validations.ts
1261
1218
  export const contactSchema = z.object({
1262
1219
  name: z.string().min(2, 'Nome muito curto'),
1263
- email: z.string().email('Email inv\xE1lido'),
1220
+ email: z.string().email('Invalid email'),
1264
1221
  message: z.string().min(10, 'Mensagem muito curta'),
1265
1222
  })
1266
1223
 
@@ -1327,204 +1284,361 @@ export const env = envSchema.parse(process.env)
1327
1284
  `;
1328
1285
  await Bun.write(join(projectPath, "EXAMPLES.md"), content);
1329
1286
  }
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"
1287
+ function generateProjectDecisions(config) {
1288
+ let decisions = "";
1289
+ if (config.stack.email) {
1290
+ decisions += `### Email Provider: ${config.stack.email}
1291
+
1292
+ **Why chosen:**
1293
+ - 3,000 emails/month free tier
1294
+ - React Email support (type-safe templates)
1295
+ - Simple API, great DX
1296
+
1297
+ **Alternatives considered:**
1298
+ - SendGrid: More complex, steeper pricing
1299
+ - Postmark: Great but no free tier
1300
+ - AWS SES: Requires more setup
1301
+
1302
+ **If you need to change:**
1303
+ 1. Update \`lib/email.ts\` client
1304
+ 2. Update env vars (\`.env\`)
1305
+ 3. Update API route implementation
1306
+
1307
+ `;
1354
1308
  }
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
- };
1309
+ if (config.stack.forms) {
1310
+ decisions += `### Form Library: ${config.stack.forms}
1311
+
1312
+ **Why chosen:**
1313
+ - Better performance than Formik
1314
+ - Smaller bundle size
1315
+ - Native TypeScript support
1316
+ - Works great with Zod
1317
+
1318
+ **Trade-off:**
1319
+ - More verbose than simple useState
1320
+ - Worth it for complex forms with validation
1321
+
1322
+ **If you need simpler forms:**
1323
+ - Use plain \`<form>\` + \`useState\`
1324
+ - Good for 1-2 field forms
1325
+
1326
+ `;
1375
1327
  }
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
- }
1328
+ if (config.features.contactForm) {
1329
+ decisions += `### Contact Form Implementation
1330
+
1331
+ **Current setup:**
1332
+ - Client-side validation (instant feedback)
1333
+ - Server-side validation (security)
1334
+ - Rate limiting (spam prevention)
1335
+
1336
+ **Why both validations:**
1337
+ - Client: Better UX (immediate feedback)
1338
+ - Server: Security (never trust client)
1339
+
1340
+ `;
1393
1341
  }
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
- }
1342
+ if (!decisions) {
1343
+ decisions = `No specific architectural decisions documented yet. As you make choices, document them here.
1344
+ `;
1400
1345
  }
1401
- return result;
1346
+ return decisions;
1402
1347
  }
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 };
1348
+ function generateProjectInventory(config) {
1349
+ let inventory = `**Implemented Components:**
1350
+ `;
1351
+ if (config.type === "landing") {
1352
+ inventory += `- Hero (\`components/sections/hero.tsx\`) - Main value proposition and CTA
1353
+ - Features (\`components/sections/features.tsx\`) - Product features grid
1354
+ - FAQ (\`components/sections/faq.tsx\`) - Frequently asked questions
1355
+ `;
1356
+ if (config.features.contactForm) {
1357
+ inventory += `- Contact Form (\`components/forms/contact-form.tsx\`) - Email contact with validation
1358
+ `;
1359
+ }
1417
1360
  }
1418
- if (needsForm === "later") {
1419
- return { enabled: true };
1361
+ if (config.type === "app") {
1362
+ inventory += `- Dashboard Layout (\`components/dashboard/layout.tsx\`) - Main app layout
1363
+ - Auth Forms (\`components/auth/\`) - Login/signup components
1364
+ `;
1420
1365
  }
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 };
1366
+ inventory += `
1367
+ **API Routes:**
1368
+ `;
1369
+ if (config.features.contactForm) {
1370
+ inventory += `- \`/api/contact\` - Form submission handler (rate-limited, ${config.stack.email || "email"} integration)
1371
+ `;
1436
1372
  }
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 };
1373
+ if (config.features.auth) {
1374
+ inventory += `- \`/api/auth/[...nextauth]\` - Authentication endpoints
1375
+ `;
1452
1376
  }
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 };
1377
+ if (!config.features.contactForm && !config.features.auth) {
1378
+ inventory += `- None yet (add API routes in \`app/api/\`)
1379
+ `;
1468
1380
  }
1469
- return {
1470
- enabled: true,
1471
- trackingId: trackingId || undefined
1472
- };
1381
+ inventory += `
1382
+ **Utilities:**
1383
+ `;
1384
+ if (config.stack.email) {
1385
+ inventory += `- \`lib/email.ts\` - ${config.stack.email} client configuration
1386
+ `;
1387
+ }
1388
+ if (config.features.contactForm) {
1389
+ inventory += `- \`lib/validations.ts\` - Zod schemas (contactSchema: name, email, message)
1390
+ `;
1391
+ }
1392
+ inventory += `- \`lib/utils.ts\` - Helper functions (cn, formatters)
1393
+ `;
1394
+ return inventory;
1473
1395
  }
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}`));
1396
+ function generateFeatureDependencies(config) {
1397
+ let deps = "";
1398
+ if (config.features.contactForm) {
1399
+ deps += `**Contact Form** depends on:
1400
+ \`\`\`
1401
+ \u251C\u2500 React Hook Form (form state management)
1402
+ \u251C\u2500 Zod (validation schemas)
1403
+ ${config.stack.email ? `\u251C\u2500 ${config.stack.email} (email sending)
1404
+ ` : ""}\u2514\u2500 /api/contact (server endpoint)
1405
+ \`\`\`
1406
+
1407
+ **To modify contact form:**
1408
+ 1. Update validation: \`lib/validations.ts\` (contactSchema)
1409
+ 2. Update UI: \`components/forms/contact-form.tsx\`
1410
+ 3. Update API: \`app/api/contact/route.ts\`
1411
+ 4. Update email template: \`emails/contact-email.tsx\` (if exists)
1412
+
1413
+ `;
1484
1414
  }
1485
- console.log();
1415
+ if (config.features.auth) {
1416
+ deps += `**Authentication** depends on:
1417
+ \`\`\`
1418
+ \u251C\u2500 ${config.stack.auth} (auth provider)
1419
+ \u251C\u2500 Database (user storage)
1420
+ \u2514\u2500 /api/auth/[...nextauth] (auth endpoints)
1421
+ \`\`\`
1422
+
1423
+ **To modify auth:**
1424
+ 1. Update config: \`lib/auth.ts\`
1425
+ 2. Update providers: Add/remove in auth config
1426
+ 3. Update callbacks: Customize JWT/session
1427
+
1428
+ `;
1429
+ }
1430
+ if (!deps) {
1431
+ deps = `No complex feature dependencies yet. Add features and their dependency maps will appear here.
1432
+ `;
1433
+ }
1434
+ return deps;
1486
1435
  }
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("");
1436
+ async function generateModificationsDoc(projectPath, config) {
1437
+ let content = `# Modification Guide
1438
+
1439
+ This file shows you exactly how to modify existing features in this project.
1440
+
1441
+ > **Context-aware:** These are the actual files in YOUR project, not generic examples.
1442
+
1443
+ `;
1444
+ if (config.type === "landing") {
1445
+ content += `## Landing Page Sections
1446
+
1447
+ ### Change Hero Text
1448
+
1449
+ **File:** \`components/sections/hero.tsx\`
1450
+ **What to edit:** Lines with \`<h1>\` and \`<p>\` tags
1451
+ **Current pattern:** Value proposition + subheading + CTA
1452
+ **Example change:**
1453
+ \`\`\`tsx
1454
+ <h1 className="text-4xl font-bold">
1455
+ Your New Headline Here
1456
+ </h1>
1457
+ <p className="text-xl text-muted-foreground">
1458
+ Your new subheading
1459
+ </p>
1460
+ \`\`\`
1461
+
1462
+ ### Add/Remove Feature Cards
1463
+
1464
+ **File:** \`components/sections/features.tsx\`
1465
+ **What to edit:** \`features\` array (usually lines 10-25)
1466
+ **Current:** 3 feature cards
1467
+ **To add:** Push new object to array: \`{ icon: Icon, title: "", description: "" }\`
1468
+ **To remove:** Delete object from array or filter it out
1469
+
1470
+ ### Modify FAQ Questions
1471
+
1472
+ **File:** \`components/sections/faq.tsx\`
1473
+ **What to edit:** \`questions\` array
1474
+ **Current:** Pre-populated with common questions
1475
+ **Pattern:** Keep answers concise (< 100 chars) for better UX
1476
+ **To add:** \`{ question: "...", answer: "..." }\`
1477
+
1478
+ `;
1502
1479
  }
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("");
1480
+ if (config.features.contactForm) {
1481
+ content += `## Contact Form
1482
+
1483
+ ### Change Form Fields
1484
+
1485
+ **Files to modify:**
1486
+ 1. \`lib/validations.ts\` - Add field to schema
1487
+ 2. \`components/forms/contact-form.tsx\` - Add UI input
1488
+ 3. \`app/api/contact/route.ts\` - Handle new field
1489
+
1490
+ **Example: Add phone field**
1491
+ \`\`\`typescript
1492
+ // 1. lib/validations.ts
1493
+ export const contactSchema = z.object({
1494
+ name: z.string().min(2),
1495
+ email: z.string().email(),
1496
+ phone: z.string().min(10), // NEW
1497
+ message: z.string().min(10),
1498
+ })
1499
+
1500
+ // 2. components/forms/contact-form.tsx
1501
+ <FormField
1502
+ name="phone"
1503
+ control={form.control}
1504
+ render={({ field }) => (
1505
+ <Input placeholder="Phone" {...field} />
1506
+ )}
1507
+ />
1508
+
1509
+ // 3. app/api/contact/route.ts
1510
+ // Phone is now available in validated data
1511
+ const { name, email, phone, message } = validated.data
1512
+ \`\`\`
1513
+
1514
+ ### Change Email Template
1515
+
1516
+ **File:** \`emails/contact-email.tsx\` (if using React Email)
1517
+ **Alternative:** Inline in \`app/api/contact/route.ts\`
1518
+ **What to edit:** Subject, body content, styling
1519
+ **Test locally:** \`bun run email:dev\` (if available)
1520
+
1521
+ ### Change Email Recipient
1522
+
1523
+ **File:** \`app/api/contact/route.ts\`
1524
+ **What to edit:** The \`to:\` field in email send
1525
+ \`\`\`typescript
1526
+ await resend.emails.send({
1527
+ to: 'your-new-email@example.com', // CHANGE THIS
1528
+ // ...
1529
+ })
1530
+ \`\`\`
1531
+
1532
+ `;
1508
1533
  }
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
- `));
1534
+ content += `## Styling Changes
1535
+
1536
+ ### Update Colors
1537
+
1538
+ **File:** \`app/globals.css\`
1539
+ **What to edit:** CSS variables in \`:root\` and \`.dark\`
1540
+ \`\`\`css
1541
+ :root {
1542
+ --primary: 220 90% 56%; /* Change this */
1543
+ }
1544
+ \`\`\`
1545
+ **Tip:** Use [shadcn theme editor](https://ui.shadcn.com/themes) to generate new colors
1546
+
1547
+ ### Change Fonts
1548
+
1549
+ **File:** \`app/layout.tsx\`
1550
+ **What to edit:** Font imports and \`className\` on \`<body>\`
1551
+ \`\`\`tsx
1552
+ import { Inter } from 'next/font/google'
1553
+
1554
+ const font = Inter({ subsets: ['latin'] })
1555
+
1556
+ <body className={font.className}>
1557
+ \`\`\`
1558
+
1559
+ ## Adding New Features
1560
+
1561
+ ### Add a New Page
1562
+
1563
+ \`\`\`bash
1564
+ # 1. Create route
1565
+ touch app/about/page.tsx
1566
+
1567
+ # 2. Add navigation link
1568
+ # Edit: components/layout/header.tsx or footer.tsx
1569
+ \`\`\`
1570
+
1571
+ ### Add shadcn/ui Component
1572
+
1573
+ \`\`\`bash
1574
+ bunx --bun shadcn@latest add [component-name]
1575
+ # Example: bunx --bun shadcn@latest add dialog
1576
+ \`\`\`
1577
+
1578
+ ## Environment Variables
1579
+
1580
+ **File:** \`.env\` (create from \`.env.example\`)
1581
+
1582
+ ${config.stack.email ? `### ${config.stack.email} API Key
1583
+ \`\`\`env
1584
+ RESEND_API_KEY=re_xxxxxxxxxxxx
1585
+ \`\`\`
1586
+ **Get key:** [${config.stack.email} Dashboard](https://resend.com/api-keys)
1587
+
1588
+ ` : ""}${config.features.analytics ? `### Google Analytics
1589
+ \`\`\`env
1590
+ NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
1591
+ \`\`\`
1592
+ **Get ID:** [Google Analytics](https://analytics.google.com)
1593
+
1594
+ ` : ""}## Common Modifications
1595
+
1596
+ ### Change Site Metadata (SEO)
1597
+
1598
+ **File:** \`app/layout.tsx\`
1599
+ **What to edit:** \`metadata\` export
1600
+ \`\`\`tsx
1601
+ export const metadata = {
1602
+ title: 'Your New Title',
1603
+ description: 'Your new description',
1604
+ // ...
1605
+ }
1606
+ \`\`\`
1607
+
1608
+ ### Add Custom Font from File
1609
+
1610
+ \`\`\`tsx
1611
+ // app/layout.tsx
1612
+ import localFont from 'next/font/local'
1613
+
1614
+ const customFont = localFont({
1615
+ src: './fonts/CustomFont.woff2',
1616
+ variable: '--font-custom',
1617
+ })
1618
+ \`\`\`
1619
+
1620
+ ---
1621
+
1622
+ **Pro tip:** Before modifying, search the codebase for the text/component you want to change:
1623
+ \`\`\`bash
1624
+ grep -r "text to find" .
1625
+ \`\`\`
1626
+ `;
1627
+ await Bun.write(join(projectPath, "MODIFICATIONS.md"), content);
1628
+ }
1629
+ async function createCompatibilitySymlinks(projectPath) {
1630
+ const agentsContent = await Bun.file(join(projectPath, "AGENTS.md")).text();
1631
+ await Bun.write(join(projectPath, ".cursorrules"), agentsContent);
1632
+ const githubDir = join(projectPath, ".github");
1633
+ await Bun.$`mkdir -p ${githubDir}`.quiet();
1634
+ await Bun.write(join(githubDir, "copilot-instructions.md"), agentsContent);
1526
1635
  }
1527
1636
  // src/commands/create.ts
1637
+ var TEMPLATES = {
1638
+ landing: "nimbuslab/create-next-landing",
1639
+ app: "nimbuslab/create-next-app",
1640
+ turborepo: "nimbuslab/create-turborepo"
1641
+ };
1528
1642
  var AI_CONFIGS = {
1529
1643
  claude: {
1530
1644
  filename: "CLAUDE.md",
@@ -1645,42 +1759,14 @@ async function checkGitHubCli() {
1645
1759
  return { installed: false, authenticated: false, username: null, orgs: [] };
1646
1760
  }
1647
1761
  }
1648
- var PRIVATE_TEMPLATES = {
1649
- fast: "nimbuslab-templates/fast-template",
1650
- "fast+": "nimbuslab-templates/fastplus-template",
1651
- "fast+-monorepo": "nimbuslab-templates/fastplus-monorepo-template",
1652
- "nimbus-core": "nimbuslab/nimbus-core"
1653
- };
1654
- var PUBLIC_TEMPLATES = {
1655
- landing: "nimbuslab/create-next-landing",
1656
- app: "nimbuslab/create-next-app",
1657
- turborepo: "nimbuslab/create-turborepo"
1658
- };
1659
- var TEMPLATES = { ...PRIVATE_TEMPLATES, ...PUBLIC_TEMPLATES };
1660
- var NIMBUSLAB_DOMAINS = ["@nimbuslab.com.br", "@nimbuslab.net.br"];
1661
- async function isNimbuslabMember() {
1662
- try {
1663
- const user = (await $2`git config user.name`.text()).trim();
1664
- const email = (await $2`git config user.email`.text()).trim();
1665
- const isMember = NIMBUSLAB_DOMAINS.some((domain) => email.endsWith(domain));
1666
- return { isMember, user, email };
1667
- } catch {
1668
- return { isMember: false, user: null, email: null };
1669
- }
1670
- }
1671
1762
  function parseFlags(args) {
1672
1763
  const flags = {
1673
1764
  yes: false,
1674
1765
  landing: false,
1675
1766
  app: false,
1676
1767
  turborepo: false,
1677
- fast: false,
1678
- fastPlus: false,
1679
- fastTurborepo: false,
1680
- core: false,
1681
1768
  noGit: false,
1682
1769
  noInstall: false,
1683
- railway: false,
1684
1770
  template: null
1685
1771
  };
1686
1772
  let projectName;
@@ -1695,20 +1781,10 @@ function parseFlags(args) {
1695
1781
  flags.app = true;
1696
1782
  } else if (arg === "--turborepo") {
1697
1783
  flags.turborepo = true;
1698
- } else if (arg === "--fast") {
1699
- flags.fast = true;
1700
- } else if (arg === "--fast-plus") {
1701
- flags.fastPlus = true;
1702
- } else if (arg === "--fast-turborepo") {
1703
- flags.fastTurborepo = true;
1704
- } else if (arg === "--core") {
1705
- flags.core = true;
1706
1784
  } else if (arg === "--no-git") {
1707
1785
  flags.noGit = true;
1708
1786
  } else if (arg === "--no-install") {
1709
1787
  flags.noInstall = true;
1710
- } else if (arg === "--railway") {
1711
- flags.railway = true;
1712
1788
  } else if (arg === "--template") {
1713
1789
  i++;
1714
1790
  flags.template = args[i] ?? null;
@@ -1719,320 +1795,56 @@ function parseFlags(args) {
1719
1795
  }
1720
1796
  return { flags, projectName };
1721
1797
  }
1722
- async function ensureRailwayCli() {
1723
- const checkCmd = process.platform === "win32" ? "where" : "which";
1724
- const hasRailway = await $2`${checkCmd} railway`.quiet().then(() => true).catch(() => false);
1725
- if (hasRailway)
1726
- return true;
1727
- console.log(import_picocolors4.default.yellow("Railway CLI not found. Installing..."));
1728
- console.log();
1729
- try {
1730
- if (process.platform === "win32") {
1731
- await $2`powershell -c "iwr https://railway.app/install.ps1 -useb | iex"`.quiet();
1732
- } else {
1733
- await $2`curl -fsSL https://railway.app/install.sh | sh`.quiet();
1734
- }
1735
- console.log(import_picocolors4.default.green("Railway CLI installed successfully!"));
1736
- return true;
1737
- } catch (error) {
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"));
1740
- return false;
1741
- }
1742
- }
1743
- async function listRailwayProjects() {
1744
- try {
1745
- const result = await $2`railway list`.text();
1746
- const lines = result.trim().split(`
1747
- `).filter((l2) => l2.trim());
1748
- return lines.slice(1).map((l2) => l2.trim());
1749
- } catch {
1750
- return [];
1751
- }
1752
- }
1753
- async function isRailwayAuthenticated() {
1754
- try {
1755
- await $2`railway whoami`.quiet();
1756
- return true;
1757
- } catch {
1758
- return false;
1759
- }
1760
- }
1761
- async function create(args) {
1762
- const checkCmd = process.platform === "win32" ? "where" : "which";
1763
- const hasBun = await $2`${checkCmd} bun`.quiet().then(() => true).catch(() => false);
1764
- const hasGit = await $2`${checkCmd} git`.quiet().then(() => true).catch(() => false);
1765
- const hasGh = await $2`${checkCmd} gh`.quiet().then(() => true).catch(() => false);
1766
- if (!hasBun) {
1767
- console.log(import_picocolors4.default.red("Error: Bun not found."));
1768
- console.log(import_picocolors4.default.dim("Install from: https://bun.sh"));
1769
- console.log();
1770
- if (process.platform === "win32") {
1771
- console.log(import_picocolors4.default.cyan('powershell -c "irm bun.sh/install.ps1 | iex"'));
1772
- } else {
1773
- console.log(import_picocolors4.default.cyan("curl -fsSL https://bun.sh/install | bash"));
1774
- }
1775
- console.log();
1776
- process.exit(1);
1777
- }
1778
- if (!hasGit) {
1779
- console.log(import_picocolors4.default.red("Error: Git not found."));
1780
- console.log(import_picocolors4.default.dim("Install git to continue."));
1781
- process.exit(1);
1782
- }
1783
- if (!hasGh) {
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"));
1786
- console.log();
1787
- }
1788
- const hasRailway = await ensureRailwayCli();
1789
- if (hasRailway) {
1790
- const railwayAuth = await isRailwayAuthenticated();
1791
- if (!railwayAuth) {
1792
- console.log(import_picocolors4.default.yellow("Railway CLI not authenticated."));
1793
- console.log(import_picocolors4.default.dim("Run: railway login"));
1794
- console.log();
1795
- }
1796
- }
1797
- const { flags, projectName } = parseFlags(args);
1798
- Ie(import_picocolors4.default.bgCyan(import_picocolors4.default.black(" New nimbuslab Project ")));
1799
- let config;
1800
- const hasTypeFlag = flags.landing || flags.app || flags.turborepo || flags.fast || flags.fastPlus || flags.fastTurborepo || flags.core;
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;
1802
- const monorepoFromFlag = flags.fastTurborepo;
1803
- if ((flags.yes || hasTypeFlag) && projectName) {
1804
- const defaultType = flags.landing || flags.app || flags.turborepo ? "landing" : "fast";
1805
- config = {
1806
- name: projectName,
1807
- type: typeFromFlag || defaultType,
1808
- monorepo: monorepoFromFlag,
1809
- git: !flags.noGit,
1810
- install: !flags.noInstall,
1811
- github: false,
1812
- githubOrg: null,
1813
- githubDescription: "",
1814
- theme: "dark",
1815
- aiAssistant: null,
1816
- contractNumber: "",
1817
- resendApiKey: "",
1818
- resendFromEmail: "",
1819
- contactEmail: "",
1820
- railwayProject: "",
1821
- railwayToken: "",
1822
- stagingUrl: "",
1823
- productionUrl: "",
1824
- customTemplate: flags.template
1825
- };
1826
- const typeLabel = flags.turborepo ? "fast+ (monorepo)" : config.type;
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"}`));
1831
- if (flags.railway)
1832
- console.log(import_picocolors4.default.dim(` Railway: configurar`));
1833
- if (flags.template)
1834
- console.log(import_picocolors4.default.dim(` Template: ${flags.template}`));
1835
- console.log();
1836
- if (flags.railway) {
1837
- const railwayAuthenticated = await isRailwayAuthenticated();
1838
- if (railwayAuthenticated) {
1839
- if (config.type === "fast") {
1840
- const projects = await listRailwayProjects();
1841
- const fastProject = projects.find((p2) => p2.toLowerCase().includes("fast by nimbuslab"));
1842
- if (fastProject) {
1843
- config.railwayProject = fastProject;
1844
- console.log(import_picocolors4.default.green(` Railway: ${fastProject}`));
1845
- }
1846
- } else {
1847
- console.log(import_picocolors4.default.dim(` Creating project Railway: ${projectName}...`));
1848
- try {
1849
- const result = await $2`echo "" | railway init -n ${projectName} -w nimbuslab --json`.text();
1850
- const newProject = JSON.parse(result);
1851
- config.railwayProject = newProject.name || projectName;
1852
- console.log(import_picocolors4.default.green(` Railway: ${config.railwayProject} criado`));
1853
- } catch {
1854
- console.log(import_picocolors4.default.yellow(` Railway: erro ao criar projeto`));
1855
- }
1856
- }
1857
- } else {
1858
- console.log(import_picocolors4.default.yellow(` Railway: not authenticated (railway login)`));
1859
- }
1860
- console.log();
1861
- }
1862
- } else {
1863
- config = await promptConfig(projectName, flags);
1864
- }
1865
- if (pD(config)) {
1866
- xe("Operation cancelled");
1867
- process.exit(0);
1868
- }
1869
- await createProject(config);
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!"));
1916
- showNextSteps(config);
1917
- }
1918
1798
  async function promptConfig(initialName, flags) {
1919
- const { isMember, user } = await isNimbuslabMember();
1920
- const greeting = user ? `Hello, ${user}!` : "Hello!";
1921
- console.log(import_picocolors4.default.dim(` ${greeting}`));
1922
- console.log();
1923
1799
  const name = await he({
1924
1800
  message: "Project name:",
1925
- placeholder: "meu-projeto",
1926
- initialValue: initialName,
1801
+ placeholder: initialName || "my-project",
1802
+ initialValue: initialName || "",
1927
1803
  validate: (value) => {
1928
1804
  if (!value)
1929
- return "Name is required";
1805
+ return "Project name is required";
1930
1806
  if (!/^[a-z0-9-]+$/.test(value)) {
1931
- return "Use only lowercase letters, numbers and hyphens";
1807
+ return "Use lowercase letters, numbers, and hyphens only";
1932
1808
  }
1933
- return;
1934
1809
  }
1935
1810
  });
1936
1811
  if (pD(name))
1937
1812
  return name;
1938
- const publicOptions = [
1939
- {
1940
- value: "landing",
1941
- label: "Landing Page",
1942
- hint: "Next.js 16 + Tailwind 4 + shadcn"
1943
- },
1944
- {
1945
- value: "app",
1946
- label: "Web App",
1947
- hint: "Landing + Better Auth + Drizzle"
1948
- },
1949
- {
1950
- value: "turborepo",
1951
- label: "Monorepo",
1952
- hint: "Turborepo + apps/packages"
1953
- }
1954
- ];
1955
- const privateOptions = isMember ? [
1956
- {
1957
- value: "fast",
1958
- label: "fast",
1959
- hint: "Landing page fast methodology"
1960
- },
1961
- {
1962
- value: "fast+",
1963
- label: "fast+",
1964
- hint: "Complete SaaS"
1965
- },
1966
- {
1967
- value: "nimbus-core",
1968
- label: "nimbus-core",
1969
- hint: "External projects (stealth mode)"
1970
- }
1971
- ] : [];
1972
1813
  const type = await ve({
1973
- message: "Project type:",
1974
- options: [...publicOptions, ...privateOptions]
1814
+ message: "Choose a template:",
1815
+ options: [
1816
+ { value: "landing", label: "Landing Page", hint: "Next.js + Tailwind + shadcn/ui" },
1817
+ { value: "app", label: "Web App", hint: "Landing + Auth + Database" },
1818
+ { value: "turborepo", label: "Monorepo", hint: "Turborepo + apps/packages" }
1819
+ ]
1975
1820
  });
1976
1821
  if (pD(type))
1977
1822
  return type;
1978
- const isPublicTemplate = ["landing", "app", "turborepo"].includes(type);
1979
- if (!isMember && !isPublicTemplate) {
1980
- console.log(import_picocolors4.default.red("Error: Template available only for nimbuslab members"));
1981
- process.exit(1);
1982
- }
1983
- if (type === "nimbus-core") {
1984
- console.log();
1985
- console.log(import_picocolors4.default.dim(" nimbus-core: Motor para projetos externos (stealth mode)"));
1986
- console.log();
1987
- const repoOption = await ve({
1988
- message: "Create repository for this project?",
1989
- options: [
1990
- { value: "github", label: "GitHub (nimbuslab, private)", hint: "recommended" },
1991
- { value: "none", label: "No repository", hint: "just local" }
1992
- ]
1993
- });
1994
- if (pD(repoOption))
1995
- return repoOption;
1996
- const clientRepo = await he({
1997
- message: "Client repo URL (to clone in workspace):",
1998
- placeholder: "git@github.com:client/repo.git ou Azure DevOps URL"
1999
- });
2000
- if (pD(clientRepo))
2001
- return clientRepo;
2002
- return {
2003
- name,
2004
- type: "nimbus-core",
2005
- monorepo: false,
2006
- git: true,
2007
- install: false,
2008
- github: repoOption === "github",
2009
- githubOrg: "nimbuslab",
2010
- githubDescription: `nimbus-core for ${name} - external project`,
2011
- theme: "dark",
2012
- aiAssistant: null,
2013
- contractNumber: "",
2014
- resendApiKey: "",
2015
- resendFromEmail: "",
2016
- contactEmail: "",
2017
- railwayProject: "",
2018
- railwayToken: "",
2019
- stagingUrl: "",
2020
- productionUrl: "",
2021
- customTemplate: null,
2022
- clientRepoUrl: clientRepo || null
2023
- };
2024
- }
2025
- let monorepo = false;
2026
- if (type === "fast+") {
2027
- const useMonorepo = await ye({
2028
- message: "Use monorepo (Turborepo)?",
2029
- initialValue: false
2030
- });
2031
- if (pD(useMonorepo))
2032
- return useMonorepo;
2033
- monorepo = useMonorepo;
2034
- }
2035
- const git = await ye({
1823
+ const theme = await ve({
1824
+ message: "Default theme:",
1825
+ options: [
1826
+ { value: "dark", label: "Dark", hint: "recommended" },
1827
+ { value: "light", label: "Light" },
1828
+ { value: "system", label: "System" }
1829
+ ]
1830
+ });
1831
+ if (pD(theme))
1832
+ return theme;
1833
+ const aiAssistant = await ve({
1834
+ message: "AI Assistant configuration:",
1835
+ options: [
1836
+ { value: "claude", label: "Claude (Anthropic)", hint: "recommended" },
1837
+ { value: "cursor", label: "Cursor" },
1838
+ { value: "copilot", label: "GitHub Copilot" },
1839
+ { value: "gemini", label: "Google Gemini" },
1840
+ { value: "windsurf", label: "Windsurf" },
1841
+ { value: "none", label: "None", hint: "skip" }
1842
+ ],
1843
+ initialValue: "claude"
1844
+ });
1845
+ if (pD(aiAssistant))
1846
+ return aiAssistant;
1847
+ const git = flags.noGit ? false : await ye({
2036
1848
  message: "Initialize Git repository?",
2037
1849
  initialValue: true
2038
1850
  });
@@ -2040,260 +1852,47 @@ async function promptConfig(initialName, flags) {
2040
1852
  return git;
2041
1853
  let github = false;
2042
1854
  let githubOrg = null;
2043
- let githubDescription = "";
1855
+ let githubVisibility = "public";
2044
1856
  if (git) {
2045
- const createGithub = await ye({
2046
- message: "Create GitHub repository?",
2047
- initialValue: false
2048
- });
2049
- if (pD(createGithub))
2050
- return createGithub;
2051
- github = createGithub;
2052
- if (github) {
2053
- const org = await ve({
2054
- message: "GitHub organization:",
2055
- options: [
2056
- { value: "nimbuslab", label: "nimbuslab", hint: "Main org" },
2057
- { value: "fast-by-nimbuslab", label: "fast-by-nimbuslab", hint: "Client projects" },
2058
- { value: "nimbuslab-templates", label: "nimbuslab-templates", hint: "Templates" },
2059
- { value: null, label: "Pessoal", hint: "Personal" }
2060
- ]
1857
+ const ghCheck = await checkGitHubCli();
1858
+ if (ghCheck.installed && ghCheck.authenticated) {
1859
+ github = await ye({
1860
+ message: "Create GitHub repository?",
1861
+ initialValue: true
2061
1862
  });
2062
- if (pD(org))
2063
- return org;
2064
- githubOrg = org;
2065
- const description = await he({
2066
- message: "Repository description:",
2067
- placeholder: "Landing page para cliente X",
2068
- initialValue: type === "fast" ? "Landing page fast by nimbuslab" : "SaaS fast+ by nimbuslab"
2069
- });
2070
- if (pD(description))
2071
- return description;
2072
- githubDescription = description;
2073
- }
2074
- }
2075
- let contractNumber = "";
2076
- if (type === "fast") {
2077
- const contract = await he({
2078
- message: "Contract number (ex: 001):",
2079
- placeholder: "001",
2080
- validate: (v2) => v2 ? undefined : "Contract number is required for fast"
2081
- });
2082
- if (pD(contract))
2083
- return contract;
2084
- contractNumber = contract;
2085
- }
2086
- if (isPublicTemplate) {
2087
- const theme = await ve({
2088
- message: "Default theme:",
2089
- options: [
2090
- { value: "dark", label: "Dark", hint: "recommended" },
2091
- { value: "light", label: "Light" },
2092
- { value: "system", label: "System", hint: "follows OS preference" }
2093
- ]
2094
- });
2095
- if (pD(theme))
2096
- return theme;
2097
- const aiAssistant = await ve({
2098
- message: "Which AI assistant do you use?",
2099
- options: [
2100
- { value: "claude", label: "Claude Code", hint: "Anthropic" },
2101
- { value: "cursor", label: "Cursor", hint: "AI-first editor" },
2102
- { value: "gemini", label: "Gemini CLI", hint: "Google" },
2103
- { value: "copilot", label: "GitHub Copilot" },
2104
- { value: "windsurf", label: "Windsurf", hint: "Codeium" },
2105
- { value: "none", label: "None", hint: "skip AI config" }
2106
- ]
2107
- });
2108
- if (pD(aiAssistant))
2109
- return aiAssistant;
2110
- let publicGithub = false;
2111
- let publicGithubOrg = null;
2112
- if (git) {
2113
- const gh = await checkGitHubCli();
2114
- if (gh.installed && gh.authenticated) {
2115
- const createRepo = await ye({
2116
- message: "Create GitHub repository?",
2117
- initialValue: false
2118
- });
2119
- if (pD(createRepo))
2120
- return createRepo;
2121
- publicGithub = createRepo;
2122
- if (publicGithub) {
2123
- const repoOptions = [
2124
- { value: gh.username, label: gh.username, hint: "personal account" },
2125
- ...gh.orgs.map((org) => ({ value: org, label: org }))
2126
- ];
2127
- const repoOwner = await ve({
2128
- message: "Where to create the repository?",
2129
- options: repoOptions
2130
- });
2131
- if (pD(repoOwner))
2132
- return repoOwner;
2133
- publicGithubOrg = repoOwner;
2134
- const repoVisibility = await ve({
2135
- message: "Repository visibility:",
2136
- options: [
2137
- { value: "private", label: "Private", hint: "recommended" },
2138
- { value: "public", label: "Public" }
2139
- ]
2140
- });
2141
- if (pD(repoVisibility))
2142
- return repoVisibility;
2143
- githubDescription = repoVisibility;
2144
- }
2145
- }
2146
- }
2147
- const install2 = await ye({
2148
- message: "Install dependencies?",
2149
- initialValue: true
2150
- });
2151
- if (pD(install2))
2152
- return install2;
2153
- return {
2154
- name,
2155
- type,
2156
- monorepo: false,
2157
- git,
2158
- install: install2,
2159
- github: publicGithub,
2160
- githubOrg: publicGithubOrg,
2161
- githubDescription,
2162
- theme,
2163
- aiAssistant: aiAssistant === "none" ? null : aiAssistant,
2164
- contractNumber: "",
2165
- resendApiKey: "",
2166
- resendFromEmail: "",
2167
- contactEmail: "",
2168
- railwayProject: "",
2169
- railwayToken: "",
2170
- stagingUrl: "",
2171
- productionUrl: "",
2172
- customTemplate: flags?.template || null
2173
- };
2174
- }
2175
- let resendApiKey = "";
2176
- let resendFromEmail = "";
2177
- let contactEmail = "";
2178
- let railwayProject = "";
2179
- let railwayToken = "";
2180
- let stagingUrl = "";
2181
- let productionUrl = "";
2182
- const currentYear = new Date().getFullYear().toString().slice(-3);
2183
- const defaultStagingUrl = type === "fast" ? `https://fast-${contractNumber}-${currentYear}.nimbuslab.net.br` : `https://${name}.nimbuslab.net.br`;
2184
- const defaultFromEmail = "no-reply@nimbuslab.com.br";
2185
- const defaultContactEmail = type === "fast" ? "fast@nimbuslab.com.br" : "suporte@nimbuslab.com.br";
2186
- const infraOptions = await fe({
2187
- message: "What do you want to configure now?",
2188
- options: [
2189
- { value: "urls", label: "URLs", hint: "staging and production" },
2190
- { value: "resend", label: "Resend", hint: "form emails" },
2191
- { value: "railway", label: "Railway", hint: "deploy and hosting" }
2192
- ],
2193
- required: false
2194
- });
2195
- if (pD(infraOptions))
2196
- return infraOptions;
2197
- const configItems = infraOptions;
2198
- if (configItems.includes("urls")) {
2199
- console.log();
2200
- console.log(import_picocolors4.default.dim(" Project URLs"));
2201
- const staging = await he({
2202
- message: "Staging URL:",
2203
- placeholder: defaultStagingUrl,
2204
- initialValue: defaultStagingUrl
2205
- });
2206
- if (pD(staging))
2207
- return staging;
2208
- stagingUrl = staging;
2209
- const production = await he({
2210
- message: "Production URL:",
2211
- placeholder: defaultStagingUrl.replace(".nimbuslab.net.br", ".com.br"),
2212
- initialValue: ""
2213
- });
2214
- if (pD(production))
2215
- return production;
2216
- productionUrl = production;
2217
- }
2218
- if (configItems.includes("resend")) {
2219
- console.log();
2220
- console.log(import_picocolors4.default.dim(" Resend (Email)"));
2221
- const resendKey = await he({
2222
- message: "RESEND_API_KEY:",
2223
- placeholder: "re_xxxxxxxxxxxx"
2224
- });
2225
- if (pD(resendKey))
2226
- return resendKey;
2227
- resendApiKey = resendKey;
2228
- const fromEmail = await he({
2229
- message: "From email:",
2230
- placeholder: defaultFromEmail,
2231
- initialValue: defaultFromEmail
2232
- });
2233
- if (pD(fromEmail))
2234
- return fromEmail;
2235
- resendFromEmail = fromEmail;
2236
- const contact = await he({
2237
- message: "Contact email (receives forms):",
2238
- placeholder: defaultContactEmail,
2239
- initialValue: defaultContactEmail
2240
- });
2241
- if (pD(contact))
2242
- return contact;
2243
- contactEmail = contact;
2244
- }
2245
- if (configItems.includes("railway")) {
2246
- const railwayAuthenticated = await isRailwayAuthenticated();
2247
- if (railwayAuthenticated) {
2248
- console.log();
2249
- console.log(import_picocolors4.default.dim(" Railway"));
2250
- const projects = await listRailwayProjects();
2251
- if (type === "fast") {
2252
- const fastProject = projects.find((p2) => p2.toLowerCase().includes("fast by nimbuslab"));
2253
- if (fastProject) {
2254
- railwayProject = fastProject;
2255
- console.log(import_picocolors4.default.green(` Project: ${fastProject} (automatico)`));
2256
- } else {
2257
- console.log(import_picocolors4.default.yellow(" Project 'Fast by nimbuslab' not found."));
2258
- console.log(import_picocolors4.default.dim(" Configure manually in .env"));
2259
- }
2260
- } else {
2261
- const projectOptions = [
2262
- ...projects.map((proj) => ({ value: proj, label: proj })),
2263
- { value: "__new__", label: "Create new project", hint: "via railway init" },
2264
- { value: "__skip__", label: "Skip", hint: "Configure later" }
1863
+ if (pD(github))
1864
+ return github;
1865
+ if (github) {
1866
+ const orgOptions = [
1867
+ { value: ghCheck.username, label: `${ghCheck.username} (personal)`, hint: "your account" },
1868
+ ...ghCheck.orgs.map((org) => ({ value: org, label: org, hint: "organization" }))
2265
1869
  ];
2266
- const selectedProject = await ve({
2267
- message: "Railway project for this SaaS:",
2268
- options: projectOptions
1870
+ githubOrg = await ve({
1871
+ message: "GitHub owner:",
1872
+ options: orgOptions,
1873
+ initialValue: ghCheck.username
2269
1874
  });
2270
- if (pD(selectedProject))
2271
- return selectedProject;
2272
- if (selectedProject === "__new__") {
2273
- const projectNameForRailway = name;
2274
- console.log(import_picocolors4.default.dim(` Creating project "${projectNameForRailway}" on Railway...`));
2275
- try {
2276
- const result = await $2`echo "" | railway init -n ${projectNameForRailway} -w nimbuslab --json`.text();
2277
- const newProject = JSON.parse(result);
2278
- railwayProject = newProject.name || projectNameForRailway;
2279
- console.log(import_picocolors4.default.green(` Projeto "${railwayProject}" created successfully!`));
2280
- console.log(import_picocolors4.default.dim(` ID: ${newProject.id || "N/A"}`));
2281
- } catch (error) {
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"));
2284
- }
2285
- } else if (selectedProject !== "__skip__") {
2286
- railwayProject = selectedProject;
2287
- console.log(import_picocolors4.default.green(` Project selected: ${railwayProject}`));
2288
- }
1875
+ if (pD(githubOrg))
1876
+ return githubOrg;
1877
+ githubVisibility = await ve({
1878
+ message: "Repository visibility:",
1879
+ options: [
1880
+ { value: "public", label: "Public", hint: "anyone can see" },
1881
+ { value: "private", label: "Private", hint: "you choose who can see" }
1882
+ ],
1883
+ initialValue: "public"
1884
+ });
1885
+ if (pD(githubVisibility))
1886
+ return githubVisibility;
2289
1887
  }
2290
- } else {
2291
- 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"));
1888
+ } else if (!ghCheck.installed) {
1889
+ console.log(import_picocolors3.default.dim(" GitHub CLI not found (repository creation will be skipped)"));
1890
+ console.log(import_picocolors3.default.dim(" Install from: https://cli.github.com"));
1891
+ } else if (!ghCheck.authenticated) {
1892
+ console.log(import_picocolors3.default.yellow(" GitHub CLI not authenticated (run: gh auth login)"));
2294
1893
  }
2295
1894
  }
2296
- const install = await ye({
1895
+ const install = flags.noInstall ? false : await ye({
2297
1896
  message: "Install dependencies?",
2298
1897
  initialValue: true
2299
1898
  });
@@ -2302,323 +1901,174 @@ async function promptConfig(initialName, flags) {
2302
1901
  return {
2303
1902
  name,
2304
1903
  type,
2305
- monorepo,
2306
1904
  git,
2307
1905
  install,
2308
1906
  github,
2309
1907
  githubOrg,
2310
- githubDescription,
2311
- theme: "dark",
2312
- aiAssistant: null,
2313
- contractNumber,
2314
- resendApiKey,
2315
- resendFromEmail,
2316
- contactEmail,
2317
- railwayProject,
2318
- railwayToken,
2319
- stagingUrl,
2320
- productionUrl,
2321
- customTemplate: flags?.template || null
1908
+ githubVisibility,
1909
+ theme,
1910
+ aiAssistant: aiAssistant === "none" ? null : aiAssistant,
1911
+ customTemplate: flags.template
2322
1912
  };
2323
1913
  }
2324
1914
  async function createProject(config) {
2325
1915
  const s = Y2();
2326
- let templateRepo;
2327
- let templateLabel;
2328
- if (config.customTemplate) {
2329
- templateRepo = config.customTemplate;
2330
- templateLabel = `customizado (${config.customTemplate})`;
2331
- } else {
2332
- const templateKey = config.type === "fast+" && config.monorepo ? "fast+-monorepo" : config.type;
2333
- templateRepo = TEMPLATES[templateKey];
2334
- templateLabel = config.monorepo ? `${config.type} (monorepo)` : config.type;
2335
- }
2336
- const isPublicTemplate = ["landing", "app", "turborepo"].includes(config.type);
2337
- s.start(`Cloning template ${templateLabel}...`);
1916
+ const projectPath = join2(process.cwd(), config.name);
2338
1917
  try {
2339
- if (isPublicTemplate) {
2340
- const httpsUrl = `https://github.com/${templateRepo}.git`;
2341
- await $2`git clone --depth 1 ${httpsUrl} ${config.name}`.quiet();
2342
- } else {
2343
- await $2`gh repo clone ${templateRepo} ${config.name} -- --depth 1`.quiet();
2344
- }
2345
- await rm(join2(config.name, ".git"), { recursive: true, force: true });
2346
- s.stop(`Template cloned`);
1918
+ await rm(projectPath, { recursive: true, force: true });
1919
+ } catch {}
1920
+ const templateRepo = config.customTemplate || TEMPLATES[config.type];
1921
+ const templateUrl = templateRepo.startsWith("http") ? templateRepo : `https://github.com/${templateRepo}`;
1922
+ s.start(`Cloning template: ${config.type}`);
1923
+ try {
1924
+ await $2`git clone --depth 1 ${templateUrl} ${config.name}`.quiet();
1925
+ s.stop(`Template cloned: ${config.type}`);
2347
1926
  } catch (error) {
2348
1927
  s.stop("Error cloning template");
2349
- throw new Error(`Failed to clone template ${templateRepo}. Check your connection or repository access.`);
1928
+ throw new Error(`Failed to clone template from ${templateUrl}`);
2350
1929
  }
2351
- if (config.type === "nimbus-core" && config.clientRepoUrl) {
2352
- const clientRepoUrl = config.clientRepoUrl;
2353
- s.start(`Cloning client repo in workspace...`);
2354
- try {
2355
- let projectName = "client-project";
2356
- if (clientRepoUrl.includes("visualstudio.com") || clientRepoUrl.includes("dev.azure.com")) {
2357
- const parts = clientRepoUrl.split("/");
2358
- projectName = parts[parts.length - 1] || "client-project";
2359
- } else {
2360
- projectName = clientRepoUrl.split("/").pop()?.replace(".git", "") || "client-project";
2361
- }
2362
- await $2`git clone ${clientRepoUrl} ${config.name}/workspace/${projectName}`.quiet();
2363
- s.stop(`Client repo cloned: workspace/${projectName}`);
2364
- } catch (error) {
2365
- s.stop("Error cloning client repo");
2366
- console.log(import_picocolors4.default.dim(" You can clone manually: cd workspace && git clone <url>"));
2367
- }
2368
- }
2369
- if (config.type !== "nimbus-core") {
2370
- s.start("Configuring project...");
1930
+ try {
1931
+ await rm(join2(projectPath, ".git"), { recursive: true, force: true });
1932
+ } catch {}
1933
+ if (config.install) {
1934
+ s.start("Installing dependencies...");
2371
1935
  try {
2372
- const pkgPath = `${config.name}/package.json`;
2373
- const pkg = await Bun.file(pkgPath).json();
2374
- pkg.name = config.name;
2375
- await Bun.write(pkgPath, JSON.stringify(pkg, null, 2));
2376
- s.stop("Project configured");
1936
+ await $2`bun install`.cwd(projectPath).quiet();
1937
+ s.stop("Dependencies installed");
2377
1938
  } catch (error) {
2378
- s.stop("Error configuring");
2379
- }
2380
- }
2381
- if (isPublicTemplate && config.theme) {
2382
- s.start(`Setting theme to ${config.theme}...`);
2383
- try {
2384
- const layoutPath = `${config.name}/src/app/layout.tsx`;
2385
- let layout = await Bun.file(layoutPath).text();
2386
- layout = layout.replace(/defaultTheme="(dark|light|system)"/, `defaultTheme="${config.theme}"`);
2387
- await Bun.write(layoutPath, layout);
2388
- s.stop(`Theme set to ${config.theme}`);
2389
- } catch {
2390
- s.stop("Theme config skipped");
2391
- }
2392
- }
2393
- if (isPublicTemplate && config.aiAssistant) {
2394
- const aiConfig = AI_CONFIGS[config.aiAssistant];
2395
- if (aiConfig) {
2396
- s.start(`Generating ${config.aiAssistant} config...`);
2397
- try {
2398
- const content = aiConfig.content(config.type);
2399
- const filePath = `${config.name}/${aiConfig.filename}`;
2400
- if (aiConfig.filename.includes("/")) {
2401
- const dir = aiConfig.filename.split("/").slice(0, -1).join("/");
2402
- await mkdir(`${config.name}/${dir}`, { recursive: true });
2403
- }
2404
- await Bun.write(filePath, content);
2405
- s.stop(`${aiConfig.filename} created`);
2406
- } catch {
2407
- s.stop("AI config skipped");
2408
- }
1939
+ s.stop("Error installing dependencies");
1940
+ console.log(import_picocolors3.default.yellow(" You can install manually with: bun install"));
2409
1941
  }
2410
1942
  }
2411
- if (config.type === "fast+") {
2412
- s.start("Configurando fast+ (SaaS)...");
2413
- s.stop("Configuracao fast+ preparada");
2414
- }
2415
1943
  if (config.git) {
2416
1944
  s.start("Initializing Git...");
2417
1945
  try {
2418
- const cwd = config.name;
2419
- await $2`git init -b main`.cwd(cwd).quiet();
2420
- await $2`git add -A`.cwd(cwd).quiet();
2421
- await $2`git commit -m "chore: setup inicial via nimbus create"`.cwd(cwd).quiet();
2422
- await $2`git checkout -b staging`.cwd(cwd).quiet();
2423
- await $2`git checkout -b develop`.cwd(cwd).quiet();
2424
- s.stop("Git initialized (main -> staging -> develop)");
1946
+ await $2`git init`.cwd(projectPath).quiet();
1947
+ await $2`git add .`.cwd(projectPath).quiet();
1948
+ await $2`git commit -m "Initial commit"`.cwd(projectPath).quiet();
1949
+ s.stop("Git initialized");
2425
1950
  } catch (error) {
2426
1951
  s.stop("Error initializing Git");
2427
- }
2428
- if (config.github) {
2429
- s.start("Creating GitHub repository...");
2430
- try {
2431
- const cwd = config.name;
2432
- const repoName = config.githubOrg ? `${config.githubOrg}/${config.name}` : config.name;
2433
- let visibility;
2434
- if (config.type === "nimbus-core") {
2435
- visibility = "--private";
2436
- } else if (isPublicTemplate) {
2437
- visibility = config.githubDescription === "public" ? "--public" : "--private";
2438
- } else {
2439
- visibility = config.githubOrg === "fast-by-nimbuslab" ? "--private" : "--public";
2440
- }
2441
- if (isPublicTemplate) {
2442
- await $2`gh repo create ${repoName} ${visibility} --source . --remote origin`.cwd(cwd).quiet();
2443
- } else {
2444
- await $2`gh repo create ${repoName} ${visibility} --description ${config.githubDescription} --source . --remote origin`.cwd(cwd).quiet();
2445
- }
2446
- await $2`git checkout main`.cwd(cwd).quiet();
2447
- await $2`git push -u origin main`.cwd(cwd).quiet();
2448
- await $2`git checkout staging`.cwd(cwd).quiet();
2449
- await $2`git push -u origin staging`.cwd(cwd).quiet();
2450
- await $2`git checkout develop`.cwd(cwd).quiet();
2451
- await $2`git push -u origin develop`.cwd(cwd).quiet();
2452
- s.stop(`GitHub: ${repoName}`);
2453
- } catch (error) {
2454
- s.stop("Error creating GitHub repository");
2455
- console.log(import_picocolors4.default.dim(" You can create manually with: gh repo create"));
2456
- }
2457
- }
2458
- }
2459
- if (config.railwayProject) {
2460
- s.start(`Linkando Railway: ${config.railwayProject}...`);
2461
- try {
2462
- await $2`railway link -p ${config.railwayProject}`.cwd(config.name).quiet();
2463
- s.stop(`Railway linkado: ${config.railwayProject}`);
2464
- } catch (error) {
2465
- s.stop("Error linking Railway");
2466
- console.log(import_picocolors4.default.dim(" Run manually: railway link"));
1952
+ console.log(import_picocolors3.default.yellow(" You can initialize manually with: git init"));
2467
1953
  }
2468
1954
  }
2469
- if (config.resendApiKey || config.stagingUrl) {
2470
- s.start("Gerando arquivo .env...");
1955
+ if (config.github && config.githubOrg) {
1956
+ s.start(`Creating GitHub repository...`);
2471
1957
  try {
2472
- const envContent = generateEnvFile2(config);
2473
- await Bun.write(`${config.name}/.env`, envContent);
2474
- s.stop("Arquivo .env criado");
1958
+ const repoName = config.name;
1959
+ const visibility = config.githubVisibility === "public" ? "--public" : "--private";
1960
+ const isPersonal = config.githubOrg && !config.githubOrg.includes("/");
1961
+ if (isPersonal) {
1962
+ await $2`gh repo create ${config.githubOrg}/${repoName} ${visibility} --source . --push`.cwd(projectPath).quiet();
1963
+ } else {
1964
+ await $2`gh repo create ${repoName} ${visibility} --source . --push`.cwd(projectPath).quiet();
1965
+ }
1966
+ const repoUrl = `https://github.com/${config.githubOrg}/${repoName}`;
1967
+ s.stop(`GitHub repository created`);
1968
+ console.log(import_picocolors3.default.green(` ${repoUrl}`));
2475
1969
  } catch (error) {
2476
- s.stop("Error creating .env");
1970
+ s.stop("Error creating GitHub repository");
1971
+ console.log(import_picocolors3.default.dim(" You can create manually with: gh repo create"));
2477
1972
  }
2478
1973
  }
2479
- if (config.install) {
2480
- s.start("Installing dependencies (pode demorar)...");
2481
- try {
2482
- await $2`bun install`.cwd(config.name).quiet();
2483
- s.stop("Dependencies installed");
2484
- } catch (error) {
2485
- s.stop("Error installing dependencies");
2486
- }
2487
- }
2488
- }
2489
- function generateEnvFile2(config) {
2490
- const lines = [
2491
- "# Gerado automaticamente pelo nimbus-cli",
2492
- "# Nao commitar este arquivo!",
2493
- "",
2494
- "# App",
2495
- `NODE_ENV=development`,
2496
- "",
2497
- "# URLs",
2498
- `NEXT_PUBLIC_APP_URL=${config.productionUrl || "http://localhost:3000"}`,
2499
- `STAGING_URL=${config.stagingUrl || ""}`,
2500
- `PRODUCTION_URL=${config.productionUrl || ""}`,
2501
- "",
2502
- "# Resend (Email)",
2503
- `RESEND_API_KEY=${config.resendApiKey || ""}`,
2504
- `RESEND_FROM_EMAIL=${config.resendFromEmail || ""}`,
2505
- `CONTACT_EMAIL=${config.contactEmail || ""}`
2506
- ];
2507
- if (config.railwayProject || config.railwayToken) {
2508
- lines.push("");
2509
- lines.push("# Railway");
2510
- if (config.railwayProject) {
2511
- lines.push(`# Project: ${config.railwayProject}`);
1974
+ if (config.aiAssistant && AI_CONFIGS[config.aiAssistant]) {
1975
+ const aiConfig = AI_CONFIGS[config.aiAssistant];
1976
+ const filePath = join2(projectPath, aiConfig.filename);
1977
+ if (aiConfig.filename.includes("/")) {
1978
+ const dir = join2(projectPath, aiConfig.filename.split("/")[0]);
1979
+ await mkdir(dir, { recursive: true });
1980
+ }
1981
+ await Bun.write(filePath, aiConfig.content(config.type));
1982
+ }
1983
+ s.start("Generating documentation...");
1984
+ const generatorConfig = {
1985
+ name: config.name,
1986
+ type: config.type,
1987
+ description: `A modern ${config.type === "landing" ? "landing page" : config.type === "app" ? "web application" : "monorepo"} built with Next.js 16, React 19, Tailwind CSS 4, and shadcn/ui.`,
1988
+ stack: {
1989
+ framework: "Next.js 16",
1990
+ styling: "Tailwind CSS 4",
1991
+ components: "shadcn/ui",
1992
+ forms: config.type !== "turborepo" ? "React Hook Form + Zod" : undefined,
1993
+ auth: config.type === "app" ? "Better Auth" : undefined
1994
+ },
1995
+ features: {
1996
+ auth: config.type === "app",
1997
+ contactForm: config.type === "landing",
1998
+ analytics: false
2512
1999
  }
2513
- lines.push(`RAILWAY_TOKEN=${config.railwayToken || "# Configure com: railway link"}`);
2514
- }
2515
- if (config.type === "fast+") {
2516
- lines.push("");
2517
- lines.push("# Database (fast+)");
2518
- lines.push("DATABASE_URL=postgresql://postgres:postgres@localhost:5432/app");
2519
- lines.push("");
2520
- lines.push("# Auth (fast+)");
2521
- lines.push("BETTER_AUTH_SECRET=");
2522
- lines.push("BETTER_AUTH_URL=http://localhost:3000");
2523
- }
2524
- return lines.join(`
2525
- `) + `
2526
- `;
2527
- }
2528
- function showNextSteps(config) {
2529
- const isPublicTemplate = ["landing", "app", "turborepo"].includes(config.type);
2530
- const needsSetup = config.type === "app";
2000
+ };
2001
+ await generateAIFriendlyDocs(projectPath, generatorConfig);
2002
+ s.stop("Documentation generated");
2531
2003
  console.log();
2532
- console.log(import_picocolors4.default.bold("Next steps:"));
2004
+ Se(import_picocolors3.default.green(`\u2713 Project created: ${config.name}`));
2533
2005
  console.log();
2534
- console.log(` ${import_picocolors4.default.cyan("cd")} ${config.name}`);
2535
- if (config.type === "nimbus-core") {
2536
- console.log();
2537
- console.log(import_picocolors4.default.dim(" nimbus-core: Motor para projetos externos"));
2538
- console.log();
2539
- console.log(import_picocolors4.default.dim(" Para usar a Lola:"));
2540
- console.log(` ${import_picocolors4.default.cyan("lola")}`);
2541
- console.log();
2542
- console.log(import_picocolors4.default.yellow(" STEALTH MODE: Commits sem mencao a nimbuslab/Lola/IA"));
2543
- console.log();
2544
- if (config.github) {
2545
- const repoUrl = `https://github.com/nimbuslab/${config.name}`;
2546
- console.log(import_picocolors4.default.green(` GitHub (private): ${repoUrl}`));
2547
- console.log();
2548
- }
2549
- console.log(import_picocolors4.default.dim(" Docs: See README.md for full instructions"));
2550
- console.log();
2551
- return;
2552
- }
2006
+ console.log(import_picocolors3.default.bold("Next steps:"));
2007
+ console.log(` ${import_picocolors3.default.cyan(`cd ${config.name}`)}`);
2553
2008
  if (!config.install) {
2554
- console.log(` ${import_picocolors4.default.cyan("bun")} install`);
2009
+ console.log(` ${import_picocolors3.default.cyan("bun install")}`);
2555
2010
  }
2556
- if (!isPublicTemplate || needsSetup) {
2557
- console.log(` ${import_picocolors4.default.cyan("bun")} setup`);
2558
- }
2559
- console.log(` ${import_picocolors4.default.cyan("bun")} dev`);
2011
+ console.log(` ${import_picocolors3.default.cyan("bun dev")}`);
2560
2012
  console.log();
2561
- if (needsSetup && isPublicTemplate) {
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)"));
2013
+ if (config.type === "app") {
2014
+ console.log(import_picocolors3.default.dim(" For database setup:"));
2015
+ console.log(` ${import_picocolors3.default.cyan("bun setup")}`);
2566
2016
  console.log();
2567
2017
  }
2568
- if (config.git) {
2569
- console.log(import_picocolors4.default.dim(" Git: main -> staging -> develop (current branch)"));
2570
- if (config.github) {
2571
- const repoUrl = config.githubOrg ? `https://github.com/${config.githubOrg}/${config.name}` : `https://github.com/${config.name}`;
2572
- console.log(import_picocolors4.default.green(` GitHub: ${repoUrl}`));
2573
- }
2574
- console.log();
2018
+ }
2019
+ async function create(args) {
2020
+ const checkCmd = process.platform === "win32" ? "where" : "which";
2021
+ console.log(import_picocolors3.default.dim("Checking dependencies..."));
2022
+ const hasGit = await $2`${checkCmd} git`.quiet().nothrow().then((r2) => r2.exitCode === 0);
2023
+ const hasBun = await $2`${checkCmd} bun`.quiet().nothrow().then((r2) => r2.exitCode === 0);
2024
+ if (!hasGit) {
2025
+ console.log(import_picocolors3.default.red("\u2717 Git not found"));
2026
+ console.log(import_picocolors3.default.dim(" Install from: https://git-scm.com"));
2027
+ process.exit(1);
2575
2028
  }
2576
- if (isPublicTemplate) {
2577
- if (config.theme !== "dark") {
2578
- console.log(import_picocolors4.default.dim(` Theme: ${config.theme}`));
2579
- }
2580
- if (config.aiAssistant) {
2581
- const aiConfig = AI_CONFIGS[config.aiAssistant];
2582
- if (aiConfig) {
2583
- console.log(import_picocolors4.default.dim(` AI config: ${aiConfig.filename}`));
2584
- }
2585
- }
2586
- if (config.theme !== "dark" || config.aiAssistant) {
2587
- console.log();
2588
- }
2029
+ if (!hasBun) {
2030
+ console.log(import_picocolors3.default.red("\u2717 Bun not found"));
2031
+ console.log(import_picocolors3.default.dim(" Install from: https://bun.sh"));
2032
+ process.exit(1);
2589
2033
  }
2590
- if (config.type === "fast+") {
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)"));
2595
- console.log();
2596
- console.log(import_picocolors4.default.dim(" Tip: Configure DATABASE_URL and BETTER_AUTH_SECRET in .env"));
2597
- if (!config.railwayToken) {
2598
- console.log(import_picocolors4.default.dim(" Railway: Create a project at https://railway.app/new"));
2599
- }
2034
+ console.log(import_picocolors3.default.green("\u2713 Dependencies OK"));
2035
+ console.log();
2036
+ const { flags, projectName } = parseFlags(args);
2037
+ Ie(import_picocolors3.default.bgCyan(import_picocolors3.default.black(" Create Next.js Project ")));
2038
+ let config;
2039
+ if (flags.yes && projectName && (flags.landing || flags.app || flags.turborepo)) {
2040
+ const type = flags.landing ? "landing" : flags.app ? "app" : "turborepo";
2041
+ config = {
2042
+ name: projectName,
2043
+ type,
2044
+ git: !flags.noGit,
2045
+ install: !flags.noInstall,
2046
+ github: false,
2047
+ githubOrg: null,
2048
+ githubVisibility: "public",
2049
+ theme: "dark",
2050
+ aiAssistant: null,
2051
+ customTemplate: flags.template
2052
+ };
2053
+ console.log(import_picocolors3.default.dim(` Project: ${projectName}`));
2054
+ console.log(import_picocolors3.default.dim(` Type: ${type}`));
2055
+ console.log(import_picocolors3.default.dim(` Git: ${config.git ? "yes" : "no"}`));
2056
+ console.log(import_picocolors3.default.dim(` Install: ${config.install ? "yes" : "no"}`));
2057
+ if (flags.template)
2058
+ console.log(import_picocolors3.default.dim(` Template: ${flags.template}`));
2600
2059
  console.log();
2601
- }
2602
- if (!isPublicTemplate) {
2603
- if (config.resendApiKey || config.stagingUrl) {
2604
- console.log(import_picocolors4.default.green(" .env configured!"));
2605
- console.log();
2606
- } else {
2607
- console.log(import_picocolors4.default.yellow(" Tip: Configure .env manually or use 'bun setup'."));
2608
- console.log();
2609
- }
2610
- }
2611
- if (isPublicTemplate) {
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}`));
2614
2060
  } else {
2615
- console.log(import_picocolors4.default.dim(" https://github.com/nimbuslab-templates"));
2061
+ config = await promptConfig(projectName, flags);
2616
2062
  }
2617
- console.log();
2063
+ if (pD(config)) {
2064
+ xe("Operation cancelled");
2065
+ process.exit(0);
2066
+ }
2067
+ await createProject(config);
2618
2068
  }
2619
2069
 
2620
2070
  // src/commands/analyze.ts
2621
- var import_picocolors5 = __toESM(require_picocolors(), 1);
2071
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
2622
2072
  import { existsSync, readFileSync } from "fs";
2623
2073
  import { join as join3 } from "path";
2624
2074
  function detectPackageManager(dir) {
@@ -2744,12 +2194,12 @@ async function analyze(args) {
2744
2194
  const targetDir = args[0] || ".";
2745
2195
  const absoluteDir = targetDir.startsWith("/") ? targetDir : join3(process.cwd(), targetDir);
2746
2196
  console.log();
2747
- console.log(import_picocolors5.default.cyan(" Analisando projeto..."));
2197
+ console.log(import_picocolors4.default.cyan(" Analisando projeto..."));
2748
2198
  console.log();
2749
2199
  const pkgPath = join3(absoluteDir, "package.json");
2750
2200
  if (!existsSync(pkgPath)) {
2751
- console.log(import_picocolors5.default.red(" Erro: package.json nao encontrado"));
2752
- console.log(import_picocolors5.default.dim(` Diretorio: ${absoluteDir}`));
2201
+ console.log(import_picocolors4.default.red(" Erro: package.json nao encontrado"));
2202
+ console.log(import_picocolors4.default.dim(` Diretorio: ${absoluteDir}`));
2753
2203
  process.exit(1);
2754
2204
  }
2755
2205
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -2772,36 +2222,36 @@ async function analyze(args) {
2772
2222
  recommendations: []
2773
2223
  };
2774
2224
  result.recommendations = generateRecommendations(result);
2775
- console.log(import_picocolors5.default.bold(" Projeto: ") + import_picocolors5.default.cyan(result.name) + import_picocolors5.default.dim(` v${result.version}`));
2225
+ console.log(import_picocolors4.default.bold(" Projeto: ") + import_picocolors4.default.cyan(result.name) + import_picocolors4.default.dim(` v${result.version}`));
2776
2226
  console.log();
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")}`);
2227
+ console.log(import_picocolors4.default.bold(" Stack Detectada:"));
2228
+ console.log(` Framework: ${result.framework ? import_picocolors4.default.green(result.framework + "@" + result.frameworkVersion) : import_picocolors4.default.dim("nenhum")}`);
2229
+ console.log(` Styling: ${result.styling.map((s) => import_picocolors4.default.green(s)).join(", ")}`);
2230
+ console.log(` Package Manager: ${result.packageManager === "bun" ? import_picocolors4.default.green(result.packageManager) : import_picocolors4.default.yellow(result.packageManager)}`);
2231
+ console.log(` TypeScript: ${result.typescript ? import_picocolors4.default.green("sim") : import_picocolors4.default.dim("nao")}`);
2232
+ console.log(` Monorepo: ${result.monorepo ? import_picocolors4.default.green(result.monorepo) : import_picocolors4.default.dim("nao")}`);
2233
+ console.log(` Auth: ${result.auth ? import_picocolors4.default.green(result.auth) : import_picocolors4.default.dim("nenhum")}`);
2234
+ console.log(` Database: ${result.database ? import_picocolors4.default.green(result.database) : import_picocolors4.default.dim("nenhum")}`);
2785
2235
  console.log();
2786
2236
  if (result.recommendations.length > 0) {
2787
- console.log(import_picocolors5.default.bold(" Recomendacoes:"));
2237
+ console.log(import_picocolors4.default.bold(" Recomendacoes:"));
2788
2238
  result.recommendations.forEach((rec, i) => {
2789
- console.log(import_picocolors5.default.yellow(` ${i + 1}. ${rec}`));
2239
+ console.log(import_picocolors4.default.yellow(` ${i + 1}. ${rec}`));
2790
2240
  });
2791
2241
  console.log();
2792
2242
  } else {
2793
- console.log(import_picocolors5.default.green(" Projeto ja esta na stack recomendada!"));
2243
+ console.log(import_picocolors4.default.green(" Projeto ja esta na stack recomendada!"));
2794
2244
  console.log();
2795
2245
  }
2796
2246
  if (args.includes("--json")) {
2797
- console.log(import_picocolors5.default.dim(" JSON:"));
2247
+ console.log(import_picocolors4.default.dim(" JSON:"));
2798
2248
  console.log(JSON.stringify(result, null, 2));
2799
2249
  }
2800
2250
  return result;
2801
2251
  }
2802
2252
 
2803
2253
  // src/commands/upgrade.ts
2804
- var import_picocolors6 = __toESM(require_picocolors(), 1);
2254
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
2805
2255
  var UPGRADE_PLANS = {
2806
2256
  next: (current) => {
2807
2257
  const major = parseInt(current.replace(/[^0-9]/g, "").slice(0, 2));
@@ -2918,10 +2368,10 @@ async function upgrade(args) {
2918
2368
  const target = args.find((a) => !a.startsWith("-"));
2919
2369
  console.log();
2920
2370
  if (showPlan || !target) {
2921
- console.log(import_picocolors6.default.cyan(" Analisando projeto para plano de upgrade..."));
2371
+ console.log(import_picocolors5.default.cyan(" Analisando projeto para plano de upgrade..."));
2922
2372
  console.log();
2923
2373
  const analysis = await analyze([".", "--quiet"]);
2924
- console.log(import_picocolors6.default.bold(" Upgrades Disponiveis:"));
2374
+ console.log(import_picocolors5.default.bold(" Upgrades Disponiveis:"));
2925
2375
  console.log();
2926
2376
  let hasUpgrades = false;
2927
2377
  if (analysis.frameworkVersion && analysis.framework === "nextjs") {
@@ -2976,44 +2426,44 @@ async function upgrade(args) {
2976
2426
  }
2977
2427
  }
2978
2428
  if (!hasUpgrades) {
2979
- console.log(import_picocolors6.default.green(" Projeto ja esta atualizado!"));
2429
+ console.log(import_picocolors5.default.green(" Projeto ja esta atualizado!"));
2980
2430
  }
2981
2431
  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"));
2432
+ console.log(import_picocolors5.default.dim(" Para executar um upgrade especifico:"));
2433
+ console.log(import_picocolors5.default.dim(" nimbus upgrade next"));
2434
+ console.log(import_picocolors5.default.dim(" nimbus upgrade tailwind"));
2435
+ console.log(import_picocolors5.default.dim(" nimbus upgrade bun"));
2986
2436
  console.log();
2987
2437
  return;
2988
2438
  }
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."));
2439
+ console.log(import_picocolors5.default.yellow(` Upgrade ${target} ainda nao implementado.`));
2440
+ console.log(import_picocolors5.default.dim(" Por enquanto, siga os passos do --plan manualmente."));
2991
2441
  console.log();
2992
2442
  }
2993
2443
  function printUpgradePlan(name, plan) {
2994
2444
  const complexityColor = {
2995
- low: import_picocolors6.default.green,
2996
- medium: import_picocolors6.default.yellow,
2997
- high: import_picocolors6.default.red
2445
+ low: import_picocolors5.default.green,
2446
+ medium: import_picocolors5.default.yellow,
2447
+ high: import_picocolors5.default.red
2998
2448
  };
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)}`);
2449
+ console.log(` ${import_picocolors5.default.bold(name)}`);
2450
+ console.log(` ${import_picocolors5.default.dim("Atual:")} ${plan.current} ${import_picocolors5.default.dim("->")} ${import_picocolors5.default.cyan(plan.target)}`);
2451
+ console.log(` ${import_picocolors5.default.dim("Complexidade:")} ${complexityColor[plan.complexity](plan.complexity)}`);
3002
2452
  console.log();
3003
- console.log(` ${import_picocolors6.default.dim("Breaking Changes:")}`);
2453
+ console.log(` ${import_picocolors5.default.dim("Breaking Changes:")}`);
3004
2454
  plan.breakingChanges.forEach((bc) => {
3005
- console.log(` ${import_picocolors6.default.yellow("!")} ${bc}`);
2455
+ console.log(` ${import_picocolors5.default.yellow("!")} ${bc}`);
3006
2456
  });
3007
2457
  console.log();
3008
- console.log(` ${import_picocolors6.default.dim("Passos:")}`);
2458
+ console.log(` ${import_picocolors5.default.dim("Passos:")}`);
3009
2459
  plan.steps.forEach((step, i) => {
3010
- console.log(` ${import_picocolors6.default.dim(`${i + 1}.`)} ${step}`);
2460
+ console.log(` ${import_picocolors5.default.dim(`${i + 1}.`)} ${step}`);
3011
2461
  });
3012
2462
  console.log();
3013
2463
  }
3014
2464
 
3015
2465
  // src/commands/update.ts
3016
- var import_picocolors7 = __toESM(require_picocolors(), 1);
2466
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
3017
2467
  import { execSync, spawnSync } from "child_process";
3018
2468
  var PACKAGE_NAME = "@nimbuslab/cli";
3019
2469
  function hasBunInstall() {
@@ -3149,7 +2599,7 @@ async function update(args) {
3149
2599
  const filteredArgs = args.filter((a) => a !== "--force" && a !== "-f");
3150
2600
  const flag = filteredArgs[0];
3151
2601
  if (flag === "--list" || flag === "-l") {
3152
- Ie(import_picocolors7.default.cyan("Versoes disponiveis"));
2602
+ Ie(import_picocolors6.default.cyan("Versoes disponiveis"));
3153
2603
  const spinner2 = Y2();
3154
2604
  spinner2.start("Buscando versoes...");
3155
2605
  const versions = await getAvailableVersions();
@@ -3161,29 +2611,29 @@ async function update(args) {
3161
2611
  const current = getCurrentVersion();
3162
2612
  const pm2 = detectPackageManager2();
3163
2613
  console.log();
3164
- console.log(import_picocolors7.default.bold("Ultimas 10 versoes:"));
2614
+ console.log(import_picocolors6.default.bold("Ultimas 10 versoes:"));
3165
2615
  versions.slice(0, 10).forEach((v2, i) => {
3166
2616
  const isCurrent = v2 === current;
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)") : "";
2617
+ const prefix = isCurrent ? import_picocolors6.default.green("-> ") : " ";
2618
+ const suffix = isCurrent ? import_picocolors6.default.dim(" (instalada)") : "";
2619
+ const isLatest = i === 0 ? import_picocolors6.default.yellow(" (latest)") : "";
3170
2620
  console.log(`${prefix}${v2}${suffix}${isLatest}`);
3171
2621
  });
3172
2622
  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`));
2623
+ console.log(import_picocolors6.default.dim(`Total: ${versions.length} versoes`));
2624
+ console.log(import_picocolors6.default.dim(`Package manager detectado: ${pm2 === "unknown" ? "nenhum" : pm2}`));
2625
+ console.log(import_picocolors6.default.dim(`Instalar versao especifica: nimbus update <versao>`));
2626
+ console.log(import_picocolors6.default.dim(`Forcar reinstalacao: nimbus update --force`));
3177
2627
  return;
3178
2628
  }
3179
2629
  const targetVersion = flag || "latest";
3180
2630
  const isSpecificVersion = flag && flag !== "latest" && !flag.startsWith("-");
3181
- Ie(import_picocolors7.default.cyan(`Atualizando ${PACKAGE_NAME}`));
2631
+ Ie(import_picocolors6.default.cyan(`Atualizando ${PACKAGE_NAME}`));
3182
2632
  const spinner = Y2();
3183
2633
  spinner.start("Verificando instalacoes...");
3184
2634
  const cleanup = cleanupDuplicateInstalls();
3185
2635
  if (cleanup.cleaned) {
3186
- spinner.stop(import_picocolors7.default.yellow(cleanup.message));
2636
+ spinner.stop(import_picocolors6.default.yellow(cleanup.message));
3187
2637
  } else {
3188
2638
  spinner.stop("OK");
3189
2639
  }
@@ -3201,7 +2651,7 @@ async function update(args) {
3201
2651
  spinner.stop(`Ultima versao: ${latestVersion || "desconhecida"}`);
3202
2652
  if (!forceFlag && latestVersion && latestVersion === currentVersion) {
3203
2653
  M2.success("Voce ja esta na ultima versao!");
3204
- console.log(import_picocolors7.default.dim(" Use --force para reinstalar"));
2654
+ console.log(import_picocolors6.default.dim(" Use --force para reinstalar"));
3205
2655
  return;
3206
2656
  }
3207
2657
  }
@@ -3239,33 +2689,33 @@ async function update(args) {
3239
2689
  const isWindows = process.platform === "win32";
3240
2690
  if (isWindows) {
3241
2691
  console.log();
3242
- console.log(import_picocolors7.default.yellow(" Reinicie o terminal para aplicar a atualizacao."));
2692
+ console.log(import_picocolors6.default.yellow(" Reinicie o terminal para aplicar a atualizacao."));
3243
2693
  } else if (isUsingFnm()) {
3244
2694
  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."));
2695
+ console.log(import_picocolors6.default.yellow(" fnm detectado - execute para aplicar:"));
2696
+ console.log(import_picocolors6.default.cyan(" hash -r"));
2697
+ console.log(import_picocolors6.default.dim(" Ou abra um novo terminal."));
3248
2698
  }
3249
- Se(import_picocolors7.default.green("Pronto!"));
2699
+ Se(import_picocolors6.default.green("Pronto!"));
3250
2700
  } catch (error) {
3251
2701
  spinner.stop("Erro na atualizacao");
3252
2702
  const err = error;
3253
2703
  M2.error("Falha ao atualizar");
3254
2704
  if (err.stderr) {
3255
- console.log(import_picocolors7.default.dim(err.stderr));
2705
+ console.log(import_picocolors6.default.dim(err.stderr));
3256
2706
  }
3257
2707
  console.log();
3258
- console.log(import_picocolors7.default.yellow("Tente manualmente:"));
2708
+ console.log(import_picocolors6.default.yellow("Tente manualmente:"));
3259
2709
  if (pm === "bun") {
3260
- console.log(import_picocolors7.default.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
2710
+ console.log(import_picocolors6.default.cyan(` bun add -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
3261
2711
  } else {
3262
- console.log(import_picocolors7.default.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
2712
+ console.log(import_picocolors6.default.cyan(` npm install -g ${PACKAGE_NAME}${isSpecificVersion ? `@${targetVersion}` : ""}`));
3263
2713
  }
3264
2714
  }
3265
2715
  }
3266
2716
 
3267
2717
  // src/commands/setup-node.ts
3268
- var import_picocolors8 = __toESM(require_picocolors(), 1);
2718
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
3269
2719
  import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
3270
2720
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
3271
2721
  import { homedir } from "os";
@@ -3534,7 +2984,7 @@ async function removeFnm(fnm) {
3534
2984
  const scoopCheck = spawnSync2("scoop", ["list"], { encoding: "utf-8", shell: true });
3535
2985
  if (scoopCheck.stdout?.includes("fnm")) {
3536
2986
  execSync2("scoop uninstall fnm", { stdio: "pipe" });
3537
- console.log(import_picocolors8.default.dim(" Removido via Scoop"));
2987
+ console.log(import_picocolors7.default.dim(" Removido via Scoop"));
3538
2988
  removed = true;
3539
2989
  }
3540
2990
  } catch {}
@@ -3543,7 +2993,7 @@ async function removeFnm(fnm) {
3543
2993
  const chocoCheck = spawnSync2("choco", ["list", "--local-only"], { encoding: "utf-8", shell: true });
3544
2994
  if (chocoCheck.stdout?.includes("fnm")) {
3545
2995
  execSync2("choco uninstall fnm -y", { stdio: "pipe" });
3546
- console.log(import_picocolors8.default.dim(" Removido via Chocolatey"));
2996
+ console.log(import_picocolors7.default.dim(" Removido via Chocolatey"));
3547
2997
  removed = true;
3548
2998
  }
3549
2999
  } catch {}
@@ -3553,7 +3003,7 @@ async function removeFnm(fnm) {
3553
3003
  const wingetCheck = spawnSync2("winget", ["list", "--name", "fnm"], { encoding: "utf-8", shell: true });
3554
3004
  if (wingetCheck.stdout?.includes("fnm")) {
3555
3005
  execSync2("winget uninstall fnm --silent", { stdio: "pipe" });
3556
- console.log(import_picocolors8.default.dim(" Removido via winget"));
3006
+ console.log(import_picocolors7.default.dim(" Removido via winget"));
3557
3007
  removed = true;
3558
3008
  }
3559
3009
  } catch {}
@@ -3569,12 +3019,12 @@ async function removeFnm(fnm) {
3569
3019
  if (existsSync2(dir)) {
3570
3020
  try {
3571
3021
  execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: "cmd.exe" });
3572
- console.log(import_picocolors8.default.dim(` Removido ${dir}`));
3022
+ console.log(import_picocolors7.default.dim(` Removido ${dir}`));
3573
3023
  removed = true;
3574
3024
  } catch {
3575
3025
  try {
3576
3026
  execSync2(`powershell -Command "Remove-Item -Path '${dir}' -Recurse -Force"`, { stdio: "pipe" });
3577
- console.log(import_picocolors8.default.dim(` Removido ${dir}`));
3027
+ console.log(import_picocolors7.default.dim(` Removido ${dir}`));
3578
3028
  removed = true;
3579
3029
  } catch {}
3580
3030
  }
@@ -3583,16 +3033,16 @@ async function removeFnm(fnm) {
3583
3033
  try {
3584
3034
  execSync2(`powershell -Command "[Environment]::SetEnvironmentVariable('FNM_DIR', $null, 'User')"`, { stdio: "pipe" });
3585
3035
  execSync2(`powershell -Command "[Environment]::SetEnvironmentVariable('FNM_MULTISHELL_PATH', $null, 'User')"`, { stdio: "pipe" });
3586
- console.log(import_picocolors8.default.dim(" Variaveis de ambiente FNM removidas"));
3036
+ console.log(import_picocolors7.default.dim(" Variaveis de ambiente FNM removidas"));
3587
3037
  removed = true;
3588
3038
  } catch {}
3589
3039
  for (const configFile of fnm.configFiles || []) {
3590
3040
  if (removeFnmFromConfig(configFile)) {
3591
- console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3041
+ console.log(import_picocolors7.default.dim(` Removido de ${configFile}`));
3592
3042
  removed = true;
3593
3043
  }
3594
3044
  }
3595
- spinner.stop(removed ? "fnm removido!" : import_picocolors8.default.yellow("fnm nao encontrado"));
3045
+ spinner.stop(removed ? "fnm removido!" : import_picocolors7.default.yellow("fnm nao encontrado"));
3596
3046
  return removed;
3597
3047
  } else {
3598
3048
  spinner.start("Removendo fnm...");
@@ -3601,13 +3051,13 @@ async function removeFnm(fnm) {
3601
3051
  const brewCheck = spawnSync2("brew", ["list", "fnm"], { encoding: "utf-8", shell: true });
3602
3052
  if (brewCheck.status === 0) {
3603
3053
  execSync2("brew uninstall fnm", { stdio: "pipe" });
3604
- console.log(import_picocolors8.default.dim(" Removido via Homebrew"));
3054
+ console.log(import_picocolors7.default.dim(" Removido via Homebrew"));
3605
3055
  removed = true;
3606
3056
  }
3607
3057
  } catch {}
3608
3058
  for (const configFile of fnm.configFiles || []) {
3609
3059
  if (removeFnmFromConfig(configFile)) {
3610
- console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3060
+ console.log(import_picocolors7.default.dim(` Removido de ${configFile}`));
3611
3061
  removed = true;
3612
3062
  }
3613
3063
  }
@@ -3618,7 +3068,7 @@ async function removeFnm(fnm) {
3618
3068
  for (const fnmDir of fnmDirs) {
3619
3069
  if (existsSync2(fnmDir)) {
3620
3070
  execSync2(`rm -rf "${fnmDir}"`, { stdio: "pipe" });
3621
- console.log(import_picocolors8.default.dim(` Removido ${fnmDir}`));
3071
+ console.log(import_picocolors7.default.dim(` Removido ${fnmDir}`));
3622
3072
  removed = true;
3623
3073
  }
3624
3074
  }
@@ -3629,7 +3079,7 @@ async function removeFnm(fnm) {
3629
3079
  for (const bin of fnmBins) {
3630
3080
  if (existsSync2(bin)) {
3631
3081
  execSync2(`rm -f "${bin}"`, { stdio: "pipe" });
3632
- console.log(import_picocolors8.default.dim(` Removido ${bin}`));
3082
+ console.log(import_picocolors7.default.dim(` Removido ${bin}`));
3633
3083
  removed = true;
3634
3084
  }
3635
3085
  }
@@ -3637,7 +3087,7 @@ async function removeFnm(fnm) {
3637
3087
  return removed;
3638
3088
  }
3639
3089
  } catch (error) {
3640
- spinner.stop(import_picocolors8.default.red("Erro ao remover fnm"));
3090
+ spinner.stop(import_picocolors7.default.red("Erro ao remover fnm"));
3641
3091
  return false;
3642
3092
  }
3643
3093
  }
@@ -3651,7 +3101,7 @@ async function removeNvm(nvm) {
3651
3101
  const wingetCheck = spawnSync2("winget", ["list", "--name", "nvm"], { encoding: "utf-8", shell: true });
3652
3102
  if (wingetCheck.stdout?.toLowerCase().includes("nvm")) {
3653
3103
  execSync2("winget uninstall nvm --silent", { stdio: "pipe" });
3654
- console.log(import_picocolors8.default.dim(" Removido via winget"));
3104
+ console.log(import_picocolors7.default.dim(" Removido via winget"));
3655
3105
  removed = true;
3656
3106
  }
3657
3107
  } catch {}
@@ -3664,46 +3114,46 @@ async function removeNvm(nvm) {
3664
3114
  if (existsSync2(dir)) {
3665
3115
  try {
3666
3116
  execSync2(`rmdir /s /q "${dir}"`, { stdio: "pipe", shell: "cmd.exe" });
3667
- console.log(import_picocolors8.default.dim(` Removido ${dir}`));
3117
+ console.log(import_picocolors7.default.dim(` Removido ${dir}`));
3668
3118
  removed = true;
3669
3119
  } catch {}
3670
3120
  }
3671
3121
  }
3672
3122
  for (const configFile of nvm.configFiles || []) {
3673
3123
  if (removeNvmFromConfig(configFile)) {
3674
- console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3124
+ console.log(import_picocolors7.default.dim(` Removido de ${configFile}`));
3675
3125
  removed = true;
3676
3126
  }
3677
3127
  }
3678
3128
  if (!removed) {
3679
- console.log(import_picocolors8.default.yellow(`
3129
+ console.log(import_picocolors7.default.yellow(`
3680
3130
  nvm-windows pode precisar de remocao manual:`));
3681
- console.log(import_picocolors8.default.dim(" 1. Abra 'Adicionar ou remover programas'"));
3682
- console.log(import_picocolors8.default.dim(" 2. Procure por 'NVM for Windows'"));
3683
- console.log(import_picocolors8.default.dim(" 3. Clique em Desinstalar"));
3131
+ console.log(import_picocolors7.default.dim(" 1. Abra 'Adicionar ou remover programas'"));
3132
+ console.log(import_picocolors7.default.dim(" 2. Procure por 'NVM for Windows'"));
3133
+ console.log(import_picocolors7.default.dim(" 3. Clique em Desinstalar"));
3684
3134
  }
3685
- spinner.stop(removed ? "nvm removido!" : import_picocolors8.default.yellow("Verifique manualmente"));
3135
+ spinner.stop(removed ? "nvm removido!" : import_picocolors7.default.yellow("Verifique manualmente"));
3686
3136
  return removed;
3687
3137
  } else {
3688
3138
  spinner.start("Removendo nvm...");
3689
3139
  let removed = false;
3690
3140
  for (const configFile of nvm.configFiles || []) {
3691
3141
  if (removeNvmFromConfig(configFile)) {
3692
- console.log(import_picocolors8.default.dim(` Removido de ${configFile}`));
3142
+ console.log(import_picocolors7.default.dim(` Removido de ${configFile}`));
3693
3143
  removed = true;
3694
3144
  }
3695
3145
  }
3696
3146
  const nvmDir = process.env.NVM_DIR || join4(HOME, ".nvm");
3697
3147
  if (existsSync2(nvmDir)) {
3698
3148
  execSync2(`rm -rf "${nvmDir}"`, { stdio: "pipe" });
3699
- console.log(import_picocolors8.default.dim(` Removido ${nvmDir}`));
3149
+ console.log(import_picocolors7.default.dim(` Removido ${nvmDir}`));
3700
3150
  removed = true;
3701
3151
  }
3702
3152
  spinner.stop(removed ? "nvm removido!" : "nvm nao encontrado");
3703
3153
  return removed;
3704
3154
  }
3705
3155
  } catch (error) {
3706
- spinner.stop(import_picocolors8.default.red("Erro ao remover nvm"));
3156
+ spinner.stop(import_picocolors7.default.red("Erro ao remover nvm"));
3707
3157
  return false;
3708
3158
  }
3709
3159
  }
@@ -3723,13 +3173,13 @@ async function installVolta() {
3723
3173
  });
3724
3174
  spinner.stop("Volta instalado!");
3725
3175
  const voltaPath = join4(HOME, ".volta", "bin");
3726
- console.log(import_picocolors8.default.dim(` Adicionando ${voltaPath} ao PATH...`));
3176
+ console.log(import_picocolors7.default.dim(` Adicionando ${voltaPath} ao PATH...`));
3727
3177
  try {
3728
3178
  execSync2(`setx PATH "%PATH%;${voltaPath}"`, { stdio: "pipe", shell: "cmd.exe" });
3729
3179
  } catch {}
3730
3180
  return true;
3731
3181
  } catch (e2) {
3732
- spinner.stop(import_picocolors8.default.yellow("winget falhou, tentando outro metodo..."));
3182
+ spinner.stop(import_picocolors7.default.yellow("winget falhou, tentando outro metodo..."));
3733
3183
  }
3734
3184
  }
3735
3185
  const chocoCheck = spawnSync2(CHECK_CMD, ["choco"], { encoding: "utf-8", shell: true });
@@ -3740,7 +3190,7 @@ async function installVolta() {
3740
3190
  spinner.stop("Volta instalado!");
3741
3191
  return true;
3742
3192
  } catch {
3743
- spinner.stop(import_picocolors8.default.yellow("Chocolatey falhou"));
3193
+ spinner.stop(import_picocolors7.default.yellow("Chocolatey falhou"));
3744
3194
  }
3745
3195
  }
3746
3196
  spinner.start("Baixando Volta diretamente...");
@@ -3764,17 +3214,17 @@ async function installVolta() {
3764
3214
  spinner.stop("Volta instalado!");
3765
3215
  return true;
3766
3216
  } catch (e2) {
3767
- spinner.stop(import_picocolors8.default.yellow("Download direto falhou"));
3217
+ spinner.stop(import_picocolors7.default.yellow("Download direto falhou"));
3768
3218
  }
3769
3219
  console.log();
3770
- console.log(import_picocolors8.default.bold(" Instale manualmente:"));
3220
+ console.log(import_picocolors7.default.bold(" Instale manualmente:"));
3771
3221
  console.log();
3772
- console.log(import_picocolors8.default.cyan(" 1. Baixe: https://github.com/volta-cli/volta/releases/latest"));
3773
- console.log(import_picocolors8.default.dim(" (arquivo volta-windows.msi)"));
3222
+ console.log(import_picocolors7.default.cyan(" 1. Baixe: https://github.com/volta-cli/volta/releases/latest"));
3223
+ console.log(import_picocolors7.default.dim(" (arquivo volta-windows.msi)"));
3774
3224
  console.log();
3775
- console.log(import_picocolors8.default.cyan(" 2. Execute o instalador"));
3225
+ console.log(import_picocolors7.default.cyan(" 2. Execute o instalador"));
3776
3226
  console.log();
3777
- console.log(import_picocolors8.default.cyan(" 3. Reinicie o terminal"));
3227
+ console.log(import_picocolors7.default.cyan(" 3. Reinicie o terminal"));
3778
3228
  console.log();
3779
3229
  return false;
3780
3230
  } else {
@@ -3793,15 +3243,15 @@ export PATH="$VOLTA_HOME/bin:$PATH"
3793
3243
  const content = readFileSync2(shellConfig, "utf-8");
3794
3244
  if (!content.includes("VOLTA_HOME")) {
3795
3245
  writeFileSync(shellConfig, content + voltaSetup);
3796
- console.log(import_picocolors8.default.dim(` Adicionado ao ${shellConfig}`));
3246
+ console.log(import_picocolors7.default.dim(` Adicionado ao ${shellConfig}`));
3797
3247
  }
3798
3248
  }
3799
3249
  spinner.stop("Volta instalado!");
3800
3250
  return true;
3801
3251
  }
3802
3252
  } catch (error) {
3803
- spinner.stop(import_picocolors8.default.red("Erro ao instalar Volta"));
3804
- console.log(import_picocolors8.default.dim(` ${error}`));
3253
+ spinner.stop(import_picocolors7.default.red("Erro ao instalar Volta"));
3254
+ console.log(import_picocolors7.default.dim(` ${error}`));
3805
3255
  return false;
3806
3256
  }
3807
3257
  }
@@ -3814,7 +3264,7 @@ async function installNodeWithVolta() {
3814
3264
  spinner.stop("Node.js instalado!");
3815
3265
  return true;
3816
3266
  } catch (error) {
3817
- spinner.stop(import_picocolors8.default.red("Erro ao instalar Node.js"));
3267
+ spinner.stop(import_picocolors7.default.red("Erro ao instalar Node.js"));
3818
3268
  return false;
3819
3269
  }
3820
3270
  }
@@ -3829,16 +3279,16 @@ async function reinstallGlobalPackages(packages) {
3829
3279
  execSync2(`"${voltaBin}" install ${pkg}`, { stdio: "pipe" });
3830
3280
  spinner.stop(`${pkg} instalado!`);
3831
3281
  } catch {
3832
- spinner.stop(import_picocolors8.default.yellow(`${pkg} - falha (instale manualmente)`));
3282
+ spinner.stop(import_picocolors7.default.yellow(`${pkg} - falha (instale manualmente)`));
3833
3283
  }
3834
3284
  }
3835
3285
  }
3836
3286
  async function setupNode(args) {
3837
3287
  const checkOnly = args.includes("--check") || args.includes("-c");
3838
3288
  console.log();
3839
- Ie(import_picocolors8.default.bgCyan(import_picocolors8.default.black(" nimbus setup node ")));
3289
+ Ie(import_picocolors7.default.bgCyan(import_picocolors7.default.black(" nimbus setup node ")));
3840
3290
  console.log();
3841
- console.log(import_picocolors8.default.bold(" Detectando ambiente..."));
3291
+ console.log(import_picocolors7.default.bold(" Detectando ambiente..."));
3842
3292
  console.log();
3843
3293
  const fnm = detectFnm();
3844
3294
  const nvm = detectNvm();
@@ -3846,27 +3296,27 @@ async function setupNode(args) {
3846
3296
  const node = detectNode();
3847
3297
  const status = (installed, version) => {
3848
3298
  if (!installed)
3849
- return import_picocolors8.default.dim("nao instalado");
3850
- return import_picocolors8.default.green(`instalado${version ? ` (${version})` : ""}`);
3299
+ return import_picocolors7.default.dim("nao instalado");
3300
+ return import_picocolors7.default.green(`instalado${version ? ` (${version})` : ""}`);
3851
3301
  };
3852
- console.log(` ${import_picocolors8.default.bold("fnm:")} ${status(fnm.installed, fnm.version)}`);
3853
- console.log(` ${import_picocolors8.default.bold("nvm:")} ${status(nvm.installed, nvm.version)}`);
3854
- console.log(` ${import_picocolors8.default.bold("volta:")} ${status(volta.installed, volta.version)}`);
3302
+ console.log(` ${import_picocolors7.default.bold("fnm:")} ${status(fnm.installed, fnm.version)}`);
3303
+ console.log(` ${import_picocolors7.default.bold("nvm:")} ${status(nvm.installed, nvm.version)}`);
3304
+ console.log(` ${import_picocolors7.default.bold("volta:")} ${status(volta.installed, volta.version)}`);
3855
3305
  console.log();
3856
- console.log(` ${import_picocolors8.default.bold("node:")} ${node.version || import_picocolors8.default.dim("nao encontrado")}`);
3306
+ console.log(` ${import_picocolors7.default.bold("node:")} ${node.version || import_picocolors7.default.dim("nao encontrado")}`);
3857
3307
  if (node.manager) {
3858
- console.log(` ${import_picocolors8.default.dim(`gerenciado por: ${node.manager}`)}`);
3308
+ console.log(` ${import_picocolors7.default.dim(`gerenciado por: ${node.manager}`)}`);
3859
3309
  }
3860
3310
  console.log();
3861
3311
  if (volta.installed && !fnm.installed && !nvm.installed) {
3862
3312
  M2.success("Ambiente OK! Volta instalado e configurado.");
3863
- Se(import_picocolors8.default.green("Nada a fazer."));
3313
+ Se(import_picocolors7.default.green("Nada a fazer."));
3864
3314
  return;
3865
3315
  }
3866
3316
  if (checkOnly) {
3867
3317
  if (fnm.installed || nvm.installed) {
3868
- console.log(import_picocolors8.default.yellow(" Recomendacao: migre para Volta"));
3869
- console.log(import_picocolors8.default.dim(" Execute: nimbus setup node"));
3318
+ console.log(import_picocolors7.default.yellow(" Recomendacao: migre para Volta"));
3319
+ console.log(import_picocolors7.default.dim(" Execute: nimbus setup node"));
3870
3320
  }
3871
3321
  Se("");
3872
3322
  return;
@@ -3874,15 +3324,15 @@ async function setupNode(args) {
3874
3324
  const hasOldManager = fnm.installed || nvm.installed;
3875
3325
  const globalPackages = getGlobalPackages();
3876
3326
  if (hasOldManager) {
3877
- console.log(import_picocolors8.default.yellow(" Gerenciadores antigos detectados!"));
3327
+ console.log(import_picocolors7.default.yellow(" Gerenciadores antigos detectados!"));
3878
3328
  console.log();
3879
- console.log(import_picocolors8.default.dim(" fnm e nvm causam problemas de cache do shell."));
3880
- console.log(import_picocolors8.default.dim(" Volta resolve isso e funciona melhor no Windows."));
3329
+ console.log(import_picocolors7.default.dim(" fnm e nvm causam problemas de cache do shell."));
3330
+ console.log(import_picocolors7.default.dim(" Volta resolve isso e funciona melhor no Windows."));
3881
3331
  console.log();
3882
3332
  if (globalPackages.length > 0) {
3883
- console.log(import_picocolors8.default.bold(" Pacotes globais encontrados:"));
3333
+ console.log(import_picocolors7.default.bold(" Pacotes globais encontrados:"));
3884
3334
  for (const pkg of globalPackages) {
3885
- console.log(import_picocolors8.default.dim(` - ${pkg}`));
3335
+ console.log(import_picocolors7.default.dim(` - ${pkg}`));
3886
3336
  }
3887
3337
  console.log();
3888
3338
  }
@@ -3897,9 +3347,9 @@ async function setupNode(args) {
3897
3347
  actions.push("Instalar Node.js via Volta");
3898
3348
  if (globalPackages.length > 0)
3899
3349
  actions.push(`Reinstalar ${globalPackages.length} pacotes globais`);
3900
- console.log(import_picocolors8.default.bold(" O que sera feito:"));
3350
+ console.log(import_picocolors7.default.bold(" O que sera feito:"));
3901
3351
  for (const action of actions) {
3902
- console.log(import_picocolors8.default.cyan(` -> ${action}`));
3352
+ console.log(import_picocolors7.default.cyan(` -> ${action}`));
3903
3353
  }
3904
3354
  console.log();
3905
3355
  const confirm = await ye({
@@ -3912,60 +3362,60 @@ async function setupNode(args) {
3912
3362
  }
3913
3363
  console.log();
3914
3364
  if (fnm.installed) {
3915
- console.log(import_picocolors8.default.bold(" Removendo fnm..."));
3365
+ console.log(import_picocolors7.default.bold(" Removendo fnm..."));
3916
3366
  await removeFnm(fnm);
3917
3367
  console.log();
3918
3368
  }
3919
3369
  if (nvm.installed) {
3920
- console.log(import_picocolors8.default.bold(" Removendo nvm..."));
3370
+ console.log(import_picocolors7.default.bold(" Removendo nvm..."));
3921
3371
  await removeNvm(nvm);
3922
3372
  console.log();
3923
3373
  }
3924
3374
  if (!volta.installed) {
3925
- console.log(import_picocolors8.default.bold(" Instalando Volta..."));
3375
+ console.log(import_picocolors7.default.bold(" Instalando Volta..."));
3926
3376
  const installed = await installVolta();
3927
3377
  if (!installed) {
3928
- Se(import_picocolors8.default.red("Falha na instalacao. Tente manualmente."));
3378
+ Se(import_picocolors7.default.red("Falha na instalacao. Tente manualmente."));
3929
3379
  return;
3930
3380
  }
3931
3381
  console.log();
3932
3382
  }
3933
- console.log(import_picocolors8.default.bold(" Instalando Node.js..."));
3383
+ console.log(import_picocolors7.default.bold(" Instalando Node.js..."));
3934
3384
  await installNodeWithVolta();
3935
3385
  console.log();
3936
3386
  if (globalPackages.length > 0) {
3937
- console.log(import_picocolors8.default.bold(" Reinstalando pacotes globais..."));
3387
+ console.log(import_picocolors7.default.bold(" Reinstalando pacotes globais..."));
3938
3388
  await reinstallGlobalPackages(globalPackages);
3939
3389
  console.log();
3940
3390
  }
3941
- console.log(import_picocolors8.default.green(" ====================================="));
3942
- console.log(import_picocolors8.default.green(" Migracao concluida!"));
3943
- console.log(import_picocolors8.default.green(" ====================================="));
3391
+ console.log(import_picocolors7.default.green(" ====================================="));
3392
+ console.log(import_picocolors7.default.green(" Migracao concluida!"));
3393
+ console.log(import_picocolors7.default.green(" ====================================="));
3944
3394
  console.log();
3945
3395
  if (IS_WINDOWS) {
3946
- console.log(import_picocolors8.default.yellow(" IMPORTANTE: Reinicie o terminal!"));
3396
+ console.log(import_picocolors7.default.yellow(" IMPORTANTE: Reinicie o terminal!"));
3947
3397
  console.log();
3948
- console.log(import_picocolors8.default.dim(" Feche todas as janelas do PowerShell/Terminal"));
3949
- console.log(import_picocolors8.default.dim(" e abra novamente para aplicar as mudancas."));
3398
+ console.log(import_picocolors7.default.dim(" Feche todas as janelas do PowerShell/Terminal"));
3399
+ console.log(import_picocolors7.default.dim(" e abra novamente para aplicar as mudancas."));
3950
3400
  } else {
3951
- console.log(import_picocolors8.default.yellow(" IMPORTANTE: Reinicie o terminal ou execute:"));
3401
+ console.log(import_picocolors7.default.yellow(" IMPORTANTE: Reinicie o terminal ou execute:"));
3952
3402
  console.log();
3953
- console.log(import_picocolors8.default.cyan(" source ~/.zshrc"));
3954
- console.log(import_picocolors8.default.dim(" # ou"));
3955
- console.log(import_picocolors8.default.cyan(" source ~/.bashrc"));
3403
+ console.log(import_picocolors7.default.cyan(" source ~/.zshrc"));
3404
+ console.log(import_picocolors7.default.dim(" # ou"));
3405
+ console.log(import_picocolors7.default.cyan(" source ~/.bashrc"));
3956
3406
  }
3957
3407
  console.log();
3958
- console.log(import_picocolors8.default.bold(" Depois, verifique:"));
3959
- console.log(import_picocolors8.default.dim(" volta --version"));
3960
- console.log(import_picocolors8.default.dim(" node --version"));
3961
- console.log(import_picocolors8.default.dim(" nimbus --version"));
3408
+ console.log(import_picocolors7.default.bold(" Depois, verifique:"));
3409
+ console.log(import_picocolors7.default.dim(" volta --version"));
3410
+ console.log(import_picocolors7.default.dim(" node --version"));
3411
+ console.log(import_picocolors7.default.dim(" nimbus --version"));
3962
3412
  console.log();
3963
- Se(import_picocolors8.default.green("Pronto! Volta configurado."));
3413
+ Se(import_picocolors7.default.green("Pronto! Volta configurado."));
3964
3414
  }
3965
3415
 
3966
3416
  // src/index.ts
3967
3417
  var PACKAGE_NAME2 = "@nimbuslab/cli";
3968
- var CURRENT_VERSION = "1.1.0";
3418
+ var CURRENT_VERSION = "1.2.1";
3969
3419
  var LOGO = `
3970
3420
  \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
3971
3421
  \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
@@ -3997,22 +3447,22 @@ function showUpdateNotice(latestVersion) {
3997
3447
  const current = CURRENT_VERSION;
3998
3448
  const latest = latestVersion;
3999
3449
  const command = "nimbus update";
4000
- const line1 = ` Nova vers\xE3o dispon\xEDvel: ${current} \u2192 ${latest}`;
3450
+ const line1 = ` New version available: ${current} \u2192 ${latest}`;
4001
3451
  const line2 = ` Atualize com: ${command}`;
4002
3452
  const maxLen = Math.max(line1.length, line2.length);
4003
3453
  const border = "\u2500".repeat(maxLen + 2);
4004
- console.log(import_picocolors9.default.yellow(` \u250C${border}\u2510`));
4005
- console.log(import_picocolors9.default.yellow(` \u2502`) + import_picocolors9.default.white(line1.padEnd(maxLen + 2)) + import_picocolors9.default.yellow(`\u2502`));
4006
- console.log(import_picocolors9.default.yellow(` \u2502`) + import_picocolors9.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors9.default.yellow(`\u2502`));
4007
- console.log(import_picocolors9.default.yellow(` \u2514${border}\u2518`));
3454
+ console.log(import_picocolors8.default.yellow(` \u250C${border}\u2510`));
3455
+ console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.white(line1.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3456
+ console.log(import_picocolors8.default.yellow(` \u2502`) + import_picocolors8.default.cyan(line2.padEnd(maxLen + 2)) + import_picocolors8.default.yellow(`\u2502`));
3457
+ console.log(import_picocolors8.default.yellow(` \u2514${border}\u2518`));
4008
3458
  console.log();
4009
3459
  }
4010
3460
  async function main() {
4011
3461
  const args = process.argv.slice(2);
4012
3462
  const command = args[0];
4013
- console.log(import_picocolors9.default.cyan(LOGO));
4014
- console.log(import_picocolors9.default.white(" nimbuslab CLI"));
4015
- console.log(import_picocolors9.default.dim(" Create awesome projects"));
3463
+ console.log(import_picocolors8.default.cyan(LOGO));
3464
+ console.log(import_picocolors8.default.white(" nimbuslab CLI"));
3465
+ console.log(import_picocolors8.default.dim(" Create awesome projects"));
4016
3466
  console.log();
4017
3467
  const latestVersion = await checkForUpdates();
4018
3468
  if (latestVersion) {
@@ -4031,8 +3481,8 @@ async function main() {
4031
3481
  if (subcommand === "node") {
4032
3482
  await setupNode(args.slice(2));
4033
3483
  } else {
4034
- console.log(import_picocolors9.default.red(`Subcomando desconhecido: ${subcommand || "(vazio)"}`));
4035
- console.log(import_picocolors9.default.dim(" Uso: nimbus setup node"));
3484
+ console.log(import_picocolors8.default.red(`Subcomando desconhecido: ${subcommand || "(vazio)"}`));
3485
+ console.log(import_picocolors8.default.dim(" Uso: nimbus setup node"));
4036
3486
  process.exit(1);
4037
3487
  }
4038
3488
  } else if (command === "help" || command === "--help" || command === "-h") {
@@ -4040,71 +3490,65 @@ async function main() {
4040
3490
  } else if (command === "version" || command === "--version" || command === "-v") {
4041
3491
  showVersion();
4042
3492
  } else {
4043
- console.log(import_picocolors9.default.red(`Comando desconhecido: ${command}`));
3493
+ console.log(import_picocolors8.default.red(`Comando desconhecido: ${command}`));
4044
3494
  showHelp();
4045
3495
  process.exit(1);
4046
3496
  }
4047
3497
  }
4048
3498
  function showHelp() {
4049
3499
  console.log(`
4050
- ${import_picocolors9.default.bold("Uso:")} nimbus [comando] [op\xE7\xF5es]
3500
+ ${import_picocolors8.default.bold("Usage:")} nimbus [command] [options]
4051
3501
 
4052
- ${import_picocolors9.default.bold("Comandos:")}
3502
+ ${import_picocolors8.default.bold("Comandos:")}
4053
3503
  create [nome] Criar novo projeto
4054
3504
  analyze [dir] Analisar stack do projeto
4055
- upgrade [alvo] Atualizar depend\xEAncias
4056
- update [vers\xE3o] Atualizar o CLI
3505
+ upgrade [target] Update dependencies
3506
+ update [version] Update CLI itself
4057
3507
  setup [alvo] Configurar ambiente
4058
- lola [a\xE7\xE3o] Lola - Code Agent
4059
3508
  help Mostrar esta ajuda
4060
- version Mostrar vers\xE3o
3509
+ version Show version
4061
3510
 
4062
- ${import_picocolors9.default.bold("Templates:")}
3511
+ ${import_picocolors8.default.bold("Templates:")}
4063
3512
  --landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
4064
3513
  --app Web app (Landing + Better Auth + Drizzle)
4065
3514
  --turborepo Monorepo (Turborepo + apps/packages)
4066
3515
 
4067
- ${import_picocolors9.default.bold("Analyze & Upgrade:")}
4068
- analyze . Detectar stack e mostrar recomenda\xE7\xF5es
3516
+ ${import_picocolors8.default.bold("Analyze & Upgrade:")}
3517
+ analyze . Detect stack and show recommendations
4069
3518
  analyze --json Output em JSON
4070
3519
  upgrade --plan Mostrar plano de upgrade
4071
3520
  upgrade next Atualizar Next.js
4072
3521
  upgrade tailwind Atualizar Tailwind CSS
4073
3522
 
4074
- ${import_picocolors9.default.bold("Update (CLI):")}
3523
+ ${import_picocolors8.default.bold("Update (CLI):")}
4075
3524
  update Atualizar para ultima versao
4076
3525
  update 0.11.0 Instalar versao especifica
4077
3526
  update --list Listar versoes disponiveis
4078
3527
  update --force Forcar reinstalacao (limpa cache)
4079
3528
 
4080
- ${import_picocolors9.default.bold("Setup (Ambiente):")}
3529
+ ${import_picocolors8.default.bold("Setup (Ambiente):")}
4081
3530
  setup node Migrar para Volta (remove fnm/nvm)
4082
3531
  setup node --check Verificar ambiente atual
4083
3532
 
4084
- ${import_picocolors9.default.bold("Op\xE7\xF5es:")}
4085
- -y, --yes Aceitar padr\xF5es
4086
- --no-git N\xE3o inicializar Git
4087
- --no-install N\xE3o instalar depend\xEAncias
3533
+ ${import_picocolors8.default.bold("Options:")}
3534
+ -y, --yes Accept defaults
3535
+ --no-git Skip Git initialization
3536
+ --no-install Skip dependency installation
4088
3537
  --template <url> Usar template customizado
4089
3538
 
4090
- ${import_picocolors9.default.bold("Lola (Code Agent):")}
4091
- lola install Instalar/atualizar Lola
4092
- lola suggest Sugerir melhoria (cria issue)
4093
-
4094
- ${import_picocolors9.default.bold("Exemplos:")}
4095
- ${import_picocolors9.default.dim("$")} nimbus create my-landing --landing
4096
- ${import_picocolors9.default.dim("$")} nimbus create my-app --app
4097
- ${import_picocolors9.default.dim("$")} nimbus analyze ./my-project
4098
- ${import_picocolors9.default.dim("$")} nimbus upgrade --plan
4099
- ${import_picocolors9.default.dim("$")} nimbus update
4100
- ${import_picocolors9.default.dim("$")} nimbus setup node
4101
- ${import_picocolors9.default.dim("$")} nimbus lola install
3539
+ ${import_picocolors8.default.bold("Exemplos:")}
3540
+ ${import_picocolors8.default.dim("$")} nimbus create my-landing --landing
3541
+ ${import_picocolors8.default.dim("$")} nimbus create my-app --app
3542
+ ${import_picocolors8.default.dim("$")} nimbus analyze ./my-project
3543
+ ${import_picocolors8.default.dim("$")} nimbus upgrade --plan
3544
+ ${import_picocolors8.default.dim("$")} nimbus update
3545
+ ${import_picocolors8.default.dim("$")} nimbus setup node
4102
3546
  `);
4103
3547
  }
4104
3548
  function showVersion() {
4105
3549
  console.log(`${PACKAGE_NAME2} v${CURRENT_VERSION}`);
4106
3550
  }
4107
3551
  main().catch((err) => {
4108
- console.error(import_picocolors9.default.red("Erro:"), err.message);
3552
+ console.error(import_picocolors8.default.red("Erro:"), err.message);
4109
3553
  process.exit(1);
4110
3554
  });