@nimbuslab/cli 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +236 -37
- package/package.json +1 -1
- package/src/commands/create.ts +279 -27
package/dist/index.js
CHANGED
|
@@ -764,27 +764,16 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
764
764
|
l2 = R2(m2 ?? l2);
|
|
765
765
|
} };
|
|
766
766
|
};
|
|
767
|
-
var Ce = async (t, n) => {
|
|
768
|
-
const r2 = {}, i = Object.keys(t);
|
|
769
|
-
for (const s of i) {
|
|
770
|
-
const c = t[s], a = await c({ results: r2 })?.catch((l2) => {
|
|
771
|
-
throw l2;
|
|
772
|
-
});
|
|
773
|
-
if (typeof n?.onCancel == "function" && pD(a)) {
|
|
774
|
-
r2[s] = "canceled", n.onCancel({ results: r2 });
|
|
775
|
-
continue;
|
|
776
|
-
}
|
|
777
|
-
r2[s] = a;
|
|
778
|
-
}
|
|
779
|
-
return r2;
|
|
780
|
-
};
|
|
781
767
|
|
|
782
768
|
// src/commands/create.ts
|
|
783
769
|
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
784
770
|
var {$: $2 } = globalThis.Bun;
|
|
785
771
|
import { rm } from "fs/promises";
|
|
786
772
|
import { join } from "path";
|
|
787
|
-
var
|
|
773
|
+
var TEMPLATES = {
|
|
774
|
+
fast: "nimbuslab-templates/fast-template",
|
|
775
|
+
"fast+": "nimbuslab-templates/fastplus-template"
|
|
776
|
+
};
|
|
788
777
|
async function create(args) {
|
|
789
778
|
const checkCmd = process.platform === "win32" ? "where" : "which";
|
|
790
779
|
const hasBun = await $2`${checkCmd} bun`.quiet().then(() => true).catch(() => false);
|
|
@@ -834,11 +823,22 @@ async function create(args) {
|
|
|
834
823
|
name: projectName,
|
|
835
824
|
type: "fast",
|
|
836
825
|
git: true,
|
|
837
|
-
install: true
|
|
826
|
+
install: true,
|
|
827
|
+
github: false,
|
|
828
|
+
githubOrg: null,
|
|
829
|
+
githubDescription: "",
|
|
830
|
+
resendApiKey: "",
|
|
831
|
+
resendFromEmail: "",
|
|
832
|
+
contactEmail: "",
|
|
833
|
+
railwayToken: "",
|
|
834
|
+
stagingUrl: "",
|
|
835
|
+
productionUrl: ""
|
|
838
836
|
};
|
|
839
837
|
console.log(import_picocolors3.default.dim(` Projeto: ${projectName}`));
|
|
840
838
|
console.log(import_picocolors3.default.dim(` Tipo: fast`));
|
|
841
839
|
console.log(import_picocolors3.default.dim(` Git: sim`));
|
|
840
|
+
console.log(import_picocolors3.default.dim(` GitHub: nao`));
|
|
841
|
+
console.log(import_picocolors3.default.dim(` Infra: configurar depois com 'bun setup'`));
|
|
842
842
|
console.log(import_picocolors3.default.dim(` Instalar: sim`));
|
|
843
843
|
console.log();
|
|
844
844
|
} else {
|
|
@@ -885,35 +885,152 @@ async function promptConfig(initialName) {
|
|
|
885
885
|
});
|
|
886
886
|
if (pD(type))
|
|
887
887
|
return type;
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
888
|
+
const git = await ye({
|
|
889
|
+
message: "Inicializar repositorio Git?",
|
|
890
|
+
initialValue: true
|
|
891
|
+
});
|
|
892
|
+
if (pD(git))
|
|
893
|
+
return git;
|
|
894
|
+
let github = false;
|
|
895
|
+
let githubOrg = null;
|
|
896
|
+
let githubDescription = "";
|
|
897
|
+
if (git) {
|
|
898
|
+
const createGithub = await ye({
|
|
899
|
+
message: "Criar repositorio no GitHub?",
|
|
900
|
+
initialValue: false
|
|
901
|
+
});
|
|
902
|
+
if (pD(createGithub))
|
|
903
|
+
return createGithub;
|
|
904
|
+
github = createGithub;
|
|
905
|
+
if (github) {
|
|
906
|
+
const org = await ve({
|
|
907
|
+
message: "Organizacao GitHub:",
|
|
908
|
+
options: [
|
|
909
|
+
{ value: "nimbuslab", label: "nimbuslab", hint: "Org principal" },
|
|
910
|
+
{ value: "fast-by-nimbuslab", label: "fast-by-nimbuslab", hint: "Projetos de clientes" },
|
|
911
|
+
{ value: "nimbuslab-templates", label: "nimbuslab-templates", hint: "Templates" },
|
|
912
|
+
{ value: null, label: "Pessoal", hint: "Sem organizacao" }
|
|
913
|
+
]
|
|
914
|
+
});
|
|
915
|
+
if (pD(org))
|
|
916
|
+
return org;
|
|
917
|
+
githubOrg = org;
|
|
918
|
+
const description = await he({
|
|
919
|
+
message: "Descricao do repositorio:",
|
|
920
|
+
placeholder: "Landing page para cliente X",
|
|
921
|
+
initialValue: type === "fast" ? "Landing page fast by nimbuslab" : "SaaS fast+ by nimbuslab"
|
|
922
|
+
});
|
|
923
|
+
if (pD(description))
|
|
924
|
+
return description;
|
|
925
|
+
githubDescription = description;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
const configureInfra = await ye({
|
|
929
|
+
message: "Configurar infra agora? (Resend, URLs)",
|
|
930
|
+
initialValue: true
|
|
931
|
+
});
|
|
932
|
+
if (pD(configureInfra))
|
|
933
|
+
return configureInfra;
|
|
934
|
+
let resendApiKey = "";
|
|
935
|
+
let resendFromEmail = "";
|
|
936
|
+
let contactEmail = "";
|
|
937
|
+
let railwayToken = "";
|
|
938
|
+
let stagingUrl = "";
|
|
939
|
+
let productionUrl = "";
|
|
940
|
+
if (configureInfra) {
|
|
941
|
+
const suggestedDomain = `${name}.com.br`;
|
|
942
|
+
console.log();
|
|
943
|
+
console.log(import_picocolors3.default.dim(" Resend (Email)"));
|
|
944
|
+
const resendKey = await he({
|
|
945
|
+
message: "RESEND_API_KEY:",
|
|
946
|
+
placeholder: "re_xxxxxxxxxxxx"
|
|
947
|
+
});
|
|
948
|
+
if (pD(resendKey))
|
|
949
|
+
return resendKey;
|
|
950
|
+
resendApiKey = resendKey;
|
|
951
|
+
const fromEmail = await he({
|
|
952
|
+
message: "Email de envio (from):",
|
|
953
|
+
placeholder: `contato@${suggestedDomain}`,
|
|
954
|
+
initialValue: `contato@${suggestedDomain}`
|
|
955
|
+
});
|
|
956
|
+
if (pD(fromEmail))
|
|
957
|
+
return fromEmail;
|
|
958
|
+
resendFromEmail = fromEmail;
|
|
959
|
+
const contact = await he({
|
|
960
|
+
message: "Email de contato (recebe formularios):",
|
|
961
|
+
placeholder: `contato@${suggestedDomain}`,
|
|
962
|
+
initialValue: `contato@${suggestedDomain}`
|
|
963
|
+
});
|
|
964
|
+
if (pD(contact))
|
|
965
|
+
return contact;
|
|
966
|
+
contactEmail = contact;
|
|
967
|
+
console.log();
|
|
968
|
+
console.log(import_picocolors3.default.dim(" URLs do projeto"));
|
|
969
|
+
const staging = await he({
|
|
970
|
+
message: "URL de staging:",
|
|
971
|
+
placeholder: `https://${name}-staging.up.railway.app`,
|
|
972
|
+
initialValue: `https://${name}-staging.up.railway.app`
|
|
973
|
+
});
|
|
974
|
+
if (pD(staging))
|
|
975
|
+
return staging;
|
|
976
|
+
stagingUrl = staging;
|
|
977
|
+
const production = await he({
|
|
978
|
+
message: "URL de producao:",
|
|
979
|
+
placeholder: `https://${suggestedDomain}`,
|
|
980
|
+
initialValue: `https://${suggestedDomain}`
|
|
981
|
+
});
|
|
982
|
+
if (pD(production))
|
|
983
|
+
return production;
|
|
984
|
+
productionUrl = production;
|
|
985
|
+
const configRailway = await ye({
|
|
986
|
+
message: "Configurar Railway token?",
|
|
987
|
+
initialValue: false
|
|
988
|
+
});
|
|
989
|
+
if (pD(configRailway))
|
|
990
|
+
return configRailway;
|
|
991
|
+
if (configRailway) {
|
|
992
|
+
const railwayTk = await he({
|
|
993
|
+
message: "RAILWAY_TOKEN:",
|
|
994
|
+
placeholder: "railway_xxxxxxxxxxxx"
|
|
995
|
+
});
|
|
996
|
+
if (pD(railwayTk))
|
|
997
|
+
return railwayTk;
|
|
998
|
+
railwayToken = railwayTk;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
const install = await ye({
|
|
1002
|
+
message: "Instalar dependencias?",
|
|
1003
|
+
initialValue: true
|
|
897
1004
|
});
|
|
898
|
-
if (pD(
|
|
899
|
-
return
|
|
1005
|
+
if (pD(install))
|
|
1006
|
+
return install;
|
|
900
1007
|
return {
|
|
901
1008
|
name,
|
|
902
1009
|
type,
|
|
903
|
-
git
|
|
904
|
-
install
|
|
1010
|
+
git,
|
|
1011
|
+
install,
|
|
1012
|
+
github,
|
|
1013
|
+
githubOrg,
|
|
1014
|
+
githubDescription,
|
|
1015
|
+
resendApiKey,
|
|
1016
|
+
resendFromEmail,
|
|
1017
|
+
contactEmail,
|
|
1018
|
+
railwayToken,
|
|
1019
|
+
stagingUrl,
|
|
1020
|
+
productionUrl
|
|
905
1021
|
};
|
|
906
1022
|
}
|
|
907
1023
|
async function createProject(config) {
|
|
908
1024
|
const s = Y2();
|
|
909
|
-
|
|
1025
|
+
const templateRepo = TEMPLATES[config.type];
|
|
1026
|
+
s.start(`Clonando template ${config.type}...`);
|
|
910
1027
|
try {
|
|
911
|
-
await $2`gh repo clone ${
|
|
1028
|
+
await $2`gh repo clone ${templateRepo} ${config.name} -- --depth 1`.quiet();
|
|
912
1029
|
await rm(join(config.name, ".git"), { recursive: true, force: true });
|
|
913
|
-
s.stop(
|
|
1030
|
+
s.stop(`Template ${config.type} clonado`);
|
|
914
1031
|
} catch (error) {
|
|
915
1032
|
s.stop("Erro ao clonar template");
|
|
916
|
-
throw new Error(
|
|
1033
|
+
throw new Error(`Falha ao clonar template ${templateRepo}. Verifique se tem acesso ao repositorio.`);
|
|
917
1034
|
}
|
|
918
1035
|
s.start("Configurando projeto...");
|
|
919
1036
|
try {
|
|
@@ -933,13 +1050,40 @@ async function createProject(config) {
|
|
|
933
1050
|
s.start("Inicializando Git...");
|
|
934
1051
|
try {
|
|
935
1052
|
const cwd = config.name;
|
|
936
|
-
await $2`git init`.cwd(cwd).quiet();
|
|
1053
|
+
await $2`git init -b main`.cwd(cwd).quiet();
|
|
937
1054
|
await $2`git add -A`.cwd(cwd).quiet();
|
|
938
1055
|
await $2`git commit -m "chore: setup inicial via nimbus create"`.cwd(cwd).quiet();
|
|
939
|
-
|
|
1056
|
+
await $2`git checkout -b staging`.cwd(cwd).quiet();
|
|
1057
|
+
await $2`git checkout -b develop`.cwd(cwd).quiet();
|
|
1058
|
+
s.stop("Git inicializado (main -> staging -> develop)");
|
|
940
1059
|
} catch (error) {
|
|
941
1060
|
s.stop("Erro ao inicializar Git");
|
|
942
1061
|
}
|
|
1062
|
+
if (config.github) {
|
|
1063
|
+
s.start("Criando repositorio no GitHub...");
|
|
1064
|
+
try {
|
|
1065
|
+
const cwd = config.name;
|
|
1066
|
+
const repoName = config.githubOrg ? `${config.githubOrg}/${config.name}` : config.name;
|
|
1067
|
+
const visibility = config.githubOrg === "fast-by-nimbuslab" ? "--private" : "--public";
|
|
1068
|
+
await $2`gh repo create ${repoName} ${visibility} --description ${config.githubDescription} --source . --remote origin --push`.cwd(cwd).quiet();
|
|
1069
|
+
await $2`git push -u origin staging`.cwd(cwd).quiet();
|
|
1070
|
+
await $2`git push -u origin develop`.cwd(cwd).quiet();
|
|
1071
|
+
s.stop(`GitHub: ${repoName} criado`);
|
|
1072
|
+
} catch (error) {
|
|
1073
|
+
s.stop("Erro ao criar repositorio GitHub");
|
|
1074
|
+
console.log(import_picocolors3.default.dim(" Voce pode criar manualmente com: gh repo create"));
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
if (config.resendApiKey || config.stagingUrl) {
|
|
1079
|
+
s.start("Gerando arquivo .env...");
|
|
1080
|
+
try {
|
|
1081
|
+
const envContent = generateEnvFile(config);
|
|
1082
|
+
await Bun.write(`${config.name}/.env`, envContent);
|
|
1083
|
+
s.stop("Arquivo .env criado");
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
s.stop("Erro ao criar .env");
|
|
1086
|
+
}
|
|
943
1087
|
}
|
|
944
1088
|
if (config.install) {
|
|
945
1089
|
s.start("Instalando dependencias (pode demorar)...");
|
|
@@ -951,6 +1095,42 @@ async function createProject(config) {
|
|
|
951
1095
|
}
|
|
952
1096
|
}
|
|
953
1097
|
}
|
|
1098
|
+
function generateEnvFile(config) {
|
|
1099
|
+
const lines = [
|
|
1100
|
+
"# Gerado automaticamente pelo nimbus-cli",
|
|
1101
|
+
"# Nao commitar este arquivo!",
|
|
1102
|
+
"",
|
|
1103
|
+
"# App",
|
|
1104
|
+
`NODE_ENV=development`,
|
|
1105
|
+
"",
|
|
1106
|
+
"# URLs",
|
|
1107
|
+
`NEXT_PUBLIC_APP_URL=${config.productionUrl || "http://localhost:3000"}`,
|
|
1108
|
+
`STAGING_URL=${config.stagingUrl || ""}`,
|
|
1109
|
+
`PRODUCTION_URL=${config.productionUrl || ""}`,
|
|
1110
|
+
"",
|
|
1111
|
+
"# Resend (Email)",
|
|
1112
|
+
`RESEND_API_KEY=${config.resendApiKey || ""}`,
|
|
1113
|
+
`RESEND_FROM_EMAIL=${config.resendFromEmail || ""}`,
|
|
1114
|
+
`CONTACT_EMAIL=${config.contactEmail || ""}`
|
|
1115
|
+
];
|
|
1116
|
+
if (config.railwayToken) {
|
|
1117
|
+
lines.push("");
|
|
1118
|
+
lines.push("# Railway");
|
|
1119
|
+
lines.push(`RAILWAY_TOKEN=${config.railwayToken}`);
|
|
1120
|
+
}
|
|
1121
|
+
if (config.type === "fast+") {
|
|
1122
|
+
lines.push("");
|
|
1123
|
+
lines.push("# Database (fast+)");
|
|
1124
|
+
lines.push("DATABASE_URL=postgresql://postgres:postgres@localhost:5432/app");
|
|
1125
|
+
lines.push("");
|
|
1126
|
+
lines.push("# Auth (fast+)");
|
|
1127
|
+
lines.push("BETTER_AUTH_SECRET=");
|
|
1128
|
+
lines.push("BETTER_AUTH_URL=http://localhost:3000");
|
|
1129
|
+
}
|
|
1130
|
+
return lines.join(`
|
|
1131
|
+
`) + `
|
|
1132
|
+
`;
|
|
1133
|
+
}
|
|
954
1134
|
function showNextSteps(config) {
|
|
955
1135
|
console.log();
|
|
956
1136
|
console.log(import_picocolors3.default.bold("Proximos passos:"));
|
|
@@ -962,11 +1142,30 @@ function showNextSteps(config) {
|
|
|
962
1142
|
console.log(` ${import_picocolors3.default.cyan("bun")} setup`);
|
|
963
1143
|
console.log(` ${import_picocolors3.default.cyan("bun")} dev`);
|
|
964
1144
|
console.log();
|
|
1145
|
+
if (config.git) {
|
|
1146
|
+
console.log(import_picocolors3.default.dim(" Git flow: main -> staging -> develop (branch atual)"));
|
|
1147
|
+
console.log();
|
|
1148
|
+
if (config.github) {
|
|
1149
|
+
const repoUrl = config.githubOrg ? `https://github.com/${config.githubOrg}/${config.name}` : `https://github.com/${config.name}`;
|
|
1150
|
+
console.log(import_picocolors3.default.green(` GitHub: ${repoUrl}`));
|
|
1151
|
+
console.log();
|
|
1152
|
+
} else {
|
|
1153
|
+
console.log(import_picocolors3.default.yellow(" Dica: Para criar repo GitHub, use 'gh repo create' ou 'bun setup'."));
|
|
1154
|
+
console.log();
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
965
1157
|
if (config.type === "fast+") {
|
|
966
|
-
console.log(import_picocolors3.default.dim(" Dica:
|
|
1158
|
+
console.log(import_picocolors3.default.dim(" Dica: Para fast+, configure DATABASE_URL e BETTER_AUTH_SECRET no .env"));
|
|
1159
|
+
console.log();
|
|
1160
|
+
}
|
|
1161
|
+
if (config.resendApiKey || config.stagingUrl) {
|
|
1162
|
+
console.log(import_picocolors3.default.green(" .env configurado com sucesso!"));
|
|
1163
|
+
console.log();
|
|
1164
|
+
} else {
|
|
1165
|
+
console.log(import_picocolors3.default.yellow(" Dica: Configure .env manualmente ou use 'bun setup'."));
|
|
967
1166
|
console.log();
|
|
968
1167
|
}
|
|
969
|
-
console.log(import_picocolors3.default.dim(" Documentacao: https://github.com/nimbuslab
|
|
1168
|
+
console.log(import_picocolors3.default.dim(" Documentacao: https://github.com/nimbuslab-templates"));
|
|
970
1169
|
console.log();
|
|
971
1170
|
}
|
|
972
1171
|
|
package/package.json
CHANGED
package/src/commands/create.ts
CHANGED
|
@@ -4,13 +4,27 @@ import { $} from "bun"
|
|
|
4
4
|
import { rm } from "node:fs/promises"
|
|
5
5
|
import { join } from "node:path"
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// Templates separados por tipo
|
|
8
|
+
const TEMPLATES = {
|
|
9
|
+
"fast": "nimbuslab-templates/fast-template",
|
|
10
|
+
"fast+": "nimbuslab-templates/fastplus-template",
|
|
11
|
+
}
|
|
8
12
|
|
|
9
13
|
interface ProjectConfig {
|
|
10
14
|
name: string
|
|
11
15
|
type: "fast" | "fast+"
|
|
12
16
|
git: boolean
|
|
13
17
|
install: boolean
|
|
18
|
+
github: boolean
|
|
19
|
+
githubOrg: string | null
|
|
20
|
+
githubDescription: string
|
|
21
|
+
// M21-M23: Configs de infra
|
|
22
|
+
resendApiKey: string
|
|
23
|
+
resendFromEmail: string
|
|
24
|
+
contactEmail: string
|
|
25
|
+
railwayToken: string
|
|
26
|
+
stagingUrl: string
|
|
27
|
+
productionUrl: string
|
|
14
28
|
}
|
|
15
29
|
|
|
16
30
|
export async function create(args: string[]) {
|
|
@@ -68,16 +82,27 @@ export async function create(args: string[]) {
|
|
|
68
82
|
let config: ProjectConfig | symbol
|
|
69
83
|
|
|
70
84
|
if (hasYes && projectName) {
|
|
71
|
-
// Modo automatico com defaults
|
|
85
|
+
// Modo automatico com defaults (sem configs de infra)
|
|
72
86
|
config = {
|
|
73
87
|
name: projectName,
|
|
74
88
|
type: "fast",
|
|
75
89
|
git: true,
|
|
76
90
|
install: true,
|
|
91
|
+
github: false,
|
|
92
|
+
githubOrg: null,
|
|
93
|
+
githubDescription: "",
|
|
94
|
+
resendApiKey: "",
|
|
95
|
+
resendFromEmail: "",
|
|
96
|
+
contactEmail: "",
|
|
97
|
+
railwayToken: "",
|
|
98
|
+
stagingUrl: "",
|
|
99
|
+
productionUrl: "",
|
|
77
100
|
}
|
|
78
101
|
console.log(pc.dim(` Projeto: ${projectName}`))
|
|
79
102
|
console.log(pc.dim(` Tipo: fast`))
|
|
80
103
|
console.log(pc.dim(` Git: sim`))
|
|
104
|
+
console.log(pc.dim(` GitHub: nao`))
|
|
105
|
+
console.log(pc.dim(` Infra: configurar depois com 'bun setup'`))
|
|
81
106
|
console.log(pc.dim(` Instalar: sim`))
|
|
82
107
|
console.log()
|
|
83
108
|
} else {
|
|
@@ -130,41 +155,175 @@ async function promptConfig(initialName?: string): Promise<ProjectConfig | symbo
|
|
|
130
155
|
|
|
131
156
|
if (p.isCancel(type)) return type
|
|
132
157
|
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
158
|
+
const git = await p.confirm({
|
|
159
|
+
message: "Inicializar repositorio Git?",
|
|
160
|
+
initialValue: true,
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
if (p.isCancel(git)) return git
|
|
164
|
+
|
|
165
|
+
// GitHub options (only if git is enabled)
|
|
166
|
+
let github = false
|
|
167
|
+
let githubOrg: string | null = null
|
|
168
|
+
let githubDescription = ""
|
|
169
|
+
|
|
170
|
+
if (git) {
|
|
171
|
+
const createGithub = await p.confirm({
|
|
172
|
+
message: "Criar repositorio no GitHub?",
|
|
173
|
+
initialValue: false,
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
if (p.isCancel(createGithub)) return createGithub
|
|
177
|
+
|
|
178
|
+
github = createGithub as boolean
|
|
179
|
+
|
|
180
|
+
if (github) {
|
|
181
|
+
// M13: Selecao de organizacao GitHub
|
|
182
|
+
const org = await p.select({
|
|
183
|
+
message: "Organizacao GitHub:",
|
|
184
|
+
options: [
|
|
185
|
+
{ value: "nimbuslab", label: "nimbuslab", hint: "Org principal" },
|
|
186
|
+
{ value: "fast-by-nimbuslab", label: "fast-by-nimbuslab", hint: "Projetos de clientes" },
|
|
187
|
+
{ value: "nimbuslab-templates", label: "nimbuslab-templates", hint: "Templates" },
|
|
188
|
+
{ value: null, label: "Pessoal", hint: "Sem organizacao" },
|
|
189
|
+
],
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
if (p.isCancel(org)) return org
|
|
193
|
+
githubOrg = org as string | null
|
|
194
|
+
|
|
195
|
+
// M14: Descricao do repo
|
|
196
|
+
const description = await p.text({
|
|
197
|
+
message: "Descricao do repositorio:",
|
|
198
|
+
placeholder: "Landing page para cliente X",
|
|
199
|
+
initialValue: type === "fast" ? "Landing page fast by nimbuslab" : "SaaS fast+ by nimbuslab",
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
if (p.isCancel(description)) return description
|
|
203
|
+
githubDescription = description as string
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// M21-M23: Configuracoes de infra (opcional)
|
|
208
|
+
const configureInfra = await p.confirm({
|
|
209
|
+
message: "Configurar infra agora? (Resend, URLs)",
|
|
210
|
+
initialValue: true,
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
if (p.isCancel(configureInfra)) return configureInfra
|
|
214
|
+
|
|
215
|
+
let resendApiKey = ""
|
|
216
|
+
let resendFromEmail = ""
|
|
217
|
+
let contactEmail = ""
|
|
218
|
+
let railwayToken = ""
|
|
219
|
+
let stagingUrl = ""
|
|
220
|
+
let productionUrl = ""
|
|
221
|
+
|
|
222
|
+
if (configureInfra) {
|
|
223
|
+
// Extrair dominio do nome para sugestoes
|
|
224
|
+
const suggestedDomain = `${name}.com.br`
|
|
225
|
+
|
|
226
|
+
// M22: Resend config
|
|
227
|
+
console.log()
|
|
228
|
+
console.log(pc.dim(" Resend (Email)"))
|
|
229
|
+
|
|
230
|
+
const resendKey = await p.text({
|
|
231
|
+
message: "RESEND_API_KEY:",
|
|
232
|
+
placeholder: "re_xxxxxxxxxxxx",
|
|
233
|
+
})
|
|
234
|
+
if (p.isCancel(resendKey)) return resendKey
|
|
235
|
+
resendApiKey = resendKey as string
|
|
236
|
+
|
|
237
|
+
const fromEmail = await p.text({
|
|
238
|
+
message: "Email de envio (from):",
|
|
239
|
+
placeholder: `contato@${suggestedDomain}`,
|
|
240
|
+
initialValue: `contato@${suggestedDomain}`,
|
|
241
|
+
})
|
|
242
|
+
if (p.isCancel(fromEmail)) return fromEmail
|
|
243
|
+
resendFromEmail = fromEmail as string
|
|
244
|
+
|
|
245
|
+
const contact = await p.text({
|
|
246
|
+
message: "Email de contato (recebe formularios):",
|
|
247
|
+
placeholder: `contato@${suggestedDomain}`,
|
|
248
|
+
initialValue: `contato@${suggestedDomain}`,
|
|
249
|
+
})
|
|
250
|
+
if (p.isCancel(contact)) return contact
|
|
251
|
+
contactEmail = contact as string
|
|
252
|
+
|
|
253
|
+
// URLs
|
|
254
|
+
console.log()
|
|
255
|
+
console.log(pc.dim(" URLs do projeto"))
|
|
256
|
+
|
|
257
|
+
const staging = await p.text({
|
|
258
|
+
message: "URL de staging:",
|
|
259
|
+
placeholder: `https://${name}-staging.up.railway.app`,
|
|
260
|
+
initialValue: `https://${name}-staging.up.railway.app`,
|
|
261
|
+
})
|
|
262
|
+
if (p.isCancel(staging)) return staging
|
|
263
|
+
stagingUrl = staging as string
|
|
264
|
+
|
|
265
|
+
const production = await p.text({
|
|
266
|
+
message: "URL de producao:",
|
|
267
|
+
placeholder: `https://${suggestedDomain}`,
|
|
268
|
+
initialValue: `https://${suggestedDomain}`,
|
|
269
|
+
})
|
|
270
|
+
if (p.isCancel(production)) return production
|
|
271
|
+
productionUrl = production as string
|
|
272
|
+
|
|
273
|
+
// Railway token (opcional)
|
|
274
|
+
const configRailway = await p.confirm({
|
|
275
|
+
message: "Configurar Railway token?",
|
|
276
|
+
initialValue: false,
|
|
277
|
+
})
|
|
278
|
+
if (p.isCancel(configRailway)) return configRailway
|
|
279
|
+
|
|
280
|
+
if (configRailway) {
|
|
281
|
+
const railwayTk = await p.text({
|
|
282
|
+
message: "RAILWAY_TOKEN:",
|
|
283
|
+
placeholder: "railway_xxxxxxxxxxxx",
|
|
284
|
+
})
|
|
285
|
+
if (p.isCancel(railwayTk)) return railwayTk
|
|
286
|
+
railwayToken = railwayTk as string
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const install = await p.confirm({
|
|
291
|
+
message: "Instalar dependencias?",
|
|
292
|
+
initialValue: true,
|
|
144
293
|
})
|
|
145
294
|
|
|
146
|
-
if (p.isCancel(
|
|
295
|
+
if (p.isCancel(install)) return install
|
|
147
296
|
|
|
148
297
|
return {
|
|
149
298
|
name: name as string,
|
|
150
299
|
type: type as "fast" | "fast+",
|
|
151
|
-
git:
|
|
152
|
-
install:
|
|
300
|
+
git: git as boolean,
|
|
301
|
+
install: install as boolean,
|
|
302
|
+
github,
|
|
303
|
+
githubOrg,
|
|
304
|
+
githubDescription,
|
|
305
|
+
resendApiKey,
|
|
306
|
+
resendFromEmail,
|
|
307
|
+
contactEmail,
|
|
308
|
+
railwayToken,
|
|
309
|
+
stagingUrl,
|
|
310
|
+
productionUrl,
|
|
153
311
|
}
|
|
154
312
|
}
|
|
155
313
|
|
|
156
314
|
async function createProject(config: ProjectConfig) {
|
|
157
315
|
const s = p.spinner()
|
|
158
316
|
|
|
159
|
-
// Clone template
|
|
160
|
-
|
|
317
|
+
// Clone template baseado no tipo (fast ou fast+)
|
|
318
|
+
const templateRepo = TEMPLATES[config.type]
|
|
319
|
+
s.start(`Clonando template ${config.type}...`)
|
|
161
320
|
try {
|
|
162
|
-
await $`gh repo clone ${
|
|
321
|
+
await $`gh repo clone ${templateRepo} ${config.name} -- --depth 1`.quiet()
|
|
163
322
|
await rm(join(config.name, ".git"), { recursive: true, force: true })
|
|
164
|
-
s.stop(
|
|
323
|
+
s.stop(`Template ${config.type} clonado`)
|
|
165
324
|
} catch (error) {
|
|
166
325
|
s.stop("Erro ao clonar template")
|
|
167
|
-
throw new Error(
|
|
326
|
+
throw new Error(`Falha ao clonar template ${templateRepo}. Verifique se tem acesso ao repositorio.`)
|
|
168
327
|
}
|
|
169
328
|
|
|
170
329
|
// Update package.json
|
|
@@ -205,6 +364,42 @@ async function createProject(config: ProjectConfig) {
|
|
|
205
364
|
} catch (error) {
|
|
206
365
|
s.stop("Erro ao inicializar Git")
|
|
207
366
|
}
|
|
367
|
+
|
|
368
|
+
// Create GitHub repo if requested (M13 + M14)
|
|
369
|
+
if (config.github) {
|
|
370
|
+
s.start("Criando repositorio no GitHub...")
|
|
371
|
+
try {
|
|
372
|
+
const cwd = config.name
|
|
373
|
+
const repoName = config.githubOrg
|
|
374
|
+
? `${config.githubOrg}/${config.name}`
|
|
375
|
+
: config.name
|
|
376
|
+
|
|
377
|
+
// Create repo with description (private by default for client projects)
|
|
378
|
+
const visibility = config.githubOrg === "fast-by-nimbuslab" ? "--private" : "--public"
|
|
379
|
+
await $`gh repo create ${repoName} ${visibility} --description ${config.githubDescription} --source . --remote origin --push`.cwd(cwd).quiet()
|
|
380
|
+
|
|
381
|
+
// Push all branches
|
|
382
|
+
await $`git push -u origin staging`.cwd(cwd).quiet()
|
|
383
|
+
await $`git push -u origin develop`.cwd(cwd).quiet()
|
|
384
|
+
|
|
385
|
+
s.stop(`GitHub: ${repoName} criado`)
|
|
386
|
+
} catch (error) {
|
|
387
|
+
s.stop("Erro ao criar repositorio GitHub")
|
|
388
|
+
console.log(pc.dim(" Voce pode criar manualmente com: gh repo create"))
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// M23: Gerar .env se configs foram fornecidas
|
|
394
|
+
if (config.resendApiKey || config.stagingUrl) {
|
|
395
|
+
s.start("Gerando arquivo .env...")
|
|
396
|
+
try {
|
|
397
|
+
const envContent = generateEnvFile(config)
|
|
398
|
+
await Bun.write(`${config.name}/.env`, envContent)
|
|
399
|
+
s.stop("Arquivo .env criado")
|
|
400
|
+
} catch (error) {
|
|
401
|
+
s.stop("Erro ao criar .env")
|
|
402
|
+
}
|
|
208
403
|
}
|
|
209
404
|
|
|
210
405
|
// Install deps
|
|
@@ -219,6 +414,47 @@ async function createProject(config: ProjectConfig) {
|
|
|
219
414
|
}
|
|
220
415
|
}
|
|
221
416
|
|
|
417
|
+
// M23: Gerar conteudo do .env
|
|
418
|
+
function generateEnvFile(config: ProjectConfig): string {
|
|
419
|
+
const lines = [
|
|
420
|
+
"# Gerado automaticamente pelo nimbus-cli",
|
|
421
|
+
"# Nao commitar este arquivo!",
|
|
422
|
+
"",
|
|
423
|
+
"# App",
|
|
424
|
+
`NODE_ENV=development`,
|
|
425
|
+
"",
|
|
426
|
+
"# URLs",
|
|
427
|
+
`NEXT_PUBLIC_APP_URL=${config.productionUrl || "http://localhost:3000"}`,
|
|
428
|
+
`STAGING_URL=${config.stagingUrl || ""}`,
|
|
429
|
+
`PRODUCTION_URL=${config.productionUrl || ""}`,
|
|
430
|
+
"",
|
|
431
|
+
"# Resend (Email)",
|
|
432
|
+
`RESEND_API_KEY=${config.resendApiKey || ""}`,
|
|
433
|
+
`RESEND_FROM_EMAIL=${config.resendFromEmail || ""}`,
|
|
434
|
+
`CONTACT_EMAIL=${config.contactEmail || ""}`,
|
|
435
|
+
]
|
|
436
|
+
|
|
437
|
+
// Railway token (se fornecido)
|
|
438
|
+
if (config.railwayToken) {
|
|
439
|
+
lines.push("")
|
|
440
|
+
lines.push("# Railway")
|
|
441
|
+
lines.push(`RAILWAY_TOKEN=${config.railwayToken}`)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Fast+ specific vars
|
|
445
|
+
if (config.type === "fast+") {
|
|
446
|
+
lines.push("")
|
|
447
|
+
lines.push("# Database (fast+)")
|
|
448
|
+
lines.push("DATABASE_URL=postgresql://postgres:postgres@localhost:5432/app")
|
|
449
|
+
lines.push("")
|
|
450
|
+
lines.push("# Auth (fast+)")
|
|
451
|
+
lines.push("BETTER_AUTH_SECRET=")
|
|
452
|
+
lines.push("BETTER_AUTH_URL=http://localhost:3000")
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return lines.join("\n") + "\n"
|
|
456
|
+
}
|
|
457
|
+
|
|
222
458
|
function showNextSteps(config: ProjectConfig) {
|
|
223
459
|
console.log()
|
|
224
460
|
console.log(pc.bold("Proximos passos:"))
|
|
@@ -237,18 +473,34 @@ function showNextSteps(config: ProjectConfig) {
|
|
|
237
473
|
if (config.git) {
|
|
238
474
|
console.log(pc.dim(" Git flow: main -> staging -> develop (branch atual)"))
|
|
239
475
|
console.log()
|
|
476
|
+
|
|
477
|
+
// GitHub info
|
|
478
|
+
if (config.github) {
|
|
479
|
+
const repoUrl = config.githubOrg
|
|
480
|
+
? `https://github.com/${config.githubOrg}/${config.name}`
|
|
481
|
+
: `https://github.com/${config.name}`
|
|
482
|
+
console.log(pc.green(` GitHub: ${repoUrl}`))
|
|
483
|
+
console.log()
|
|
484
|
+
} else {
|
|
485
|
+
console.log(pc.yellow(" Dica: Para criar repo GitHub, use 'gh repo create' ou 'bun setup'."))
|
|
486
|
+
console.log()
|
|
487
|
+
}
|
|
240
488
|
}
|
|
241
489
|
|
|
242
490
|
if (config.type === "fast+") {
|
|
243
|
-
console.log(pc.dim(" Dica:
|
|
491
|
+
console.log(pc.dim(" Dica: Para fast+, configure DATABASE_URL e BETTER_AUTH_SECRET no .env"))
|
|
244
492
|
console.log()
|
|
245
493
|
}
|
|
246
494
|
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
495
|
+
// Info sobre .env
|
|
496
|
+
if (config.resendApiKey || config.stagingUrl) {
|
|
497
|
+
console.log(pc.green(" .env configurado com sucesso!"))
|
|
498
|
+
console.log()
|
|
499
|
+
} else {
|
|
500
|
+
console.log(pc.yellow(" Dica: Configure .env manualmente ou use 'bun setup'."))
|
|
501
|
+
console.log()
|
|
502
|
+
}
|
|
251
503
|
|
|
252
|
-
console.log(pc.dim(" Documentacao: https://github.com/nimbuslab
|
|
504
|
+
console.log(pc.dim(" Documentacao: https://github.com/nimbuslab-templates"))
|
|
253
505
|
console.log()
|
|
254
506
|
}
|