@nimbuslab/cli 0.2.2 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,12 +5,11 @@ CLI oficial da nimbuslab para criar projetos fast e fast+.
5
5
  ## Instalacao
6
6
 
7
7
  ```bash
8
- # Via npm/bun global
8
+ # Via bun (recomendado)
9
9
  bun add -g @nimbuslab/cli
10
- npm install -g @nimbuslab/cli
11
10
 
12
- # Via GitHub Packages
13
- npm install -g @nimbuslab/cli --registry=https://npm.pkg.github.com
11
+ # Via npm
12
+ npm install -g @nimbuslab/cli
14
13
  ```
15
14
 
16
15
  ## Uso
package/dist/index.js CHANGED
@@ -526,6 +526,41 @@ 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
+ };
529
564
  var OD = Object.defineProperty;
530
565
  var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
531
566
  var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
@@ -697,6 +732,47 @@ ${import_picocolors2.default.cyan(d2)}
697
732
  }
698
733
  } }).prompt();
699
734
  };
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
+ };
700
776
  var xe = (t = "") => {
701
777
  process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
702
778
 
@@ -734,7 +810,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
734
810
  }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
735
811
  const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
736
812
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
737
- }, H = (m2 = "") => {
813
+ }, H2 = (m2 = "") => {
738
814
  a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
739
815
  `);
740
816
  let h2 = 0, w2 = 0;
@@ -760,7 +836,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
760
836
  `) : process.stdout.write(`${w2} ${l2}
761
837
  `), E(), s();
762
838
  };
