@create-lft-app/cli 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/cli.js CHANGED
@@ -1,20 +1,89 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // bin/cli.ts
4
- import "dotenv/config";
5
4
  import { program } from "commander";
6
5
 
7
6
  // src/index.ts
8
- import path5 from "path";
9
- import { confirm as confirm2 } from "@inquirer/prompts";
7
+ import path4 from "path";
8
+ import { confirm } from "@inquirer/prompts";
9
+
10
+ // src/config/static-config.ts
11
+ import { config } from "dotenv";
12
+ import { fileURLToPath } from "url";
13
+ import { dirname, resolve } from "path";
14
+ var __filename = fileURLToPath(import.meta.url);
15
+ var __dirname = dirname(__filename);
16
+ config({ path: resolve(__dirname, "../../.env"), quiet: true });
17
+ var STATIC_CONFIG = {
18
+ github: {
19
+ token: process.env.LFT_GITHUB_TOKEN || "",
20
+ username: process.env.LFT_GITHUB_USERNAME || "",
21
+ org: process.env.LFT_GITHUB_ORG || ""
22
+ },
23
+ supabase: {
24
+ token: process.env.LFT_SUPABASE_TOKEN || "",
25
+ orgId: process.env.LFT_SUPABASE_ORG_ID || "",
26
+ region: process.env.LFT_SUPABASE_REGION || "us-east-1"
27
+ },
28
+ jira: {
29
+ email: process.env.LFT_JIRA_EMAIL || "",
30
+ token: process.env.LFT_JIRA_TOKEN || "",
31
+ domain: process.env.LFT_JIRA_DOMAIN || ""
32
+ }
33
+ };
10
34
 
11
35
  // src/config/index.ts
12
- import fs from "fs/promises";
13
- import path from "path";
14
- import os from "os";
15
- import { createCipheriv, createDecipheriv, randomBytes, createHash } from "crypto";
16
- import nodeMachineId from "node-machine-id";
17
- import { input, password, select, confirm } from "@inquirer/prompts";
36
+ async function loadConfig() {
37
+ return {
38
+ version: "1.0.0",
39
+ credentials: {
40
+ github: {
41
+ token: STATIC_CONFIG.github.token,
42
+ username: STATIC_CONFIG.github.username
43
+ },
44
+ supabase: {
45
+ accessToken: STATIC_CONFIG.supabase.token,
46
+ organizationId: STATIC_CONFIG.supabase.orgId
47
+ },
48
+ jira: {
49
+ email: STATIC_CONFIG.jira.email,
50
+ apiToken: STATIC_CONFIG.jira.token,
51
+ domain: STATIC_CONFIG.jira.domain
52
+ }
53
+ },
54
+ defaults: {
55
+ githubOrg: STATIC_CONFIG.github.org || void 0,
56
+ supabaseRegion: STATIC_CONFIG.supabase.region,
57
+ jiraProjectType: "software"
58
+ }
59
+ };
60
+ }
61
+ async function hasConfig() {
62
+ return STATIC_CONFIG.github.token !== "" && STATIC_CONFIG.supabase.token !== "" && STATIC_CONFIG.jira.token !== "";
63
+ }
64
+
65
+ // src/services/github.ts
66
+ import { Octokit } from "octokit";
67
+
68
+ // src/ui/spinner.ts
69
+ import ora from "ora";
70
+ function createSpinner(text) {
71
+ return ora({
72
+ text,
73
+ spinner: "dots"
74
+ });
75
+ }
76
+ async function withSpinner(text, fn, successText) {
77
+ const spinner = createSpinner(text).start();
78
+ try {
79
+ const result = await fn();
80
+ spinner.succeed(successText || text);
81
+ return result;
82
+ } catch (error) {
83
+ spinner.fail();
84
+ throw error;
85
+ }
86
+ }
18
87
 
19
88
  // src/ui/logger.ts
20
89
  import chalk from "chalk";
@@ -63,324 +132,20 @@ var logger = {
63
132
  }
64
133
  };
65
134
 
