@perma-tools/cli 0.0.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.
- package/README.md +159 -0
- package/dist/actions.d.ts +12 -0
- package/dist/actions.js +157 -0
- package/dist/cli-parser.d.ts +21 -0
- package/dist/cli-parser.js +141 -0
- package/dist/configs/axios.config.d.ts +2 -0
- package/dist/configs/axios.config.js +12 -0
- package/dist/configs/biome.config.d.ts +2 -0
- package/dist/configs/biome.config.js +12 -0
- package/dist/configs/cookies-next.config.d.ts +2 -0
- package/dist/configs/cookies-next.config.js +6 -0
- package/dist/configs/date-fns.config.d.ts +2 -0
- package/dist/configs/date-fns.config.js +6 -0
- package/dist/configs/eslint-prettier.config.d.ts +2 -0
- package/dist/configs/eslint-prettier.config.js +35 -0
- package/dist/configs/framer-motion.config.d.ts +2 -0
- package/dist/configs/framer-motion.config.js +6 -0
- package/dist/configs/ky.config.d.ts +2 -0
- package/dist/configs/ky.config.js +12 -0
- package/dist/configs/lucide-react.config.d.ts +2 -0
- package/dist/configs/lucide-react.config.js +6 -0
- package/dist/configs/nuqs.config.d.ts +2 -0
- package/dist/configs/nuqs.config.js +12 -0
- package/dist/configs/react-hook-form.config.d.ts +2 -0
- package/dist/configs/react-hook-form.config.js +6 -0
- package/dist/configs/recharts.config.d.ts +2 -0
- package/dist/configs/recharts.config.js +6 -0
- package/dist/configs/tanstack-query.config.d.ts +2 -0
- package/dist/configs/tanstack-query.config.js +19 -0
- package/dist/configs/zod.config.d.ts +2 -0
- package/dist/configs/zod.config.js +6 -0
- package/dist/dependency-versions.d.ts +13 -0
- package/dist/dependency-versions.js +50 -0
- package/dist/git-setup.d.ts +23 -0
- package/dist/git-setup.js +275 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +537 -0
- package/dist/project-generator.d.ts +15 -0
- package/dist/project-generator.js +311 -0
- package/dist/snippet-manager.d.ts +11 -0
- package/dist/snippet-manager.js +76 -0
- package/dist/snippets/axios/index.ts +6 -0
- package/dist/snippets/biome/biome.json +93 -0
- package/dist/snippets/eslint-prettier/eslintignore +6 -0
- package/dist/snippets/eslint-prettier/eslintrc.js +3 -0
- package/dist/snippets/eslint-prettier/prettierignore +9 -0
- package/dist/snippets/eslint-prettier/prettierrc.js +9 -0
- package/dist/snippets/ky/index.ts +5 -0
- package/dist/snippets/react-query/index.tsx +53 -0
- package/dist/snippets/vscode/extensions.json +3 -0
- package/dist/snippets/vscode/settings.json +19 -0
- package/dist/templates/frontend/next15/base/.env.example +3 -0
- package/dist/templates/frontend/next15/base/README.md +50 -0
- package/dist/templates/frontend/next15/base/next.config.ts +7 -0
- package/dist/templates/frontend/next15/base/package.json +23 -0
- package/dist/templates/frontend/next15/base/postcss.config.mjs +8 -0
- package/dist/templates/frontend/next15/base/public/public.md +12 -0
- package/dist/templates/frontend/next15/base/src/@types/@types.md +7 -0
- package/dist/templates/frontend/next15/base/src/@types/types.d.ts +1 -0
- package/dist/templates/frontend/next15/base/src/app/(application)/page.tsx +50 -0
- package/dist/templates/frontend/next15/base/src/app/favicon.ico +0 -0
- package/dist/templates/frontend/next15/base/src/app/layout.tsx +23 -0
- package/dist/templates/frontend/next15/base/src/app/providers.tsx +5 -0
- package/dist/templates/frontend/next15/base/src/components/components.md +9 -0
- package/dist/templates/frontend/next15/base/src/constants/constants.md +10 -0
- package/dist/templates/frontend/next15/base/src/hooks/hooks.md +11 -0
- package/dist/templates/frontend/next15/base/src/lib/lib.md +9 -0
- package/dist/templates/frontend/next15/base/src/services/services.md +14 -0
- package/dist/templates/frontend/next15/base/src/styles/globals.css +1 -0
- package/dist/templates/frontend/next15/base/src/types/types.md +15 -0
- package/dist/templates/frontend/next15/base/src/utils/utils.md +18 -0
- package/dist/templates/frontend/next15/base/tsconfig.json +26 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.js +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const tanstackQueryConfig = {
|
|
2
|
+
name: "tanstack-query",
|
|
3
|
+
dependencies: ["@tanstack/react-query"],
|
|
4
|
+
devDependencies: ["@tanstack/react-query-devtools"],
|
|
5
|
+
actions: [
|
|
6
|
+
{
|
|
7
|
+
type: "copy-file",
|
|
8
|
+
source: "snippets/react-query/index.tsx",
|
|
9
|
+
destination: "src/lib/tanstack-query.tsx",
|
|
10
|
+
priority: 1,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
type: "inject-provider",
|
|
14
|
+
providerImport: `import { QueryClientProvider } from '@/lib/tanstack-query';`,
|
|
15
|
+
providerWrapper: "QueryClientProvider",
|
|
16
|
+
priority: 2,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versões específicas e testadas das dependências
|
|
3
|
+
* Atualizado em: Fevereiro 2026
|
|
4
|
+
*/
|
|
5
|
+
export declare const DEPENDENCY_VERSIONS: Record<string, string>;
|
|
6
|
+
/**
|
|
7
|
+
* Retorna a versão específica de uma dependência ou 'latest' como fallback
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDependencyVersion(packageName: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Retorna múltiplas versões de dependências
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDependencyVersions(packageNames: string[]): Record<string, string>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versões específicas e testadas das dependências
|
|
3
|
+
* Atualizado em: Fevereiro 2026
|
|
4
|
+
*/
|
|
5
|
+
export const DEPENDENCY_VERSIONS = {
|
|
6
|
+
// HTTP Clients
|
|
7
|
+
ky: "^1.7.3",
|
|
8
|
+
axios: "^1.7.9",
|
|
9
|
+
// State Management & Data Fetching
|
|
10
|
+
"@tanstack/react-query": "^5.62.11",
|
|
11
|
+
"@tanstack/react-query-devtools": "^5.62.11",
|
|
12
|
+
nuqs: "^2.2.4",
|
|
13
|
+
// Form & Validation
|
|
14
|
+
zod: "^3.24.1",
|
|
15
|
+
"react-hook-form": "^7.54.2",
|
|
16
|
+
"@hookform/resolvers": "^3.10.0",
|
|
17
|
+
// Utilities
|
|
18
|
+
"date-fns": "^4.1.0",
|
|
19
|
+
"cookies-next": "^4.3.0",
|
|
20
|
+
// UI/UX
|
|
21
|
+
"framer-motion": "^11.15.0",
|
|
22
|
+
"lucide-react": "^0.468.0",
|
|
23
|
+
recharts: "^2.15.0",
|
|
24
|
+
// Linters & Formatters
|
|
25
|
+
"@biomejs/biome": "^1.9.4",
|
|
26
|
+
eslint: "^9",
|
|
27
|
+
"eslint-config-next": "^15.1.4",
|
|
28
|
+
prettier: "^3.4.2",
|
|
29
|
+
"prettier-plugin-tailwindcss": "^0.6.9",
|
|
30
|
+
// shadcn/ui dependencies (instaladas automaticamente pelo shadcn init)
|
|
31
|
+
"class-variance-authority": "^0.7.1",
|
|
32
|
+
clsx: "^2.1.1",
|
|
33
|
+
"tailwind-merge": "^2.6.0",
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Retorna a versão específica de uma dependência ou 'latest' como fallback
|
|
37
|
+
*/
|
|
38
|
+
export function getDependencyVersion(packageName) {
|
|
39
|
+
return DEPENDENCY_VERSIONS[packageName] || "latest";
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Retorna múltiplas versões de dependências
|
|
43
|
+
*/
|
|
44
|
+
export function getDependencyVersions(packageNames) {
|
|
45
|
+
const versions = {};
|
|
46
|
+
for (const packageName of packageNames) {
|
|
47
|
+
versions[packageName] = getDependencyVersion(packageName);
|
|
48
|
+
}
|
|
49
|
+
return versions;
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface GitSetupOptions {
|
|
2
|
+
projectPath: string;
|
|
3
|
+
projectName: string;
|
|
4
|
+
repoName: string;
|
|
5
|
+
repoOrg?: string;
|
|
6
|
+
visibility: "public" | "private";
|
|
7
|
+
withVercel?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class GitSetup {
|
|
10
|
+
private options;
|
|
11
|
+
constructor(options: GitSetupOptions);
|
|
12
|
+
initialize(): Promise<void>;
|
|
13
|
+
createGitHubRepo(): Promise<string>;
|
|
14
|
+
setupVercelDeploy(): Promise<void>;
|
|
15
|
+
private ensureGitignore;
|
|
16
|
+
private getRepoUrl;
|
|
17
|
+
private runCommand;
|
|
18
|
+
private runCommandWithOutput;
|
|
19
|
+
static getGitHubOrganizations(): Promise<string[]>;
|
|
20
|
+
static isGitHubCLIAvailable(): Promise<boolean>;
|
|
21
|
+
static isVercelCLIAvailable(): Promise<boolean>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export class GitSetup {
|
|
5
|
+
options;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
async initialize() {
|
|
10
|
+
console.log("\n🔧 Configurando Git...");
|
|
11
|
+
// 1. Inicializar repositório Git com branch main
|
|
12
|
+
await this.runCommand("git", ["init", "-b", "main"], this.options.projectPath);
|
|
13
|
+
// 2. Criar .gitignore se não existir
|
|
14
|
+
await this.ensureGitignore();
|
|
15
|
+
// 3. Adicionar todos os arquivos
|
|
16
|
+
await this.runCommand("git", ["add", "."], this.options.projectPath);
|
|
17
|
+
// 4. Fazer commit inicial
|
|
18
|
+
await this.runCommand("git", ["commit", "-m", "chore: initial commit from @perma-tools/cli"], this.options.projectPath);
|
|
19
|
+
console.log("✅ Git inicializado!");
|
|
20
|
+
}
|
|
21
|
+
async createGitHubRepo() {
|
|
22
|
+
console.log("\n📦 Criando repositório no GitHub...");
|
|
23
|
+
const visibilityFlag = this.options.visibility === "private" ? "--private" : "--public";
|
|
24
|
+
// Montar nome completo do repo (com org se fornecida)
|
|
25
|
+
const fullRepoName = this.options.repoOrg
|
|
26
|
+
? `${this.options.repoOrg}/${this.options.repoName}`
|
|
27
|
+
: this.options.repoName;
|
|
28
|
+
try {
|
|
29
|
+
await this.runCommand("gh", [
|
|
30
|
+
"repo",
|
|
31
|
+
"create",
|
|
32
|
+
fullRepoName,
|
|
33
|
+
visibilityFlag,
|
|
34
|
+
"--source",
|
|
35
|
+
".",
|
|
36
|
+
"--push",
|
|
37
|
+
], this.options.projectPath);
|
|
38
|
+
console.log("✅ Repositório criado e código enviado!");
|
|
39
|
+
// Aguardar alguns segundos para o GitHub processar o repositório
|
|
40
|
+
console.log("⏳ Aguardando GitHub processar o repositório...");
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, 60000));
|
|
42
|
+
// Obter URL do repositório
|
|
43
|
+
const repoUrl = await this.getRepoUrl();
|
|
44
|
+
return repoUrl;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new Error("Erro ao criar repositório. Certifique-se de que o GitHub CLI (gh) está instalado e autenticado.");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async setupVercelDeploy() {
|
|
51
|
+
console.log("\n🚀 Conectando projeto à Vercel...");
|
|
52
|
+
// Tentar até 5 vezes conectar o repositório com delay de 20 segundos entre tentativas
|
|
53
|
+
let linkSuccess = false;
|
|
54
|
+
for (let i = 0; i < 5; i++) {
|
|
55
|
+
try {
|
|
56
|
+
if (i > 0) {
|
|
57
|
+
console.log(`\n🔄 Tentativa ${i + 1} de 5...`);
|
|
58
|
+
// Deletar pasta .vercel para forçar nova criação/conexão
|
|
59
|
+
const vercelDir = join(this.options.projectPath, ".vercel");
|
|
60
|
+
try {
|
|
61
|
+
await rm(vercelDir, { recursive: true, force: true });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Ignorar se não existir
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Primeiro, fazer o link do repositório com a Vercel
|
|
68
|
+
// Usar runCommandWithOutput para capturar erros no output
|
|
69
|
+
await this.runCommandWithOutput("vercel", ["link", "--yes"], this.options.projectPath);
|
|
70
|
+
console.log("✅ Repositório conectado com sucesso!");
|
|
71
|
+
linkSuccess = true;
|
|
72
|
+
break; // Sucesso! Sair do loop
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (i === 4) {
|
|
76
|
+
// Última tentativa falhou
|
|
77
|
+
console.error("❌ Erro ao conectar repositório com a Vercel após 5 tentativas.");
|
|
78
|
+
console.error("💡 Certifique-se de que o Vercel CLI está instalado e autenticado.");
|
|
79
|
+
console.error("💡 Execute: npm i -g vercel && vercel login");
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
// Aguardar 20 segundos antes da próxima tentativa
|
|
83
|
+
console.log("⏳ Aguardando 20 segundos antes da próxima tentativa...");
|
|
84
|
+
await new Promise((resolve) => setTimeout(resolve, 20000));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Se conseguiu fazer o link, fazer o deploy
|
|
88
|
+
if (linkSuccess) {
|
|
89
|
+
console.log("\n🚀 Fazendo deploy na Vercel...");
|
|
90
|
+
try {
|
|
91
|
+
await this.runCommand("vercel", ["--prod", "--yes"], this.options.projectPath);
|
|
92
|
+
console.log("✅ Deploy realizado com sucesso!");
|
|
93
|
+
console.log("💡 Deploys automáticos estão configurados para cada push no repositório.");
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error("❌ Erro ao fazer deploy na Vercel.");
|
|
97
|
+
console.error("💡 O link foi criado, mas o deploy falhou. Tente: cd " +
|
|
98
|
+
this.options.projectName +
|
|
99
|
+
" && vercel --prod");
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async ensureGitignore() {
|
|
105
|
+
const gitignorePath = join(this.options.projectPath, ".gitignore");
|
|
106
|
+
// Já deve existir do template, mas garantir
|
|
107
|
+
const defaultGitignore = `# dependencies
|
|
108
|
+
node_modules
|
|
109
|
+
.pnp
|
|
110
|
+
.pnp.js
|
|
111
|
+
|
|
112
|
+
# testing
|
|
113
|
+
coverage
|
|
114
|
+
|
|
115
|
+
# next.js
|
|
116
|
+
.next/
|
|
117
|
+
out/
|
|
118
|
+
|
|
119
|
+
# production
|
|
120
|
+
build
|
|
121
|
+
dist
|
|
122
|
+
|
|
123
|
+
# misc
|
|
124
|
+
.DS_Store
|
|
125
|
+
*.pem
|
|
126
|
+
|
|
127
|
+
# debug
|
|
128
|
+
npm-debug.log*
|
|
129
|
+
yarn-debug.log*
|
|
130
|
+
yarn-error.log*
|
|
131
|
+
|
|
132
|
+
# local env files
|
|
133
|
+
.env*.local
|
|
134
|
+
.env
|
|
135
|
+
|
|
136
|
+
# vercel
|
|
137
|
+
.vercel
|
|
138
|
+
|
|
139
|
+
# typescript
|
|
140
|
+
*.tsbuildinfo
|
|
141
|
+
next-env.d.ts
|
|
142
|
+
`;
|
|
143
|
+
try {
|
|
144
|
+
await writeFile(gitignorePath, defaultGitignore, { flag: "wx" });
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Arquivo já existe, tudo bem
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async getRepoUrl() {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
let output = "";
|
|
153
|
+
const child = spawn("git", ["remote", "get-url", "origin"], {
|
|
154
|
+
cwd: this.options.projectPath,
|
|
155
|
+
});
|
|
156
|
+
child.stdout.on("data", (data) => {
|
|
157
|
+
output += data.toString();
|
|
158
|
+
});
|
|
159
|
+
child.on("close", (code) => {
|
|
160
|
+
if (code === 0) {
|
|
161
|
+
resolve(output.trim());
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
reject(new Error("Erro ao obter URL do repositório"));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
child.on("error", (error) => {
|
|
168
|
+
reject(error);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
runCommand(command, args, cwd, options) {
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
const child = spawn(command, args, {
|
|
175
|
+
cwd,
|
|
176
|
+
stdio: "inherit",
|
|
177
|
+
...options,
|
|
178
|
+
});
|
|
179
|
+
child.on("close", (code) => {
|
|
180
|
+
if (code === 0) {
|
|
181
|
+
resolve();
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
reject(new Error(`Comando falhou com código ${code}`));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
child.on("error", (error) => {
|
|
188
|
+
reject(error);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
runCommandWithOutput(command, args, cwd, options) {
|
|
193
|
+
return new Promise((resolve, reject) => {
|
|
194
|
+
let stdout = "";
|
|
195
|
+
let stderr = "";
|
|
196
|
+
const child = spawn(command, args, {
|
|
197
|
+
cwd,
|
|
198
|
+
stdio: "pipe",
|
|
199
|
+
...options,
|
|
200
|
+
});
|
|
201
|
+
child.stdout?.on("data", (data) => {
|
|
202
|
+
const text = data.toString();
|
|
203
|
+
stdout += text;
|
|
204
|
+
process.stdout.write(text); // Mostrar no terminal também
|
|
205
|
+
});
|
|
206
|
+
child.stderr?.on("data", (data) => {
|
|
207
|
+
const text = data.toString();
|
|
208
|
+
stderr += text;
|
|
209
|
+
process.stderr.write(text); // Mostrar no terminal também
|
|
210
|
+
});
|
|
211
|
+
child.on("close", (code) => {
|
|
212
|
+
// Verificar se tem erro no output, independente do exit code
|
|
213
|
+
const output = stdout + stderr;
|
|
214
|
+
if (code !== 0 ||
|
|
215
|
+
output.includes("Error:") ||
|
|
216
|
+
output.includes("Failed to connect")) {
|
|
217
|
+
reject(new Error(`Comando falhou: ${output.substring(output.lastIndexOf("Error:") || 0)}`));
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
resolve({ stdout, stderr });
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
child.on("error", (error) => {
|
|
224
|
+
reject(error);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
static async getGitHubOrganizations() {
|
|
229
|
+
return new Promise((resolve) => {
|
|
230
|
+
let output = "";
|
|
231
|
+
const child = spawn("gh", ["api", "user/orgs", "--jq", ".[].login"]);
|
|
232
|
+
child.stdout.on("data", (data) => {
|
|
233
|
+
output += data.toString();
|
|
234
|
+
});
|
|
235
|
+
child.on("close", (code) => {
|
|
236
|
+
if (code === 0) {
|
|
237
|
+
const orgs = output.trim().split("\n").filter(Boolean);
|
|
238
|
+
resolve(orgs);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
resolve([]); // Se falhar, retorna array vazio
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
child.on("error", () => {
|
|
245
|
+
resolve([]); // Se falhar, retorna array vazio
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
static async isGitHubCLIAvailable() {
|
|
250
|
+
return new Promise((resolve) => {
|
|
251
|
+
const child = spawn("gh", ["auth", "status"], {
|
|
252
|
+
stdio: "pipe",
|
|
253
|
+
});
|
|
254
|
+
child.on("close", (code) => {
|
|
255
|
+
resolve(code === 0);
|
|
256
|
+
});
|
|
257
|
+
child.on("error", () => {
|
|
258
|
+
resolve(false);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
static async isVercelCLIAvailable() {
|
|
263
|
+
return new Promise((resolve) => {
|
|
264
|
+
const child = spawn("vercel", ["whoami"], {
|
|
265
|
+
stdio: "pipe",
|
|
266
|
+
});
|
|
267
|
+
child.on("close", (code) => {
|
|
268
|
+
resolve(code === 0);
|
|
269
|
+
});
|
|
270
|
+
child.on("error", () => {
|
|
271
|
+
resolve(false);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
package/dist/index.d.ts
ADDED