763
- return { start: H, stop: N2, message: (m2 = "") => {
839
+ return { start: H2, stop: N2, message: (m2 = "") => {
764
840
  l2 = R2(m2 ?? l2);
765
841
  } };
766
842
  };
@@ -986,12 +1062,6 @@ async function promptConfig(initialName) {
986
1062
  return contract;
987
1063
  contractNumber = contract;
988
1064
  }
989
- const configureInfra = await ye({
990
- message: "Configurar infra agora? (Resend, URLs)",
991
- initialValue: true
992
- });
993
- if (pD(configureInfra))
994
- return configureInfra;
995
1065
  let resendApiKey = "";
996
1066
  let resendFromEmail = "";
997
1067
  let contactEmail = "";
@@ -999,11 +1069,43 @@ async function promptConfig(initialName) {
999
1069
  let railwayToken = "";
1000
1070
  let stagingUrl = "";
1001
1071
  let productionUrl = "";
1002
- if (configureInfra) {
1003
- const currentYear = new Date().getFullYear().toString().slice(-2);
1004
- const defaultStagingUrl = type === "fast" ? `https://fast-${contractNumber}-${currentYear}.nimbuslab.net.br` : `https://${name}.nimbuslab.net.br`;
1005
- const defaultFromEmail = "no-reply@nimbuslab.com.br";
1006
- const defaultContactEmail = type === "fast" ? "fast@nimbuslab.com.br" : "suporte@nimbuslab.com.br";
1072
+ const currentYear = new Date().getFullYear().toString().slice(-3);
1073
+ const defaultStagingUrl = type === "fast" ? `https://fast-${contractNumber}-${currentYear}.nimbuslab.net.br` : `https://${name}.nimbuslab.net.br`;
1074
+ const defaultFromEmail = "no-reply@nimbuslab.com.br";
1075
+ const defaultContactEmail = type === "fast" ? "fast@nimbuslab.com.br" : "suporte@nimbuslab.com.br";
1076
+ const infraOptions = await fe({
1077
+ message: "O que deseja configurar agora?",
1078
+ options: [
1079
+ { value: "urls", label: "URLs", hint: "staging e producao" },
1080
+ { value: "resend", label: "Resend", hint: "emails do formulario" },
1081
+ { value: "railway", label: "Railway", hint: "deploy e hospedagem" }
1082
+ ],
1083
+ required: false
1084
+ });
1085
+ if (pD(infraOptions))
1086
+ return infraOptions;
1087
+ const configItems = infraOptions;
1088
+ if (configItems.includes("urls")) {
1089
+ console.log();
1090
+ console.log(import_picocolors3.default.dim(" URLs do projeto"));
1091
+ const staging = await he({
1092
+ message: "URL de staging:",
1093
+ placeholder: defaultStagingUrl,
1094
+ initialValue: defaultStagingUrl
1095
+ });
1096
+ if (pD(staging))
1097
+ return staging;
1098
+ stagingUrl = staging;
1099
+ const production = await he({
1100
+ message: "URL de producao:",
1101
+ placeholder: defaultStagingUrl.replace(".nimbuslab.net.br", ".com.br"),
1102
+ initialValue: ""
1103
+ });
1104
+ if (pD(production))
1105
+ return production;
1106
+ productionUrl = production;
1107
+ }
1108
+ if (configItems.includes("resend")) {
1007
1109
  console.log();
1008
1110
  console.log(import_picocolors3.default.dim(" Resend (Email)"));
1009
1111
  const resendKey = await he({
@@ -1029,24 +1131,8 @@ async function promptConfig(initialName) {
1029
1131
  if (pD(contact))
1030
1132
  return contact;
1031
1133
  contactEmail = contact;
1032
- console.log();
1033
- console.log(import_picocolors3.default.dim(" URLs do projeto"));
1034
- const staging = await he({
1035
- message: "URL de staging:",
1036
- placeholder: defaultStagingUrl,
1037
- initialValue: defaultStagingUrl
1038
- });
1039
- if (pD(staging))
1040
- return staging;
1041
- stagingUrl = staging;
1042
- const production = await he({
1043
- message: "URL de producao:",
1044
- placeholder: defaultStagingUrl.replace(".nimbuslab.net.br", ".com.br"),
1045
- initialValue: ""
1046
- });
1047
- if (pD(production))
1048
- return production;
1049
- productionUrl = production;
1134
+ }
1135
+ if (configItems.includes("railway")) {
1050
1136
  const railwayAuthenticated = await isRailwayAuthenticated();
1051
1137
  if (railwayAuthenticated) {
1052
1138
  console.log();
@@ -1064,7 +1150,7 @@ async function promptConfig(initialName) {
1064
1150
  } else {
1065
1151
  const projectOptions = [
1066
1152
  ...projects.map((proj) => ({ value: proj, label: proj })),
1067
- { value: "__new__", label: "Criar novo projeto", hint: "Abrir railway.app/new" },
1153
+ { value: "__new__", label: "Criar novo projeto", hint: "via railway init" },
1068
1154
  { value: "__skip__", label: "Pular", hint: "Configurar depois" }
1069
1155
  ];
1070
1156
  const selectedProject = await ve({
@@ -1074,8 +1160,18 @@ async function promptConfig(initialName) {
1074
1160
  if (pD(selectedProject))
1075
1161
  return selectedProject;
1076
1162
  if (selectedProject === "__new__") {
1077
- console.log(import_picocolors3.default.yellow(" Crie o projeto em: https://railway.app/new"));
1078
- console.log(import_picocolors3.default.dim(" Configure RAILWAY_TOKEN depois no .env"));
1163
+ const projectNameForRailway = name;
1164
+ console.log(import_picocolors3.default.dim(` Criando projeto "${projectNameForRailway}" no Railway...`));
1165
+ try {
1166
+ const result = await $2`railway init -n ${projectNameForRailway} --json`.text();
1167
+ const newProject = JSON.parse(result);
1168
+ railwayProject = newProject.name || projectNameForRailway;
1169
+ console.log(import_picocolors3.default.green(` Projeto "${railwayProject}" criado com sucesso!`));
1170
+ console.log(import_picocolors3.default.dim(` ID: ${newProject.id || "N/A"}`));
1171
+ } catch (error) {
1172
+ console.log(import_picocolors3.default.yellow(" Erro ao criar projeto via CLI."));
1173
+ console.log(import_picocolors3.default.dim(" Crie manualmente em: https://railway.app/new"));
1174
+ }
1079
1175
  } else if (selectedProject !== "__skip__") {
1080
1176
  railwayProject = selectedProject;
1081
1177
  console.log(import_picocolors3.default.green(` Projeto selecionado: ${railwayProject}`));
@@ -1170,6 +1266,16 @@ async function createProject(config) {
1170
1266
  }
1171
1267
  }
1172
1268
  }
1269
+ if (config.railwayProject) {
1270
+ s.start(`Linkando Railway: ${config.railwayProject}...`);
1271
+ try {
1272
+ await $2`railway link -p ${config.railwayProject}`.cwd(config.name).quiet();
1273
+ s.stop(`Railway linkado: ${config.railwayProject}`);
1274
+ } catch (error) {
1275
+ s.stop("Erro ao linkar Railway");
1276
+ console.log(import_picocolors3.default.dim(" Execute manualmente: railway link"));
1277
+ }
1278
+ }
1173
1279
  if (config.resendApiKey || config.stagingUrl) {
1174
1280
  s.start("Gerando arquivo .env...");
1175
1281
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nimbuslab/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.6",
4
4
  "description": "CLI para criar projetos nimbuslab",
5
5
  "type": "module",
6
6
  "bin": {
@@ -281,14 +281,7 @@ async function promptConfig(initialName?: string): Promise<ProjectConfig | symbo
281
281
  contractNumber = contract as string
282
282
  }
283
283
 
284
- // M21-M23: Configuracoes de infra (opcional)
285
- const configureInfra = await p.confirm({
286
- message: "Configurar infra agora? (Resend, URLs)",
287
- initialValue: true,
288
- })
289
-
290
- if (p.isCancel(configureInfra)) return configureInfra
291
-
284
+ // Configuracoes de infra (separadas)
292
285
  let resendApiKey = ""
293
286
  let resendFromEmail = ""
294
287
  let contactEmail = ""
@@ -297,26 +290,56 @@ async function promptConfig(initialName?: string): Promise<ProjectConfig | symbo
297
290
  let stagingUrl = ""
298
291
  let productionUrl = ""
299
292
 
300
- if (configureInfra) {
301
- const currentYear = new Date().getFullYear().toString().slice(-2) // 25, 26, etc
302
-
303
- // M26: URLs padrão baseadas no tipo
304
- // fast: fast-{contrato}-{ano}.nimbuslab.net.br
305
- // fast+: {nome}.nimbuslab.net.br
306
- const defaultStagingUrl = type === "fast"
307
- ? `https://fast-${contractNumber}-${currentYear}.nimbuslab.net.br`
308
- : `https://${name}.nimbuslab.net.br`
309
-
310
- // M27: Emails padrão
311
- // from: no-reply@nimbuslab.com.br
312
- // to fast: fast@nimbuslab.com.br
313
- // to fast+: suporte@nimbuslab.com.br
314
- const defaultFromEmail = "no-reply@nimbuslab.com.br"
315
- const defaultContactEmail = type === "fast"
316
- ? "fast@nimbuslab.com.br"
317
- : "suporte@nimbuslab.com.br"
318
-
319
- // M27: Resend config
293
+ const currentYear = new Date().getFullYear().toString().slice(-3) // 025, 026, etc
294
+
295
+ // Defaults
296
+ const defaultStagingUrl = type === "fast"
297
+ ? `https://fast-${contractNumber}-${currentYear}.nimbuslab.net.br`
298
+ : `https://${name}.nimbuslab.net.br`
299
+ const defaultFromEmail = "no-reply@nimbuslab.com.br"
300
+ const defaultContactEmail = type === "fast"
301
+ ? "fast@nimbuslab.com.br"
302
+ : "suporte@nimbuslab.com.br"
303
+
304
+ // Menu de configuracoes opcionais
305
+ const infraOptions = await p.multiselect({
306
+ message: "O que deseja configurar agora?",
307
+ options: [
308
+ { value: "urls", label: "URLs", hint: "staging e producao" },
309
+ { value: "resend", label: "Resend", hint: "emails do formulario" },
310
+ { value: "railway", label: "Railway", hint: "deploy e hospedagem" },
311
+ ],
312
+ required: false,
313
+ })
314
+
315
+ if (p.isCancel(infraOptions)) return infraOptions
316
+
317
+ const configItems = infraOptions as string[]
318
+
319
+ // URLs
320
+ if (configItems.includes("urls")) {
321
+ console.log()
322
+ console.log(pc.dim(" URLs do projeto"))
323
+
324
+ const staging = await p.text({
325
+ message: "URL de staging:",
326
+ placeholder: defaultStagingUrl,
327
+ initialValue: defaultStagingUrl,
328
+ })
329
+ if (p.isCancel(staging)) return staging
330
+ stagingUrl = staging as string
331
+
332
+ const production = await p.text({
333
+ message: "URL de producao:",
334
+ placeholder: defaultStagingUrl.replace('.nimbuslab.net.br', '.com.br'),
335
+ initialValue: "",
336
+ })
337
+ if (p.isCancel(production)) return production
338
+ productionUrl = production as string
339
+ }
340
+
341
+ // Resend
342
+ if (configItems.includes("resend")) {
320
343
  console.log()
321
344
  console.log(pc.dim(" Resend (Email)"))
322
345
 
@@ -342,27 +365,10 @@ async function promptConfig(initialName?: string): Promise<ProjectConfig | symbo
342
365
  })
343
366
  if (p.isCancel(contact)) return contact
344
367
  contactEmail = contact as string
368
+ }
345
369
 
346
- // M26: URLs
347
- console.log()
348
- console.log(pc.dim(" URLs do projeto"))
349
-
350
- const staging = await p.text({
351
- message: "URL de staging:",
352
- placeholder: defaultStagingUrl,
353
- initialValue: defaultStagingUrl,
354
- })
355
- if (p.isCancel(staging)) return staging
356
- stagingUrl = staging as string
357
-
358
- const production = await p.text({
359
- message: "URL de producao:",
360
- placeholder: defaultStagingUrl.replace('.nimbuslab.net.br', '.com.br'),
361
- initialValue: "",
362
- })
363
- if (p.isCancel(production)) return production
364
- productionUrl = production as string
365
-
370
+ // Railway
371
+ if (configItems.includes("railway")) {
366
372
  // M30: Railway via CLI
367
373
  const railwayAuthenticated = await isRailwayAuthenticated()
368
374
 
@@ -386,7 +392,7 @@ async function promptConfig(initialName?: string): Promise<ProjectConfig | symbo
386
392
  // Fast+ pode escolher projeto existente ou criar novo
387
393
  const projectOptions = [
388
394
  ...projects.map(proj => ({ value: proj, label: proj })),
389
- { value: "__new__", label: "Criar novo projeto", hint: "Abrir railway.app/new" },
395
+ { value: "__new__", label: "Criar novo projeto", hint: "via railway init" },
390
396
  { value: "__skip__", label: "Pular", hint: "Configurar depois" },
391
397
  ]
392
398
 
@@ -398,8 +404,19 @@ async function promptConfig(initialName?: string): Promise<ProjectConfig | symbo
398
404
  if (p.isCancel(selectedProject)) return selectedProject
399
405
 
400
406
  if (selectedProject === "__new__") {
401
- console.log(pc.yellow(" Crie o projeto em: https://railway.app/new"))
402
- console.log(pc.dim(" Configure RAILWAY_TOKEN depois no .env"))
407
+ // Criar projeto via Railway CLI
408
+ const projectNameForRailway = name as string
409
+ console.log(pc.dim(` Criando projeto "${projectNameForRailway}" no Railway...`))
410
+ try {
411
+ const result = await $`railway init -n ${projectNameForRailway} --json`.text()
412
+ const newProject = JSON.parse(result)
413
+ railwayProject = newProject.name || projectNameForRailway
414
+ console.log(pc.green(` Projeto "${railwayProject}" criado com sucesso!`))
415
+ console.log(pc.dim(` ID: ${newProject.id || "N/A"}`))
416
+ } catch (error) {
417
+ console.log(pc.yellow(" Erro ao criar projeto via CLI."))
418
+ console.log(pc.dim(" Crie manualmente em: https://railway.app/new"))
419
+ }
403
420
  } else if (selectedProject !== "__skip__") {
404
421
  railwayProject = selectedProject as string
405
422
  console.log(pc.green(` Projeto selecionado: ${railwayProject}`))
@@ -523,6 +540,18 @@ async function createProject(config: ProjectConfig) {
523
540
  }
524
541
  }
525
542
 
543
+ // Railway link (se projeto foi selecionado/criado)
544
+ if (config.railwayProject) {
545
+ s.start(`Linkando Railway: ${config.railwayProject}...`)
546
+ try {
547
+ await $`railway link -p ${config.railwayProject}`.cwd(config.name).quiet()
548
+ s.stop(`Railway linkado: ${config.railwayProject}`)
549
+ } catch (error) {
550
+ s.stop("Erro ao linkar Railway")
551
+ console.log(pc.dim(" Execute manualmente: railway link"))
552
+ }
553
+ }
554
+
526
555
  // M23: Gerar .env se configs foram fornecidas
527
556
  if (config.resendApiKey || config.stagingUrl) {
528
557
  s.start("Gerando arquivo .env...")