66
- // src/ui/spinner.ts
67
- import ora from "ora";
68
- function createSpinner(text) {
69
- return ora({
70
- text,
71
- spinner: "dots"
72
- });
73
- }
74
- async function withSpinner(text, fn, successText) {
75
- const spinner = createSpinner(text).start();
76
- try {
77
- const result = await fn();
78
- spinner.succeed(successText || text);
79
- return result;
80
- } catch (error) {
81
- spinner.fail();
82
- throw error;
83
- }
84
- }
85
-
86
- // src/config/index.ts
87
- var { machineIdSync } = nodeMachineId;
88
- var CONFIG_FILE = path.join(os.homedir(), ".lftrc");
89
- var ALGORITHM = "aes-256-gcm";
90
- function getEncryptionKey() {
91
- const machineId = machineIdSync();
92
- return createHash("sha256").update(machineId + "lft-secret").digest();
93
- }
94
- function encryptConfig(config) {
95
- const key = getEncryptionKey();
96
- const iv = randomBytes(16);
97
- const cipher = createCipheriv(ALGORITHM, key, iv);
98
- let encrypted = cipher.update(JSON.stringify(config), "utf8", "hex");
99
- encrypted += cipher.final("hex");
100
- const authTag = cipher.getAuthTag();
101
- return JSON.stringify({
102
- iv: iv.toString("hex"),
103
- tag: authTag.toString("hex"),
104
- data: encrypted
105
- });
106
- }
107
- function decryptConfig(encrypted) {
108
- const { iv, tag, data } = JSON.parse(encrypted);
109
- const key = getEncryptionKey();
110
- const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(iv, "hex"));
111
- decipher.setAuthTag(Buffer.from(tag, "hex"));
112
- let decrypted = decipher.update(data, "hex", "utf8");
113
- decrypted += decipher.final("utf8");
114
- return JSON.parse(decrypted);
115
- }
116
- var ENV_VARS = {
117
- GITHUB_TOKEN: "LFT_GITHUB_TOKEN",
118
- GITHUB_USERNAME: "LFT_GITHUB_USERNAME",
119
- GITHUB_ORG: "LFT_GITHUB_ORG",
120
- SUPABASE_TOKEN: "LFT_SUPABASE_TOKEN",
121
- SUPABASE_ORG_ID: "LFT_SUPABASE_ORG_ID",
122
- SUPABASE_REGION: "LFT_SUPABASE_REGION",
123
- JIRA_EMAIL: "LFT_JIRA_EMAIL",
124
- JIRA_TOKEN: "LFT_JIRA_TOKEN",
125
- JIRA_DOMAIN: "LFT_JIRA_DOMAIN"
126
- };
127
- function loadConfigFromEnv() {
128
- const githubToken = process.env[ENV_VARS.GITHUB_TOKEN];
129
- const githubUsername = process.env[ENV_VARS.GITHUB_USERNAME];
130
- const supabaseToken = process.env[ENV_VARS.SUPABASE_TOKEN];
131
- const supabaseOrgId = process.env[ENV_VARS.SUPABASE_ORG_ID];
132
- const jiraEmail = process.env[ENV_VARS.JIRA_EMAIL];
133
- const jiraToken = process.env[ENV_VARS.JIRA_TOKEN];
134
- const jiraDomain = process.env[ENV_VARS.JIRA_DOMAIN];
135
- if (!githubToken || !supabaseToken || !jiraToken) {
136
- return null;
137
- }
138
- return {
139
- version: "1.0.0",
140
- credentials: {
141
- github: {
142
- token: githubToken,
143
- username: githubUsername || ""
144
- },
145
- supabase: {
146
- accessToken: supabaseToken,
147
- organizationId: supabaseOrgId || ""
148
- },
149
- jira: {
150
- email: jiraEmail || "",
151
- apiToken: jiraToken,
152
- domain: jiraDomain || ""
153
- }
154
- },
155
- defaults: {
156
- githubOrg: process.env[ENV_VARS.GITHUB_ORG],
157
- supabaseRegion: process.env[ENV_VARS.SUPABASE_REGION] || "us-east-1",
158
- jiraProjectType: "software"
159
- }
160
- };
161
- }
162
- function hasEnvConfig() {
163
- return !!(process.env[ENV_VARS.GITHUB_TOKEN] && process.env[ENV_VARS.SUPABASE_TOKEN] && process.env[ENV_VARS.JIRA_TOKEN]);
164
- }
165
- async function hasConfig() {
166
- if (hasEnvConfig()) return true;
135
+ // src/services/github.ts
136
+ async function createGitHubRepo(projectName, config2) {
137
+ const octokit = new Octokit({ auth: config2.credentials.github.token });
138
+ const org = config2.defaults.githubOrg;
139
+ const owner = org || config2.credentials.github.username;
167
140
  try {
168
- await fs.access(CONFIG_FILE);
169
- return true;
170
- } catch {
171
- return false;
172
- }
173
- }
174
- async function loadConfig() {
175
- const envConfig = loadConfigFromEnv();
176
- if (envConfig) {
177
- return envConfig;
178
- }
179
- const encrypted = await fs.readFile(CONFIG_FILE, "utf8");
180
- return decryptConfig(encrypted);
181
- }
182
- async function saveConfig(config) {
183
- const encrypted = encryptConfig(config);
184
- await fs.writeFile(CONFIG_FILE, encrypted, "utf8");
185
- }
186
- async function showConfig() {
187
- if (!await hasConfig()) {
188
- logger.warning("No hay configuraci\xF3n guardada");
189
- logger.info('Ejecuta "create-lft-app config" para configurar');
190
- return;
191
- }
192
- const config = await loadConfig();
193
- logger.newLine();
194
- logger.title("Configuraci\xF3n actual:");
195
- logger.newLine();
196
- logger.subtitle("GitHub:");
197
- logger.table([
198
- { label: "Usuario", value: config.credentials.github.username },
199
- { label: "Token", value: "***" + config.credentials.github.token.slice(-4) },
200
- { label: "Org por defecto", value: config.defaults.githubOrg || "(ninguna)" }
201
- ]);
202
- logger.newLine();
203
- logger.subtitle("Supabase:");
204
- logger.table([
205
- { label: "Org ID", value: config.credentials.supabase.organizationId },
206
- { label: "Token", value: "***" + config.credentials.supabase.accessToken.slice(-4) },
207
- { label: "Regi\xF3n", value: config.defaults.supabaseRegion }
208
- ]);
209
- logger.newLine();
210
- logger.subtitle("Jira:");
211
- logger.table([
212
- { label: "Email", value: config.credentials.jira.email },
213
- { label: "Dominio", value: config.credentials.jira.domain },
214
- { label: "Token", value: "***" + config.credentials.jira.apiToken.slice(-4) }
215
- ]);
216
- }
217
- async function resetConfig() {
218
- if (!await hasConfig()) {
219
- logger.info("No hay configuraci\xF3n para resetear");
220
- return;
221
- }
222
- const shouldReset = await confirm({
223
- message: "\xBFEst\xE1s seguro de que quieres eliminar la configuraci\xF3n?",
224
- default: false
225
- });
226
- if (shouldReset) {
227
- await fs.unlink(CONFIG_FILE);
228
- logger.success("Configuraci\xF3n eliminada");
229
- }
230
- }
231
- async function configureCredentials(options = {}) {
232
- let config;
233
- if (await hasConfig()) {
234
- config = await loadConfig();
235
- logger.info("Configuraci\xF3n existente encontrada. Actualizando...");
236
- } else {
237
- config = {
238
- version: "1.0.0",
239
- credentials: {
240
- github: { token: "", username: "" },
241
- supabase: { accessToken: "", organizationId: "" },
242
- jira: { email: "", apiToken: "", domain: "" }
243
- },
244
- defaults: {
245
- supabaseRegion: "us-east-1",
246
- jiraProjectType: "software"
247
- }
248
- };
249
- }
250
- const configureAll = !options.onlyGithub && !options.onlySupabase && !options.onlyJira;
251
- if (configureAll || options.onlyGithub) {
252
- logger.newLine();
253
- logger.title("Configuraci\xF3n de GitHub");
254
- logger.subtitle("Necesitas un Personal Access Token con permisos: repo, read:org");
255
- logger.link("Crear token", "https://github.com/settings/tokens/new");
256
- logger.newLine();
257
- const githubToken = await password({
258
- message: "GitHub Personal Access Token:",
259
- mask: "*"
260
- });
261
- const isValid = await withSpinner(
262
- "Validando token de GitHub...",
263
- async () => {
264
- const response = await fetch("https://api.github.com/user", {
265
- headers: { Authorization: `Bearer ${githubToken}` }
266
- });
267
- if (!response.ok) return null;
268
- return response.json();
269
- }
270
- );
271
- if (!isValid) {
272
- throw new Error("Token de GitHub inv\xE1lido");
273
- }
274
- config.credentials.github.token = githubToken;
275
- config.credentials.github.username = isValid.login;
276
- logger.success(`Conectado como: ${isValid.login}`);
277
- const useOrg = await confirm({
278
- message: "\xBFQuieres usar una organizaci\xF3n por defecto?",
279
- default: false
280
- });
281
- if (useOrg) {
282
- config.defaults.githubOrg = await input({
283
- message: "Nombre de la organizaci\xF3n:"
284
- });
285
- }
286
- }
287
- if (configureAll || options.onlySupabase) {
288
- logger.newLine();
289
- logger.title("Configuraci\xF3n de Supabase");
290
- logger.subtitle("Necesitas un Access Token de la Management API");
291
- logger.link("Crear token", "https://supabase.com/dashboard/account/tokens");
292
- logger.newLine();
293
- const supabaseToken = await password({
294
- message: "Supabase Access Token:",
295
- mask: "*"
296
- });
297
- const orgs = await withSpinner(
298
- "Obteniendo organizaciones de Supabase...",
299
- async () => {
300
- const response = await fetch("https://api.supabase.com/v1/organizations", {
301
- headers: { Authorization: `Bearer ${supabaseToken}` }
302
- });
303
- if (!response.ok) return null;
304
- return response.json();
305
- }
306
- );
307
- if (!orgs || orgs.length === 0) {
308
- throw new Error("Token de Supabase inv\xE1lido o no tienes organizaciones");
309
- }
310
- config.credentials.supabase.accessToken = supabaseToken;
311
- if (orgs.length === 1) {
312
- config.credentials.supabase.organizationId = orgs[0].id;
313
- logger.success(`Usando organizaci\xF3n: ${orgs[0].name}`);
314
- } else {
315
- const selectedOrg = await select({
316
- message: "Selecciona la organizaci\xF3n:",
317
- choices: orgs.map((org) => ({ name: org.name, value: org.id }))
318
- });
319
- config.credentials.supabase.organizationId = selectedOrg;
320
- }
321
- config.defaults.supabaseRegion = await select({
322
- message: "Regi\xF3n por defecto:",
323
- choices: [
324
- { name: "US East (Virginia)", value: "us-east-1" },
325
- { name: "US West (Oregon)", value: "us-west-1" },
326
- { name: "EU West (Ireland)", value: "eu-west-1" },
327
- { name: "AP Southeast (Singapore)", value: "ap-southeast-1" },
328
- { name: "AP Northeast (Tokyo)", value: "ap-northeast-1" },
329
- { name: "SA East (S\xE3o Paulo)", value: "sa-east-1" }
330
- ],
331
- default: "us-east-1"
332
- });
333
- }
334
- if (configureAll || options.onlyJira) {
335
- logger.newLine();
336
- logger.title("Configuraci\xF3n de Jira");
337
- logger.subtitle("Necesitas un API Token de Atlassian");
338
- logger.link("Crear token", "https://id.atlassian.com/manage-profile/security/api-tokens");
339
- logger.newLine();
340
- const jiraEmail = await input({
341
- message: "Email de Atlassian:"
141
+ const existing = await octokit.rest.repos.get({
142
+ owner,
143
+ repo: projectName
342
144
  });
343
- const jiraToken = await password({
344
- message: "Jira API Token:",
345
- mask: "*"
346
- });
347
- const jiraDomain = await input({
348
- message: "Dominio de Jira (ej: empresa.atlassian.net):",
349
- validate: (value) => {
350
- if (!value.includes(".atlassian.net")) {
351
- return "El dominio debe terminar en .atlassian.net";
352
- }
353
- return true;
354
- }
355
- });
356
- const isValid = await withSpinner(
357
- "Validando credenciales de Jira...",
358
- async () => {
359
- const auth = Buffer.from(`${jiraEmail}:${jiraToken}`).toString("base64");
360
- const response = await fetch(`https://${jiraDomain}/rest/api/3/myself`, {
361
- headers: { Authorization: `Basic ${auth}` }
362
- });
363
- return response.ok;
364
- }
365
- );
366
- if (!isValid) {
367
- throw new Error("Credenciales de Jira inv\xE1lidas");
368
- }
369
- config.credentials.jira.email = jiraEmail;
370
- config.credentials.jira.apiToken = jiraToken;
371
- config.credentials.jira.domain = jiraDomain;
372
- logger.success("Credenciales de Jira v\xE1lidas");
145
+ logger.success(`GitHub: ${owner}/${projectName} (ya existe)`);
146
+ return existing.data.html_url;
147
+ } catch {
373
148
  }
374
- await saveConfig(config);
375
- logger.newLine();
376
- logger.success("Configuraci\xF3n guardada en ~/.lftrc");
377
- }
378
-
379
- // src/services/github.ts
380
- import { Octokit } from "octokit";
381
- async function createGitHubRepo(projectName, config) {
382
- const octokit = new Octokit({ auth: config.credentials.github.token });
383
- const org = config.defaults.githubOrg;
384
149
  return withSpinner(
385
150
  "Creando repositorio en GitHub...",
386
151
  async () => {
@@ -403,7 +168,7 @@ async function createGitHubRepo(projectName, config) {
403
168
  }
404
169
  return repo.data.html_url;
405
170
  },
406
- `Repositorio creado: ${org || config.credentials.github.username}/${projectName}`
171
+ `GitHub: ${owner}/${projectName}`
407
172
  );
408
173
  }
409
174
 
@@ -422,7 +187,7 @@ async function waitForProjectReady(projectId, token, maxAttempts = 60) {
422
187
  return;
423
188
  }
424
189
  }
425
- await new Promise((resolve) => setTimeout(resolve, 5e3));
190
+ await new Promise((resolve2) => setTimeout(resolve2, 5e3));
426
191
  spinner.text = `Provisionando base de datos... (${Math.floor((i + 1) * 5 / 60)}min ${(i + 1) * 5 % 60}s)`;
427
192
  }
428
193
  spinner.fail("Timeout esperando a que el proyecto est\xE9 listo");
@@ -443,10 +208,28 @@ async function getProjectApiKeys(projectId, token) {
443
208
  }
444
209
  return { anonKey, serviceKey };
445
210
  }
