@create-lft-app/cli 1.0.6 → 1.0.10
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 +47 -36
- package/dist/bin/cli.js +116 -44
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/index.js +84 -40
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,49 +11,81 @@ npm install -g @create-lft-app/cli
|
|
|
11
11
|
O ejecutar directamente con npx:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx @create-lft-app/cli mi-proyecto
|
|
14
|
+
npx @create-lft-app/cli mi-proyecto --config /ruta/a/credenciales.json
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
## Configuracion de credenciales
|
|
18
|
+
|
|
19
|
+
Antes de usar el CLI, necesitas crear un archivo de credenciales JSON:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"github": {
|
|
24
|
+
"token": "ghp_xxxxxxxxxxxx",
|
|
25
|
+
"username": "tu-usuario",
|
|
26
|
+
"org": "tu-organizacion"
|
|
27
|
+
},
|
|
28
|
+
"supabase": {
|
|
29
|
+
"token": "sbp_xxxxxxxxxxxx",
|
|
30
|
+
"orgId": "tu-org-id",
|
|
31
|
+
"region": "us-east-1"
|
|
32
|
+
},
|
|
33
|
+
"jira": {
|
|
34
|
+
"email": "tu-email@ejemplo.com",
|
|
35
|
+
"token": "ATATT3xxxxxxxxxxxx",
|
|
36
|
+
"domain": "tu-dominio.atlassian.net"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Donde obtener los tokens
|
|
42
|
+
|
|
43
|
+
- **GitHub Token**: https://github.com/settings/tokens/new (permisos: `repo`, `read:org`)
|
|
44
|
+
- **Supabase Token**: https://supabase.com/dashboard/account/tokens
|
|
45
|
+
- **Supabase Org ID**: Esta en la URL de tu dashboard: `/dashboard/org/[ORG-ID]/settings`
|
|
46
|
+
- **Jira Token**: https://id.atlassian.com/manage-profile/security/api-tokens
|
|
47
|
+
|
|
17
48
|
## Uso
|
|
18
49
|
|
|
19
50
|
### Crear un proyecto nuevo
|
|
20
51
|
|
|
21
52
|
```bash
|
|
22
|
-
create-lft-app mi-proyecto
|
|
53
|
+
create-lft-app mi-proyecto --config /ruta/a/credenciales.json
|
|
23
54
|
```
|
|
24
55
|
|
|
25
56
|
### Crear proyecto con confirmacion automatica
|
|
26
57
|
|
|
27
58
|
```bash
|
|
28
|
-
create-lft-app mi-proyecto -y
|
|
59
|
+
create-lft-app mi-proyecto --config /ruta/a/credenciales.json -y
|
|
29
60
|
```
|
|
30
61
|
|
|
31
62
|
### Opciones disponibles
|
|
32
63
|
|
|
33
64
|
```bash
|
|
34
|
-
create-lft-app
|
|
65
|
+
create-lft-app <nombre-proyecto> --config <path> [opciones]
|
|
35
66
|
|
|
36
67
|
Opciones:
|
|
37
|
-
-V, --version
|
|
38
|
-
--
|
|
39
|
-
--skip-
|
|
40
|
-
--skip-
|
|
41
|
-
--skip-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
68
|
+
-V, --version Muestra la version
|
|
69
|
+
--config <path> Ruta al archivo de credenciales JSON (obligatorio)
|
|
70
|
+
--skip-github No crear repositorio en GitHub
|
|
71
|
+
--skip-supabase No crear proyecto en Supabase
|
|
72
|
+
--skip-jira No crear proyecto en Jira
|
|
73
|
+
--skip-git No inicializar git ni hacer push
|
|
74
|
+
-y, --yes Aceptar todas las confirmaciones
|
|
75
|
+
-h, --help Muestra ayuda
|
|
44
76
|
```
|
|
45
77
|
|
|
46
78
|
### Ejemplos
|
|
47
79
|
|
|
48
80
|
```bash
|
|
49
81
|
# Crear proyecto completo
|
|
50
|
-
create-lft-app mi-app
|
|
82
|
+
create-lft-app mi-app --config ~/credenciales.json
|
|
51
83
|
|
|
52
84
|
# Crear solo con GitHub y Next.js (sin Supabase ni Jira)
|
|
53
|
-
create-lft-app mi-app --skip-supabase --skip-jira
|
|
85
|
+
create-lft-app mi-app --config ~/credenciales.json --skip-supabase --skip-jira
|
|
54
86
|
|
|
55
87
|
# Crear proyecto local sin servicios externos
|
|
56
|
-
create-lft-app mi-app --skip-github --skip-supabase --skip-jira --skip-git
|
|
88
|
+
create-lft-app mi-app --config ~/credenciales.json --skip-github --skip-supabase --skip-jira --skip-git
|
|
57
89
|
```
|
|
58
90
|
|
|
59
91
|
## Que crea el CLI
|
|
@@ -79,27 +111,6 @@ Si alguno de los recursos ya existe (repo, proyecto Supabase, proyecto Jira, o d
|
|
|
79
111
|
|
|
80
112
|
Esta seccion es solo para desarrolladores que mantienen el paquete.
|
|
81
113
|
|
|
82
|
-
### Configuracion de credenciales
|
|
83
|
-
|
|
84
|
-
Para desarrollo local, crea un archivo `.env` en la raiz del proyecto:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
# GitHub
|
|
88
|
-
LFT_GITHUB_TOKEN=ghp_xxxxxxxxxxxx
|
|
89
|
-
LFT_GITHUB_USERNAME=tu-usuario
|
|
90
|
-
LFT_GITHUB_ORG=tu-organizacion
|
|
91
|
-
|
|
92
|
-
# Supabase
|
|
93
|
-
LFT_SUPABASE_TOKEN=sbp_xxxxxxxxxxxx
|
|
94
|
-
LFT_SUPABASE_ORG_ID=xxxxxxxxxxxx
|
|
95
|
-
LFT_SUPABASE_REGION=us-east-1
|
|
96
|
-
|
|
97
|
-
# Jira
|
|
98
|
-
LFT_JIRA_TOKEN=ATATT3xxxxxxxxxxx
|
|
99
|
-
LFT_JIRA_EMAIL=tu-email@ejemplo.com
|
|
100
|
-
LFT_JIRA_DOMAIN=tu-dominio.atlassian.net
|
|
101
|
-
```
|
|
102
|
-
|
|
103
114
|
### Comandos de desarrollo
|
|
104
115
|
|
|
105
116
|
```bash
|
|
@@ -110,7 +121,7 @@ npm install
|
|
|
110
121
|
npm run build
|
|
111
122
|
|
|
112
123
|
# Ejecutar localmente
|
|
113
|
-
node dist/bin/cli.js mi-proyecto
|
|
124
|
+
node dist/bin/cli.js mi-proyecto --config /ruta/a/credenciales.json
|
|
114
125
|
|
|
115
126
|
# Publicar nueva version
|
|
116
127
|
npm version patch
|
package/dist/bin/cli.js
CHANGED
|
@@ -8,29 +8,77 @@ import path4 from "path";
|
|
|
8
8
|
import { confirm } from "@inquirer/prompts";
|
|
9
9
|
|
|
10
10
|
// src/config/static-config.ts
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
var
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
var STATIC_CONFIG = {
|
|
11
|
+
import { existsSync, readFileSync } from "fs";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
var DEFAULT_CONFIG_PATH = join(homedir(), ".lft-credentials.json");
|
|
15
|
+
var configFilePath = DEFAULT_CONFIG_PATH;
|
|
16
|
+
var EMPTY_CONFIG = {
|
|
18
17
|
github: {
|
|
19
|
-
token:
|
|
20
|
-
username:
|
|
21
|
-
org:
|
|
18
|
+
token: "",
|
|
19
|
+
username: "",
|
|
20
|
+
org: ""
|
|
22
21
|
},
|
|
23
22
|
supabase: {
|
|
24
|
-
token:
|
|
25
|
-
orgId:
|
|
26
|
-
region:
|
|
23
|
+
token: "",
|
|
24
|
+
orgId: "",
|
|
25
|
+
region: "us-east-1"
|
|
27
26
|
},
|
|
28
27
|
jira: {
|
|
29
|
-
email:
|
|
30
|
-
token:
|
|
31
|
-
domain:
|
|
28
|
+
email: "",
|
|
29
|
+
token: "",
|
|
30
|
+
domain: ""
|
|
32
31
|
}
|
|
33
32
|
};
|
|
33
|
+
var loadedConfig = null;
|
|
34
|
+
function setConfigPath(path5) {
|
|
35
|
+
configFilePath = path5;
|
|
36
|
+
loadedConfig = null;
|
|
37
|
+
}
|
|
38
|
+
function getConfigPath() {
|
|
39
|
+
return configFilePath;
|
|
40
|
+
}
|
|
41
|
+
function configFileExists() {
|
|
42
|
+
return existsSync(configFilePath);
|
|
43
|
+
}
|
|
44
|
+
function loadConfigFromFile() {
|
|
45
|
+
if (loadedConfig) {
|
|
46
|
+
return loadedConfig;
|
|
47
|
+
}
|
|
48
|
+
if (!existsSync(configFilePath)) {
|
|
49
|
+
return EMPTY_CONFIG;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const content = readFileSync(configFilePath, "utf-8");
|
|
53
|
+
const parsed = JSON.parse(content);
|
|
54
|
+
loadedConfig = {
|
|
55
|
+
github: {
|
|
56
|
+
token: parsed.github?.token || "",
|
|
57
|
+
username: parsed.github?.username || "",
|
|
58
|
+
org: parsed.github?.org || ""
|
|
59
|
+
},
|
|
60
|
+
supabase: {
|
|
61
|
+
token: parsed.supabase?.token || "",
|
|
62
|
+
orgId: parsed.supabase?.orgId || "",
|
|
63
|
+
region: parsed.supabase?.region || "us-east-1"
|
|
64
|
+
},
|
|
65
|
+
jira: {
|
|
66
|
+
email: parsed.jira?.email || "",
|
|
67
|
+
token: parsed.jira?.token || "",
|
|
68
|
+
domain: parsed.jira?.domain || ""
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
return loadedConfig;
|
|
72
|
+
} catch {
|
|
73
|
+
return EMPTY_CONFIG;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
var STATIC_CONFIG = new Proxy(EMPTY_CONFIG, {
|
|
77
|
+
get(_target, prop) {
|
|
78
|
+
const config = loadConfigFromFile();
|
|
79
|
+
return config[prop];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
34
82
|
|
|
35
83
|
// src/config/index.ts
|
|
36
84
|
async function loadConfig() {
|
|
@@ -59,6 +107,9 @@ async function loadConfig() {
|
|
|
59
107
|
};
|
|
60
108
|
}
|
|
61
109
|
async function hasConfig() {
|
|
110
|
+
if (!configFileExists()) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
62
113
|
return STATIC_CONFIG.github.token !== "" && STATIC_CONFIG.supabase.token !== "" && STATIC_CONFIG.jira.token !== "";
|
|
63
114
|
}
|
|
64
115
|
|
|
@@ -133,10 +184,10 @@ var logger = {
|
|
|
133
184
|
};
|
|
134
185
|
|
|
135
186
|
// src/services/github.ts
|
|
136
|
-
async function createGitHubRepo(projectName,
|
|
137
|
-
const octokit = new Octokit({ auth:
|
|
138
|
-
const org =
|
|
139
|
-
const owner = org ||
|
|
187
|
+
async function createGitHubRepo(projectName, config) {
|
|
188
|
+
const octokit = new Octokit({ auth: config.credentials.github.token });
|
|
189
|
+
const org = config.defaults.githubOrg;
|
|
190
|
+
const owner = org || config.credentials.github.username;
|
|
140
191
|
try {
|
|
141
192
|
const existing = await octokit.rest.repos.get({
|
|
142
193
|
owner,
|
|
@@ -187,7 +238,7 @@ async function waitForProjectReady(projectId, token, maxAttempts = 60) {
|
|
|
187
238
|
return;
|
|
188
239
|
}
|
|
189
240
|
}
|
|
190
|
-
await new Promise((
|
|
241
|
+
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
191
242
|
spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${(i + 1) * 5 % 60}s)`;
|
|
192
243
|
}
|
|
193
244
|
spinner.fail("Timeout esperando a que el proyecto est\xE9 listo");
|
|
@@ -216,10 +267,10 @@ async function findExistingProject(projectName, token) {
|
|
|
216
267
|
const projects = await response.json();
|
|
217
268
|
return projects.find((p) => p.name === projectName) || null;
|
|
218
269
|
}
|
|
219
|
-
async function createSupabaseProject(projectName,
|
|
220
|
-
const token =
|
|
221
|
-
const orgId =
|
|
222
|
-
const region =
|
|
270
|
+
async function createSupabaseProject(projectName, config) {
|
|
271
|
+
const token = config.credentials.supabase.accessToken;
|
|
272
|
+
const orgId = config.credentials.supabase.organizationId;
|
|
273
|
+
const region = config.defaults.supabaseRegion;
|
|
223
274
|
const existing = await findExistingProject(projectName, token);
|
|
224
275
|
if (existing) {
|
|
225
276
|
logger.success(`Supabase: ${projectName} (ya existe)`);
|
|
@@ -319,8 +370,8 @@ async function findExistingJiraProject(projectName, auth, domain) {
|
|
|
319
370
|
const data = await response.json();
|
|
320
371
|
return data.values.find((p) => p.name === projectName) || null;
|
|
321
372
|
}
|
|
322
|
-
async function createJiraProject(projectName,
|
|
323
|
-
const { email, apiToken, domain } =
|
|
373
|
+
async function createJiraProject(projectName, config) {
|
|
374
|
+
const { email, apiToken, domain } = config.credentials.jira;
|
|
324
375
|
const auth = Buffer.from(`${email}:${apiToken}`).toString("base64");
|
|
325
376
|
const projectKey = generateJiraKey(projectName);
|
|
326
377
|
const existing = await findExistingJiraProject(projectName, auth, domain);
|
|
@@ -390,11 +441,11 @@ async function createJiraProject(projectName, config2) {
|
|
|
390
441
|
|
|
391
442
|
// src/steps/scaffold-nextjs.ts
|
|
392
443
|
import { execa } from "execa";
|
|
393
|
-
import { existsSync } from "fs";
|
|
444
|
+
import { existsSync as existsSync2 } from "fs";
|
|
394
445
|
import path from "path";
|
|
395
446
|
async function scaffoldNextJs(projectName, projectPath) {
|
|
396
447
|
const targetDir = path.join(process.cwd(), projectName);
|
|
397
|
-
if (
|
|
448
|
+
if (existsSync2(targetDir)) {
|
|
398
449
|
logger.success(`Next.js: ${projectName} (ya existe)`);
|
|
399
450
|
return;
|
|
400
451
|
}
|
|
@@ -426,14 +477,14 @@ async function scaffoldNextJs(projectName, projectPath) {
|
|
|
426
477
|
// src/steps/copy-template.ts
|
|
427
478
|
import { cp, mkdir, readFile, writeFile } from "fs/promises";
|
|
428
479
|
import path2 from "path";
|
|
429
|
-
import { fileURLToPath
|
|
430
|
-
var
|
|
431
|
-
var
|
|
480
|
+
import { fileURLToPath } from "url";
|
|
481
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
482
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
432
483
|
async function copyTemplate(projectPath) {
|
|
433
484
|
await withSpinner(
|
|
434
485
|
"Copiando template LFT...",
|
|
435
486
|
async () => {
|
|
436
|
-
const templatesDir = path2.join(
|
|
487
|
+
const templatesDir = path2.join(__dirname2, "..", "..", "templates");
|
|
437
488
|
const srcDir = path2.join(projectPath, "src");
|
|
438
489
|
await cp(
|
|
439
490
|
path2.join(templatesDir, "components", "ui"),
|
|
@@ -680,19 +731,19 @@ async function createProject(projectName, options = {}) {
|
|
|
680
731
|
logger.warning('No se encontr\xF3 configuraci\xF3n. Ejecuta "create-lft-app config" primero.');
|
|
681
732
|
throw new Error("Configuraci\xF3n no encontrada");
|
|
682
733
|
}
|
|
683
|
-
const
|
|
734
|
+
const config = await loadConfig();
|
|
684
735
|
logger.newLine();
|
|
685
736
|
logger.title("Resumen de recursos a crear:");
|
|
686
737
|
logger.newLine();
|
|
687
738
|
const resources = [];
|
|
688
739
|
if (!options.skipGithub) {
|
|
689
|
-
resources.push({ label: "GitHub", value: `${
|
|
740
|
+
resources.push({ label: "GitHub", value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });
|
|
690
741
|
}
|
|
691
742
|
if (!options.skipSupabase) {
|
|
692
|
-
resources.push({ label: "Supabase", value: `${projectName} en ${
|
|
743
|
+
resources.push({ label: "Supabase", value: `${projectName} en ${config.defaults.supabaseRegion}` });
|
|
693
744
|
}
|
|
694
745
|
if (!options.skipJira) {
|
|
695
|
-
resources.push({ label: "Jira", value: `Proyecto "${projectName}" en ${
|
|
746
|
+
resources.push({ label: "Jira", value: `Proyecto "${projectName}" en ${config.credentials.jira.domain}` });
|
|
696
747
|
}
|
|
697
748
|
resources.push({ label: "Next.js", value: "App Router + TypeScript + Tailwind + Dashboard" });
|
|
698
749
|
logger.table(resources);
|
|
@@ -715,14 +766,14 @@ async function createProject(projectName, options = {}) {
|
|
|
715
766
|
const externalTasks = [];
|
|
716
767
|
if (!options.skipGithub) {
|
|
717
768
|
externalTasks.push(
|
|
718
|
-
createGitHubRepo(projectName,
|
|
769
|
+
createGitHubRepo(projectName, config).then((url) => {
|
|
719
770
|
urls.github = url;
|
|
720
771
|
})
|
|
721
772
|
);
|
|
722
773
|
}
|
|
723
774
|
if (!options.skipSupabase) {
|
|
724
775
|
externalTasks.push(
|
|
725
|
-
createSupabaseProject(projectName,
|
|
776
|
+
createSupabaseProject(projectName, config).then((result) => {
|
|
726
777
|
urls.supabase = result.url;
|
|
727
778
|
supabaseKeys = result;
|
|
728
779
|
})
|
|
@@ -730,7 +781,7 @@ async function createProject(projectName, options = {}) {
|
|
|
730
781
|
}
|
|
731
782
|
if (!options.skipJira) {
|
|
732
783
|
externalTasks.push(
|
|
733
|
-
createJiraProject(projectName,
|
|
784
|
+
createJiraProject(projectName, config).then((url) => {
|
|
734
785
|
urls.jira = url;
|
|
735
786
|
})
|
|
736
787
|
);
|
|
@@ -756,16 +807,37 @@ var packageJson = {
|
|
|
756
807
|
description: "CLI para crear proyectos LFT con Next.js, GitHub, Supabase y Jira"
|
|
757
808
|
};
|
|
758
809
|
program.name("create-lft-app").description(packageJson.description).version(packageJson.version);
|
|
759
|
-
program.argument("[project-name]", "Nombre del proyecto a crear").option("--skip-github", "No crear repositorio en GitHub").option("--skip-supabase", "No crear proyecto en Supabase").option("--skip-jira", "No crear workspace en Jira").option("--skip-git", "No inicializar git ni hacer push").option("-y, --yes", "Aceptar todas las confirmaciones").action(async (projectName, options) => {
|
|
810
|
+
program.argument("[project-name]", "Nombre del proyecto a crear").requiredOption("--config <path>", "Ruta al archivo de credenciales JSON (obligatorio)").option("--skip-github", "No crear repositorio en GitHub").option("--skip-supabase", "No crear proyecto en Supabase").option("--skip-jira", "No crear workspace en Jira").option("--skip-git", "No inicializar git ni hacer push").option("-y, --yes", "Aceptar todas las confirmaciones").action(async (projectName, options) => {
|
|
760
811
|
showBanner();
|
|
812
|
+
setConfigPath(options.config);
|
|
761
813
|
if (!projectName) {
|
|
762
814
|
logger.error("Debes especificar un nombre de proyecto");
|
|
763
|
-
logger.info("Uso: create-lft-app <nombre-proyecto>");
|
|
815
|
+
logger.info("Uso: create-lft-app <nombre-proyecto> --config <ruta-credenciales>");
|
|
764
816
|
process.exit(1);
|
|
765
817
|
}
|
|
766
818
|
if (!await hasConfig()) {
|
|
767
|
-
|
|
768
|
-
logger.
|
|
819
|
+
const configPath = getConfigPath();
|
|
820
|
+
logger.error(`No se encontr\xF3 el archivo de credenciales: ${configPath}`);
|
|
821
|
+
logger.newLine();
|
|
822
|
+
logger.info("El archivo debe tener el siguiente formato:");
|
|
823
|
+
logger.newLine();
|
|
824
|
+
console.log(`{
|
|
825
|
+
"github": {
|
|
826
|
+
"token": "ghp_xxxxxxxxxxxx",
|
|
827
|
+
"username": "tu-usuario",
|
|
828
|
+
"org": "tu-organizacion"
|
|
829
|
+
},
|
|
830
|
+
"supabase": {
|
|
831
|
+
"token": "sbp_xxxxxxxxxxxx",
|
|
832
|
+
"orgId": "tu-org-id",
|
|
833
|
+
"region": "us-east-1"
|
|
834
|
+
},
|
|
835
|
+
"jira": {
|
|
836
|
+
"email": "tu-email@ejemplo.com",
|
|
837
|
+
"token": "ATATT3xxxxxxxxxxxx",
|
|
838
|
+
"domain": "tu-dominio.atlassian.net"
|
|
839
|
+
}
|
|
840
|
+
}`);
|
|
769
841
|
process.exit(1);
|
|
770
842
|
}
|
|
771
843
|
try {
|
package/dist/bin/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../bin/cli.ts","../../src/index.ts","../../src/config/static-config.ts","../../src/config/index.ts","../../src/services/github.ts","../../src/ui/spinner.ts","../../src/ui/logger.ts","../../src/services/supabase.ts","../../src/utils/validation.ts","../../src/services/jira.ts","../../src/steps/scaffold-nextjs.ts","../../src/steps/copy-template.ts","../../src/steps/install-deps.ts","../../src/steps/create-env.ts","../../src/steps/setup-git.ts","../../src/ui/banner.ts"],"sourcesContent":["import { program } from 'commander';\nimport { createProject } from '../src/index.js';\nimport { hasConfig } from '../src/config/index.js';\nimport { showBanner } from '../src/ui/banner.js';\nimport { logger } from '../src/ui/logger.js';\n\nconst packageJson = {\n name: 'create-lft-app',\n version: '1.0.0',\n description: 'CLI para crear proyectos LFT con Next.js, GitHub, Supabase y Jira',\n};\n\nprogram\n .name('create-lft-app')\n .description(packageJson.description)\n .version(packageJson.version);\n\nprogram\n .argument('[project-name]', 'Nombre del proyecto a crear')\n .option('--skip-github', 'No crear repositorio en GitHub')\n .option('--skip-supabase', 'No crear proyecto en Supabase')\n .option('--skip-jira', 'No crear workspace en Jira')\n .option('--skip-git', 'No inicializar git ni hacer push')\n .option('-y, --yes', 'Aceptar todas las confirmaciones')\n .action(async (projectName: string | undefined, options) => {\n showBanner();\n\n if (!projectName) {\n logger.error('Debes especificar un nombre de proyecto');\n logger.info('Uso: create-lft-app <nombre-proyecto>');\n process.exit(1);\n }\n\n if (!await hasConfig()) {\n logger.error('Las credenciales no están configuradas en el paquete');\n logger.info('Contacta al administrador del CLI');\n process.exit(1);\n }\n\n try {\n await createProject(projectName, {\n skipGithub: options.skipGithub,\n skipSupabase: options.skipSupabase,\n skipJira: options.skipJira,\n skipGit: options.skipGit,\n autoConfirm: options.yes,\n });\n } catch (error) {\n if (error instanceof Error) {\n logger.error(error.message);\n }\n process.exit(1);\n }\n });\n\nprogram.parse();","import path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport { loadConfig, hasConfig } from './config/index.js';\nimport { createGitHubRepo } from './services/github.js';\nimport { createSupabaseProject } from './services/supabase.js';\nimport { createJiraProject } from './services/jira.js';\nimport { scaffoldNextJs } from './steps/scaffold-nextjs.js';\nimport { copyTemplate } from './steps/copy-template.js';\nimport { installDependencies } from './steps/install-deps.js';\nimport { createEnvFile } from './steps/create-env.js';\nimport { setupGit } from './steps/setup-git.js';\nimport { logger } from './ui/logger.js';\nimport { showSuccessBanner } from './ui/banner.js';\nimport { validateProjectName } from './utils/validation.js';\n\nexport interface CreateProjectOptions {\n skipGithub?: boolean;\n skipSupabase?: boolean;\n skipJira?: boolean;\n skipGit?: boolean;\n autoConfirm?: boolean;\n}\n\nexport async function createProject(\n projectName: string,\n options: CreateProjectOptions = {}\n): Promise<void> {\n // Validar nombre del proyecto\n const validation = validateProjectName(projectName);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // Verificar que el directorio no exista\n const projectPath = path.resolve(process.cwd(), projectName);\n\n // Cargar configuración\n if (!await hasConfig()) {\n logger.warning('No se encontró configuración. Ejecuta \"create-lft-app config\" primero.');\n throw new Error('Configuración no encontrada');\n }\n\n const config = await loadConfig();\n\n // Mostrar resumen\n logger.newLine();\n logger.title('Resumen de recursos a crear:');\n logger.newLine();\n\n const resources = [];\n if (!options.skipGithub) {\n resources.push({ label: 'GitHub', value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });\n }\n if (!options.skipSupabase) {\n resources.push({ label: 'Supabase', value: `${projectName} en ${config.defaults.supabaseRegion}` });\n }\n if (!options.skipJira) {\n resources.push({ label: 'Jira', value: `Proyecto \"${projectName}\" en ${config.credentials.jira.domain}` });\n }\n resources.push({ label: 'Next.js', value: 'App Router + TypeScript + Tailwind + Dashboard' });\n\n logger.table(resources);\n logger.newLine();\n\n // Confirmar\n if (!options.autoConfirm) {\n const shouldContinue = await confirm({\n message: '¿Continuar con la creación?',\n default: true,\n });\n\n if (!shouldContinue) {\n logger.info('Operación cancelada');\n return;\n }\n }\n\n logger.newLine();\n logger.divider();\n logger.newLine();\n\n const urls: { github?: string; supabase?: string; jira?: string } = {};\n let supabaseKeys: { url: string; anonKey: string; serviceKey: string } | undefined;\n\n // Crear recursos externos en paralelo\n const externalTasks: Promise<void>[] = [];\n\n if (!options.skipGithub) {\n externalTasks.push(\n createGitHubRepo(projectName, config).then((url) => {\n urls.github = url;\n })\n );\n }\n\n if (!options.skipSupabase) {\n externalTasks.push(\n createSupabaseProject(projectName, config).then((result) => {\n urls.supabase = result.url;\n supabaseKeys = result;\n })\n );\n }\n\n if (!options.skipJira) {\n externalTasks.push(\n createJiraProject(projectName, config).then((url) => {\n urls.jira = url;\n })\n );\n }\n\n // Esperar a que terminen los recursos externos\n await Promise.all(externalTasks);\n\n // Scaffold Next.js\n await scaffoldNextJs(projectName, projectPath);\n\n // Copiar template\n await copyTemplate(projectPath);\n\n // Instalar dependencias\n await installDependencies(projectPath);\n\n // Crear .env.local\n if (supabaseKeys) {\n await createEnvFile(projectPath, supabaseKeys);\n }\n\n // Setup git\n if (!options.skipGit && urls.github) {\n await setupGit(projectPath, urls.github);\n }\n\n // Mostrar resumen final\n logger.newLine();\n showSuccessBanner(projectName, urls);\n}\n","// ================================================\n// CONFIGURACIÓN - LEE DESDE VARIABLES DE ENTORNO\n// ================================================\nimport { config } from 'dotenv';\nimport { fileURLToPath } from 'url';\nimport { dirname, resolve } from 'path';\n\n// Cargar .env desde el directorio del paquete\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconfig({ path: resolve(__dirname, '../../.env'), quiet: true });\n\nexport const STATIC_CONFIG = {\n github: {\n token: process.env.LFT_GITHUB_TOKEN || '',\n username: process.env.LFT_GITHUB_USERNAME || '',\n org: process.env.LFT_GITHUB_ORG || '',\n },\n supabase: {\n token: process.env.LFT_SUPABASE_TOKEN || '',\n orgId: process.env.LFT_SUPABASE_ORG_ID || '',\n region: process.env.LFT_SUPABASE_REGION || 'us-east-1',\n },\n jira: {\n email: process.env.LFT_JIRA_EMAIL || '',\n token: process.env.LFT_JIRA_TOKEN || '',\n domain: process.env.LFT_JIRA_DOMAIN || '',\n },\n};\n","import { STATIC_CONFIG } from './static-config.js';\n\nexport interface LFTConfig {\n version: string;\n credentials: {\n github: {\n token: string;\n username: string;\n };\n supabase: {\n accessToken: string;\n organizationId: string;\n };\n jira: {\n email: string;\n apiToken: string;\n domain: string;\n };\n };\n defaults: {\n githubOrg?: string;\n supabaseRegion: string;\n jiraProjectType: string;\n };\n}\n\nexport async function loadConfig(): Promise<LFTConfig> {\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: STATIC_CONFIG.github.token,\n username: STATIC_CONFIG.github.username,\n },\n supabase: {\n accessToken: STATIC_CONFIG.supabase.token,\n organizationId: STATIC_CONFIG.supabase.orgId,\n },\n jira: {\n email: STATIC_CONFIG.jira.email,\n apiToken: STATIC_CONFIG.jira.token,\n domain: STATIC_CONFIG.jira.domain,\n },\n },\n defaults: {\n githubOrg: STATIC_CONFIG.github.org || undefined,\n supabaseRegion: STATIC_CONFIG.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n return (\n STATIC_CONFIG.github.token !== '' &&\n STATIC_CONFIG.supabase.token !== '' &&\n STATIC_CONFIG.jira.token !== ''\n );\n}\n","import { Octokit } from 'octokit';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\nexport async function createGitHubRepo(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const octokit = new Octokit({ auth: config.credentials.github.token });\n const org = config.defaults.githubOrg;\n const owner = org || config.credentials.github.username;\n\n // Verificar si el repo ya existe\n try {\n const existing = await octokit.rest.repos.get({\n owner,\n repo: projectName,\n });\n logger.success(`GitHub: ${owner}/${projectName} (ya existe)`);\n return existing.data.html_url;\n } catch {\n // No existe, continuar con la creación\n }\n\n return withSpinner(\n 'Creando repositorio en GitHub...',\n async () => {\n let repo;\n\n if (org) {\n repo = await octokit.rest.repos.createInOrg({\n org,\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n } else {\n repo = await octokit.rest.repos.createForAuthenticatedUser({\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n }\n\n return repo.data.html_url;\n },\n `GitHub: ${owner}/${projectName}`\n );\n}\n\nexport async function validateGitHubToken(token: string): Promise<{ valid: boolean; username?: string }> {\n try {\n const octokit = new Octokit({ auth: token });\n const { data } = await octokit.rest.users.getAuthenticated();\n return { valid: true, username: data.login };\n } catch {\n return { valid: false };\n }\n}\n","import ora, { type Ora } from 'ora';\n\nexport function createSpinner(text: string): Ora {\n return ora({\n text,\n spinner: 'dots',\n });\n}\n\nexport async function withSpinner<T>(\n text: string,\n fn: () => Promise<T>,\n successText?: string\n): Promise<T> {\n const spinner = createSpinner(text).start();\n\n try {\n const result = await fn();\n spinner.succeed(successText || text);\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (message: string) => {\n console.log(chalk.blue('ℹ'), message);\n },\n\n success: (message: string) => {\n console.log(chalk.green('✔'), message);\n },\n\n warning: (message: string) => {\n console.log(chalk.yellow('⚠'), message);\n },\n\n error: (message: string) => {\n console.log(chalk.red('✖'), message);\n },\n\n step: (step: number, total: number, message: string) => {\n console.log(chalk.cyan(`[${step}/${total}]`), message);\n },\n\n newLine: () => {\n console.log();\n },\n\n divider: () => {\n console.log(chalk.gray('─'.repeat(50)));\n },\n\n title: (message: string) => {\n console.log(chalk.bold.white(message));\n },\n\n subtitle: (message: string) => {\n console.log(chalk.gray(message));\n },\n\n link: (label: string, url: string) => {\n console.log(` ${chalk.gray(label + ':')} ${chalk.cyan.underline(url)}`);\n },\n\n list: (items: string[]) => {\n items.forEach((item) => {\n console.log(chalk.gray(' •'), item);\n });\n },\n\n table: (rows: Array<{ label: string; value: string }>) => {\n const maxLabelLength = Math.max(...rows.map((r) => r.label.length));\n rows.forEach(({ label, value }) => {\n const paddedLabel = label.padEnd(maxLabelLength);\n console.log(` ${chalk.gray(paddedLabel)} ${value}`);\n });\n },\n};\n","import { withSpinner, createSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface SupabaseProjectResponse {\n id: string;\n name: string;\n organization_id: string;\n region: string;\n status: string;\n}\n\ninterface SupabaseApiKey {\n name: string;\n api_key: string;\n}\n\nexport interface SupabaseProjectResult {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nconst SUPABASE_API_URL = 'https://api.supabase.com/v1';\n\nasync function waitForProjectReady(\n projectId: string,\n token: string,\n maxAttempts = 60\n): Promise<void> {\n const spinner = createSpinner('Provisionando base de datos (esto puede tomar ~2 minutos)...').start();\n\n for (let i = 0; i < maxAttempts; i++) {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (response.ok) {\n const project = (await response.json()) as SupabaseProjectResponse;\n if (project.status === 'ACTIVE_HEALTHY') {\n spinner.succeed('Base de datos provisionada');\n return;\n }\n }\n\n // Esperar 5 segundos antes del siguiente intento\n await new Promise((resolve) => setTimeout(resolve, 5000));\n spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${((i + 1) * 5) % 60}s)`;\n }\n\n spinner.fail('Timeout esperando a que el proyecto esté listo');\n throw new Error('Timeout: el proyecto de Supabase no se activó a tiempo');\n}\n\nasync function getProjectApiKeys(\n projectId: string,\n token: string\n): Promise<{ anonKey: string; serviceKey: string }> {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}/api-keys`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) {\n throw new Error('No se pudieron obtener las API keys de Supabase');\n }\n\n const keys = (await response.json()) as SupabaseApiKey[];\n\n const anonKey = keys.find((k) => k.name === 'anon')?.api_key;\n const serviceKey = keys.find((k) => k.name === 'service_role')?.api_key;\n\n if (!anonKey || !serviceKey) {\n throw new Error('No se encontraron las API keys necesarias');\n }\n\n return { anonKey, serviceKey };\n}\n\nasync function findExistingProject(\n projectName: string,\n token: string\n): Promise<SupabaseProjectResponse | null> {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) return null;\n\n const projects = (await response.json()) as SupabaseProjectResponse[];\n return projects.find((p) => p.name === projectName) || null;\n}\n\nexport async function createSupabaseProject(\n projectName: string,\n config: LFTConfig\n): Promise<SupabaseProjectResult> {\n const token = config.credentials.supabase.accessToken;\n const orgId = config.credentials.supabase.organizationId;\n const region = config.defaults.supabaseRegion;\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingProject(projectName, token);\n if (existing) {\n logger.success(`Supabase: ${projectName} (ya existe)`);\n const { anonKey, serviceKey } = await getProjectApiKeys(existing.id, token);\n return {\n url: `https://${existing.id}.supabase.co`,\n anonKey,\n serviceKey,\n };\n }\n\n // Generar una contraseña segura para la base de datos\n const dbPassword = generateSecurePassword();\n\n // Crear proyecto\n const project = await withSpinner(\n 'Creando proyecto en Supabase...',\n async () => {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n name: projectName,\n organization_id: orgId,\n region,\n plan: 'free',\n db_pass: dbPassword,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Error creando proyecto Supabase: ${error}`);\n }\n\n return response.json() as Promise<SupabaseProjectResponse>;\n }\n );\n\n // Esperar a que el proyecto esté listo\n await waitForProjectReady(project.id, token);\n\n // Obtener API keys\n const { anonKey, serviceKey } = await getProjectApiKeys(project.id, token);\n\n const projectUrl = `https://${project.id}.supabase.co`;\n\n return {\n url: projectUrl,\n anonKey,\n serviceKey,\n };\n}\n\nfunction generateSecurePassword(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';\n let password = '';\n for (let i = 0; i < 32; i++) {\n password += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return password;\n}\n","export interface ValidationResult {\n valid: boolean;\n error?: string;\n}\n\nexport function validateProjectName(name: string): ValidationResult {\n // Verificar que no esté vacío\n if (!name || name.trim() === '') {\n return { valid: false, error: 'El nombre del proyecto no puede estar vacío' };\n }\n\n // Verificar caracteres válidos (solo letras, números, guiones y guiones bajos)\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n return {\n valid: false,\n error: 'El nombre solo puede contener letras, números, guiones (-) y guiones bajos (_)',\n };\n }\n\n // Verificar que no empiece con guión o número\n if (/^[-_0-9]/.test(name)) {\n return {\n valid: false,\n error: 'El nombre debe empezar con una letra',\n };\n }\n\n // Verificar longitud\n if (name.length < 2) {\n return { valid: false, error: 'El nombre debe tener al menos 2 caracteres' };\n }\n\n if (name.length > 50) {\n return { valid: false, error: 'El nombre no puede tener más de 50 caracteres' };\n }\n\n // No verificamos si el directorio existe porque ahora manejamos recursos existentes\n return { valid: true };\n}\n\nexport function generateJiraKey(projectName: string): string {\n // Generar key de Jira: máximo 10 caracteres, solo mayúsculas\n const cleaned = projectName\n .replace(/[^a-zA-Z0-9]/g, '')\n .toUpperCase()\n .slice(0, 10);\n\n return cleaned || 'PROJ';\n}\n","import { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport { generateJiraKey } from '../utils/validation.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface JiraProjectResponse {\n id: string;\n key: string;\n name: string;\n self: string;\n}\n\nasync function findExistingJiraProject(\n projectName: string,\n auth: string,\n domain: string\n): Promise<JiraProjectResponse | null> {\n const response = await fetch(\n `https://${domain}/rest/api/3/project/search?query=${encodeURIComponent(projectName)}`,\n {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { values: JiraProjectResponse[] };\n return data.values.find((p) => p.name === projectName) || null;\n}\n\nexport async function createJiraProject(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const { email, apiToken, domain } = config.credentials.jira;\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const projectKey = generateJiraKey(projectName);\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingJiraProject(projectName, auth, domain);\n if (existing) {\n logger.success(`Jira: ${existing.key} (ya existe)`);\n return `https://${domain}/browse/${existing.key}`;\n }\n\n return withSpinner(\n 'Creando proyecto en Jira...',\n async () => {\n // Primero obtener el leadAccountId del usuario actual\n const meResponse = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n });\n\n if (!meResponse.ok) {\n throw new Error('No se pudo obtener información del usuario de Jira');\n }\n\n const me = (await meResponse.json()) as { accountId: string };\n\n // Crear el proyecto\n const response = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: projectKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n\n // Si el key ya existe, intentar con un sufijo numérico\n if (error.includes('project key')) {\n const newKey = `${projectKey}${Date.now().toString().slice(-4)}`;\n const retryResponse = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: newKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!retryResponse.ok) {\n throw new Error(`Error creando proyecto Jira: ${await retryResponse.text()}`);\n }\n\n const project = (await retryResponse.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n }\n\n throw new Error(`Error creando proyecto Jira: ${error}`);\n }\n\n const project = (await response.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n },\n `Proyecto Jira: ${projectKey}`\n );\n}\n\nexport async function validateJiraCredentials(\n email: string,\n apiToken: string,\n domain: string\n): Promise<boolean> {\n try {\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const response = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: { Authorization: `Basic ${auth}` },\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { execa } from 'execa';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\n\nexport async function scaffoldNextJs(\n projectName: string,\n projectPath: string\n): Promise<void> {\n const targetDir = path.join(process.cwd(), projectName);\n\n if (existsSync(targetDir)) {\n logger.success(`Next.js: ${projectName} (ya existe)`);\n return;\n }\n\n await withSpinner(\n 'Inicializando proyecto Next.js...',\n async () => {\n await execa('npx', [\n 'create-next-app@latest',\n projectName,\n '--typescript',\n '--tailwind',\n '--eslint',\n '--app',\n '--turbopack',\n '--src-dir',\n '--import-alias', '@/*',\n '--use-npm',\n '--yes',\n ], {\n cwd: process.cwd(),\n stdio: 'pipe',\n });\n },\n `Next.js: ${projectName}`\n );\n}\n","import { cp, mkdir, readFile, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport async function copyTemplate(projectPath: string): Promise<void> {\n await withSpinner(\n 'Copiando template LFT...',\n async () => {\n // Ruta a los templates (relativa al dist)\n const templatesDir = path.join(__dirname, '..', '..', 'templates');\n const srcDir = path.join(projectPath, 'src');\n\n // Copiar componentes UI\n await cp(\n path.join(templatesDir, 'components', 'ui'),\n path.join(srcDir, 'components', 'ui'),\n { recursive: true }\n );\n\n // Copiar componentes de layout\n await cp(\n path.join(templatesDir, 'components', 'layout'),\n path.join(srcDir, 'components', 'layout'),\n { recursive: true }\n );\n\n // Copiar componentes de dashboard\n await cp(\n path.join(templatesDir, 'components', 'dashboard'),\n path.join(srcDir, 'components', 'dashboard'),\n { recursive: true }\n );\n\n // Copiar lib/utils.ts\n await mkdir(path.join(srcDir, 'lib'), { recursive: true });\n await cp(\n path.join(templatesDir, 'lib', 'utils.ts'),\n path.join(srcDir, 'lib', 'utils.ts')\n );\n\n // Copiar hooks\n await mkdir(path.join(srcDir, 'hooks'), { recursive: true });\n await cp(\n path.join(templatesDir, 'hooks'),\n path.join(srcDir, 'hooks'),\n { recursive: true }\n );\n\n // Copiar páginas de app\n await cp(\n path.join(templatesDir, 'app', 'layout.tsx'),\n path.join(srcDir, 'app', 'layout.tsx')\n );\n\n await cp(\n path.join(templatesDir, 'app', 'page.tsx'),\n path.join(srcDir, 'app', 'page.tsx')\n );\n\n // Copiar dashboard page\n await mkdir(path.join(srcDir, 'app', 'dashboard'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'dashboard', 'page.tsx'),\n path.join(srcDir, 'app', 'dashboard', 'page.tsx')\n );\n\n // Copiar auth/login page\n await mkdir(path.join(srcDir, 'app', 'auth', 'login'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'auth', 'login', 'page.tsx'),\n path.join(srcDir, 'app', 'auth', 'login', 'page.tsx')\n );\n\n // Merge globals.css\n await mergeGlobalStyles(projectPath, templatesDir);\n },\n 'Template LFT copiado (47 componentes + páginas)'\n );\n}\n\nasync function mergeGlobalStyles(\n projectPath: string,\n templatesDir: string\n): Promise<void> {\n const templateCssPath = path.join(templatesDir, 'app', 'globals.css');\n const projectCssPath = path.join(projectPath, 'src', 'app', 'globals.css');\n\n try {\n const templateCss = await readFile(templateCssPath, 'utf-8');\n const existingCss = await readFile(projectCssPath, 'utf-8');\n\n // Mantener las directivas de Tailwind del proyecto y agregar custom CSS\n const merged = existingCss + '\\n\\n/* LFT Custom Styles */\\n' + templateCss;\n await writeFile(projectCssPath, merged);\n } catch {\n // Si no existe el template CSS, no hacer nada\n }\n}\n","import { execa } from 'execa';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst TEMPLATE_DEPENDENCIES = [\n // Radix UI primitives\n '@radix-ui/react-accordion',\n '@radix-ui/react-alert-dialog',\n '@radix-ui/react-avatar',\n '@radix-ui/react-checkbox',\n '@radix-ui/react-collapsible',\n '@radix-ui/react-dialog',\n '@radix-ui/react-dropdown-menu',\n '@radix-ui/react-label',\n '@radix-ui/react-popover',\n '@radix-ui/react-progress',\n '@radix-ui/react-radio-group',\n '@radix-ui/react-scroll-area',\n '@radix-ui/react-select',\n '@radix-ui/react-separator',\n '@radix-ui/react-slider',\n '@radix-ui/react-slot',\n '@radix-ui/react-switch',\n '@radix-ui/react-tabs',\n '@radix-ui/react-tooltip',\n\n // UI Utilities\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n\n // Icons\n 'lucide-react',\n\n // Form handling\n 'react-hook-form',\n '@hookform/resolvers',\n\n // Command menu\n 'cmdk',\n\n // Date picker\n 'react-day-picker',\n 'date-fns',\n\n // Toast notifications\n 'sonner',\n\n // Validation\n 'zod',\n\n // Supabase client\n '@supabase/supabase-js',\n '@supabase/ssr',\n];\n\nconst TEMPLATE_DEV_DEPENDENCIES = [\n 'tailwindcss-animate',\n];\n\nexport async function installDependencies(projectPath: string): Promise<void> {\n await withSpinner(\n `Instalando dependencias (${TEMPLATE_DEPENDENCIES.length} paquetes)...`,\n async () => {\n // Instalar dependencias de producción\n await execa('npm', ['install', ...TEMPLATE_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n\n // Instalar dependencias de desarrollo\n await execa('npm', ['install', '-D', ...TEMPLATE_DEV_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n },\n 'Dependencias instaladas'\n );\n}\n","import { writeFile, readFile, appendFile } from 'fs/promises';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\n\ninterface SupabaseKeys {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nexport async function createEnvFile(\n projectPath: string,\n supabaseKeys: SupabaseKeys\n): Promise<void> {\n await withSpinner(\n 'Creando archivo .env.local...',\n async () => {\n const envContent = `# Supabase\nNEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}\nNEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}\nSUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}\n`;\n\n await writeFile(\n path.join(projectPath, '.env.local'),\n envContent\n );\n\n // Asegurar que .env.local esté en .gitignore\n const gitignorePath = path.join(projectPath, '.gitignore');\n try {\n const gitignore = await readFile(gitignorePath, 'utf-8');\n if (!gitignore.includes('.env.local')) {\n await appendFile(gitignorePath, '\\n# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n } catch {\n // Si no existe .gitignore, crearlo\n await writeFile(gitignorePath, '# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n },\n 'Archivo .env.local creado con credenciales de Supabase'\n );\n}\n","import { simpleGit } from 'simple-git';\nimport { withSpinner } from '../ui/spinner.js';\n\nexport async function setupGit(\n projectPath: string,\n remoteUrl: string\n): Promise<void> {\n const git = simpleGit(projectPath);\n\n await withSpinner(\n 'Configurando Git...',\n async () => {\n // Verificar si ya es un repo git\n const isRepo = await git.checkIsRepo();\n\n if (!isRepo) {\n await git.init();\n }\n\n // Agregar remote\n try {\n await git.addRemote('origin', remoteUrl);\n } catch {\n // Remote ya existe, actualizarlo\n await git.remote(['set-url', 'origin', remoteUrl]);\n }\n\n // Stage todos los archivos\n await git.add('.');\n\n // Commit inicial\n await git.commit('Initial commit - created with create-lft-app', {\n '--author': 'create-lft-app <noreply@lft.dev>',\n });\n\n // Renombrar branch a main si es necesario\n try {\n await git.branch(['-M', 'main']);\n } catch {\n // Ya está en main\n }\n\n // Push\n await git.push(['--set-upstream', 'origin', 'main']);\n },\n 'Git configurado y código pusheado'\n );\n}\n","import boxen from 'boxen';\nimport chalk from 'chalk';\n\nexport function showBanner(): void {\n const title = chalk.bold.cyan('create-lft-app');\n const version = chalk.gray('v1.0.0');\n const description = chalk.white('Scaffolding para proyectos LFT');\n\n const banner = boxen(`${title} ${version}\\n${description}`, {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'cyan',\n });\n\n console.log(banner);\n}\n\nexport function showSuccessBanner(projectName: string, urls: {\n github?: string;\n supabase?: string;\n jira?: string;\n}): void {\n const lines = [\n chalk.green.bold(`Proyecto \"${projectName}\" creado exitosamente!`),\n '',\n chalk.white('Directorio:') + ` ./${projectName}`,\n '',\n ];\n\n if (urls.github || urls.supabase || urls.jira) {\n lines.push(chalk.white('Enlaces:'));\n if (urls.github) {\n lines.push(` ${chalk.gray('GitHub:')} ${chalk.cyan(urls.github)}`);\n }\n if (urls.supabase) {\n lines.push(` ${chalk.gray('Supabase:')} ${chalk.cyan(urls.supabase)}`);\n }\n if (urls.jira) {\n lines.push(` ${chalk.gray('Jira:')} ${chalk.cyan(urls.jira)}`);\n }\n lines.push('');\n }\n\n lines.push(chalk.white('Siguiente pasos:'));\n lines.push(` ${chalk.cyan('cd')} ${projectName}`);\n lines.push(` ${chalk.cyan('npm run dev')}`);\n\n const banner = boxen(lines.join('\\n'), {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'green',\n });\n\n console.log(banner);\n}\n"],"mappings":"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","names":["path","config","resolve","config","anonKey","serviceKey","config","project","path","fileURLToPath","__filename","fileURLToPath","__dirname","path","execa","execa","writeFile","readFile","path","writeFile","path","readFile","chalk","path","config"]}
|
|
1
|
+
{"version":3,"sources":["../../bin/cli.ts","../../src/index.ts","../../src/config/static-config.ts","../../src/config/index.ts","../../src/services/github.ts","../../src/ui/spinner.ts","../../src/ui/logger.ts","../../src/services/supabase.ts","../../src/utils/validation.ts","../../src/services/jira.ts","../../src/steps/scaffold-nextjs.ts","../../src/steps/copy-template.ts","../../src/steps/install-deps.ts","../../src/steps/create-env.ts","../../src/steps/setup-git.ts","../../src/ui/banner.ts"],"sourcesContent":["import { program } from 'commander';\nimport { createProject } from '../src/index.js';\nimport { hasConfig, setConfigPath, getConfigPath } from '../src/config/index.js';\nimport { showBanner } from '../src/ui/banner.js';\nimport { logger } from '../src/ui/logger.js';\n\nconst packageJson = {\n name: 'create-lft-app',\n version: '1.0.0',\n description: 'CLI para crear proyectos LFT con Next.js, GitHub, Supabase y Jira',\n};\n\nprogram\n .name('create-lft-app')\n .description(packageJson.description)\n .version(packageJson.version);\n\nprogram\n .argument('[project-name]', 'Nombre del proyecto a crear')\n .requiredOption('--config <path>', 'Ruta al archivo de credenciales JSON (obligatorio)')\n .option('--skip-github', 'No crear repositorio en GitHub')\n .option('--skip-supabase', 'No crear proyecto en Supabase')\n .option('--skip-jira', 'No crear workspace en Jira')\n .option('--skip-git', 'No inicializar git ni hacer push')\n .option('-y, --yes', 'Aceptar todas las confirmaciones')\n .action(async (projectName: string | undefined, options) => {\n showBanner();\n\n // Establecer la ruta del archivo de config\n setConfigPath(options.config);\n\n if (!projectName) {\n logger.error('Debes especificar un nombre de proyecto');\n logger.info('Uso: create-lft-app <nombre-proyecto> --config <ruta-credenciales>');\n process.exit(1);\n }\n\n if (!await hasConfig()) {\n const configPath = getConfigPath();\n logger.error(`No se encontró el archivo de credenciales: ${configPath}`);\n logger.newLine();\n logger.info('El archivo debe tener el siguiente formato:');\n logger.newLine();\n console.log(`{\n \"github\": {\n \"token\": \"ghp_xxxxxxxxxxxx\",\n \"username\": \"tu-usuario\",\n \"org\": \"tu-organizacion\"\n },\n \"supabase\": {\n \"token\": \"sbp_xxxxxxxxxxxx\",\n \"orgId\": \"tu-org-id\",\n \"region\": \"us-east-1\"\n },\n \"jira\": {\n \"email\": \"tu-email@ejemplo.com\",\n \"token\": \"ATATT3xxxxxxxxxxxx\",\n \"domain\": \"tu-dominio.atlassian.net\"\n }\n}`);\n process.exit(1);\n }\n\n try {\n await createProject(projectName, {\n skipGithub: options.skipGithub,\n skipSupabase: options.skipSupabase,\n skipJira: options.skipJira,\n skipGit: options.skipGit,\n autoConfirm: options.yes,\n });\n } catch (error) {\n if (error instanceof Error) {\n logger.error(error.message);\n }\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport { loadConfig, hasConfig } from './config/index.js';\nimport { createGitHubRepo } from './services/github.js';\nimport { createSupabaseProject } from './services/supabase.js';\nimport { createJiraProject } from './services/jira.js';\nimport { scaffoldNextJs } from './steps/scaffold-nextjs.js';\nimport { copyTemplate } from './steps/copy-template.js';\nimport { installDependencies } from './steps/install-deps.js';\nimport { createEnvFile } from './steps/create-env.js';\nimport { setupGit } from './steps/setup-git.js';\nimport { logger } from './ui/logger.js';\nimport { showSuccessBanner } from './ui/banner.js';\nimport { validateProjectName } from './utils/validation.js';\n\nexport interface CreateProjectOptions {\n skipGithub?: boolean;\n skipSupabase?: boolean;\n skipJira?: boolean;\n skipGit?: boolean;\n autoConfirm?: boolean;\n}\n\nexport async function createProject(\n projectName: string,\n options: CreateProjectOptions = {}\n): Promise<void> {\n // Validar nombre del proyecto\n const validation = validateProjectName(projectName);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // Verificar que el directorio no exista\n const projectPath = path.resolve(process.cwd(), projectName);\n\n // Cargar configuración\n if (!await hasConfig()) {\n logger.warning('No se encontró configuración. Ejecuta \"create-lft-app config\" primero.');\n throw new Error('Configuración no encontrada');\n }\n\n const config = await loadConfig();\n\n // Mostrar resumen\n logger.newLine();\n logger.title('Resumen de recursos a crear:');\n logger.newLine();\n\n const resources = [];\n if (!options.skipGithub) {\n resources.push({ label: 'GitHub', value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });\n }\n if (!options.skipSupabase) {\n resources.push({ label: 'Supabase', value: `${projectName} en ${config.defaults.supabaseRegion}` });\n }\n if (!options.skipJira) {\n resources.push({ label: 'Jira', value: `Proyecto \"${projectName}\" en ${config.credentials.jira.domain}` });\n }\n resources.push({ label: 'Next.js', value: 'App Router + TypeScript + Tailwind + Dashboard' });\n\n logger.table(resources);\n logger.newLine();\n\n // Confirmar\n if (!options.autoConfirm) {\n const shouldContinue = await confirm({\n message: '¿Continuar con la creación?',\n default: true,\n });\n\n if (!shouldContinue) {\n logger.info('Operación cancelada');\n return;\n }\n }\n\n logger.newLine();\n logger.divider();\n logger.newLine();\n\n const urls: { github?: string; supabase?: string; jira?: string } = {};\n let supabaseKeys: { url: string; anonKey: string; serviceKey: string } | undefined;\n\n // Crear recursos externos en paralelo\n const externalTasks: Promise<void>[] = [];\n\n if (!options.skipGithub) {\n externalTasks.push(\n createGitHubRepo(projectName, config).then((url) => {\n urls.github = url;\n })\n );\n }\n\n if (!options.skipSupabase) {\n externalTasks.push(\n createSupabaseProject(projectName, config).then((result) => {\n urls.supabase = result.url;\n supabaseKeys = result;\n })\n );\n }\n\n if (!options.skipJira) {\n externalTasks.push(\n createJiraProject(projectName, config).then((url) => {\n urls.jira = url;\n })\n );\n }\n\n // Esperar a que terminen los recursos externos\n await Promise.all(externalTasks);\n\n // Scaffold Next.js\n await scaffoldNextJs(projectName, projectPath);\n\n // Copiar template\n await copyTemplate(projectPath);\n\n // Instalar dependencias\n await installDependencies(projectPath);\n\n // Crear .env.local\n if (supabaseKeys) {\n await createEnvFile(projectPath, supabaseKeys);\n }\n\n // Setup git\n if (!options.skipGit && urls.github) {\n await setupGit(projectPath, urls.github);\n }\n\n // Mostrar resumen final\n logger.newLine();\n showSuccessBanner(projectName, urls);\n}\n","// ================================================\n// CONFIGURACIÓN EN RUNTIME - Lee desde archivo JSON\n// ================================================\n\nimport { existsSync, readFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\n// Ruta por defecto del archivo de credenciales\nconst DEFAULT_CONFIG_PATH = join(homedir(), '.lft-credentials.json');\n\n// Variable para almacenar la ruta del config (puede ser sobreescrita por --config)\nlet configFilePath: string = DEFAULT_CONFIG_PATH;\n\nexport interface StaticConfigType {\n github: {\n token: string;\n username: string;\n org: string;\n };\n supabase: {\n token: string;\n orgId: string;\n region: string;\n };\n jira: {\n email: string;\n token: string;\n domain: string;\n };\n}\n\n// Configuración vacía por defecto\nconst EMPTY_CONFIG: StaticConfigType = {\n github: {\n token: '',\n username: '',\n org: '',\n },\n supabase: {\n token: '',\n orgId: '',\n region: 'us-east-1',\n },\n jira: {\n email: '',\n token: '',\n domain: '',\n },\n};\n\n// Cache de la configuración cargada\nlet loadedConfig: StaticConfigType | null = null;\n\n/**\n * Establece la ruta del archivo de configuración\n */\nexport function setConfigPath(path: string): void {\n configFilePath = path;\n loadedConfig = null; // Invalidar cache\n}\n\n/**\n * Obtiene la ruta actual del archivo de configuración\n */\nexport function getConfigPath(): string {\n return configFilePath;\n}\n\n/**\n * Verifica si el archivo de configuración existe\n */\nexport function configFileExists(): boolean {\n return existsSync(configFilePath);\n}\n\n/**\n * Carga la configuración desde el archivo JSON\n */\nfunction loadConfigFromFile(): StaticConfigType {\n if (loadedConfig) {\n return loadedConfig;\n }\n\n if (!existsSync(configFilePath)) {\n return EMPTY_CONFIG;\n }\n\n try {\n const content = readFileSync(configFilePath, 'utf-8');\n const parsed = JSON.parse(content);\n\n // Validar estructura básica\n loadedConfig = {\n github: {\n token: parsed.github?.token || '',\n username: parsed.github?.username || '',\n org: parsed.github?.org || '',\n },\n supabase: {\n token: parsed.supabase?.token || '',\n orgId: parsed.supabase?.orgId || '',\n region: parsed.supabase?.region || 'us-east-1',\n },\n jira: {\n email: parsed.jira?.email || '',\n token: parsed.jira?.token || '',\n domain: parsed.jira?.domain || '',\n },\n };\n\n return loadedConfig;\n } catch {\n return EMPTY_CONFIG;\n }\n}\n\n// Exportar como getter para que siempre lea la configuración actual\nexport const STATIC_CONFIG: StaticConfigType = new Proxy(EMPTY_CONFIG, {\n get(_target, prop: keyof StaticConfigType) {\n const config = loadConfigFromFile();\n return config[prop];\n },\n});","import { STATIC_CONFIG, configFileExists, getConfigPath, setConfigPath } from './static-config.js';\n\nexport { setConfigPath, getConfigPath } from './static-config.js';\n\nexport interface LFTConfig {\n version: string;\n credentials: {\n github: {\n token: string;\n username: string;\n };\n supabase: {\n accessToken: string;\n organizationId: string;\n };\n jira: {\n email: string;\n apiToken: string;\n domain: string;\n };\n };\n defaults: {\n githubOrg?: string;\n supabaseRegion: string;\n jiraProjectType: string;\n };\n}\n\nexport async function loadConfig(): Promise<LFTConfig> {\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: STATIC_CONFIG.github.token,\n username: STATIC_CONFIG.github.username,\n },\n supabase: {\n accessToken: STATIC_CONFIG.supabase.token,\n organizationId: STATIC_CONFIG.supabase.orgId,\n },\n jira: {\n email: STATIC_CONFIG.jira.email,\n apiToken: STATIC_CONFIG.jira.token,\n domain: STATIC_CONFIG.jira.domain,\n },\n },\n defaults: {\n githubOrg: STATIC_CONFIG.github.org || undefined,\n supabaseRegion: STATIC_CONFIG.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n if (!configFileExists()) {\n return false;\n }\n\n // Verificar que las credenciales no estén vacías\n return (\n STATIC_CONFIG.github.token !== '' &&\n STATIC_CONFIG.supabase.token !== '' &&\n STATIC_CONFIG.jira.token !== ''\n );\n}\n","import { Octokit } from 'octokit';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\nexport async function createGitHubRepo(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const octokit = new Octokit({ auth: config.credentials.github.token });\n const org = config.defaults.githubOrg;\n const owner = org || config.credentials.github.username;\n\n // Verificar si el repo ya existe\n try {\n const existing = await octokit.rest.repos.get({\n owner,\n repo: projectName,\n });\n logger.success(`GitHub: ${owner}/${projectName} (ya existe)`);\n return existing.data.html_url;\n } catch {\n // No existe, continuar con la creación\n }\n\n return withSpinner(\n 'Creando repositorio en GitHub...',\n async () => {\n let repo;\n\n if (org) {\n repo = await octokit.rest.repos.createInOrg({\n org,\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n } else {\n repo = await octokit.rest.repos.createForAuthenticatedUser({\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n }\n\n return repo.data.html_url;\n },\n `GitHub: ${owner}/${projectName}`\n );\n}\n\nexport async function validateGitHubToken(token: string): Promise<{ valid: boolean; username?: string }> {\n try {\n const octokit = new Octokit({ auth: token });\n const { data } = await octokit.rest.users.getAuthenticated();\n return { valid: true, username: data.login };\n } catch {\n return { valid: false };\n }\n}\n","import ora, { type Ora } from 'ora';\n\nexport function createSpinner(text: string): Ora {\n return ora({\n text,\n spinner: 'dots',\n });\n}\n\nexport async function withSpinner<T>(\n text: string,\n fn: () => Promise<T>,\n successText?: string\n): Promise<T> {\n const spinner = createSpinner(text).start();\n\n try {\n const result = await fn();\n spinner.succeed(successText || text);\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (message: string) => {\n console.log(chalk.blue('ℹ'), message);\n },\n\n success: (message: string) => {\n console.log(chalk.green('✔'), message);\n },\n\n warning: (message: string) => {\n console.log(chalk.yellow('⚠'), message);\n },\n\n error: (message: string) => {\n console.log(chalk.red('✖'), message);\n },\n\n step: (step: number, total: number, message: string) => {\n console.log(chalk.cyan(`[${step}/${total}]`), message);\n },\n\n newLine: () => {\n console.log();\n },\n\n divider: () => {\n console.log(chalk.gray('─'.repeat(50)));\n },\n\n title: (message: string) => {\n console.log(chalk.bold.white(message));\n },\n\n subtitle: (message: string) => {\n console.log(chalk.gray(message));\n },\n\n link: (label: string, url: string) => {\n console.log(` ${chalk.gray(label + ':')} ${chalk.cyan.underline(url)}`);\n },\n\n list: (items: string[]) => {\n items.forEach((item) => {\n console.log(chalk.gray(' •'), item);\n });\n },\n\n table: (rows: Array<{ label: string; value: string }>) => {\n const maxLabelLength = Math.max(...rows.map((r) => r.label.length));\n rows.forEach(({ label, value }) => {\n const paddedLabel = label.padEnd(maxLabelLength);\n console.log(` ${chalk.gray(paddedLabel)} ${value}`);\n });\n },\n};\n","import { withSpinner, createSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface SupabaseProjectResponse {\n id: string;\n name: string;\n organization_id: string;\n region: string;\n status: string;\n}\n\ninterface SupabaseApiKey {\n name: string;\n api_key: string;\n}\n\nexport interface SupabaseProjectResult {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nconst SUPABASE_API_URL = 'https://api.supabase.com/v1';\n\nasync function waitForProjectReady(\n projectId: string,\n token: string,\n maxAttempts = 60\n): Promise<void> {\n const spinner = createSpinner('Provisionando base de datos (esto puede tomar ~2 minutos)...').start();\n\n for (let i = 0; i < maxAttempts; i++) {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (response.ok) {\n const project = (await response.json()) as SupabaseProjectResponse;\n if (project.status === 'ACTIVE_HEALTHY') {\n spinner.succeed('Base de datos provisionada');\n return;\n }\n }\n\n // Esperar 5 segundos antes del siguiente intento\n await new Promise((resolve) => setTimeout(resolve, 5000));\n spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${((i + 1) * 5) % 60}s)`;\n }\n\n spinner.fail('Timeout esperando a que el proyecto esté listo');\n throw new Error('Timeout: el proyecto de Supabase no se activó a tiempo');\n}\n\nasync function getProjectApiKeys(\n projectId: string,\n token: string\n): Promise<{ anonKey: string; serviceKey: string }> {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}/api-keys`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) {\n throw new Error('No se pudieron obtener las API keys de Supabase');\n }\n\n const keys = (await response.json()) as SupabaseApiKey[];\n\n const anonKey = keys.find((k) => k.name === 'anon')?.api_key;\n const serviceKey = keys.find((k) => k.name === 'service_role')?.api_key;\n\n if (!anonKey || !serviceKey) {\n throw new Error('No se encontraron las API keys necesarias');\n }\n\n return { anonKey, serviceKey };\n}\n\nasync function findExistingProject(\n projectName: string,\n token: string\n): Promise<SupabaseProjectResponse | null> {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) return null;\n\n const projects = (await response.json()) as SupabaseProjectResponse[];\n return projects.find((p) => p.name === projectName) || null;\n}\n\nexport async function createSupabaseProject(\n projectName: string,\n config: LFTConfig\n): Promise<SupabaseProjectResult> {\n const token = config.credentials.supabase.accessToken;\n const orgId = config.credentials.supabase.organizationId;\n const region = config.defaults.supabaseRegion;\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingProject(projectName, token);\n if (existing) {\n logger.success(`Supabase: ${projectName} (ya existe)`);\n const { anonKey, serviceKey } = await getProjectApiKeys(existing.id, token);\n return {\n url: `https://${existing.id}.supabase.co`,\n anonKey,\n serviceKey,\n };\n }\n\n // Generar una contraseña segura para la base de datos\n const dbPassword = generateSecurePassword();\n\n // Crear proyecto\n const project = await withSpinner(\n 'Creando proyecto en Supabase...',\n async () => {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n name: projectName,\n organization_id: orgId,\n region,\n plan: 'free',\n db_pass: dbPassword,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Error creando proyecto Supabase: ${error}`);\n }\n\n return response.json() as Promise<SupabaseProjectResponse>;\n }\n );\n\n // Esperar a que el proyecto esté listo\n await waitForProjectReady(project.id, token);\n\n // Obtener API keys\n const { anonKey, serviceKey } = await getProjectApiKeys(project.id, token);\n\n const projectUrl = `https://${project.id}.supabase.co`;\n\n return {\n url: projectUrl,\n anonKey,\n serviceKey,\n };\n}\n\nfunction generateSecurePassword(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';\n let password = '';\n for (let i = 0; i < 32; i++) {\n password += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return password;\n}\n","export interface ValidationResult {\n valid: boolean;\n error?: string;\n}\n\nexport function validateProjectName(name: string): ValidationResult {\n // Verificar que no esté vacío\n if (!name || name.trim() === '') {\n return { valid: false, error: 'El nombre del proyecto no puede estar vacío' };\n }\n\n // Verificar caracteres válidos (solo letras, números, guiones y guiones bajos)\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n return {\n valid: false,\n error: 'El nombre solo puede contener letras, números, guiones (-) y guiones bajos (_)',\n };\n }\n\n // Verificar que no empiece con guión o número\n if (/^[-_0-9]/.test(name)) {\n return {\n valid: false,\n error: 'El nombre debe empezar con una letra',\n };\n }\n\n // Verificar longitud\n if (name.length < 2) {\n return { valid: false, error: 'El nombre debe tener al menos 2 caracteres' };\n }\n\n if (name.length > 50) {\n return { valid: false, error: 'El nombre no puede tener más de 50 caracteres' };\n }\n\n // No verificamos si el directorio existe porque ahora manejamos recursos existentes\n return { valid: true };\n}\n\nexport function generateJiraKey(projectName: string): string {\n // Generar key de Jira: máximo 10 caracteres, solo mayúsculas\n const cleaned = projectName\n .replace(/[^a-zA-Z0-9]/g, '')\n .toUpperCase()\n .slice(0, 10);\n\n return cleaned || 'PROJ';\n}\n","import { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport { generateJiraKey } from '../utils/validation.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface JiraProjectResponse {\n id: string;\n key: string;\n name: string;\n self: string;\n}\n\nasync function findExistingJiraProject(\n projectName: string,\n auth: string,\n domain: string\n): Promise<JiraProjectResponse | null> {\n const response = await fetch(\n `https://${domain}/rest/api/3/project/search?query=${encodeURIComponent(projectName)}`,\n {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { values: JiraProjectResponse[] };\n return data.values.find((p) => p.name === projectName) || null;\n}\n\nexport async function createJiraProject(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const { email, apiToken, domain } = config.credentials.jira;\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const projectKey = generateJiraKey(projectName);\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingJiraProject(projectName, auth, domain);\n if (existing) {\n logger.success(`Jira: ${existing.key} (ya existe)`);\n return `https://${domain}/browse/${existing.key}`;\n }\n\n return withSpinner(\n 'Creando proyecto en Jira...',\n async () => {\n // Primero obtener el leadAccountId del usuario actual\n const meResponse = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n });\n\n if (!meResponse.ok) {\n throw new Error('No se pudo obtener información del usuario de Jira');\n }\n\n const me = (await meResponse.json()) as { accountId: string };\n\n // Crear el proyecto\n const response = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: projectKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n\n // Si el key ya existe, intentar con un sufijo numérico\n if (error.includes('project key')) {\n const newKey = `${projectKey}${Date.now().toString().slice(-4)}`;\n const retryResponse = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: newKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!retryResponse.ok) {\n throw new Error(`Error creando proyecto Jira: ${await retryResponse.text()}`);\n }\n\n const project = (await retryResponse.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n }\n\n throw new Error(`Error creando proyecto Jira: ${error}`);\n }\n\n const project = (await response.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n },\n `Proyecto Jira: ${projectKey}`\n );\n}\n\nexport async function validateJiraCredentials(\n email: string,\n apiToken: string,\n domain: string\n): Promise<boolean> {\n try {\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const response = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: { Authorization: `Basic ${auth}` },\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { execa } from 'execa';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\n\nexport async function scaffoldNextJs(\n projectName: string,\n projectPath: string\n): Promise<void> {\n const targetDir = path.join(process.cwd(), projectName);\n\n if (existsSync(targetDir)) {\n logger.success(`Next.js: ${projectName} (ya existe)`);\n return;\n }\n\n await withSpinner(\n 'Inicializando proyecto Next.js...',\n async () => {\n await execa('npx', [\n 'create-next-app@latest',\n projectName,\n '--typescript',\n '--tailwind',\n '--eslint',\n '--app',\n '--turbopack',\n '--src-dir',\n '--import-alias', '@/*',\n '--use-npm',\n '--yes',\n ], {\n cwd: process.cwd(),\n stdio: 'pipe',\n });\n },\n `Next.js: ${projectName}`\n );\n}\n","import { cp, mkdir, readFile, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport async function copyTemplate(projectPath: string): Promise<void> {\n await withSpinner(\n 'Copiando template LFT...',\n async () => {\n // Ruta a los templates (relativa al dist)\n const templatesDir = path.join(__dirname, '..', '..', 'templates');\n const srcDir = path.join(projectPath, 'src');\n\n // Copiar componentes UI\n await cp(\n path.join(templatesDir, 'components', 'ui'),\n path.join(srcDir, 'components', 'ui'),\n { recursive: true }\n );\n\n // Copiar componentes de layout\n await cp(\n path.join(templatesDir, 'components', 'layout'),\n path.join(srcDir, 'components', 'layout'),\n { recursive: true }\n );\n\n // Copiar componentes de dashboard\n await cp(\n path.join(templatesDir, 'components', 'dashboard'),\n path.join(srcDir, 'components', 'dashboard'),\n { recursive: true }\n );\n\n // Copiar lib/utils.ts\n await mkdir(path.join(srcDir, 'lib'), { recursive: true });\n await cp(\n path.join(templatesDir, 'lib', 'utils.ts'),\n path.join(srcDir, 'lib', 'utils.ts')\n );\n\n // Copiar hooks\n await mkdir(path.join(srcDir, 'hooks'), { recursive: true });\n await cp(\n path.join(templatesDir, 'hooks'),\n path.join(srcDir, 'hooks'),\n { recursive: true }\n );\n\n // Copiar páginas de app\n await cp(\n path.join(templatesDir, 'app', 'layout.tsx'),\n path.join(srcDir, 'app', 'layout.tsx')\n );\n\n await cp(\n path.join(templatesDir, 'app', 'page.tsx'),\n path.join(srcDir, 'app', 'page.tsx')\n );\n\n // Copiar dashboard page\n await mkdir(path.join(srcDir, 'app', 'dashboard'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'dashboard', 'page.tsx'),\n path.join(srcDir, 'app', 'dashboard', 'page.tsx')\n );\n\n // Copiar auth/login page\n await mkdir(path.join(srcDir, 'app', 'auth', 'login'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'auth', 'login', 'page.tsx'),\n path.join(srcDir, 'app', 'auth', 'login', 'page.tsx')\n );\n\n // Merge globals.css\n await mergeGlobalStyles(projectPath, templatesDir);\n },\n 'Template LFT copiado (47 componentes + páginas)'\n );\n}\n\nasync function mergeGlobalStyles(\n projectPath: string,\n templatesDir: string\n): Promise<void> {\n const templateCssPath = path.join(templatesDir, 'app', 'globals.css');\n const projectCssPath = path.join(projectPath, 'src', 'app', 'globals.css');\n\n try {\n const templateCss = await readFile(templateCssPath, 'utf-8');\n const existingCss = await readFile(projectCssPath, 'utf-8');\n\n // Mantener las directivas de Tailwind del proyecto y agregar custom CSS\n const merged = existingCss + '\\n\\n/* LFT Custom Styles */\\n' + templateCss;\n await writeFile(projectCssPath, merged);\n } catch {\n // Si no existe el template CSS, no hacer nada\n }\n}\n","import { execa } from 'execa';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst TEMPLATE_DEPENDENCIES = [\n // Radix UI primitives\n '@radix-ui/react-accordion',\n '@radix-ui/react-alert-dialog',\n '@radix-ui/react-avatar',\n '@radix-ui/react-checkbox',\n '@radix-ui/react-collapsible',\n '@radix-ui/react-dialog',\n '@radix-ui/react-dropdown-menu',\n '@radix-ui/react-label',\n '@radix-ui/react-popover',\n '@radix-ui/react-progress',\n '@radix-ui/react-radio-group',\n '@radix-ui/react-scroll-area',\n '@radix-ui/react-select',\n '@radix-ui/react-separator',\n '@radix-ui/react-slider',\n '@radix-ui/react-slot',\n '@radix-ui/react-switch',\n '@radix-ui/react-tabs',\n '@radix-ui/react-tooltip',\n\n // UI Utilities\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n\n // Icons\n 'lucide-react',\n\n // Form handling\n 'react-hook-form',\n '@hookform/resolvers',\n\n // Command menu\n 'cmdk',\n\n // Date picker\n 'react-day-picker',\n 'date-fns',\n\n // Toast notifications\n 'sonner',\n\n // Validation\n 'zod',\n\n // Supabase client\n '@supabase/supabase-js',\n '@supabase/ssr',\n];\n\nconst TEMPLATE_DEV_DEPENDENCIES = [\n 'tailwindcss-animate',\n];\n\nexport async function installDependencies(projectPath: string): Promise<void> {\n await withSpinner(\n `Instalando dependencias (${TEMPLATE_DEPENDENCIES.length} paquetes)...`,\n async () => {\n // Instalar dependencias de producción\n await execa('npm', ['install', ...TEMPLATE_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n\n // Instalar dependencias de desarrollo\n await execa('npm', ['install', '-D', ...TEMPLATE_DEV_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n },\n 'Dependencias instaladas'\n );\n}\n","import { writeFile, readFile, appendFile } from 'fs/promises';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\n\ninterface SupabaseKeys {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nexport async function createEnvFile(\n projectPath: string,\n supabaseKeys: SupabaseKeys\n): Promise<void> {\n await withSpinner(\n 'Creando archivo .env.local...',\n async () => {\n const envContent = `# Supabase\nNEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}\nNEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}\nSUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}\n`;\n\n await writeFile(\n path.join(projectPath, '.env.local'),\n envContent\n );\n\n // Asegurar que .env.local esté en .gitignore\n const gitignorePath = path.join(projectPath, '.gitignore');\n try {\n const gitignore = await readFile(gitignorePath, 'utf-8');\n if (!gitignore.includes('.env.local')) {\n await appendFile(gitignorePath, '\\n# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n } catch {\n // Si no existe .gitignore, crearlo\n await writeFile(gitignorePath, '# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n },\n 'Archivo .env.local creado con credenciales de Supabase'\n );\n}\n","import { simpleGit } from 'simple-git';\nimport { withSpinner } from '../ui/spinner.js';\n\nexport async function setupGit(\n projectPath: string,\n remoteUrl: string\n): Promise<void> {\n const git = simpleGit(projectPath);\n\n await withSpinner(\n 'Configurando Git...',\n async () => {\n // Verificar si ya es un repo git\n const isRepo = await git.checkIsRepo();\n\n if (!isRepo) {\n await git.init();\n }\n\n // Agregar remote\n try {\n await git.addRemote('origin', remoteUrl);\n } catch {\n // Remote ya existe, actualizarlo\n await git.remote(['set-url', 'origin', remoteUrl]);\n }\n\n // Stage todos los archivos\n await git.add('.');\n\n // Commit inicial\n await git.commit('Initial commit - created with create-lft-app', {\n '--author': 'create-lft-app <noreply@lft.dev>',\n });\n\n // Renombrar branch a main si es necesario\n try {\n await git.branch(['-M', 'main']);\n } catch {\n // Ya está en main\n }\n\n // Push\n await git.push(['--set-upstream', 'origin', 'main']);\n },\n 'Git configurado y código pusheado'\n );\n}\n","import boxen from 'boxen';\nimport chalk from 'chalk';\n\nexport function showBanner(): void {\n const title = chalk.bold.cyan('create-lft-app');\n const version = chalk.gray('v1.0.0');\n const description = chalk.white('Scaffolding para proyectos LFT');\n\n const banner = boxen(`${title} ${version}\\n${description}`, {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'cyan',\n });\n\n console.log(banner);\n}\n\nexport function showSuccessBanner(projectName: string, urls: {\n github?: string;\n supabase?: string;\n jira?: string;\n}): void {\n const lines = [\n chalk.green.bold(`Proyecto \"${projectName}\" creado exitosamente!`),\n '',\n chalk.white('Directorio:') + ` ./${projectName}`,\n '',\n ];\n\n if (urls.github || urls.supabase || urls.jira) {\n lines.push(chalk.white('Enlaces:'));\n if (urls.github) {\n lines.push(` ${chalk.gray('GitHub:')} ${chalk.cyan(urls.github)}`);\n }\n if (urls.supabase) {\n lines.push(` ${chalk.gray('Supabase:')} ${chalk.cyan(urls.supabase)}`);\n }\n if (urls.jira) {\n lines.push(` ${chalk.gray('Jira:')} ${chalk.cyan(urls.jira)}`);\n }\n lines.push('');\n }\n\n lines.push(chalk.white('Siguiente pasos:'));\n lines.push(` ${chalk.cyan('cd')} ${projectName}`);\n lines.push(` ${chalk.cyan('npm run dev')}`);\n\n const banner = boxen(lines.join('\\n'), {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'green',\n });\n\n console.log(banner);\n}\n"],"mappings":"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","names":["path","path","anonKey","serviceKey","project","existsSync","existsSync","path","__filename","__dirname","path","execa","execa","writeFile","readFile","path","writeFile","path","readFile","chalk","path"]}
|
package/dist/src/index.js
CHANGED
|
@@ -5,29 +5,70 @@ import path4 from "path";
|
|
|
5
5
|
import { confirm } from "@inquirer/prompts";
|
|
6
6
|
|
|
7
7
|
// src/config/static-config.ts
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
var STATIC_CONFIG = {
|
|
8
|
+
import { existsSync, readFileSync } from "fs";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
var DEFAULT_CONFIG_PATH = join(homedir(), ".lft-credentials.json");
|
|
12
|
+
var configFilePath = DEFAULT_CONFIG_PATH;
|
|
13
|
+
var EMPTY_CONFIG = {
|
|
15
14
|
github: {
|
|
16
|
-
token:
|
|
17
|
-
username:
|
|
18
|
-
org:
|
|
15
|
+
token: "",
|
|
16
|
+
username: "",
|
|
17
|
+
org: ""
|
|
19
18
|
},
|
|
20
19
|
supabase: {
|
|
21
|
-
token:
|
|
22
|
-
orgId:
|
|
23
|
-
region:
|
|
20
|
+
token: "",
|
|
21
|
+
orgId: "",
|
|
22
|
+
region: "us-east-1"
|
|
24
23
|
},
|
|
25
24
|
jira: {
|
|
26
|
-
email:
|
|
27
|
-
token:
|
|
28
|
-
domain:
|
|
25
|
+
email: "",
|
|
26
|
+
token: "",
|
|
27
|
+
domain: ""
|
|
29
28
|
}
|
|
30
29
|
};
|
|
30
|
+
var loadedConfig = null;
|
|
31
|
+
function configFileExists() {
|
|
32
|
+
return existsSync(configFilePath);
|
|
33
|
+
}
|
|
34
|
+
function loadConfigFromFile() {
|
|
35
|
+
if (loadedConfig) {
|
|
36
|
+
return loadedConfig;
|
|
37
|
+
}
|
|
38
|
+
if (!existsSync(configFilePath)) {
|
|
39
|
+
return EMPTY_CONFIG;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const content = readFileSync(configFilePath, "utf-8");
|
|
43
|
+
const parsed = JSON.parse(content);
|
|
44
|
+
loadedConfig = {
|
|
45
|
+
github: {
|
|
46
|
+
token: parsed.github?.token || "",
|
|
47
|
+
username: parsed.github?.username || "",
|
|
48
|
+
org: parsed.github?.org || ""
|
|
49
|
+
},
|
|
50
|
+
supabase: {
|
|
51
|
+
token: parsed.supabase?.token || "",
|
|
52
|
+
orgId: parsed.supabase?.orgId || "",
|
|
53
|
+
region: parsed.supabase?.region || "us-east-1"
|
|
54
|
+
},
|
|
55
|
+
jira: {
|
|
56
|
+
email: parsed.jira?.email || "",
|
|
57
|
+
token: parsed.jira?.token || "",
|
|
58
|
+
domain: parsed.jira?.domain || ""
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return loadedConfig;
|
|
62
|
+
} catch {
|
|
63
|
+
return EMPTY_CONFIG;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
var STATIC_CONFIG = new Proxy(EMPTY_CONFIG, {
|
|
67
|
+
get(_target, prop) {
|
|
68
|
+
const config = loadConfigFromFile();
|
|
69
|
+
return config[prop];
|
|
70
|
+
}
|
|
71
|
+
});
|
|
31
72
|
|
|
32
73
|
// src/config/index.ts
|
|
33
74
|
async function loadConfig() {
|
|
@@ -56,6 +97,9 @@ async function loadConfig() {
|
|
|
56
97
|
};
|
|
57
98
|
}
|
|
58
99
|
async function hasConfig() {
|
|
100
|
+
if (!configFileExists()) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
59
103
|
return STATIC_CONFIG.github.token !== "" && STATIC_CONFIG.supabase.token !== "" && STATIC_CONFIG.jira.token !== "";
|
|
60
104
|
}
|
|
61
105
|
|
|
@@ -130,10 +174,10 @@ var logger = {
|
|
|
130
174
|
};
|
|
131
175
|
|
|
132
176
|
// src/services/github.ts
|
|
133
|
-
async function createGitHubRepo(projectName,
|
|
134
|
-
const octokit = new Octokit({ auth:
|
|
135
|
-
const org =
|
|
136
|
-
const owner = org ||
|
|
177
|
+
async function createGitHubRepo(projectName, config) {
|
|
178
|
+
const octokit = new Octokit({ auth: config.credentials.github.token });
|
|
179
|
+
const org = config.defaults.githubOrg;
|
|
180
|
+
const owner = org || config.credentials.github.username;
|
|
137
181
|
try {
|
|
138
182
|
const existing = await octokit.rest.repos.get({
|
|
139
183
|
owner,
|
|
@@ -184,7 +228,7 @@ async function waitForProjectReady(projectId, token, maxAttempts = 60) {
|
|
|
184
228
|
return;
|
|
185
229
|
}
|
|
186
230
|
}
|
|
187
|
-
await new Promise((
|
|
231
|
+
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
188
232
|
spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${(i + 1) * 5 % 60}s)`;
|
|
189
233
|
}
|
|
190
234
|
spinner.fail("Timeout esperando a que el proyecto est\xE9 listo");
|
|
@@ -213,10 +257,10 @@ async function findExistingProject(projectName, token) {
|
|
|
213
257
|
const projects = await response.json();
|
|
214
258
|
return projects.find((p) => p.name === projectName) || null;
|
|
215
259
|
}
|
|
216
|
-
async function createSupabaseProject(projectName,
|
|
217
|
-
const token =
|
|
218
|
-
const orgId =
|
|
219
|
-
const region =
|
|
260
|
+
async function createSupabaseProject(projectName, config) {
|
|
261
|
+
const token = config.credentials.supabase.accessToken;
|
|
262
|
+
const orgId = config.credentials.supabase.organizationId;
|
|
263
|
+
const region = config.defaults.supabaseRegion;
|
|
220
264
|
const existing = await findExistingProject(projectName, token);
|
|
221
265
|
if (existing) {
|
|
222
266
|
logger.success(`Supabase: ${projectName} (ya existe)`);
|
|
@@ -316,8 +360,8 @@ async function findExistingJiraProject(projectName, auth, domain) {
|
|
|
316
360
|
const data = await response.json();
|
|
317
361
|
return data.values.find((p) => p.name === projectName) || null;
|
|
318
362
|
}
|
|
319
|
-
async function createJiraProject(projectName,
|
|
320
|
-
const { email, apiToken, domain } =
|
|
363
|
+
async function createJiraProject(projectName, config) {
|
|
364
|
+
const { email, apiToken, domain } = config.credentials.jira;
|
|
321
365
|
const auth = Buffer.from(`${email}:${apiToken}`).toString("base64");
|
|
322
366
|
const projectKey = generateJiraKey(projectName);
|
|
323
367
|
const existing = await findExistingJiraProject(projectName, auth, domain);
|
|
@@ -387,11 +431,11 @@ async function createJiraProject(projectName, config2) {
|
|
|
387
431
|
|
|
388
432
|
// src/steps/scaffold-nextjs.ts
|
|
389
433
|
import { execa } from "execa";
|
|
390
|
-
import { existsSync } from "fs";
|
|
434
|
+
import { existsSync as existsSync2 } from "fs";
|
|
391
435
|
import path from "path";
|
|
392
436
|
async function scaffoldNextJs(projectName, projectPath) {
|
|
393
437
|
const targetDir = path.join(process.cwd(), projectName);
|
|
394
|
-
if (
|
|
438
|
+
if (existsSync2(targetDir)) {
|
|
395
439
|
logger.success(`Next.js: ${projectName} (ya existe)`);
|
|
396
440
|
return;
|
|
397
441
|
}
|
|
@@ -423,14 +467,14 @@ async function scaffoldNextJs(projectName, projectPath) {
|
|
|
423
467
|
// src/steps/copy-template.ts
|
|
424
468
|
import { cp, mkdir, readFile, writeFile } from "fs/promises";
|
|
425
469
|
import path2 from "path";
|
|
426
|
-
import { fileURLToPath
|
|
427
|
-
var
|
|
428
|
-
var
|
|
470
|
+
import { fileURLToPath } from "url";
|
|
471
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
472
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
429
473
|
async function copyTemplate(projectPath) {
|
|
430
474
|
await withSpinner(
|
|
431
475
|
"Copiando template LFT...",
|
|
432
476
|
async () => {
|
|
433
|
-
const templatesDir = path2.join(
|
|
477
|
+
const templatesDir = path2.join(__dirname2, "..", "..", "templates");
|
|
434
478
|
const srcDir = path2.join(projectPath, "src");
|
|
435
479
|
await cp(
|
|
436
480
|
path2.join(templatesDir, "components", "ui"),
|
|
@@ -664,19 +708,19 @@ async function createProject(projectName, options = {}) {
|
|
|
664
708
|
logger.warning('No se encontr\xF3 configuraci\xF3n. Ejecuta "create-lft-app config" primero.');
|
|
665
709
|
throw new Error("Configuraci\xF3n no encontrada");
|
|
666
710
|
}
|
|
667
|
-
const
|
|
711
|
+
const config = await loadConfig();
|
|
668
712
|
logger.newLine();
|
|
669
713
|
logger.title("Resumen de recursos a crear:");
|
|
670
714
|
logger.newLine();
|
|
671
715
|
const resources = [];
|
|
672
716
|
if (!options.skipGithub) {
|
|
673
|
-
resources.push({ label: "GitHub", value: `${
|
|
717
|
+
resources.push({ label: "GitHub", value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });
|
|
674
718
|
}
|
|
675
719
|
if (!options.skipSupabase) {
|
|
676
|
-
resources.push({ label: "Supabase", value: `${projectName} en ${
|
|
720
|
+
resources.push({ label: "Supabase", value: `${projectName} en ${config.defaults.supabaseRegion}` });
|
|
677
721
|
}
|
|
678
722
|
if (!options.skipJira) {
|
|
679
|
-
resources.push({ label: "Jira", value: `Proyecto "${projectName}" en ${
|
|
723
|
+
resources.push({ label: "Jira", value: `Proyecto "${projectName}" en ${config.credentials.jira.domain}` });
|
|
680
724
|
}
|
|
681
725
|
resources.push({ label: "Next.js", value: "App Router + TypeScript + Tailwind + Dashboard" });
|
|
682
726
|
logger.table(resources);
|
|
@@ -699,14 +743,14 @@ async function createProject(projectName, options = {}) {
|
|
|
699
743
|
const externalTasks = [];
|
|
700
744
|
if (!options.skipGithub) {
|
|
701
745
|
externalTasks.push(
|
|
702
|
-
createGitHubRepo(projectName,
|
|
746
|
+
createGitHubRepo(projectName, config).then((url) => {
|
|
703
747
|
urls.github = url;
|
|
704
748
|
})
|
|
705
749
|
);
|
|
706
750
|
}
|
|
707
751
|
if (!options.skipSupabase) {
|
|
708
752
|
externalTasks.push(
|
|
709
|
-
createSupabaseProject(projectName,
|
|
753
|
+
createSupabaseProject(projectName, config).then((result) => {
|
|
710
754
|
urls.supabase = result.url;
|
|
711
755
|
supabaseKeys = result;
|
|
712
756
|
})
|
|
@@ -714,7 +758,7 @@ async function createProject(projectName, options = {}) {
|
|
|
714
758
|
}
|
|
715
759
|
if (!options.skipJira) {
|
|
716
760
|
externalTasks.push(
|
|
717
|
-
createJiraProject(projectName,
|
|
761
|
+
createJiraProject(projectName, config).then((url) => {
|
|
718
762
|
urls.jira = url;
|
|
719
763
|
})
|
|
720
764
|
);
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/config/static-config.ts","../../src/config/index.ts","../../src/services/github.ts","../../src/ui/spinner.ts","../../src/ui/logger.ts","../../src/services/supabase.ts","../../src/utils/validation.ts","../../src/services/jira.ts","../../src/steps/scaffold-nextjs.ts","../../src/steps/copy-template.ts","../../src/steps/install-deps.ts","../../src/steps/create-env.ts","../../src/steps/setup-git.ts","../../src/ui/banner.ts"],"sourcesContent":["import path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport { loadConfig, hasConfig } from './config/index.js';\nimport { createGitHubRepo } from './services/github.js';\nimport { createSupabaseProject } from './services/supabase.js';\nimport { createJiraProject } from './services/jira.js';\nimport { scaffoldNextJs } from './steps/scaffold-nextjs.js';\nimport { copyTemplate } from './steps/copy-template.js';\nimport { installDependencies } from './steps/install-deps.js';\nimport { createEnvFile } from './steps/create-env.js';\nimport { setupGit } from './steps/setup-git.js';\nimport { logger } from './ui/logger.js';\nimport { showSuccessBanner } from './ui/banner.js';\nimport { validateProjectName } from './utils/validation.js';\n\nexport interface CreateProjectOptions {\n skipGithub?: boolean;\n skipSupabase?: boolean;\n skipJira?: boolean;\n skipGit?: boolean;\n autoConfirm?: boolean;\n}\n\nexport async function createProject(\n projectName: string,\n options: CreateProjectOptions = {}\n): Promise<void> {\n // Validar nombre del proyecto\n const validation = validateProjectName(projectName);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // Verificar que el directorio no exista\n const projectPath = path.resolve(process.cwd(), projectName);\n\n // Cargar configuración\n if (!await hasConfig()) {\n logger.warning('No se encontró configuración. Ejecuta \"create-lft-app config\" primero.');\n throw new Error('Configuración no encontrada');\n }\n\n const config = await loadConfig();\n\n // Mostrar resumen\n logger.newLine();\n logger.title('Resumen de recursos a crear:');\n logger.newLine();\n\n const resources = [];\n if (!options.skipGithub) {\n resources.push({ label: 'GitHub', value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });\n }\n if (!options.skipSupabase) {\n resources.push({ label: 'Supabase', value: `${projectName} en ${config.defaults.supabaseRegion}` });\n }\n if (!options.skipJira) {\n resources.push({ label: 'Jira', value: `Proyecto \"${projectName}\" en ${config.credentials.jira.domain}` });\n }\n resources.push({ label: 'Next.js', value: 'App Router + TypeScript + Tailwind + Dashboard' });\n\n logger.table(resources);\n logger.newLine();\n\n // Confirmar\n if (!options.autoConfirm) {\n const shouldContinue = await confirm({\n message: '¿Continuar con la creación?',\n default: true,\n });\n\n if (!shouldContinue) {\n logger.info('Operación cancelada');\n return;\n }\n }\n\n logger.newLine();\n logger.divider();\n logger.newLine();\n\n const urls: { github?: string; supabase?: string; jira?: string } = {};\n let supabaseKeys: { url: string; anonKey: string; serviceKey: string } | undefined;\n\n // Crear recursos externos en paralelo\n const externalTasks: Promise<void>[] = [];\n\n if (!options.skipGithub) {\n externalTasks.push(\n createGitHubRepo(projectName, config).then((url) => {\n urls.github = url;\n })\n );\n }\n\n if (!options.skipSupabase) {\n externalTasks.push(\n createSupabaseProject(projectName, config).then((result) => {\n urls.supabase = result.url;\n supabaseKeys = result;\n })\n );\n }\n\n if (!options.skipJira) {\n externalTasks.push(\n createJiraProject(projectName, config).then((url) => {\n urls.jira = url;\n })\n );\n }\n\n // Esperar a que terminen los recursos externos\n await Promise.all(externalTasks);\n\n // Scaffold Next.js\n await scaffoldNextJs(projectName, projectPath);\n\n // Copiar template\n await copyTemplate(projectPath);\n\n // Instalar dependencias\n await installDependencies(projectPath);\n\n // Crear .env.local\n if (supabaseKeys) {\n await createEnvFile(projectPath, supabaseKeys);\n }\n\n // Setup git\n if (!options.skipGit && urls.github) {\n await setupGit(projectPath, urls.github);\n }\n\n // Mostrar resumen final\n logger.newLine();\n showSuccessBanner(projectName, urls);\n}\n","// ================================================\n// CONFIGURACIÓN - LEE DESDE VARIABLES DE ENTORNO\n// ================================================\nimport { config } from 'dotenv';\nimport { fileURLToPath } from 'url';\nimport { dirname, resolve } from 'path';\n\n// Cargar .env desde el directorio del paquete\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconfig({ path: resolve(__dirname, '../../.env'), quiet: true });\n\nexport const STATIC_CONFIG = {\n github: {\n token: process.env.LFT_GITHUB_TOKEN || '',\n username: process.env.LFT_GITHUB_USERNAME || '',\n org: process.env.LFT_GITHUB_ORG || '',\n },\n supabase: {\n token: process.env.LFT_SUPABASE_TOKEN || '',\n orgId: process.env.LFT_SUPABASE_ORG_ID || '',\n region: process.env.LFT_SUPABASE_REGION || 'us-east-1',\n },\n jira: {\n email: process.env.LFT_JIRA_EMAIL || '',\n token: process.env.LFT_JIRA_TOKEN || '',\n domain: process.env.LFT_JIRA_DOMAIN || '',\n },\n};\n","import { STATIC_CONFIG } from './static-config.js';\n\nexport interface LFTConfig {\n version: string;\n credentials: {\n github: {\n token: string;\n username: string;\n };\n supabase: {\n accessToken: string;\n organizationId: string;\n };\n jira: {\n email: string;\n apiToken: string;\n domain: string;\n };\n };\n defaults: {\n githubOrg?: string;\n supabaseRegion: string;\n jiraProjectType: string;\n };\n}\n\nexport async function loadConfig(): Promise<LFTConfig> {\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: STATIC_CONFIG.github.token,\n username: STATIC_CONFIG.github.username,\n },\n supabase: {\n accessToken: STATIC_CONFIG.supabase.token,\n organizationId: STATIC_CONFIG.supabase.orgId,\n },\n jira: {\n email: STATIC_CONFIG.jira.email,\n apiToken: STATIC_CONFIG.jira.token,\n domain: STATIC_CONFIG.jira.domain,\n },\n },\n defaults: {\n githubOrg: STATIC_CONFIG.github.org || undefined,\n supabaseRegion: STATIC_CONFIG.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n return (\n STATIC_CONFIG.github.token !== '' &&\n STATIC_CONFIG.supabase.token !== '' &&\n STATIC_CONFIG.jira.token !== ''\n );\n}\n","import { Octokit } from 'octokit';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\nexport async function createGitHubRepo(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const octokit = new Octokit({ auth: config.credentials.github.token });\n const org = config.defaults.githubOrg;\n const owner = org || config.credentials.github.username;\n\n // Verificar si el repo ya existe\n try {\n const existing = await octokit.rest.repos.get({\n owner,\n repo: projectName,\n });\n logger.success(`GitHub: ${owner}/${projectName} (ya existe)`);\n return existing.data.html_url;\n } catch {\n // No existe, continuar con la creación\n }\n\n return withSpinner(\n 'Creando repositorio en GitHub...',\n async () => {\n let repo;\n\n if (org) {\n repo = await octokit.rest.repos.createInOrg({\n org,\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n } else {\n repo = await octokit.rest.repos.createForAuthenticatedUser({\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n }\n\n return repo.data.html_url;\n },\n `GitHub: ${owner}/${projectName}`\n );\n}\n\nexport async function validateGitHubToken(token: string): Promise<{ valid: boolean; username?: string }> {\n try {\n const octokit = new Octokit({ auth: token });\n const { data } = await octokit.rest.users.getAuthenticated();\n return { valid: true, username: data.login };\n } catch {\n return { valid: false };\n }\n}\n","import ora, { type Ora } from 'ora';\n\nexport function createSpinner(text: string): Ora {\n return ora({\n text,\n spinner: 'dots',\n });\n}\n\nexport async function withSpinner<T>(\n text: string,\n fn: () => Promise<T>,\n successText?: string\n): Promise<T> {\n const spinner = createSpinner(text).start();\n\n try {\n const result = await fn();\n spinner.succeed(successText || text);\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (message: string) => {\n console.log(chalk.blue('ℹ'), message);\n },\n\n success: (message: string) => {\n console.log(chalk.green('✔'), message);\n },\n\n warning: (message: string) => {\n console.log(chalk.yellow('⚠'), message);\n },\n\n error: (message: string) => {\n console.log(chalk.red('✖'), message);\n },\n\n step: (step: number, total: number, message: string) => {\n console.log(chalk.cyan(`[${step}/${total}]`), message);\n },\n\n newLine: () => {\n console.log();\n },\n\n divider: () => {\n console.log(chalk.gray('─'.repeat(50)));\n },\n\n title: (message: string) => {\n console.log(chalk.bold.white(message));\n },\n\n subtitle: (message: string) => {\n console.log(chalk.gray(message));\n },\n\n link: (label: string, url: string) => {\n console.log(` ${chalk.gray(label + ':')} ${chalk.cyan.underline(url)}`);\n },\n\n list: (items: string[]) => {\n items.forEach((item) => {\n console.log(chalk.gray(' •'), item);\n });\n },\n\n table: (rows: Array<{ label: string; value: string }>) => {\n const maxLabelLength = Math.max(...rows.map((r) => r.label.length));\n rows.forEach(({ label, value }) => {\n const paddedLabel = label.padEnd(maxLabelLength);\n console.log(` ${chalk.gray(paddedLabel)} ${value}`);\n });\n },\n};\n","import { withSpinner, createSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface SupabaseProjectResponse {\n id: string;\n name: string;\n organization_id: string;\n region: string;\n status: string;\n}\n\ninterface SupabaseApiKey {\n name: string;\n api_key: string;\n}\n\nexport interface SupabaseProjectResult {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nconst SUPABASE_API_URL = 'https://api.supabase.com/v1';\n\nasync function waitForProjectReady(\n projectId: string,\n token: string,\n maxAttempts = 60\n): Promise<void> {\n const spinner = createSpinner('Provisionando base de datos (esto puede tomar ~2 minutos)...').start();\n\n for (let i = 0; i < maxAttempts; i++) {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (response.ok) {\n const project = (await response.json()) as SupabaseProjectResponse;\n if (project.status === 'ACTIVE_HEALTHY') {\n spinner.succeed('Base de datos provisionada');\n return;\n }\n }\n\n // Esperar 5 segundos antes del siguiente intento\n await new Promise((resolve) => setTimeout(resolve, 5000));\n spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${((i + 1) * 5) % 60}s)`;\n }\n\n spinner.fail('Timeout esperando a que el proyecto esté listo');\n throw new Error('Timeout: el proyecto de Supabase no se activó a tiempo');\n}\n\nasync function getProjectApiKeys(\n projectId: string,\n token: string\n): Promise<{ anonKey: string; serviceKey: string }> {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}/api-keys`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) {\n throw new Error('No se pudieron obtener las API keys de Supabase');\n }\n\n const keys = (await response.json()) as SupabaseApiKey[];\n\n const anonKey = keys.find((k) => k.name === 'anon')?.api_key;\n const serviceKey = keys.find((k) => k.name === 'service_role')?.api_key;\n\n if (!anonKey || !serviceKey) {\n throw new Error('No se encontraron las API keys necesarias');\n }\n\n return { anonKey, serviceKey };\n}\n\nasync function findExistingProject(\n projectName: string,\n token: string\n): Promise<SupabaseProjectResponse | null> {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) return null;\n\n const projects = (await response.json()) as SupabaseProjectResponse[];\n return projects.find((p) => p.name === projectName) || null;\n}\n\nexport async function createSupabaseProject(\n projectName: string,\n config: LFTConfig\n): Promise<SupabaseProjectResult> {\n const token = config.credentials.supabase.accessToken;\n const orgId = config.credentials.supabase.organizationId;\n const region = config.defaults.supabaseRegion;\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingProject(projectName, token);\n if (existing) {\n logger.success(`Supabase: ${projectName} (ya existe)`);\n const { anonKey, serviceKey } = await getProjectApiKeys(existing.id, token);\n return {\n url: `https://${existing.id}.supabase.co`,\n anonKey,\n serviceKey,\n };\n }\n\n // Generar una contraseña segura para la base de datos\n const dbPassword = generateSecurePassword();\n\n // Crear proyecto\n const project = await withSpinner(\n 'Creando proyecto en Supabase...',\n async () => {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n name: projectName,\n organization_id: orgId,\n region,\n plan: 'free',\n db_pass: dbPassword,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Error creando proyecto Supabase: ${error}`);\n }\n\n return response.json() as Promise<SupabaseProjectResponse>;\n }\n );\n\n // Esperar a que el proyecto esté listo\n await waitForProjectReady(project.id, token);\n\n // Obtener API keys\n const { anonKey, serviceKey } = await getProjectApiKeys(project.id, token);\n\n const projectUrl = `https://${project.id}.supabase.co`;\n\n return {\n url: projectUrl,\n anonKey,\n serviceKey,\n };\n}\n\nfunction generateSecurePassword(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';\n let password = '';\n for (let i = 0; i < 32; i++) {\n password += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return password;\n}\n","export interface ValidationResult {\n valid: boolean;\n error?: string;\n}\n\nexport function validateProjectName(name: string): ValidationResult {\n // Verificar que no esté vacío\n if (!name || name.trim() === '') {\n return { valid: false, error: 'El nombre del proyecto no puede estar vacío' };\n }\n\n // Verificar caracteres válidos (solo letras, números, guiones y guiones bajos)\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n return {\n valid: false,\n error: 'El nombre solo puede contener letras, números, guiones (-) y guiones bajos (_)',\n };\n }\n\n // Verificar que no empiece con guión o número\n if (/^[-_0-9]/.test(name)) {\n return {\n valid: false,\n error: 'El nombre debe empezar con una letra',\n };\n }\n\n // Verificar longitud\n if (name.length < 2) {\n return { valid: false, error: 'El nombre debe tener al menos 2 caracteres' };\n }\n\n if (name.length > 50) {\n return { valid: false, error: 'El nombre no puede tener más de 50 caracteres' };\n }\n\n // No verificamos si el directorio existe porque ahora manejamos recursos existentes\n return { valid: true };\n}\n\nexport function generateJiraKey(projectName: string): string {\n // Generar key de Jira: máximo 10 caracteres, solo mayúsculas\n const cleaned = projectName\n .replace(/[^a-zA-Z0-9]/g, '')\n .toUpperCase()\n .slice(0, 10);\n\n return cleaned || 'PROJ';\n}\n","import { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport { generateJiraKey } from '../utils/validation.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface JiraProjectResponse {\n id: string;\n key: string;\n name: string;\n self: string;\n}\n\nasync function findExistingJiraProject(\n projectName: string,\n auth: string,\n domain: string\n): Promise<JiraProjectResponse | null> {\n const response = await fetch(\n `https://${domain}/rest/api/3/project/search?query=${encodeURIComponent(projectName)}`,\n {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { values: JiraProjectResponse[] };\n return data.values.find((p) => p.name === projectName) || null;\n}\n\nexport async function createJiraProject(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const { email, apiToken, domain } = config.credentials.jira;\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const projectKey = generateJiraKey(projectName);\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingJiraProject(projectName, auth, domain);\n if (existing) {\n logger.success(`Jira: ${existing.key} (ya existe)`);\n return `https://${domain}/browse/${existing.key}`;\n }\n\n return withSpinner(\n 'Creando proyecto en Jira...',\n async () => {\n // Primero obtener el leadAccountId del usuario actual\n const meResponse = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n });\n\n if (!meResponse.ok) {\n throw new Error('No se pudo obtener información del usuario de Jira');\n }\n\n const me = (await meResponse.json()) as { accountId: string };\n\n // Crear el proyecto\n const response = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: projectKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n\n // Si el key ya existe, intentar con un sufijo numérico\n if (error.includes('project key')) {\n const newKey = `${projectKey}${Date.now().toString().slice(-4)}`;\n const retryResponse = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: newKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!retryResponse.ok) {\n throw new Error(`Error creando proyecto Jira: ${await retryResponse.text()}`);\n }\n\n const project = (await retryResponse.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n }\n\n throw new Error(`Error creando proyecto Jira: ${error}`);\n }\n\n const project = (await response.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n },\n `Proyecto Jira: ${projectKey}`\n );\n}\n\nexport async function validateJiraCredentials(\n email: string,\n apiToken: string,\n domain: string\n): Promise<boolean> {\n try {\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const response = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: { Authorization: `Basic ${auth}` },\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { execa } from 'execa';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\n\nexport async function scaffoldNextJs(\n projectName: string,\n projectPath: string\n): Promise<void> {\n const targetDir = path.join(process.cwd(), projectName);\n\n if (existsSync(targetDir)) {\n logger.success(`Next.js: ${projectName} (ya existe)`);\n return;\n }\n\n await withSpinner(\n 'Inicializando proyecto Next.js...',\n async () => {\n await execa('npx', [\n 'create-next-app@latest',\n projectName,\n '--typescript',\n '--tailwind',\n '--eslint',\n '--app',\n '--turbopack',\n '--src-dir',\n '--import-alias', '@/*',\n '--use-npm',\n '--yes',\n ], {\n cwd: process.cwd(),\n stdio: 'pipe',\n });\n },\n `Next.js: ${projectName}`\n );\n}\n","import { cp, mkdir, readFile, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport async function copyTemplate(projectPath: string): Promise<void> {\n await withSpinner(\n 'Copiando template LFT...',\n async () => {\n // Ruta a los templates (relativa al dist)\n const templatesDir = path.join(__dirname, '..', '..', 'templates');\n const srcDir = path.join(projectPath, 'src');\n\n // Copiar componentes UI\n await cp(\n path.join(templatesDir, 'components', 'ui'),\n path.join(srcDir, 'components', 'ui'),\n { recursive: true }\n );\n\n // Copiar componentes de layout\n await cp(\n path.join(templatesDir, 'components', 'layout'),\n path.join(srcDir, 'components', 'layout'),\n { recursive: true }\n );\n\n // Copiar componentes de dashboard\n await cp(\n path.join(templatesDir, 'components', 'dashboard'),\n path.join(srcDir, 'components', 'dashboard'),\n { recursive: true }\n );\n\n // Copiar lib/utils.ts\n await mkdir(path.join(srcDir, 'lib'), { recursive: true });\n await cp(\n path.join(templatesDir, 'lib', 'utils.ts'),\n path.join(srcDir, 'lib', 'utils.ts')\n );\n\n // Copiar hooks\n await mkdir(path.join(srcDir, 'hooks'), { recursive: true });\n await cp(\n path.join(templatesDir, 'hooks'),\n path.join(srcDir, 'hooks'),\n { recursive: true }\n );\n\n // Copiar páginas de app\n await cp(\n path.join(templatesDir, 'app', 'layout.tsx'),\n path.join(srcDir, 'app', 'layout.tsx')\n );\n\n await cp(\n path.join(templatesDir, 'app', 'page.tsx'),\n path.join(srcDir, 'app', 'page.tsx')\n );\n\n // Copiar dashboard page\n await mkdir(path.join(srcDir, 'app', 'dashboard'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'dashboard', 'page.tsx'),\n path.join(srcDir, 'app', 'dashboard', 'page.tsx')\n );\n\n // Copiar auth/login page\n await mkdir(path.join(srcDir, 'app', 'auth', 'login'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'auth', 'login', 'page.tsx'),\n path.join(srcDir, 'app', 'auth', 'login', 'page.tsx')\n );\n\n // Merge globals.css\n await mergeGlobalStyles(projectPath, templatesDir);\n },\n 'Template LFT copiado (47 componentes + páginas)'\n );\n}\n\nasync function mergeGlobalStyles(\n projectPath: string,\n templatesDir: string\n): Promise<void> {\n const templateCssPath = path.join(templatesDir, 'app', 'globals.css');\n const projectCssPath = path.join(projectPath, 'src', 'app', 'globals.css');\n\n try {\n const templateCss = await readFile(templateCssPath, 'utf-8');\n const existingCss = await readFile(projectCssPath, 'utf-8');\n\n // Mantener las directivas de Tailwind del proyecto y agregar custom CSS\n const merged = existingCss + '\\n\\n/* LFT Custom Styles */\\n' + templateCss;\n await writeFile(projectCssPath, merged);\n } catch {\n // Si no existe el template CSS, no hacer nada\n }\n}\n","import { execa } from 'execa';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst TEMPLATE_DEPENDENCIES = [\n // Radix UI primitives\n '@radix-ui/react-accordion',\n '@radix-ui/react-alert-dialog',\n '@radix-ui/react-avatar',\n '@radix-ui/react-checkbox',\n '@radix-ui/react-collapsible',\n '@radix-ui/react-dialog',\n '@radix-ui/react-dropdown-menu',\n '@radix-ui/react-label',\n '@radix-ui/react-popover',\n '@radix-ui/react-progress',\n '@radix-ui/react-radio-group',\n '@radix-ui/react-scroll-area',\n '@radix-ui/react-select',\n '@radix-ui/react-separator',\n '@radix-ui/react-slider',\n '@radix-ui/react-slot',\n '@radix-ui/react-switch',\n '@radix-ui/react-tabs',\n '@radix-ui/react-tooltip',\n\n // UI Utilities\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n\n // Icons\n 'lucide-react',\n\n // Form handling\n 'react-hook-form',\n '@hookform/resolvers',\n\n // Command menu\n 'cmdk',\n\n // Date picker\n 'react-day-picker',\n 'date-fns',\n\n // Toast notifications\n 'sonner',\n\n // Validation\n 'zod',\n\n // Supabase client\n '@supabase/supabase-js',\n '@supabase/ssr',\n];\n\nconst TEMPLATE_DEV_DEPENDENCIES = [\n 'tailwindcss-animate',\n];\n\nexport async function installDependencies(projectPath: string): Promise<void> {\n await withSpinner(\n `Instalando dependencias (${TEMPLATE_DEPENDENCIES.length} paquetes)...`,\n async () => {\n // Instalar dependencias de producción\n await execa('npm', ['install', ...TEMPLATE_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n\n // Instalar dependencias de desarrollo\n await execa('npm', ['install', '-D', ...TEMPLATE_DEV_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n },\n 'Dependencias instaladas'\n );\n}\n","import { writeFile, readFile, appendFile } from 'fs/promises';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\n\ninterface SupabaseKeys {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nexport async function createEnvFile(\n projectPath: string,\n supabaseKeys: SupabaseKeys\n): Promise<void> {\n await withSpinner(\n 'Creando archivo .env.local...',\n async () => {\n const envContent = `# Supabase\nNEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}\nNEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}\nSUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}\n`;\n\n await writeFile(\n path.join(projectPath, '.env.local'),\n envContent\n );\n\n // Asegurar que .env.local esté en .gitignore\n const gitignorePath = path.join(projectPath, '.gitignore');\n try {\n const gitignore = await readFile(gitignorePath, 'utf-8');\n if (!gitignore.includes('.env.local')) {\n await appendFile(gitignorePath, '\\n# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n } catch {\n // Si no existe .gitignore, crearlo\n await writeFile(gitignorePath, '# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n },\n 'Archivo .env.local creado con credenciales de Supabase'\n );\n}\n","import { simpleGit } from 'simple-git';\nimport { withSpinner } from '../ui/spinner.js';\n\nexport async function setupGit(\n projectPath: string,\n remoteUrl: string\n): Promise<void> {\n const git = simpleGit(projectPath);\n\n await withSpinner(\n 'Configurando Git...',\n async () => {\n // Verificar si ya es un repo git\n const isRepo = await git.checkIsRepo();\n\n if (!isRepo) {\n await git.init();\n }\n\n // Agregar remote\n try {\n await git.addRemote('origin', remoteUrl);\n } catch {\n // Remote ya existe, actualizarlo\n await git.remote(['set-url', 'origin', remoteUrl]);\n }\n\n // Stage todos los archivos\n await git.add('.');\n\n // Commit inicial\n await git.commit('Initial commit - created with create-lft-app', {\n '--author': 'create-lft-app <noreply@lft.dev>',\n });\n\n // Renombrar branch a main si es necesario\n try {\n await git.branch(['-M', 'main']);\n } catch {\n // Ya está en main\n }\n\n // Push\n await git.push(['--set-upstream', 'origin', 'main']);\n },\n 'Git configurado y código pusheado'\n );\n}\n","import boxen from 'boxen';\nimport chalk from 'chalk';\n\nexport function showBanner(): void {\n const title = chalk.bold.cyan('create-lft-app');\n const version = chalk.gray('v1.0.0');\n const description = chalk.white('Scaffolding para proyectos LFT');\n\n const banner = boxen(`${title} ${version}\\n${description}`, {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'cyan',\n });\n\n console.log(banner);\n}\n\nexport function showSuccessBanner(projectName: string, urls: {\n github?: string;\n supabase?: string;\n jira?: string;\n}): void {\n const lines = [\n chalk.green.bold(`Proyecto \"${projectName}\" creado exitosamente!`),\n '',\n chalk.white('Directorio:') + ` ./${projectName}`,\n '',\n ];\n\n if (urls.github || urls.supabase || urls.jira) {\n lines.push(chalk.white('Enlaces:'));\n if (urls.github) {\n lines.push(` ${chalk.gray('GitHub:')} ${chalk.cyan(urls.github)}`);\n }\n if (urls.supabase) {\n lines.push(` ${chalk.gray('Supabase:')} ${chalk.cyan(urls.supabase)}`);\n }\n if (urls.jira) {\n lines.push(` ${chalk.gray('Jira:')} ${chalk.cyan(urls.jira)}`);\n }\n lines.push('');\n }\n\n lines.push(chalk.white('Siguiente pasos:'));\n lines.push(` ${chalk.cyan('cd')} ${projectName}`);\n lines.push(` ${chalk.cyan('npm run dev')}`);\n\n const banner = boxen(lines.join('\\n'), {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'green',\n });\n\n console.log(banner);\n}\n"],"mappings":"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","names":["path","config","resolve","config","anonKey","serviceKey","config","project","path","fileURLToPath","__filename","fileURLToPath","__dirname","path","execa","execa","writeFile","readFile","path","writeFile","path","readFile","chalk","chalk","path","config"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../src/config/static-config.ts","../../src/config/index.ts","../../src/services/github.ts","../../src/ui/spinner.ts","../../src/ui/logger.ts","../../src/services/supabase.ts","../../src/utils/validation.ts","../../src/services/jira.ts","../../src/steps/scaffold-nextjs.ts","../../src/steps/copy-template.ts","../../src/steps/install-deps.ts","../../src/steps/create-env.ts","../../src/steps/setup-git.ts","../../src/ui/banner.ts"],"sourcesContent":["import path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport { loadConfig, hasConfig } from './config/index.js';\nimport { createGitHubRepo } from './services/github.js';\nimport { createSupabaseProject } from './services/supabase.js';\nimport { createJiraProject } from './services/jira.js';\nimport { scaffoldNextJs } from './steps/scaffold-nextjs.js';\nimport { copyTemplate } from './steps/copy-template.js';\nimport { installDependencies } from './steps/install-deps.js';\nimport { createEnvFile } from './steps/create-env.js';\nimport { setupGit } from './steps/setup-git.js';\nimport { logger } from './ui/logger.js';\nimport { showSuccessBanner } from './ui/banner.js';\nimport { validateProjectName } from './utils/validation.js';\n\nexport interface CreateProjectOptions {\n skipGithub?: boolean;\n skipSupabase?: boolean;\n skipJira?: boolean;\n skipGit?: boolean;\n autoConfirm?: boolean;\n}\n\nexport async function createProject(\n projectName: string,\n options: CreateProjectOptions = {}\n): Promise<void> {\n // Validar nombre del proyecto\n const validation = validateProjectName(projectName);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // Verificar que el directorio no exista\n const projectPath = path.resolve(process.cwd(), projectName);\n\n // Cargar configuración\n if (!await hasConfig()) {\n logger.warning('No se encontró configuración. Ejecuta \"create-lft-app config\" primero.');\n throw new Error('Configuración no encontrada');\n }\n\n const config = await loadConfig();\n\n // Mostrar resumen\n logger.newLine();\n logger.title('Resumen de recursos a crear:');\n logger.newLine();\n\n const resources = [];\n if (!options.skipGithub) {\n resources.push({ label: 'GitHub', value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });\n }\n if (!options.skipSupabase) {\n resources.push({ label: 'Supabase', value: `${projectName} en ${config.defaults.supabaseRegion}` });\n }\n if (!options.skipJira) {\n resources.push({ label: 'Jira', value: `Proyecto \"${projectName}\" en ${config.credentials.jira.domain}` });\n }\n resources.push({ label: 'Next.js', value: 'App Router + TypeScript + Tailwind + Dashboard' });\n\n logger.table(resources);\n logger.newLine();\n\n // Confirmar\n if (!options.autoConfirm) {\n const shouldContinue = await confirm({\n message: '¿Continuar con la creación?',\n default: true,\n });\n\n if (!shouldContinue) {\n logger.info('Operación cancelada');\n return;\n }\n }\n\n logger.newLine();\n logger.divider();\n logger.newLine();\n\n const urls: { github?: string; supabase?: string; jira?: string } = {};\n let supabaseKeys: { url: string; anonKey: string; serviceKey: string } | undefined;\n\n // Crear recursos externos en paralelo\n const externalTasks: Promise<void>[] = [];\n\n if (!options.skipGithub) {\n externalTasks.push(\n createGitHubRepo(projectName, config).then((url) => {\n urls.github = url;\n })\n );\n }\n\n if (!options.skipSupabase) {\n externalTasks.push(\n createSupabaseProject(projectName, config).then((result) => {\n urls.supabase = result.url;\n supabaseKeys = result;\n })\n );\n }\n\n if (!options.skipJira) {\n externalTasks.push(\n createJiraProject(projectName, config).then((url) => {\n urls.jira = url;\n })\n );\n }\n\n // Esperar a que terminen los recursos externos\n await Promise.all(externalTasks);\n\n // Scaffold Next.js\n await scaffoldNextJs(projectName, projectPath);\n\n // Copiar template\n await copyTemplate(projectPath);\n\n // Instalar dependencias\n await installDependencies(projectPath);\n\n // Crear .env.local\n if (supabaseKeys) {\n await createEnvFile(projectPath, supabaseKeys);\n }\n\n // Setup git\n if (!options.skipGit && urls.github) {\n await setupGit(projectPath, urls.github);\n }\n\n // Mostrar resumen final\n logger.newLine();\n showSuccessBanner(projectName, urls);\n}\n","// ================================================\n// CONFIGURACIÓN EN RUNTIME - Lee desde archivo JSON\n// ================================================\n\nimport { existsSync, readFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\n// Ruta por defecto del archivo de credenciales\nconst DEFAULT_CONFIG_PATH = join(homedir(), '.lft-credentials.json');\n\n// Variable para almacenar la ruta del config (puede ser sobreescrita por --config)\nlet configFilePath: string = DEFAULT_CONFIG_PATH;\n\nexport interface StaticConfigType {\n github: {\n token: string;\n username: string;\n org: string;\n };\n supabase: {\n token: string;\n orgId: string;\n region: string;\n };\n jira: {\n email: string;\n token: string;\n domain: string;\n };\n}\n\n// Configuración vacía por defecto\nconst EMPTY_CONFIG: StaticConfigType = {\n github: {\n token: '',\n username: '',\n org: '',\n },\n supabase: {\n token: '',\n orgId: '',\n region: 'us-east-1',\n },\n jira: {\n email: '',\n token: '',\n domain: '',\n },\n};\n\n// Cache de la configuración cargada\nlet loadedConfig: StaticConfigType | null = null;\n\n/**\n * Establece la ruta del archivo de configuración\n */\nexport function setConfigPath(path: string): void {\n configFilePath = path;\n loadedConfig = null; // Invalidar cache\n}\n\n/**\n * Obtiene la ruta actual del archivo de configuración\n */\nexport function getConfigPath(): string {\n return configFilePath;\n}\n\n/**\n * Verifica si el archivo de configuración existe\n */\nexport function configFileExists(): boolean {\n return existsSync(configFilePath);\n}\n\n/**\n * Carga la configuración desde el archivo JSON\n */\nfunction loadConfigFromFile(): StaticConfigType {\n if (loadedConfig) {\n return loadedConfig;\n }\n\n if (!existsSync(configFilePath)) {\n return EMPTY_CONFIG;\n }\n\n try {\n const content = readFileSync(configFilePath, 'utf-8');\n const parsed = JSON.parse(content);\n\n // Validar estructura básica\n loadedConfig = {\n github: {\n token: parsed.github?.token || '',\n username: parsed.github?.username || '',\n org: parsed.github?.org || '',\n },\n supabase: {\n token: parsed.supabase?.token || '',\n orgId: parsed.supabase?.orgId || '',\n region: parsed.supabase?.region || 'us-east-1',\n },\n jira: {\n email: parsed.jira?.email || '',\n token: parsed.jira?.token || '',\n domain: parsed.jira?.domain || '',\n },\n };\n\n return loadedConfig;\n } catch {\n return EMPTY_CONFIG;\n }\n}\n\n// Exportar como getter para que siempre lea la configuración actual\nexport const STATIC_CONFIG: StaticConfigType = new Proxy(EMPTY_CONFIG, {\n get(_target, prop: keyof StaticConfigType) {\n const config = loadConfigFromFile();\n return config[prop];\n },\n});","import { STATIC_CONFIG, configFileExists, getConfigPath, setConfigPath } from './static-config.js';\n\nexport { setConfigPath, getConfigPath } from './static-config.js';\n\nexport interface LFTConfig {\n version: string;\n credentials: {\n github: {\n token: string;\n username: string;\n };\n supabase: {\n accessToken: string;\n organizationId: string;\n };\n jira: {\n email: string;\n apiToken: string;\n domain: string;\n };\n };\n defaults: {\n githubOrg?: string;\n supabaseRegion: string;\n jiraProjectType: string;\n };\n}\n\nexport async function loadConfig(): Promise<LFTConfig> {\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: STATIC_CONFIG.github.token,\n username: STATIC_CONFIG.github.username,\n },\n supabase: {\n accessToken: STATIC_CONFIG.supabase.token,\n organizationId: STATIC_CONFIG.supabase.orgId,\n },\n jira: {\n email: STATIC_CONFIG.jira.email,\n apiToken: STATIC_CONFIG.jira.token,\n domain: STATIC_CONFIG.jira.domain,\n },\n },\n defaults: {\n githubOrg: STATIC_CONFIG.github.org || undefined,\n supabaseRegion: STATIC_CONFIG.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n if (!configFileExists()) {\n return false;\n }\n\n // Verificar que las credenciales no estén vacías\n return (\n STATIC_CONFIG.github.token !== '' &&\n STATIC_CONFIG.supabase.token !== '' &&\n STATIC_CONFIG.jira.token !== ''\n );\n}\n","import { Octokit } from 'octokit';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\nexport async function createGitHubRepo(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const octokit = new Octokit({ auth: config.credentials.github.token });\n const org = config.defaults.githubOrg;\n const owner = org || config.credentials.github.username;\n\n // Verificar si el repo ya existe\n try {\n const existing = await octokit.rest.repos.get({\n owner,\n repo: projectName,\n });\n logger.success(`GitHub: ${owner}/${projectName} (ya existe)`);\n return existing.data.html_url;\n } catch {\n // No existe, continuar con la creación\n }\n\n return withSpinner(\n 'Creando repositorio en GitHub...',\n async () => {\n let repo;\n\n if (org) {\n repo = await octokit.rest.repos.createInOrg({\n org,\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n } else {\n repo = await octokit.rest.repos.createForAuthenticatedUser({\n name: projectName,\n private: true,\n auto_init: false,\n description: `Proyecto ${projectName} creado con create-lft-app`,\n });\n }\n\n return repo.data.html_url;\n },\n `GitHub: ${owner}/${projectName}`\n );\n}\n\nexport async function validateGitHubToken(token: string): Promise<{ valid: boolean; username?: string }> {\n try {\n const octokit = new Octokit({ auth: token });\n const { data } = await octokit.rest.users.getAuthenticated();\n return { valid: true, username: data.login };\n } catch {\n return { valid: false };\n }\n}\n","import ora, { type Ora } from 'ora';\n\nexport function createSpinner(text: string): Ora {\n return ora({\n text,\n spinner: 'dots',\n });\n}\n\nexport async function withSpinner<T>(\n text: string,\n fn: () => Promise<T>,\n successText?: string\n): Promise<T> {\n const spinner = createSpinner(text).start();\n\n try {\n const result = await fn();\n spinner.succeed(successText || text);\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (message: string) => {\n console.log(chalk.blue('ℹ'), message);\n },\n\n success: (message: string) => {\n console.log(chalk.green('✔'), message);\n },\n\n warning: (message: string) => {\n console.log(chalk.yellow('⚠'), message);\n },\n\n error: (message: string) => {\n console.log(chalk.red('✖'), message);\n },\n\n step: (step: number, total: number, message: string) => {\n console.log(chalk.cyan(`[${step}/${total}]`), message);\n },\n\n newLine: () => {\n console.log();\n },\n\n divider: () => {\n console.log(chalk.gray('─'.repeat(50)));\n },\n\n title: (message: string) => {\n console.log(chalk.bold.white(message));\n },\n\n subtitle: (message: string) => {\n console.log(chalk.gray(message));\n },\n\n link: (label: string, url: string) => {\n console.log(` ${chalk.gray(label + ':')} ${chalk.cyan.underline(url)}`);\n },\n\n list: (items: string[]) => {\n items.forEach((item) => {\n console.log(chalk.gray(' •'), item);\n });\n },\n\n table: (rows: Array<{ label: string; value: string }>) => {\n const maxLabelLength = Math.max(...rows.map((r) => r.label.length));\n rows.forEach(({ label, value }) => {\n const paddedLabel = label.padEnd(maxLabelLength);\n console.log(` ${chalk.gray(paddedLabel)} ${value}`);\n });\n },\n};\n","import { withSpinner, createSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface SupabaseProjectResponse {\n id: string;\n name: string;\n organization_id: string;\n region: string;\n status: string;\n}\n\ninterface SupabaseApiKey {\n name: string;\n api_key: string;\n}\n\nexport interface SupabaseProjectResult {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nconst SUPABASE_API_URL = 'https://api.supabase.com/v1';\n\nasync function waitForProjectReady(\n projectId: string,\n token: string,\n maxAttempts = 60\n): Promise<void> {\n const spinner = createSpinner('Provisionando base de datos (esto puede tomar ~2 minutos)...').start();\n\n for (let i = 0; i < maxAttempts; i++) {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (response.ok) {\n const project = (await response.json()) as SupabaseProjectResponse;\n if (project.status === 'ACTIVE_HEALTHY') {\n spinner.succeed('Base de datos provisionada');\n return;\n }\n }\n\n // Esperar 5 segundos antes del siguiente intento\n await new Promise((resolve) => setTimeout(resolve, 5000));\n spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${((i + 1) * 5) % 60}s)`;\n }\n\n spinner.fail('Timeout esperando a que el proyecto esté listo');\n throw new Error('Timeout: el proyecto de Supabase no se activó a tiempo');\n}\n\nasync function getProjectApiKeys(\n projectId: string,\n token: string\n): Promise<{ anonKey: string; serviceKey: string }> {\n const response = await fetch(`${SUPABASE_API_URL}/projects/${projectId}/api-keys`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) {\n throw new Error('No se pudieron obtener las API keys de Supabase');\n }\n\n const keys = (await response.json()) as SupabaseApiKey[];\n\n const anonKey = keys.find((k) => k.name === 'anon')?.api_key;\n const serviceKey = keys.find((k) => k.name === 'service_role')?.api_key;\n\n if (!anonKey || !serviceKey) {\n throw new Error('No se encontraron las API keys necesarias');\n }\n\n return { anonKey, serviceKey };\n}\n\nasync function findExistingProject(\n projectName: string,\n token: string\n): Promise<SupabaseProjectResponse | null> {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) return null;\n\n const projects = (await response.json()) as SupabaseProjectResponse[];\n return projects.find((p) => p.name === projectName) || null;\n}\n\nexport async function createSupabaseProject(\n projectName: string,\n config: LFTConfig\n): Promise<SupabaseProjectResult> {\n const token = config.credentials.supabase.accessToken;\n const orgId = config.credentials.supabase.organizationId;\n const region = config.defaults.supabaseRegion;\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingProject(projectName, token);\n if (existing) {\n logger.success(`Supabase: ${projectName} (ya existe)`);\n const { anonKey, serviceKey } = await getProjectApiKeys(existing.id, token);\n return {\n url: `https://${existing.id}.supabase.co`,\n anonKey,\n serviceKey,\n };\n }\n\n // Generar una contraseña segura para la base de datos\n const dbPassword = generateSecurePassword();\n\n // Crear proyecto\n const project = await withSpinner(\n 'Creando proyecto en Supabase...',\n async () => {\n const response = await fetch(`${SUPABASE_API_URL}/projects`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n name: projectName,\n organization_id: orgId,\n region,\n plan: 'free',\n db_pass: dbPassword,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Error creando proyecto Supabase: ${error}`);\n }\n\n return response.json() as Promise<SupabaseProjectResponse>;\n }\n );\n\n // Esperar a que el proyecto esté listo\n await waitForProjectReady(project.id, token);\n\n // Obtener API keys\n const { anonKey, serviceKey } = await getProjectApiKeys(project.id, token);\n\n const projectUrl = `https://${project.id}.supabase.co`;\n\n return {\n url: projectUrl,\n anonKey,\n serviceKey,\n };\n}\n\nfunction generateSecurePassword(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';\n let password = '';\n for (let i = 0; i < 32; i++) {\n password += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return password;\n}\n","export interface ValidationResult {\n valid: boolean;\n error?: string;\n}\n\nexport function validateProjectName(name: string): ValidationResult {\n // Verificar que no esté vacío\n if (!name || name.trim() === '') {\n return { valid: false, error: 'El nombre del proyecto no puede estar vacío' };\n }\n\n // Verificar caracteres válidos (solo letras, números, guiones y guiones bajos)\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n return {\n valid: false,\n error: 'El nombre solo puede contener letras, números, guiones (-) y guiones bajos (_)',\n };\n }\n\n // Verificar que no empiece con guión o número\n if (/^[-_0-9]/.test(name)) {\n return {\n valid: false,\n error: 'El nombre debe empezar con una letra',\n };\n }\n\n // Verificar longitud\n if (name.length < 2) {\n return { valid: false, error: 'El nombre debe tener al menos 2 caracteres' };\n }\n\n if (name.length > 50) {\n return { valid: false, error: 'El nombre no puede tener más de 50 caracteres' };\n }\n\n // No verificamos si el directorio existe porque ahora manejamos recursos existentes\n return { valid: true };\n}\n\nexport function generateJiraKey(projectName: string): string {\n // Generar key de Jira: máximo 10 caracteres, solo mayúsculas\n const cleaned = projectName\n .replace(/[^a-zA-Z0-9]/g, '')\n .toUpperCase()\n .slice(0, 10);\n\n return cleaned || 'PROJ';\n}\n","import { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\nimport { generateJiraKey } from '../utils/validation.js';\nimport type { LFTConfig } from '../config/index.js';\n\ninterface JiraProjectResponse {\n id: string;\n key: string;\n name: string;\n self: string;\n}\n\nasync function findExistingJiraProject(\n projectName: string,\n auth: string,\n domain: string\n): Promise<JiraProjectResponse | null> {\n const response = await fetch(\n `https://${domain}/rest/api/3/project/search?query=${encodeURIComponent(projectName)}`,\n {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { values: JiraProjectResponse[] };\n return data.values.find((p) => p.name === projectName) || null;\n}\n\nexport async function createJiraProject(\n projectName: string,\n config: LFTConfig\n): Promise<string> {\n const { email, apiToken, domain } = config.credentials.jira;\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const projectKey = generateJiraKey(projectName);\n\n // Verificar si ya existe un proyecto con ese nombre\n const existing = await findExistingJiraProject(projectName, auth, domain);\n if (existing) {\n logger.success(`Jira: ${existing.key} (ya existe)`);\n return `https://${domain}/browse/${existing.key}`;\n }\n\n return withSpinner(\n 'Creando proyecto en Jira...',\n async () => {\n // Primero obtener el leadAccountId del usuario actual\n const meResponse = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n });\n\n if (!meResponse.ok) {\n throw new Error('No se pudo obtener información del usuario de Jira');\n }\n\n const me = (await meResponse.json()) as { accountId: string };\n\n // Crear el proyecto\n const response = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: projectKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n\n // Si el key ya existe, intentar con un sufijo numérico\n if (error.includes('project key')) {\n const newKey = `${projectKey}${Date.now().toString().slice(-4)}`;\n const retryResponse = await fetch(`https://${domain}/rest/api/3/project`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: newKey,\n name: projectName,\n projectTypeKey: 'software',\n projectTemplateKey: 'com.pyxis.greenhopper.jira:gh-simplified-agility-scrum',\n leadAccountId: me.accountId,\n }),\n });\n\n if (!retryResponse.ok) {\n throw new Error(`Error creando proyecto Jira: ${await retryResponse.text()}`);\n }\n\n const project = (await retryResponse.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n }\n\n throw new Error(`Error creando proyecto Jira: ${error}`);\n }\n\n const project = (await response.json()) as JiraProjectResponse;\n return `https://${domain}/browse/${project.key}`;\n },\n `Proyecto Jira: ${projectKey}`\n );\n}\n\nexport async function validateJiraCredentials(\n email: string,\n apiToken: string,\n domain: string\n): Promise<boolean> {\n try {\n const auth = Buffer.from(`${email}:${apiToken}`).toString('base64');\n const response = await fetch(`https://${domain}/rest/api/3/myself`, {\n headers: { Authorization: `Basic ${auth}` },\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n","import { execa } from 'execa';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\nimport { logger } from '../ui/logger.js';\n\nexport async function scaffoldNextJs(\n projectName: string,\n projectPath: string\n): Promise<void> {\n const targetDir = path.join(process.cwd(), projectName);\n\n if (existsSync(targetDir)) {\n logger.success(`Next.js: ${projectName} (ya existe)`);\n return;\n }\n\n await withSpinner(\n 'Inicializando proyecto Next.js...',\n async () => {\n await execa('npx', [\n 'create-next-app@latest',\n projectName,\n '--typescript',\n '--tailwind',\n '--eslint',\n '--app',\n '--turbopack',\n '--src-dir',\n '--import-alias', '@/*',\n '--use-npm',\n '--yes',\n ], {\n cwd: process.cwd(),\n stdio: 'pipe',\n });\n },\n `Next.js: ${projectName}`\n );\n}\n","import { cp, mkdir, readFile, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport async function copyTemplate(projectPath: string): Promise<void> {\n await withSpinner(\n 'Copiando template LFT...',\n async () => {\n // Ruta a los templates (relativa al dist)\n const templatesDir = path.join(__dirname, '..', '..', 'templates');\n const srcDir = path.join(projectPath, 'src');\n\n // Copiar componentes UI\n await cp(\n path.join(templatesDir, 'components', 'ui'),\n path.join(srcDir, 'components', 'ui'),\n { recursive: true }\n );\n\n // Copiar componentes de layout\n await cp(\n path.join(templatesDir, 'components', 'layout'),\n path.join(srcDir, 'components', 'layout'),\n { recursive: true }\n );\n\n // Copiar componentes de dashboard\n await cp(\n path.join(templatesDir, 'components', 'dashboard'),\n path.join(srcDir, 'components', 'dashboard'),\n { recursive: true }\n );\n\n // Copiar lib/utils.ts\n await mkdir(path.join(srcDir, 'lib'), { recursive: true });\n await cp(\n path.join(templatesDir, 'lib', 'utils.ts'),\n path.join(srcDir, 'lib', 'utils.ts')\n );\n\n // Copiar hooks\n await mkdir(path.join(srcDir, 'hooks'), { recursive: true });\n await cp(\n path.join(templatesDir, 'hooks'),\n path.join(srcDir, 'hooks'),\n { recursive: true }\n );\n\n // Copiar páginas de app\n await cp(\n path.join(templatesDir, 'app', 'layout.tsx'),\n path.join(srcDir, 'app', 'layout.tsx')\n );\n\n await cp(\n path.join(templatesDir, 'app', 'page.tsx'),\n path.join(srcDir, 'app', 'page.tsx')\n );\n\n // Copiar dashboard page\n await mkdir(path.join(srcDir, 'app', 'dashboard'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'dashboard', 'page.tsx'),\n path.join(srcDir, 'app', 'dashboard', 'page.tsx')\n );\n\n // Copiar auth/login page\n await mkdir(path.join(srcDir, 'app', 'auth', 'login'), { recursive: true });\n await cp(\n path.join(templatesDir, 'app', 'auth', 'login', 'page.tsx'),\n path.join(srcDir, 'app', 'auth', 'login', 'page.tsx')\n );\n\n // Merge globals.css\n await mergeGlobalStyles(projectPath, templatesDir);\n },\n 'Template LFT copiado (47 componentes + páginas)'\n );\n}\n\nasync function mergeGlobalStyles(\n projectPath: string,\n templatesDir: string\n): Promise<void> {\n const templateCssPath = path.join(templatesDir, 'app', 'globals.css');\n const projectCssPath = path.join(projectPath, 'src', 'app', 'globals.css');\n\n try {\n const templateCss = await readFile(templateCssPath, 'utf-8');\n const existingCss = await readFile(projectCssPath, 'utf-8');\n\n // Mantener las directivas de Tailwind del proyecto y agregar custom CSS\n const merged = existingCss + '\\n\\n/* LFT Custom Styles */\\n' + templateCss;\n await writeFile(projectCssPath, merged);\n } catch {\n // Si no existe el template CSS, no hacer nada\n }\n}\n","import { execa } from 'execa';\nimport { withSpinner } from '../ui/spinner.js';\n\nconst TEMPLATE_DEPENDENCIES = [\n // Radix UI primitives\n '@radix-ui/react-accordion',\n '@radix-ui/react-alert-dialog',\n '@radix-ui/react-avatar',\n '@radix-ui/react-checkbox',\n '@radix-ui/react-collapsible',\n '@radix-ui/react-dialog',\n '@radix-ui/react-dropdown-menu',\n '@radix-ui/react-label',\n '@radix-ui/react-popover',\n '@radix-ui/react-progress',\n '@radix-ui/react-radio-group',\n '@radix-ui/react-scroll-area',\n '@radix-ui/react-select',\n '@radix-ui/react-separator',\n '@radix-ui/react-slider',\n '@radix-ui/react-slot',\n '@radix-ui/react-switch',\n '@radix-ui/react-tabs',\n '@radix-ui/react-tooltip',\n\n // UI Utilities\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n\n // Icons\n 'lucide-react',\n\n // Form handling\n 'react-hook-form',\n '@hookform/resolvers',\n\n // Command menu\n 'cmdk',\n\n // Date picker\n 'react-day-picker',\n 'date-fns',\n\n // Toast notifications\n 'sonner',\n\n // Validation\n 'zod',\n\n // Supabase client\n '@supabase/supabase-js',\n '@supabase/ssr',\n];\n\nconst TEMPLATE_DEV_DEPENDENCIES = [\n 'tailwindcss-animate',\n];\n\nexport async function installDependencies(projectPath: string): Promise<void> {\n await withSpinner(\n `Instalando dependencias (${TEMPLATE_DEPENDENCIES.length} paquetes)...`,\n async () => {\n // Instalar dependencias de producción\n await execa('npm', ['install', ...TEMPLATE_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n\n // Instalar dependencias de desarrollo\n await execa('npm', ['install', '-D', ...TEMPLATE_DEV_DEPENDENCIES], {\n cwd: projectPath,\n stdio: 'pipe',\n });\n },\n 'Dependencias instaladas'\n );\n}\n","import { writeFile, readFile, appendFile } from 'fs/promises';\nimport path from 'path';\nimport { withSpinner } from '../ui/spinner.js';\n\ninterface SupabaseKeys {\n url: string;\n anonKey: string;\n serviceKey: string;\n}\n\nexport async function createEnvFile(\n projectPath: string,\n supabaseKeys: SupabaseKeys\n): Promise<void> {\n await withSpinner(\n 'Creando archivo .env.local...',\n async () => {\n const envContent = `# Supabase\nNEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}\nNEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}\nSUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}\n`;\n\n await writeFile(\n path.join(projectPath, '.env.local'),\n envContent\n );\n\n // Asegurar que .env.local esté en .gitignore\n const gitignorePath = path.join(projectPath, '.gitignore');\n try {\n const gitignore = await readFile(gitignorePath, 'utf-8');\n if (!gitignore.includes('.env.local')) {\n await appendFile(gitignorePath, '\\n# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n } catch {\n // Si no existe .gitignore, crearlo\n await writeFile(gitignorePath, '# Environment variables\\n.env.local\\n.env*.local\\n');\n }\n },\n 'Archivo .env.local creado con credenciales de Supabase'\n );\n}\n","import { simpleGit } from 'simple-git';\nimport { withSpinner } from '../ui/spinner.js';\n\nexport async function setupGit(\n projectPath: string,\n remoteUrl: string\n): Promise<void> {\n const git = simpleGit(projectPath);\n\n await withSpinner(\n 'Configurando Git...',\n async () => {\n // Verificar si ya es un repo git\n const isRepo = await git.checkIsRepo();\n\n if (!isRepo) {\n await git.init();\n }\n\n // Agregar remote\n try {\n await git.addRemote('origin', remoteUrl);\n } catch {\n // Remote ya existe, actualizarlo\n await git.remote(['set-url', 'origin', remoteUrl]);\n }\n\n // Stage todos los archivos\n await git.add('.');\n\n // Commit inicial\n await git.commit('Initial commit - created with create-lft-app', {\n '--author': 'create-lft-app <noreply@lft.dev>',\n });\n\n // Renombrar branch a main si es necesario\n try {\n await git.branch(['-M', 'main']);\n } catch {\n // Ya está en main\n }\n\n // Push\n await git.push(['--set-upstream', 'origin', 'main']);\n },\n 'Git configurado y código pusheado'\n );\n}\n","import boxen from 'boxen';\nimport chalk from 'chalk';\n\nexport function showBanner(): void {\n const title = chalk.bold.cyan('create-lft-app');\n const version = chalk.gray('v1.0.0');\n const description = chalk.white('Scaffolding para proyectos LFT');\n\n const banner = boxen(`${title} ${version}\\n${description}`, {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'cyan',\n });\n\n console.log(banner);\n}\n\nexport function showSuccessBanner(projectName: string, urls: {\n github?: string;\n supabase?: string;\n jira?: string;\n}): void {\n const lines = [\n chalk.green.bold(`Proyecto \"${projectName}\" creado exitosamente!`),\n '',\n chalk.white('Directorio:') + ` ./${projectName}`,\n '',\n ];\n\n if (urls.github || urls.supabase || urls.jira) {\n lines.push(chalk.white('Enlaces:'));\n if (urls.github) {\n lines.push(` ${chalk.gray('GitHub:')} ${chalk.cyan(urls.github)}`);\n }\n if (urls.supabase) {\n lines.push(` ${chalk.gray('Supabase:')} ${chalk.cyan(urls.supabase)}`);\n }\n if (urls.jira) {\n lines.push(` ${chalk.gray('Jira:')} ${chalk.cyan(urls.jira)}`);\n }\n lines.push('');\n }\n\n lines.push(chalk.white('Siguiente pasos:'));\n lines.push(` ${chalk.cyan('cd')} ${projectName}`);\n lines.push(` ${chalk.cyan('npm run dev')}`);\n\n const banner = boxen(lines.join('\\n'), {\n padding: 1,\n margin: 1,\n borderStyle: 'round',\n borderColor: 'green',\n });\n\n console.log(banner);\n}\n"],"mappings":"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","names":["path","anonKey","serviceKey","project","existsSync","existsSync","path","__filename","__dirname","path","execa","execa","writeFile","readFile","path","writeFile","path","readFile","chalk","chalk","path"]}
|