@create-lft-app/cli 1.0.2 → 1.0.3

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,383 +1,85 @@
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";
10
-
11
- // 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";
7
+ import path4 from "path";
8
+ import { confirm } from "@inquirer/prompts";
18
9
 
19
- // src/ui/logger.ts
20
- import chalk from "chalk";
21
- var logger = {
22
- info: (message) => {
23
- console.log(chalk.blue("\u2139"), message);
24
- },
25
- success: (message) => {
26
- console.log(chalk.green("\u2714"), message);
27
- },
28
- warning: (message) => {
29
- console.log(chalk.yellow("\u26A0"), message);
30
- },
31
- error: (message) => {
32
- console.log(chalk.red("\u2716"), message);
33
- },
34
- step: (step, total, message) => {
35
- console.log(chalk.cyan(`[${step}/${total}]`), message);
36
- },
37
- newLine: () => {
38
- console.log();
39
- },
40
- divider: () => {
41
- console.log(chalk.gray("\u2500".repeat(50)));
42
- },
43
- title: (message) => {
44
- console.log(chalk.bold.white(message));
45
- },
46
- subtitle: (message) => {
47
- console.log(chalk.gray(message));
10
+ // src/config/static-config.ts
11
+ var STATIC_CONFIG = {
12
+ github: {
13
+ token: "__GITHUB_TOKEN__",
14
+ username: "__GITHUB_USERNAME__",
15
+ org: "__GITHUB_ORG__"
48
16
  },
49
- link: (label, url) => {
50
- console.log(` ${chalk.gray(label + ":")} ${chalk.cyan.underline(url)}`);
51
- },
52
- list: (items) => {
53
- items.forEach((item) => {
54
- console.log(chalk.gray(" \u2022"), item);
55
- });
17
+ supabase: {
18
+ token: "__SUPABASE_TOKEN__",
19
+ orgId: "__SUPABASE_ORG_ID__",
20
+ region: "us-east-1"
56
21
  },
57
- table: (rows) => {
58
- const maxLabelLength = Math.max(...rows.map((r) => r.label.length));
59
- rows.forEach(({ label, value }) => {
60
- const paddedLabel = label.padEnd(maxLabelLength);
61
- console.log(` ${chalk.gray(paddedLabel)} ${value}`);
62
- });
22
+ jira: {
23
+ email: "__JIRA_EMAIL__",
24
+ token: "__JIRA_TOKEN__",
25
+ domain: "__JIRA_DOMAIN__"
63
26
  }
64
27
  };
65
28
 
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
29
  // 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
- }
30
+ async function loadConfig() {
138
31
  return {
139
32
  version: "1.0.0",
140
33
  credentials: {
141
34
  github: {
142
- token: githubToken,
143
- username: githubUsername || ""
35
+ token: STATIC_CONFIG.github.token,
36
+ username: STATIC_CONFIG.github.username
144
37
  },
145
38
  supabase: {
146
- accessToken: supabaseToken,
147
- organizationId: supabaseOrgId || ""
39
+ accessToken: STATIC_CONFIG.supabase.token,
40
+ organizationId: STATIC_CONFIG.supabase.orgId
148
41
  },
149
42
  jira: {
150
- email: jiraEmail || "",
151
- apiToken: jiraToken,
152
- domain: jiraDomain || ""
43
+ email: STATIC_CONFIG.jira.email,
44
+ apiToken: STATIC_CONFIG.jira.token,
45
+ domain: STATIC_CONFIG.jira.domain
153
46
  }
154
47
  },
155
48
  defaults: {
156
- githubOrg: process.env[ENV_VARS.GITHUB_ORG],
157
- supabaseRegion: process.env[ENV_VARS.SUPABASE_REGION] || "us-east-1",
49
+ githubOrg: STATIC_CONFIG.github.org || void 0,
50
+ supabaseRegion: STATIC_CONFIG.supabase.region,
158
51
  jiraProjectType: "software"
159
52
  }
160
53
  };
161
54
  }
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
55
  async function hasConfig() {
166
- if (hasEnvConfig()) return true;
167
- try {
168
- await fs.access(CONFIG_FILE);
169
- return true;
170
- } catch {
171
- return false;
172
- }
56
+ return STATIC_CONFIG.github.token !== "__GITHUB_TOKEN__" && STATIC_CONFIG.supabase.token !== "__SUPABASE_TOKEN__" && STATIC_CONFIG.jira.token !== "__JIRA_TOKEN__";
173
57
  }
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
58
+
59
+ // src/services/github.ts
60
+ import { Octokit } from "octokit";
61
+
62
+ // src/ui/spinner.ts
63
+ import ora from "ora";
64
+ function createSpinner(text) {
65
+ return ora({
66
+ text,
67
+ spinner: "dots"
225
68
  });
226
- if (shouldReset) {
227
- await fs.unlink(CONFIG_FILE);
228
- logger.success("Configuraci\xF3n eliminada");
229
- }
230
69
  }
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:"
342
- });
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");
70
+ async function withSpinner(text, fn, successText) {
71
+ const spinner = createSpinner(text).start();
72
+ try {
73
+ const result = await fn();
74
+ spinner.succeed(successText || text);
75
+ return result;
76
+ } catch (error) {
77
+ spinner.fail();
78
+ throw error;
373
79
  }
374
- await saveConfig(config);
375
- logger.newLine();
376
- logger.success("Configuraci\xF3n guardada en ~/.lftrc");
377
80
  }
378
81
 
379
82
  // src/services/github.ts
380
- import { Octokit } from "octokit";
381
83
  async function createGitHubRepo(projectName, config) {
382
84
  const octokit = new Octokit({ auth: config.credentials.github.token });
383
85
  const org = config.defaults.githubOrg;
@@ -483,16 +185,16 @@ async function createSupabaseProject(projectName, config) {
483
185
  }
484
186
  function generateSecurePassword() {
485
187
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*";
486
- let password2 = "";
188
+ let password = "";
487
189
  for (let i = 0; i < 32; i++) {
488
- password2 += chars.charAt(Math.floor(Math.random() * chars.length));
190
+ password += chars.charAt(Math.floor(Math.random() * chars.length));
489
191
  }
490
- return password2;
192
+ return password;
491
193
  }
492
194
 
493
195
  // src/utils/validation.ts
494
- import fs2 from "fs";
495
- import path2 from "path";
196
+ import fs from "fs";
197
+ import path from "path";
496
198
  function validateProjectName(name) {
497
199
  if (!name || name.trim() === "") {
498
200
  return { valid: false, error: "El nombre del proyecto no puede estar vac\xEDo" };
@@ -516,8 +218,8 @@ function validateProjectName(name) {
516
218
  if (name.length > 50) {
517
219
  return { valid: false, error: "El nombre no puede tener m\xE1s de 50 caracteres" };
518
220
  }
519
- const projectPath = path2.resolve(process.cwd(), name);
520
- if (fs2.existsSync(projectPath)) {
221
+ const projectPath = path.resolve(process.cwd(), name);
222
+ if (fs.existsSync(projectPath)) {
521
223
  return { valid: false, error: `El directorio "${name}" ya existe` };
522
224
  }
523
225
  return { valid: true };
@@ -621,59 +323,59 @@ async function scaffoldNextJs(projectName, projectPath) {
621
323
 
622
324
  // src/steps/copy-template.ts
623
325
  import { cp, mkdir, readFile, writeFile } from "fs/promises";
624
- import path3 from "path";
326
+ import path2 from "path";
625
327
  import { fileURLToPath } from "url";
626
328
  var __filename2 = fileURLToPath(import.meta.url);
627
- var __dirname2 = path3.dirname(__filename2);
329
+ var __dirname2 = path2.dirname(__filename2);
628
330
  async function copyTemplate(projectPath) {
629
331
  await withSpinner(
630
332
  "Copiando template LFT...",
631
333
  async () => {
632
- const templatesDir = path3.join(__dirname2, "..", "..", "templates");
633
- const srcDir = path3.join(projectPath, "src");
334
+ const templatesDir = path2.join(__dirname2, "..", "..", "templates");
335
+ const srcDir = path2.join(projectPath, "src");
634
336
  await cp(
635
- path3.join(templatesDir, "components", "ui"),
636
- path3.join(srcDir, "components", "ui"),
337
+ path2.join(templatesDir, "components", "ui"),
338
+ path2.join(srcDir, "components", "ui"),
637
339
  { recursive: true }
638
340
  );
639
341
  await cp(
640
- path3.join(templatesDir, "components", "layout"),
641
- path3.join(srcDir, "components", "layout"),
342
+ path2.join(templatesDir, "components", "layout"),
343
+ path2.join(srcDir, "components", "layout"),
642
344
  { recursive: true }
643
345
  );
644
346
  await cp(
645
- path3.join(templatesDir, "components", "dashboard"),
646
- path3.join(srcDir, "components", "dashboard"),
347
+ path2.join(templatesDir, "components", "dashboard"),
348
+ path2.join(srcDir, "components", "dashboard"),
647
349
  { recursive: true }
648
350
  );
649
- await mkdir(path3.join(srcDir, "lib"), { recursive: true });
351
+ await mkdir(path2.join(srcDir, "lib"), { recursive: true });
650
352
  await cp(
651
- path3.join(templatesDir, "lib", "utils.ts"),
652
- path3.join(srcDir, "lib", "utils.ts")
353
+ path2.join(templatesDir, "lib", "utils.ts"),
354
+ path2.join(srcDir, "lib", "utils.ts")
653
355
  );
654
- await mkdir(path3.join(srcDir, "hooks"), { recursive: true });
356
+ await mkdir(path2.join(srcDir, "hooks"), { recursive: true });
655
357
  await cp(
656
- path3.join(templatesDir, "hooks"),
657
- path3.join(srcDir, "hooks"),
358
+ path2.join(templatesDir, "hooks"),
359
+ path2.join(srcDir, "hooks"),
658
360
  { recursive: true }
659
361
  );
660
362
  await cp(
661
- path3.join(templatesDir, "app", "layout.tsx"),
662
- path3.join(srcDir, "app", "layout.tsx")
363
+ path2.join(templatesDir, "app", "layout.tsx"),
364
+ path2.join(srcDir, "app", "layout.tsx")
663
365
  );
664
366
  await cp(
665
- path3.join(templatesDir, "app", "page.tsx"),
666
- path3.join(srcDir, "app", "page.tsx")
367
+ path2.join(templatesDir, "app", "page.tsx"),
368
+ path2.join(srcDir, "app", "page.tsx")
667
369
  );
668
- await mkdir(path3.join(srcDir, "app", "dashboard"), { recursive: true });
370
+ await mkdir(path2.join(srcDir, "app", "dashboard"), { recursive: true });
669
371
  await cp(
670
- path3.join(templatesDir, "app", "dashboard", "page.tsx"),
671
- path3.join(srcDir, "app", "dashboard", "page.tsx")
372
+ path2.join(templatesDir, "app", "dashboard", "page.tsx"),
373
+ path2.join(srcDir, "app", "dashboard", "page.tsx")
672
374
  );
673
- await mkdir(path3.join(srcDir, "app", "auth", "login"), { recursive: true });
375
+ await mkdir(path2.join(srcDir, "app", "auth", "login"), { recursive: true });
674
376
  await cp(
675
- path3.join(templatesDir, "app", "auth", "login", "page.tsx"),
676
- path3.join(srcDir, "app", "auth", "login", "page.tsx")
377
+ path2.join(templatesDir, "app", "auth", "login", "page.tsx"),
378
+ path2.join(srcDir, "app", "auth", "login", "page.tsx")
677
379
  );
678
380
  await mergeGlobalStyles(projectPath, templatesDir);
679
381
  },
@@ -681,8 +383,8 @@ async function copyTemplate(projectPath) {
681
383
  );
682
384
  }
683
385
  async function mergeGlobalStyles(projectPath, templatesDir) {
684
- const templateCssPath = path3.join(templatesDir, "app", "globals.css");
685
- const projectCssPath = path3.join(projectPath, "src", "app", "globals.css");
386
+ const templateCssPath = path2.join(templatesDir, "app", "globals.css");
387
+ const projectCssPath = path2.join(projectPath, "src", "app", "globals.css");
686
388
  try {
687
389
  const templateCss = await readFile(templateCssPath, "utf-8");
688
390
  const existingCss = await readFile(projectCssPath, "utf-8");
@@ -759,7 +461,7 @@ async function installDependencies(projectPath) {
759
461
 
760
462
  // src/steps/create-env.ts
761
463
  import { writeFile as writeFile2, readFile as readFile2, appendFile } from "fs/promises";
762
- import path4 from "path";
464
+ import path3 from "path";
763
465
  async function createEnvFile(projectPath, supabaseKeys) {
764
466
  await withSpinner(
765
467
  "Creando archivo .env.local...",
@@ -770,10 +472,10 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}
770
472
  SUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}
771
473
  `;
772
474
  await writeFile2(
773
- path4.join(projectPath, ".env.local"),
475
+ path3.join(projectPath, ".env.local"),
774
476
  envContent
775
477
  );
776
- const gitignorePath = path4.join(projectPath, ".gitignore");
478
+ const gitignorePath = path3.join(projectPath, ".gitignore");
777
479
  try {
778
480
  const gitignore = await readFile2(gitignorePath, "utf-8");
779
481
  if (!gitignore.includes(".env.local")) {
@@ -817,6 +519,53 @@ async function setupGit(projectPath, remoteUrl) {
817
519
  );
818
520
  }
819
521
 
522
+ // src/ui/logger.ts
523
+ import chalk from "chalk";
524
+ var logger = {
525
+ info: (message) => {
526
+ console.log(chalk.blue("\u2139"), message);
527
+ },
528
+ success: (message) => {
529
+ console.log(chalk.green("\u2714"), message);
530
+ },
531
+ warning: (message) => {
532
+ console.log(chalk.yellow("\u26A0"), message);
533
+ },
534
+ error: (message) => {
535
+ console.log(chalk.red("\u2716"), message);
536
+ },
537
+ step: (step, total, message) => {
538
+ console.log(chalk.cyan(`[${step}/${total}]`), message);
539
+ },
540
+ newLine: () => {
541
+ console.log();
542
+ },
543
+ divider: () => {
544
+ console.log(chalk.gray("\u2500".repeat(50)));
545
+ },
546
+ title: (message) => {
547
+ console.log(chalk.bold.white(message));
548
+ },
549
+ subtitle: (message) => {
550
+ console.log(chalk.gray(message));
551
+ },
552
+ link: (label, url) => {
553
+ console.log(` ${chalk.gray(label + ":")} ${chalk.cyan.underline(url)}`);
554
+ },
555
+ list: (items) => {
556
+ items.forEach((item) => {
557
+ console.log(chalk.gray(" \u2022"), item);
558
+ });
559
+ },
560
+ table: (rows) => {
561
+ const maxLabelLength = Math.max(...rows.map((r) => r.label.length));
562
+ rows.forEach(({ label, value }) => {
563
+ const paddedLabel = label.padEnd(maxLabelLength);
564
+ console.log(` ${chalk.gray(paddedLabel)} ${value}`);
565
+ });
566
+ }
567
+ };
568
+
820
569
  // src/ui/banner.ts
821
570
  import boxen from "boxen";
822
571
  import chalk2 from "chalk";
@@ -871,7 +620,7 @@ async function createProject(projectName, options = {}) {
871
620
  if (!validation.valid) {
872
621
  throw new Error(validation.error);
873
622
  }
874
- const projectPath = path5.resolve(process.cwd(), projectName);
623
+ const projectPath = path4.resolve(process.cwd(), projectName);
875
624
  if (!await hasConfig()) {
876
625
  logger.warning('No se encontr\xF3 configuraci\xF3n. Ejecuta "create-lft-app config" primero.');
877
626
  throw new Error("Configuraci\xF3n no encontrada");
@@ -894,7 +643,7 @@ async function createProject(projectName, options = {}) {
894
643
  logger.table(resources);
895
644
  logger.newLine();
896
645
  if (!options.autoConfirm) {
897
- const shouldContinue = await confirm2({
646
+ const shouldContinue = await confirm({
898
647
  message: "\xBFContinuar con la creaci\xF3n?",
899
648
  default: true
900
649
  });
@@ -959,6 +708,11 @@ program.argument("[project-name]", "Nombre del proyecto a crear").option("--skip
959
708
  logger.info("Uso: create-lft-app <nombre-proyecto>");
960
709
  process.exit(1);
961
710
  }
711
+ if (!await hasConfig()) {
712
+ logger.error("Las credenciales no est\xE1n configuradas en el paquete");
713
+ logger.info("Contacta al administrador del CLI");
714
+ process.exit(1);
715
+ }
962
716
  try {
963
717
  await createProject(projectName, {
964
718
  skipGithub: options.skipGithub,
@@ -974,21 +728,5 @@ program.argument("[project-name]", "Nombre del proyecto a crear").option("--skip
974
728
  process.exit(1);
975
729
  }
976
730
  });
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
731
  program.parse();
994
732
  //# sourceMappingURL=cli.js.map