446
- async function createSupabaseProject(projectName, config) {
447
- const token = config.credentials.supabase.accessToken;
448
- const orgId = config.credentials.supabase.organizationId;
449
- const region = config.defaults.supabaseRegion;
211
+ async function findExistingProject(projectName, token) {
212
+ const response = await fetch(`${SUPABASE_API_URL}/projects`, {
213
+ headers: { Authorization: `Bearer ${token}` }
214
+ });
215
+ if (!response.ok) return null;
216
+ const projects = await response.json();
217
+ return projects.find((p) => p.name === projectName) || null;
218
+ }
219
+ async function createSupabaseProject(projectName, config2) {
220
+ const token = config2.credentials.supabase.accessToken;
221
+ const orgId = config2.credentials.supabase.organizationId;
222
+ const region = config2.defaults.supabaseRegion;
223
+ const existing = await findExistingProject(projectName, token);
224
+ if (existing) {
225
+ logger.success(`Supabase: ${projectName} (ya existe)`);
226
+ const { anonKey: anonKey2, serviceKey: serviceKey2 } = await getProjectApiKeys(existing.id, token);
227
+ return {
228
+ url: `https://${existing.id}.supabase.co`,
229
+ anonKey: anonKey2,
230
+ serviceKey: serviceKey2
231
+ };
232
+ }
450
233
  const dbPassword = generateSecurePassword();
451
234
  const project = await withSpinner(
452
235
  "Creando proyecto en Supabase...",
@@ -483,16 +266,14 @@ async function createSupabaseProject(projectName, config) {
483
266
  }
484
267
  function generateSecurePassword() {
485
268
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*";
486
- let password2 = "";
269
+ let password = "";
487
270
  for (let i = 0; i < 32; i++) {
488
- password2 += chars.charAt(Math.floor(Math.random() * chars.length));
271
+ password += chars.charAt(Math.floor(Math.random() * chars.length));
489
272
  }
490
- return password2;
273
+ return password;
491
274
  }
492
275
 
493
276
  // src/utils/validation.ts
494
- import fs2 from "fs";
495
- import path2 from "path";
496
277
  function validateProjectName(name) {
497
278
  if (!name || name.trim() === "") {
498
279
  return { valid: false, error: "El nombre del proyecto no puede estar vac\xEDo" };
@@ -516,10 +297,6 @@ function validateProjectName(name) {
516
297
  if (name.length > 50) {
517
298
  return { valid: false, error: "El nombre no puede tener m\xE1s de 50 caracteres" };
518
299
  }
519
- const projectPath = path2.resolve(process.cwd(), name);
520
- if (fs2.existsSync(projectPath)) {
521
- return { valid: false, error: `El directorio "${name}" ya existe` };
522
- }
523
300
  return { valid: true };
524
301
  }
525
302
  function generateJiraKey(projectName) {
@@ -528,10 +305,29 @@ function generateJiraKey(projectName) {
528
305
  }
529
306
 
530
307
  // src/services/jira.ts
531
- async function createJiraProject(projectName, config) {
532
- const { email, apiToken, domain } = config.credentials.jira;
308
+ async function findExistingJiraProject(projectName, auth, domain) {
309
+ const response = await fetch(
310
+ `https://${domain}/rest/api/3/project/search?query=${encodeURIComponent(projectName)}`,
311
+ {
312
+ headers: {
313
+ Authorization: `Basic ${auth}`,
314
+ "Content-Type": "application/json"
315
+ }
316
+ }
317
+ );
318
+ if (!response.ok) return null;
319
+ const data = await response.json();
320
+ return data.values.find((p) => p.name === projectName) || null;
321
+ }
322
+ async function createJiraProject(projectName, config2) {
323
+ const { email, apiToken, domain } = config2.credentials.jira;
533
324
  const auth = Buffer.from(`${email}:${apiToken}`).toString("base64");
534
325
  const projectKey = generateJiraKey(projectName);
326
+ const existing = await findExistingJiraProject(projectName, auth, domain);
327
+ if (existing) {
328
+ logger.success(`Jira: ${existing.key} (ya existe)`);
329
+ return `https://${domain}/browse/${existing.key}`;
330
+ }
535
331
  return withSpinner(
536
332
  "Creando proyecto en Jira...",
537
333
  async () => {
@@ -588,13 +384,20 @@ async function createJiraProject(projectName, config) {
588
384
  const project = await response.json();
589
385
  return `https://${domain}/browse/${project.key}`;
590
386
  },
591
- `Proyecto Jira creado: ${projectKey}`
387
+ `Proyecto Jira: ${projectKey}`
592
388
  );
593
389
  }
594
390
 
595
391
  // src/steps/scaffold-nextjs.ts
596
392
  import { execa } from "execa";
393
+ import { existsSync } from "fs";
394
+ import path from "path";
597
395
  async function scaffoldNextJs(projectName, projectPath) {
396
+ const targetDir = path.join(process.cwd(), projectName);
397
+ if (existsSync(targetDir)) {
398
+ logger.success(`Next.js: ${projectName} (ya existe)`);
399
+ return;
400
+ }
598
401
  await withSpinner(
599
402
  "Inicializando proyecto Next.js...",
600
403
  async () => {
@@ -609,71 +412,72 @@ async function scaffoldNextJs(projectName, projectPath) {
609
412
  "--src-dir",
610
413
  "--import-alias",
611
414
  "@/*",
612
- "--use-npm"
415
+ "--use-npm",
416
+ "--yes"
613
417
  ], {
614
418
  cwd: process.cwd(),
615
419
  stdio: "pipe"
616
420
  });
617
421
  },
618
- "Proyecto Next.js inicializado"
422
+ `Next.js: ${projectName}`
619
423
  );
620
424
  }
621
425
 
622
426
  // src/steps/copy-template.ts
623
427
  import { cp, mkdir, readFile, writeFile } from "fs/promises";
624
- import path3 from "path";
625
- import { fileURLToPath } from "url";
626
- var __filename2 = fileURLToPath(import.meta.url);
627
- var __dirname2 = path3.dirname(__filename2);
428
+ import path2 from "path";
429
+ import { fileURLToPath as fileURLToPath2 } from "url";
430
+ var __filename3 = fileURLToPath2(import.meta.url);
431
+ var __dirname3 = path2.dirname(__filename3);
628
432
  async function copyTemplate(projectPath) {
629
433
  await withSpinner(
630
434
  "Copiando template LFT...",
631
435
  async () => {
632
- const templatesDir = path3.join(__dirname2, "..", "..", "templates");
633
- const srcDir = path3.join(projectPath, "src");
436
+ const templatesDir = path2.join(__dirname3, "..", "..", "templates");
437
+ const srcDir = path2.join(projectPath, "src");
634
438
  await cp(
635
- path3.join(templatesDir, "components", "ui"),
636
- path3.join(srcDir, "components", "ui"),
439
+ path2.join(templatesDir, "components", "ui"),
440
+ path2.join(srcDir, "components", "ui"),
637
441
  { recursive: true }
638
442
  );
639
443
  await cp(
640
- path3.join(templatesDir, "components", "layout"),
641
- path3.join(srcDir, "components", "layout"),
444
+ path2.join(templatesDir, "components", "layout"),
445
+ path2.join(srcDir, "components", "layout"),
642
446
  { recursive: true }
643
447
  );
644
448
  await cp(
645
- path3.join(templatesDir, "components", "dashboard"),
646
- path3.join(srcDir, "components", "dashboard"),
449
+ path2.join(templatesDir, "components", "dashboard"),
450
+ path2.join(srcDir, "components", "dashboard"),
647
451
  { recursive: true }
648
452
  );
649
- await mkdir(path3.join(srcDir, "lib"), { recursive: true });
453
+ await mkdir(path2.join(srcDir, "lib"), { recursive: true });
650
454
  await cp(
651
- path3.join(templatesDir, "lib", "utils.ts"),
652
- path3.join(srcDir, "lib", "utils.ts")
455
+ path2.join(templatesDir, "lib", "utils.ts"),
456
+ path2.join(srcDir, "lib", "utils.ts")
653
457
  );
654
- await mkdir(path3.join(srcDir, "hooks"), { recursive: true });
458
+ await mkdir(path2.join(srcDir, "hooks"), { recursive: true });
655
459
  await cp(
656
- path3.join(templatesDir, "hooks"),
657
- path3.join(srcDir, "hooks"),
460
+ path2.join(templatesDir, "hooks"),
461
+ path2.join(srcDir, "hooks"),
658
462
  { recursive: true }
659
463
  );
660
464
  await cp(
661
- path3.join(templatesDir, "app", "layout.tsx"),
662
- path3.join(srcDir, "app", "layout.tsx")
465
+ path2.join(templatesDir, "app", "layout.tsx"),
466
+ path2.join(srcDir, "app", "layout.tsx")
663
467
  );
664
468
  await cp(
665
- path3.join(templatesDir, "app", "page.tsx"),
666
- path3.join(srcDir, "app", "page.tsx")
469
+ path2.join(templatesDir, "app", "page.tsx"),
470
+ path2.join(srcDir, "app", "page.tsx")
667
471
  );
668
- await mkdir(path3.join(srcDir, "app", "dashboard"), { recursive: true });
472
+ await mkdir(path2.join(srcDir, "app", "dashboard"), { recursive: true });
669
473
  await cp(
670
- path3.join(templatesDir, "app", "dashboard", "page.tsx"),
671
- path3.join(srcDir, "app", "dashboard", "page.tsx")
474
+ path2.join(templatesDir, "app", "dashboard", "page.tsx"),
475
+ path2.join(srcDir, "app", "dashboard", "page.tsx")
672
476
  );
673
- await mkdir(path3.join(srcDir, "app", "auth", "login"), { recursive: true });
477
+ await mkdir(path2.join(srcDir, "app", "auth", "login"), { recursive: true });
674
478
  await cp(
675
- path3.join(templatesDir, "app", "auth", "login", "page.tsx"),
676
- path3.join(srcDir, "app", "auth", "login", "page.tsx")
479
+ path2.join(templatesDir, "app", "auth", "login", "page.tsx"),
480
+ path2.join(srcDir, "app", "auth", "login", "page.tsx")
677
481
  );
678
482
  await mergeGlobalStyles(projectPath, templatesDir);
679
483
  },
@@ -681,8 +485,8 @@ async function copyTemplate(projectPath) {
681
485
  );
682
486
  }
683
487
  async function mergeGlobalStyles(projectPath, templatesDir) {
684
- const templateCssPath = path3.join(templatesDir, "app", "globals.css");
685
- const projectCssPath = path3.join(projectPath, "src", "app", "globals.css");
488
+ const templateCssPath = path2.join(templatesDir, "app", "globals.css");
489
+ const projectCssPath = path2.join(projectPath, "src", "app", "globals.css");
686
490
  try {
687
491
  const templateCss = await readFile(templateCssPath, "utf-8");
688
492
  const existingCss = await readFile(projectCssPath, "utf-8");
@@ -759,7 +563,7 @@ async function installDependencies(projectPath) {
759
563
 
760
564
  // src/steps/create-env.ts
761
565
  import { writeFile as writeFile2, readFile as readFile2, appendFile } from "fs/promises";
762
- import path4 from "path";
566
+ import path3 from "path";
763
567
  async function createEnvFile(projectPath, supabaseKeys) {
764
568
  await withSpinner(
765
569
  "Creando archivo .env.local...",
@@ -770,10 +574,10 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}
770
574
  SUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}
771
575
  `;
772
576
  await writeFile2(
773
- path4.join(projectPath, ".env.local"),
577
+ path3.join(projectPath, ".env.local"),
774
578
  envContent
775
579
  );
776
- const gitignorePath = path4.join(projectPath, ".gitignore");
580
+ const gitignorePath = path3.join(projectPath, ".gitignore");
777
581
  try {
778
582
  const gitignore = await readFile2(gitignorePath, "utf-8");
779
583
  if (!gitignore.includes(".env.local")) {
@@ -871,30 +675,30 @@ async function createProject(projectName, options = {}) {
871
675
  if (!validation.valid) {
872
676
  throw new Error(validation.error);
873
677
  }
874
- const projectPath = path5.resolve(process.cwd(), projectName);
678
+ const projectPath = path4.resolve(process.cwd(), projectName);
875
679
  if (!await hasConfig()) {
876
680
  logger.warning('No se encontr\xF3 configuraci\xF3n. Ejecuta "create-lft-app config" primero.');
877
681
  throw new Error("Configuraci\xF3n no encontrada");
878
682
  }
879
- const config = await loadConfig();
683
+ const config2 = await loadConfig();
880
684
  logger.newLine();
881
685
  logger.title("Resumen de recursos a crear:");
882
686
  logger.newLine();
883
687
  const resources = [];
884
688
  if (!options.skipGithub) {
885
- resources.push({ label: "GitHub", value: `${config.defaults.githubOrg || config.credentials.github.username}/${projectName} (privado)` });
689
+ resources.push({ label: "GitHub", value: `${config2.defaults.githubOrg || config2.credentials.github.username}/${projectName} (privado)` });
886
690
  }
887
691
  if (!options.skipSupabase) {
888
- resources.push({ label: "Supabase", value: `${projectName} en ${config.defaults.supabaseRegion}` });
692
+ resources.push({ label: "Supabase", value: `${projectName} en ${config2.defaults.supabaseRegion}` });
889
693
  }
890
694
  if (!options.skipJira) {
891
- resources.push({ label: "Jira", value: `Proyecto "${projectName}" en ${config.credentials.jira.domain}` });
695
+ resources.push({ label: "Jira", value: `Proyecto "${projectName}" en ${config2.credentials.jira.domain}` });
892
696
  }
893
697
  resources.push({ label: "Next.js", value: "App Router + TypeScript + Tailwind + Dashboard" });
894
698
  logger.table(resources);
895
699
  logger.newLine();
896
700
  if (!options.autoConfirm) {
897
- const shouldContinue = await confirm2({
701
+ const shouldContinue = await confirm({
898
702
  message: "\xBFContinuar con la creaci\xF3n?",
899
703
  default: true
900
704
  });
@@ -911,14 +715,14 @@ async function createProject(projectName, options = {}) {
911
715
  const externalTasks = [];
912
716
  if (!options.skipGithub) {
913
717
  externalTasks.push(
914
- createGitHubRepo(projectName, config).then((url) => {
718
+ createGitHubRepo(projectName, config2).then((url) => {
915
719
  urls.github = url;
916
720
  })
917
721
  );
918
722
  }
919
723
  if (!options.skipSupabase) {
920
724
  externalTasks.push(
921
- createSupabaseProject(projectName, config).then((result) => {
725
+ createSupabaseProject(projectName, config2).then((result) => {
922
726
  urls.supabase = result.url;
923
727
  supabaseKeys = result;
924
728
  })
@@ -926,7 +730,7 @@ async function createProject(projectName, options = {}) {
926
730
  }
927
731
  if (!options.skipJira) {
928
732
  externalTasks.push(
929
- createJiraProject(projectName, config).then((url) => {
733
+ createJiraProject(projectName, config2).then((url) => {
930
734
  urls.jira = url;
931
735
  })
932
736
  );
@@ -959,6 +763,11 @@ program.argument("[project-name]", "Nombre del proyecto a crear").option("--skip
959
763
  logger.info("Uso: create-lft-app <nombre-proyecto>");
960
764
  process.exit(1);
961
765
  }
766
+ if (!await hasConfig()) {
767
+ logger.error("Las credenciales no est\xE1n configuradas en el paquete");
768
+ logger.info("Contacta al administrador del CLI");
769
+ process.exit(1);
770
+ }
962
771
  try {
963
772
  await createProject(projectName, {
964
773
  skipGithub: options.skipGithub,
@@ -974,21 +783,5 @@ program.argument("[project-name]", "Nombre del proyecto a crear").option("--skip
974
783
  process.exit(1);
975
784
  }
976
785
  });
977
- program.command("config").description("Configurar credenciales de APIs").option("--show", "Mostrar configuraci\xF3n actual").option("--reset", "Resetear configuraci\xF3n").option("--github", "Configurar solo GitHub").option("--supabase", "Configurar solo Supabase").option("--jira", "Configurar solo Jira").action(async (options) => {
978
- showBanner();
979
- if (options.show) {
980
- await showConfig();
981
- return;
982
- }
983
- if (options.reset) {
984
- await resetConfig();
985
- return;
986
- }
987
- await configureCredentials({
988
- onlyGithub: options.github,
989
- onlySupabase: options.supabase,
990
- onlyJira: options.jira
991
- });
992
- });
993
786
  program.parse();
994
787
  //# sourceMappingURL=cli.js.map