@create-lft-app/cli 1.0.12 → 1.0.14

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
@@ -449,7 +449,7 @@ async function scaffoldNextJs(projectName, projectPath) {
449
449
  }
450
450
 
451
451
  // src/steps/copy-template.ts
452
- import { cp, mkdir, readFile, writeFile } from "fs/promises";
452
+ import { cp, mkdir } from "fs/promises";
453
453
  import path2 from "path";
454
454
  import { fileURLToPath } from "url";
455
455
  var __filename2 = fileURLToPath(import.meta.url);
@@ -475,10 +475,15 @@ async function copyTemplate(projectPath) {
475
475
  path2.join(srcDir, "components", "dashboard"),
476
476
  { recursive: true }
477
477
  );
478
- await mkdir(path2.join(srcDir, "lib"), { recursive: true });
479
478
  await cp(
480
- path2.join(templatesDir, "lib", "utils.ts"),
481
- path2.join(srcDir, "lib", "utils.ts")
479
+ path2.join(templatesDir, "lib"),
480
+ path2.join(srcDir, "lib"),
481
+ { recursive: true }
482
+ );
483
+ await cp(
484
+ path2.join(templatesDir, "modules"),
485
+ path2.join(srcDir, "modules"),
486
+ { recursive: true }
482
487
  );
483
488
  await mkdir(path2.join(srcDir, "hooks"), { recursive: true });
484
489
  await cp(
@@ -504,22 +509,14 @@ async function copyTemplate(projectPath) {
504
509
  path2.join(templatesDir, "app", "auth", "login", "page.tsx"),
505
510
  path2.join(srcDir, "app", "auth", "login", "page.tsx")
506
511
  );
507
- await mergeGlobalStyles(projectPath, templatesDir);
512
+ await cp(
513
+ path2.join(templatesDir, "app", "globals.css"),
514
+ path2.join(srcDir, "app", "globals.css")
515
+ );
508
516
  },
509
517
  "Template LFT copiado (47 componentes + p\xE1ginas)"
510
518
  );
511
519
  }
512
- async function mergeGlobalStyles(projectPath, templatesDir) {
513
- const templateCssPath = path2.join(templatesDir, "app", "globals.css");
514
- const projectCssPath = path2.join(projectPath, "src", "app", "globals.css");
515
- try {
516
- const templateCss = await readFile(templateCssPath, "utf-8");
517
- const existingCss = await readFile(projectCssPath, "utf-8");
518
- const merged = existingCss + "\n\n/* LFT Custom Styles */\n" + templateCss;
519
- await writeFile(projectCssPath, merged);
520
- } catch {
521
- }
522
- }
523
520
 
524
521
  // src/steps/install-deps.ts
525
522
  import { execa as execa2 } from "execa";
@@ -560,6 +557,10 @@ var TEMPLATE_DEPENDENCIES = [
560
557
  "date-fns",
561
558
  // Toast notifications
562
559
  "sonner",
560
+ // Theme
561
+ "next-themes",
562
+ // Animations
563
+ "tw-animate-css",
563
564
  // Validation
564
565
  "zod",
565
566
  // Supabase client
@@ -587,7 +588,7 @@ async function installDependencies(projectPath) {
587
588
  }
588
589
 
589
590
  // src/steps/create-env.ts
590
- import { writeFile as writeFile2, readFile as readFile2, appendFile } from "fs/promises";
591
+ import { writeFile, readFile, appendFile } from "fs/promises";
591
592
  import path3 from "path";
592
593
  async function createEnvFile(projectPath, supabaseKeys) {
593
594
  await withSpinner(
@@ -598,18 +599,18 @@ NEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}
598
599
  NEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}
599
600
  SUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}
600
601
  `;
601
- await writeFile2(
602
+ await writeFile(
602
603
  path3.join(projectPath, ".env.local"),
603
604
  envContent
604
605
  );
605
606
  const gitignorePath = path3.join(projectPath, ".gitignore");
606
607
  try {
607
- const gitignore = await readFile2(gitignorePath, "utf-8");
608
+ const gitignore = await readFile(gitignorePath, "utf-8");
608
609
  if (!gitignore.includes(".env.local")) {
609
610
  await appendFile(gitignorePath, "\n# Environment variables\n.env.local\n.env*.local\n");
610
611
  }
611
612
  } catch {
612
- await writeFile2(gitignorePath, "# Environment variables\n.env.local\n.env*.local\n");
613
+ await writeFile(gitignorePath, "# Environment variables\n.env.local\n.env*.local\n");
613
614
  }
614
615
  },
615
616
  "Archivo .env.local creado con credenciales de Supabase"
@@ -1 +1 @@
1
- {"version":3,"sources":["../../bin/cli.ts","../../src/index.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","import { existsSync, readFileSync } from 'fs';\n\n// Variable para almacenar la ruta del config\nlet configFilePath: string = '';\n\ninterface ConfigFile {\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// Cache de la configuración cargada\nlet loadedConfig: ConfigFile | 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;\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 * Carga la configuración desde el archivo JSON\n */\nfunction loadConfigFromFile(): ConfigFile | null {\n if (loadedConfig) {\n return loadedConfig;\n }\n\n if (!configFilePath || !existsSync(configFilePath)) {\n return null;\n }\n\n try {\n const content = readFileSync(configFilePath, 'utf-8');\n const parsed = JSON.parse(content);\n\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 null;\n }\n}\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 const config = loadConfigFromFile();\n\n if (!config) {\n throw new Error('No se pudo cargar la configuración');\n }\n\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: config.github.token,\n username: config.github.username,\n },\n supabase: {\n accessToken: config.supabase.token,\n organizationId: config.supabase.orgId,\n },\n jira: {\n email: config.jira.email,\n apiToken: config.jira.token,\n domain: config.jira.domain,\n },\n },\n defaults: {\n githubOrg: config.github.org || undefined,\n supabaseRegion: config.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n const config = loadConfigFromFile();\n\n if (!config) {\n return false;\n }\n\n return (\n config.github.token !== '' &&\n config.supabase.token !== '' &&\n 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"]}
1
+ {"version":3,"sources":["../../bin/cli.ts","../../src/index.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","import { existsSync, readFileSync } from 'fs';\n\n// Variable para almacenar la ruta del config\nlet configFilePath: string = '';\n\ninterface ConfigFile {\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// Cache de la configuración cargada\nlet loadedConfig: ConfigFile | 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;\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 * Carga la configuración desde el archivo JSON\n */\nfunction loadConfigFromFile(): ConfigFile | null {\n if (loadedConfig) {\n return loadedConfig;\n }\n\n if (!configFilePath || !existsSync(configFilePath)) {\n return null;\n }\n\n try {\n const content = readFileSync(configFilePath, 'utf-8');\n const parsed = JSON.parse(content);\n\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 null;\n }\n}\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 const config = loadConfigFromFile();\n\n if (!config) {\n throw new Error('No se pudo cargar la configuración');\n }\n\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: config.github.token,\n username: config.github.username,\n },\n supabase: {\n accessToken: config.supabase.token,\n organizationId: config.supabase.orgId,\n },\n jira: {\n email: config.jira.email,\n apiToken: config.jira.token,\n domain: config.jira.domain,\n },\n },\n defaults: {\n githubOrg: config.github.org || undefined,\n supabaseRegion: config.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n const config = loadConfigFromFile();\n\n if (!config) {\n return false;\n }\n\n return (\n config.github.token !== '' &&\n config.supabase.token !== '' &&\n 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 } 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 + supabase)\n await cp(\n path.join(templatesDir, 'lib'),\n path.join(srcDir, 'lib'),\n { recursive: true }\n );\n\n // Copiar modules (auth actions)\n await cp(\n path.join(templatesDir, 'modules'),\n path.join(srcDir, 'modules'),\n { recursive: true }\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 // Reemplazar globals.css con el completo del template\n await cp(\n path.join(templatesDir, 'app', 'globals.css'),\n path.join(srcDir, 'app', 'globals.css')\n );\n },\n 'Template LFT copiado (47 componentes + páginas)'\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 // Theme\n 'next-themes',\n\n // Animations\n 'tw-animate-css',\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":";;;AAAA,SAAS,eAAe;;;ACAxB,OAAOA,WAAU;AACjB,SAAS,eAAe;;;ACDxB,SAAS,YAAY,oBAAoB;AAGzC,IAAI,iBAAyB;AAqB7B,IAAI,eAAkC;AAK/B,SAAS,cAAcC,OAAoB;AAChD,mBAAiBA;AACjB,iBAAe;AACjB;AAKO,SAAS,gBAAwB;AACtC,SAAO;AACT;AAKA,SAAS,qBAAwC;AAC/C,MAAI,cAAc;AAChB,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,kBAAkB,CAAC,WAAW,cAAc,GAAG;AAClD,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,aAAa,gBAAgB,OAAO;AACpD,UAAM,SAAS,KAAK,MAAM,OAAO;AAEjC,mBAAe;AAAA,MACb,QAAQ;AAAA,QACN,OAAO,OAAO,QAAQ,SAAS;AAAA,QAC/B,UAAU,OAAO,QAAQ,YAAY;AAAA,QACrC,KAAK,OAAO,QAAQ,OAAO;AAAA,MAC7B;AAAA,MACA,UAAU;AAAA,QACR,OAAO,OAAO,UAAU,SAAS;AAAA,QACjC,OAAO,OAAO,UAAU,SAAS;AAAA,QACjC,QAAQ,OAAO,UAAU,UAAU;AAAA,MACrC;AAAA,MACA,MAAM;AAAA,QACJ,OAAO,OAAO,MAAM,SAAS;AAAA,QAC7B,OAAO,OAAO,MAAM,SAAS;AAAA,QAC7B,QAAQ,OAAO,MAAM,UAAU;AAAA,MACjC;AAAA,IACF;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA0BA,eAAsB,aAAiC;AACrD,QAAM,SAAS,mBAAmB;AAElC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,uCAAoC;AAAA,EACtD;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,MACX,QAAQ;AAAA,QACN,OAAO,OAAO,OAAO;AAAA,QACrB,UAAU,OAAO,OAAO;AAAA,MAC1B;AAAA,MACA,UAAU;AAAA,QACR,aAAa,OAAO,SAAS;AAAA,QAC7B,gBAAgB,OAAO,SAAS;AAAA,MAClC;AAAA,MACA,MAAM;AAAA,QACJ,OAAO,OAAO,KAAK;AAAA,QACnB,UAAU,OAAO,KAAK;AAAA,QACtB,QAAQ,OAAO,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,WAAW,OAAO,OAAO,OAAO;AAAA,MAChC,gBAAgB,OAAO,SAAS;AAAA,MAChC,iBAAiB;AAAA,IACnB;AAAA,EACF;AACF;AAEA,eAAsB,YAA8B;AAClD,QAAM,SAAS,mBAAmB;AAElC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SACE,OAAO,OAAO,UAAU,MACxB,OAAO,SAAS,UAAU,MAC1B,OAAO,KAAK,UAAU;AAE1B;;;ACrJA,SAAS,eAAe;;;ACAxB,OAAO,SAAuB;AAEvB,SAAS,cAAc,MAAmB;AAC/C,SAAO,IAAI;AAAA,IACT;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AACH;AAEA,eAAsB,YACpB,MACA,IACA,aACY;AACZ,QAAM,UAAU,cAAc,IAAI,EAAE,MAAM;AAE1C,MAAI;AACF,UAAM,SAAS,MAAM,GAAG;AACxB,YAAQ,QAAQ,eAAe,IAAI;AACnC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,KAAK;AACb,UAAM;AAAA,EACR;AACF;;;ACxBA,OAAO,WAAW;AAEX,IAAM,SAAS;AAAA,EACpB,MAAM,CAAC,YAAoB;AACzB,YAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,OAAO;AAAA,EACtC;AAAA,EAEA,SAAS,CAAC,YAAoB;AAC5B,YAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,OAAO;AAAA,EACvC;AAAA,EAEA,SAAS,CAAC,YAAoB;AAC5B,YAAQ,IAAI,MAAM,OAAO,QAAG,GAAG,OAAO;AAAA,EACxC;AAAA,EAEA,OAAO,CAAC,YAAoB;AAC1B,YAAQ,IAAI,MAAM,IAAI,QAAG,GAAG,OAAO;AAAA,EACrC;AAAA,EAEA,MAAM,CAAC,MAAc,OAAe,YAAoB;AACtD,YAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,OAAO;AAAA,EACvD;AAAA,EAEA,SAAS,MAAM;AACb,YAAQ,IAAI;AAAA,EACd;AAAA,EAEA,SAAS,MAAM;AACb,YAAQ,IAAI,MAAM,KAAK,SAAI,OAAO,EAAE,CAAC,CAAC;AAAA,EACxC;AAAA,EAEA,OAAO,CAAC,YAAoB;AAC1B,YAAQ,IAAI,MAAM,KAAK,MAAM,OAAO,CAAC;AAAA,EACvC;AAAA,EAEA,UAAU,CAAC,YAAoB;AAC7B,YAAQ,IAAI,MAAM,KAAK,OAAO,CAAC;AAAA,EACjC;AAAA,EAEA,MAAM,CAAC,OAAe,QAAgB;AACpC,YAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,GAAG,CAAC,IAAI,MAAM,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,EACzE;AAAA,EAEA,MAAM,CAAC,UAAoB;AACzB,UAAM,QAAQ,CAAC,SAAS;AACtB,cAAQ,IAAI,MAAM,KAAK,UAAK,GAAG,IAAI;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,CAAC,SAAkD;AACxD,UAAM,iBAAiB,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC;AAClE,SAAK,QAAQ,CAAC,EAAE,OAAO,MAAM,MAAM;AACjC,YAAM,cAAc,MAAM,OAAO,cAAc;AAC/C,cAAQ,IAAI,KAAK,MAAM,KAAK,WAAW,CAAC,KAAK,KAAK,EAAE;AAAA,IACtD,CAAC;AAAA,EACH;AACF;;;AFnDA,eAAsB,iBACpB,aACA,QACiB;AACjB,QAAM,UAAU,IAAI,QAAQ,EAAE,MAAM,OAAO,YAAY,OAAO,MAAM,CAAC;AACrE,QAAM,MAAM,OAAO,SAAS;AAC5B,QAAM,QAAQ,OAAO,OAAO,YAAY,OAAO;AAG/C,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,KAAK,MAAM,IAAI;AAAA,MAC5C;AAAA,MACA,MAAM;AAAA,IACR,CAAC;AACD,WAAO,QAAQ,WAAW,KAAK,IAAI,WAAW,cAAc;AAC5D,WAAO,SAAS,KAAK;AAAA,EACvB,QAAQ;AAAA,EAER;AAEA,SAAO;AAAA,IACL;AAAA,IACA,YAAY;AACV,UAAI;AAEJ,UAAI,KAAK;AACP,eAAO,MAAM,QAAQ,KAAK,MAAM,YAAY;AAAA,UAC1C;AAAA,UACA,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA,UACX,aAAa,YAAY,WAAW;AAAA,QACtC,CAAC;AAAA,MACH,OAAO;AACL,eAAO,MAAM,QAAQ,KAAK,MAAM,2BAA2B;AAAA,UACzD,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA,UACX,aAAa,YAAY,WAAW;AAAA,QACtC,CAAC;AAAA,MACH;AAEA,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,IACA,WAAW,KAAK,IAAI,WAAW;AAAA,EACjC;AACF;;;AG5BA,IAAM,mBAAmB;AAEzB,eAAe,oBACb,WACA,OACA,cAAc,IACC;AACf,QAAM,UAAU,cAAc,8DAA8D,EAAE,MAAM;AAEpG,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,UAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,aAAa,SAAS,IAAI;AAAA,MACxE,SAAS,EAAE,eAAe,UAAU,KAAK,GAAG;AAAA,IAC9C,CAAC;AAED,QAAI,SAAS,IAAI;AACf,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,UAAI,QAAQ,WAAW,kBAAkB;AACvC,gBAAQ,QAAQ,4BAA4B;AAC5C;AAAA,MACF;AAAA,IACF;AAGA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AACxD,YAAQ,OAAO,mCAAmC,KAAK,OAAO,IAAI,KAAK,IAAI,EAAE,CAAC,QAAS,IAAI,KAAK,IAAK,EAAE;AAAA,EACzG;AAEA,UAAQ,KAAK,mDAAgD;AAC7D,QAAM,IAAI,MAAM,2DAAwD;AAC1E;AAEA,eAAe,kBACb,WACA,OACkD;AAClD,QAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,aAAa,SAAS,aAAa;AAAA,IACjF,SAAS,EAAE,eAAe,UAAU,KAAK,GAAG;AAAA,EAC9C,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAM,UAAU,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,GAAG;AACrD,QAAM,aAAa,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,cAAc,GAAG;AAEhE,MAAI,CAAC,WAAW,CAAC,YAAY;AAC3B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,SAAO,EAAE,SAAS,WAAW;AAC/B;AAEA,eAAe,oBACb,aACA,OACyC;AACzC,QAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,aAAa;AAAA,IAC3D,SAAS,EAAE,eAAe,UAAU,KAAK,GAAG;AAAA,EAC9C,CAAC;AAED,MAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,QAAM,WAAY,MAAM,SAAS,KAAK;AACtC,SAAO,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW,KAAK;AACzD;AAEA,eAAsB,sBACpB,aACA,QACgC;AAChC,QAAM,QAAQ,OAAO,YAAY,SAAS;AAC1C,QAAM,QAAQ,OAAO,YAAY,SAAS;AAC1C,QAAM,SAAS,OAAO,SAAS;AAG/B,QAAM,WAAW,MAAM,oBAAoB,aAAa,KAAK;AAC7D,MAAI,UAAU;AACZ,WAAO,QAAQ,aAAa,WAAW,cAAc;AACrD,UAAM,EAAE,SAAAC,UAAS,YAAAC,YAAW,IAAI,MAAM,kBAAkB,SAAS,IAAI,KAAK;AAC1E,WAAO;AAAA,MACL,KAAK,WAAW,SAAS,EAAE;AAAA,MAC3B,SAAAD;AAAA,MACA,YAAAC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,uBAAuB;AAG1C,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA,YAAY;AACV,YAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,aAAa;AAAA,QAC3D,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,KAAK;AAAA,UAC9B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,MAAM;AAAA,UACN,iBAAiB;AAAA,UACjB;AAAA,UACA,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,cAAM,IAAI,MAAM,oCAAoC,KAAK,EAAE;AAAA,MAC7D;AAEA,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,oBAAoB,QAAQ,IAAI,KAAK;AAG3C,QAAM,EAAE,SAAS,WAAW,IAAI,MAAM,kBAAkB,QAAQ,IAAI,KAAK;AAEzE,QAAM,aAAa,WAAW,QAAQ,EAAE;AAExC,SAAO;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,yBAAiC;AACxC,QAAM,QAAQ;AACd,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,gBAAY,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AAAA,EACnE;AACA,SAAO;AACT;;;AChKO,SAAS,oBAAoB,MAAgC;AAElE,MAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,IAAI;AAC/B,WAAO,EAAE,OAAO,OAAO,OAAO,iDAA8C;AAAA,EAC9E;AAGA,QAAM,eAAe;AACrB,MAAI,CAAC,aAAa,KAAK,IAAI,GAAG;AAC5B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,WAAW,KAAK,IAAI,GAAG;AACzB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO,EAAE,OAAO,OAAO,OAAO,6CAA6C;AAAA,EAC7E;AAEA,MAAI,KAAK,SAAS,IAAI;AACpB,WAAO,EAAE,OAAO,OAAO,OAAO,mDAAgD;AAAA,EAChF;AAGA,SAAO,EAAE,OAAO,KAAK;AACvB;AAEO,SAAS,gBAAgB,aAA6B;AAE3D,QAAM,UAAU,YACb,QAAQ,iBAAiB,EAAE,EAC3B,YAAY,EACZ,MAAM,GAAG,EAAE;AAEd,SAAO,WAAW;AACpB;;;ACrCA,eAAe,wBACb,aACA,MACA,QACqC;AACrC,QAAM,WAAW,MAAM;AAAA,IACrB,WAAW,MAAM,oCAAoC,mBAAmB,WAAW,CAAC;AAAA,IACpF;AAAA,MACE,SAAS;AAAA,QACP,eAAe,SAAS,IAAI;AAAA,QAC5B,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW,KAAK;AAC5D;AAEA,eAAsB,kBACpB,aACA,QACiB;AACjB,QAAM,EAAE,OAAO,UAAU,OAAO,IAAI,OAAO,YAAY;AACvD,QAAM,OAAO,OAAO,KAAK,GAAG,KAAK,IAAI,QAAQ,EAAE,EAAE,SAAS,QAAQ;AAClE,QAAM,aAAa,gBAAgB,WAAW;AAG9C,QAAM,WAAW,MAAM,wBAAwB,aAAa,MAAM,MAAM;AACxE,MAAI,UAAU;AACZ,WAAO,QAAQ,SAAS,SAAS,GAAG,cAAc;AAClD,WAAO,WAAW,MAAM,WAAW,SAAS,GAAG;AAAA,EACjD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,YAAY;AAEV,YAAM,aAAa,MAAM,MAAM,WAAW,MAAM,sBAAsB;AAAA,QACpE,SAAS;AAAA,UACP,eAAe,SAAS,IAAI;AAAA,UAC5B,gBAAgB;AAAA,QAClB;AAAA,MACF,CAAC;AAED,UAAI,CAAC,WAAW,IAAI;AAClB,cAAM,IAAI,MAAM,uDAAoD;AAAA,MACtE;AAEA,YAAM,KAAM,MAAM,WAAW,KAAK;AAGlC,YAAM,WAAW,MAAM,MAAM,WAAW,MAAM,uBAAuB;AAAA,QACnE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,SAAS,IAAI;AAAA,UAC5B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,KAAK;AAAA,UACL,MAAM;AAAA,UACN,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,UACpB,eAAe,GAAG;AAAA,QACpB,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAK;AAGlC,YAAI,MAAM,SAAS,aAAa,GAAG;AACjC,gBAAM,SAAS,GAAG,UAAU,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAC9D,gBAAM,gBAAgB,MAAM,MAAM,WAAW,MAAM,uBAAuB;AAAA,YACxE,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,eAAe,SAAS,IAAI;AAAA,cAC5B,gBAAgB;AAAA,YAClB;AAAA,YACA,MAAM,KAAK,UAAU;AAAA,cACnB,KAAK;AAAA,cACL,MAAM;AAAA,cACN,gBAAgB;AAAA,cAChB,oBAAoB;AAAA,cACpB,eAAe,GAAG;AAAA,YACpB,CAAC;AAAA,UACH,CAAC;AAED,cAAI,CAAC,cAAc,IAAI;AACrB,kBAAM,IAAI,MAAM,gCAAgC,MAAM,cAAc,KAAK,CAAC,EAAE;AAAA,UAC9E;AAEA,gBAAMC,WAAW,MAAM,cAAc,KAAK;AAC1C,iBAAO,WAAW,MAAM,WAAWA,SAAQ,GAAG;AAAA,QAChD;AAEA,cAAM,IAAI,MAAM,gCAAgC,KAAK,EAAE;AAAA,MACzD;AAEA,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,aAAO,WAAW,MAAM,WAAW,QAAQ,GAAG;AAAA,IAChD;AAAA,IACA,kBAAkB,UAAU;AAAA,EAC9B;AACF;;;ACtHA,SAAS,aAAa;AACtB,SAAS,cAAAC,mBAAkB;AAC3B,OAAO,UAAU;AAIjB,eAAsB,eACpB,aACA,aACe;AACf,QAAM,YAAY,KAAK,KAAK,QAAQ,IAAI,GAAG,WAAW;AAEtD,MAAIC,YAAW,SAAS,GAAG;AACzB,WAAO,QAAQ,YAAY,WAAW,cAAc;AACpD;AAAA,EACF;AAEA,QAAM;AAAA,IACJ;AAAA,IACA,YAAY;AACV,YAAM,MAAM,OAAO;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QAAkB;AAAA,QAClB;AAAA,QACA;AAAA,MACF,GAAG;AAAA,QACD,KAAK,QAAQ,IAAI;AAAA,QACjB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,YAAY,WAAW;AAAA,EACzB;AACF;;;ACvCA,SAAS,IAAI,aAAa;AAC1B,OAAOC,WAAU;AACjB,SAAS,qBAAqB;AAG9B,IAAMC,cAAa,cAAc,YAAY,GAAG;AAChD,IAAMC,aAAYC,MAAK,QAAQF,WAAU;AAEzC,eAAsB,aAAa,aAAoC;AACrE,QAAM;AAAA,IACJ;AAAA,IACA,YAAY;AAEV,YAAM,eAAeE,MAAK,KAAKD,YAAW,MAAM,MAAM,WAAW;AACjE,YAAM,SAASC,MAAK,KAAK,aAAa,KAAK;AAG3C,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,cAAc,IAAI;AAAA,QAC1CA,MAAK,KAAK,QAAQ,cAAc,IAAI;AAAA,QACpC,EAAE,WAAW,KAAK;AAAA,MACpB;AAGA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,cAAc,QAAQ;AAAA,QAC9CA,MAAK,KAAK,QAAQ,cAAc,QAAQ;AAAA,QACxC,EAAE,WAAW,KAAK;AAAA,MACpB;AAGA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,cAAc,WAAW;AAAA,QACjDA,MAAK,KAAK,QAAQ,cAAc,WAAW;AAAA,QAC3C,EAAE,WAAW,KAAK;AAAA,MACpB;AAGA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,KAAK;AAAA,QAC7BA,MAAK,KAAK,QAAQ,KAAK;AAAA,QACvB,EAAE,WAAW,KAAK;AAAA,MACpB;AAGA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,SAAS;AAAA,QACjCA,MAAK,KAAK,QAAQ,SAAS;AAAA,QAC3B,EAAE,WAAW,KAAK;AAAA,MACpB;AAGA,YAAM,MAAMA,MAAK,KAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3D,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,OAAO;AAAA,QAC/BA,MAAK,KAAK,QAAQ,OAAO;AAAA,QACzB,EAAE,WAAW,KAAK;AAAA,MACpB;AAGA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,OAAO,YAAY;AAAA,QAC3CA,MAAK,KAAK,QAAQ,OAAO,YAAY;AAAA,MACvC;AAEA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,OAAO,UAAU;AAAA,QACzCA,MAAK,KAAK,QAAQ,OAAO,UAAU;AAAA,MACrC;AAGA,YAAM,MAAMA,MAAK,KAAK,QAAQ,OAAO,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AACtE,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,OAAO,aAAa,UAAU;AAAA,QACtDA,MAAK,KAAK,QAAQ,OAAO,aAAa,UAAU;AAAA,MAClD;AAGA,YAAM,MAAMA,MAAK,KAAK,QAAQ,OAAO,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1E,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,OAAO,QAAQ,SAAS,UAAU;AAAA,QAC1DA,MAAK,KAAK,QAAQ,OAAO,QAAQ,SAAS,UAAU;AAAA,MACtD;AAGA,YAAM;AAAA,QACJA,MAAK,KAAK,cAAc,OAAO,aAAa;AAAA,QAC5CA,MAAK,KAAK,QAAQ,OAAO,aAAa;AAAA,MACxC;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;;;AC5FA,SAAS,SAAAC,cAAa;AAGtB,IAAM,wBAAwB;AAAA;AAAA,EAE5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EACA;AACF;AAEA,IAAM,4BAA4B;AAAA,EAChC;AACF;AAEA,eAAsB,oBAAoB,aAAoC;AAC5E,QAAM;AAAA,IACJ,4BAA4B,sBAAsB,MAAM;AAAA,IACxD,YAAY;AAEV,YAAMC,OAAM,OAAO,CAAC,WAAW,GAAG,qBAAqB,GAAG;AAAA,QACxD,KAAK;AAAA,QACL,OAAO;AAAA,MACT,CAAC;AAGD,YAAMA,OAAM,OAAO,CAAC,WAAW,MAAM,GAAG,yBAAyB,GAAG;AAAA,QAClE,KAAK;AAAA,QACL,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA;AAAA,EACF;AACF;;;ACnFA,SAAS,WAAW,UAAU,kBAAkB;AAChD,OAAOC,WAAU;AASjB,eAAsB,cACpB,aACA,cACe;AACf,QAAM;AAAA,IACJ;AAAA,IACA,YAAY;AACV,YAAM,aAAa;AAAA,2BACE,aAAa,GAAG;AAAA,gCACX,aAAa,OAAO;AAAA,4BACxB,aAAa,UAAU;AAAA;AAG7C,YAAM;AAAA,QACJC,MAAK,KAAK,aAAa,YAAY;AAAA,QACnC;AAAA,MACF;AAGA,YAAM,gBAAgBA,MAAK,KAAK,aAAa,YAAY;AACzD,UAAI;AACF,cAAM,YAAY,MAAM,SAAS,eAAe,OAAO;AACvD,YAAI,CAAC,UAAU,SAAS,YAAY,GAAG;AACrC,gBAAM,WAAW,eAAe,sDAAsD;AAAA,QACxF;AAAA,MACF,QAAQ;AAEN,cAAM,UAAU,eAAe,oDAAoD;AAAA,MACrF;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;;;AC1CA,SAAS,iBAAiB;AAG1B,eAAsB,SACpB,aACA,WACe;AACf,QAAM,MAAM,UAAU,WAAW;AAEjC,QAAM;AAAA,IACJ;AAAA,IACA,YAAY;AAEV,YAAM,SAAS,MAAM,IAAI,YAAY;AAErC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,KAAK;AAAA,MACjB;AAGA,UAAI;AACF,cAAM,IAAI,UAAU,UAAU,SAAS;AAAA,MACzC,QAAQ;AAEN,cAAM,IAAI,OAAO,CAAC,WAAW,UAAU,SAAS,CAAC;AAAA,MACnD;AAGA,YAAM,IAAI,IAAI,GAAG;AAGjB,YAAM,IAAI,OAAO,gDAAgD;AAAA,QAC/D,YAAY;AAAA,MACd,CAAC;AAGD,UAAI;AACF,cAAM,IAAI,OAAO,CAAC,MAAM,MAAM,CAAC;AAAA,MACjC,QAAQ;AAAA,MAER;AAGA,YAAM,IAAI,KAAK,CAAC,kBAAkB,UAAU,MAAM,CAAC;AAAA,IACrD;AAAA,IACA;AAAA,EACF;AACF;;;AC/CA,OAAO,WAAW;AAClB,OAAOC,YAAW;AAEX,SAAS,aAAmB;AACjC,QAAM,QAAQA,OAAM,KAAK,KAAK,gBAAgB;AAC9C,QAAM,UAAUA,OAAM,KAAK,QAAQ;AACnC,QAAM,cAAcA,OAAM,MAAM,gCAAgC;AAEhE,QAAM,SAAS,MAAM,GAAG,KAAK,IAAI,OAAO;AAAA,EAAK,WAAW,IAAI;AAAA,IAC1D,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,aAAa;AAAA,EACf,CAAC;AAED,UAAQ,IAAI,MAAM;AACpB;AAEO,SAAS,kBAAkB,aAAqB,MAI9C;AACP,QAAM,QAAQ;AAAA,IACZA,OAAM,MAAM,KAAK,aAAa,WAAW,wBAAwB;AAAA,IACjE;AAAA,IACAA,OAAM,MAAM,aAAa,IAAI,MAAM,WAAW;AAAA,IAC9C;AAAA,EACF;AAEA,MAAI,KAAK,UAAU,KAAK,YAAY,KAAK,MAAM;AAC7C,UAAM,KAAKA,OAAM,MAAM,UAAU,CAAC;AAClC,QAAI,KAAK,QAAQ;AACf,YAAM,KAAK,KAAKA,OAAM,KAAK,SAAS,CAAC,MAAMA,OAAM,KAAK,KAAK,MAAM,CAAC,EAAE;AAAA,IACtE;AACA,QAAI,KAAK,UAAU;AACjB,YAAM,KAAK,KAAKA,OAAM,KAAK,WAAW,CAAC,IAAIA,OAAM,KAAK,KAAK,QAAQ,CAAC,EAAE;AAAA,IACxE;AACA,QAAI,KAAK,MAAM;AACb,YAAM,KAAK,KAAKA,OAAM,KAAK,OAAO,CAAC,QAAQA,OAAM,KAAK,KAAK,IAAI,CAAC,EAAE;AAAA,IACpE;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAKA,OAAM,MAAM,kBAAkB,CAAC;AAC1C,QAAM,KAAK,KAAKA,OAAM,KAAK,IAAI,CAAC,IAAI,WAAW,EAAE;AACjD,QAAM,KAAK,KAAKA,OAAM,KAAK,aAAa,CAAC,EAAE;AAE3C,QAAM,SAAS,MAAM,MAAM,KAAK,IAAI,GAAG;AAAA,IACrC,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,aAAa;AAAA,EACf,CAAC;AAED,UAAQ,IAAI,MAAM;AACpB;;;AbjCA,eAAsB,cACpB,aACA,UAAgC,CAAC,GAClB;AAEf,QAAM,aAAa,oBAAoB,WAAW;AAClD,MAAI,CAAC,WAAW,OAAO;AACrB,UAAM,IAAI,MAAM,WAAW,KAAK;AAAA,EAClC;AAGA,QAAM,cAAcC,MAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW;AAG3D,MAAI,CAAC,MAAM,UAAU,GAAG;AACtB,WAAO,QAAQ,8EAAwE;AACvF,UAAM,IAAI,MAAM,gCAA6B;AAAA,EAC/C;AAEA,QAAM,SAAS,MAAM,WAAW;AAGhC,SAAO,QAAQ;AACf,SAAO,MAAM,8BAA8B;AAC3C,SAAO,QAAQ;AAEf,QAAM,YAAY,CAAC;AACnB,MAAI,CAAC,QAAQ,YAAY;AACvB,cAAU,KAAK,EAAE,OAAO,UAAU,OAAO,GAAG,OAAO,SAAS,aAAa,OAAO,YAAY,OAAO,QAAQ,IAAI,WAAW,aAAa,CAAC;AAAA,EAC1I;AACA,MAAI,CAAC,QAAQ,cAAc;AACzB,cAAU,KAAK,EAAE,OAAO,YAAY,OAAO,GAAG,WAAW,OAAO,OAAO,SAAS,cAAc,GAAG,CAAC;AAAA,EACpG;AACA,MAAI,CAAC,QAAQ,UAAU;AACrB,cAAU,KAAK,EAAE,OAAO,QAAQ,OAAO,aAAa,WAAW,QAAQ,OAAO,YAAY,KAAK,MAAM,GAAG,CAAC;AAAA,EAC3G;AACA,YAAU,KAAK,EAAE,OAAO,WAAW,OAAO,iDAAiD,CAAC;AAE5F,SAAO,MAAM,SAAS;AACtB,SAAO,QAAQ;AAGf,MAAI,CAAC,QAAQ,aAAa;AACxB,UAAM,iBAAiB,MAAM,QAAQ;AAAA,MACnC,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAED,QAAI,CAAC,gBAAgB;AACnB,aAAO,KAAK,wBAAqB;AACjC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,QAAQ;AACf,SAAO,QAAQ;AACf,SAAO,QAAQ;AAEf,QAAM,OAA8D,CAAC;AACrE,MAAI;AAGJ,QAAM,gBAAiC,CAAC;AAExC,MAAI,CAAC,QAAQ,YAAY;AACvB,kBAAc;AAAA,MACZ,iBAAiB,aAAa,MAAM,EAAE,KAAK,CAAC,QAAQ;AAClD,aAAK,SAAS;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ,cAAc;AACzB,kBAAc;AAAA,MACZ,sBAAsB,aAAa,MAAM,EAAE,KAAK,CAAC,WAAW;AAC1D,aAAK,WAAW,OAAO;AACvB,uBAAe;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ,UAAU;AACrB,kBAAc;AAAA,MACZ,kBAAkB,aAAa,MAAM,EAAE,KAAK,CAAC,QAAQ;AACnD,aAAK,OAAO;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,QAAQ,IAAI,aAAa;AAG/B,QAAM,eAAe,aAAa,WAAW;AAG7C,QAAM,aAAa,WAAW;AAG9B,QAAM,oBAAoB,WAAW;AAGrC,MAAI,cAAc;AAChB,UAAM,cAAc,aAAa,YAAY;AAAA,EAC/C;AAGA,MAAI,CAAC,QAAQ,WAAW,KAAK,QAAQ;AACnC,UAAM,SAAS,aAAa,KAAK,MAAM;AAAA,EACzC;AAGA,SAAO,QAAQ;AACf,oBAAkB,aAAa,IAAI;AACrC;;;ADnIA,IAAM,cAAc;AAAA,EAClB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AACf;AAEA,QACG,KAAK,gBAAgB,EACrB,YAAY,YAAY,WAAW,EACnC,QAAQ,YAAY,OAAO;AAE9B,QACG,SAAS,kBAAkB,6BAA6B,EACxD,eAAe,mBAAmB,oDAAoD,EACtF,OAAO,iBAAiB,gCAAgC,EACxD,OAAO,mBAAmB,+BAA+B,EACzD,OAAO,eAAe,4BAA4B,EAClD,OAAO,cAAc,kCAAkC,EACvD,OAAO,aAAa,kCAAkC,EACtD,OAAO,OAAO,aAAiC,YAAY;AAC1D,aAAW;AAGX,gBAAc,QAAQ,MAAM;AAE5B,MAAI,CAAC,aAAa;AAChB,WAAO,MAAM,yCAAyC;AACtD,WAAO,KAAK,oEAAoE;AAChF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,MAAM,UAAU,GAAG;AACtB,UAAM,aAAa,cAAc;AACjC,WAAO,MAAM,iDAA8C,UAAU,EAAE;AACvE,WAAO,QAAQ;AACf,WAAO,KAAK,6CAA6C;AACzD,WAAO,QAAQ;AACf,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBhB;AACI,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACF,UAAM,cAAc,aAAa;AAAA,MAC/B,YAAY,QAAQ;AAAA,MACpB,cAAc,QAAQ;AAAA,MACtB,UAAU,QAAQ;AAAA,MAClB,SAAS,QAAQ;AAAA,MACjB,aAAa,QAAQ;AAAA,IACvB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,iBAAiB,OAAO;AAC1B,aAAO,MAAM,MAAM,OAAO;AAAA,IAC5B;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":["path","path","anonKey","serviceKey","project","existsSync","existsSync","path","__filename","__dirname","path","execa","execa","path","path","chalk","path"]}
package/dist/src/index.js CHANGED
@@ -439,7 +439,7 @@ async function scaffoldNextJs(projectName, projectPath) {
439
439
  }
440
440
 
441
441
  // src/steps/copy-template.ts
442
- import { cp, mkdir, readFile, writeFile } from "fs/promises";
442
+ import { cp, mkdir } from "fs/promises";
443
443
  import path2 from "path";
444
444
  import { fileURLToPath } from "url";
445
445
  var __filename2 = fileURLToPath(import.meta.url);
@@ -465,10 +465,15 @@ async function copyTemplate(projectPath) {
465
465
  path2.join(srcDir, "components", "dashboard"),
466
466
  { recursive: true }
467
467
  );
468
- await mkdir(path2.join(srcDir, "lib"), { recursive: true });
469
468
  await cp(
470
- path2.join(templatesDir, "lib", "utils.ts"),
471
- path2.join(srcDir, "lib", "utils.ts")
469
+ path2.join(templatesDir, "lib"),
470
+ path2.join(srcDir, "lib"),
471
+ { recursive: true }
472
+ );
473
+ await cp(
474
+ path2.join(templatesDir, "modules"),
475
+ path2.join(srcDir, "modules"),
476
+ { recursive: true }
472
477
  );
473
478
  await mkdir(path2.join(srcDir, "hooks"), { recursive: true });
474
479
  await cp(
@@ -494,22 +499,14 @@ async function copyTemplate(projectPath) {
494
499
  path2.join(templatesDir, "app", "auth", "login", "page.tsx"),
495
500
  path2.join(srcDir, "app", "auth", "login", "page.tsx")
496
501
  );
497
- await mergeGlobalStyles(projectPath, templatesDir);
502
+ await cp(
503
+ path2.join(templatesDir, "app", "globals.css"),
504
+ path2.join(srcDir, "app", "globals.css")
505
+ );
498
506
  },
499
507
  "Template LFT copiado (47 componentes + p\xE1ginas)"
500
508
  );
501
509
  }
502
- async function mergeGlobalStyles(projectPath, templatesDir) {
503
- const templateCssPath = path2.join(templatesDir, "app", "globals.css");
504
- const projectCssPath = path2.join(projectPath, "src", "app", "globals.css");
505
- try {
506
- const templateCss = await readFile(templateCssPath, "utf-8");
507
- const existingCss = await readFile(projectCssPath, "utf-8");
508
- const merged = existingCss + "\n\n/* LFT Custom Styles */\n" + templateCss;
509
- await writeFile(projectCssPath, merged);
510
- } catch {
511
- }
512
- }
513
510
 
514
511
  // src/steps/install-deps.ts
515
512
  import { execa as execa2 } from "execa";
@@ -550,6 +547,10 @@ var TEMPLATE_DEPENDENCIES = [
550
547
  "date-fns",
551
548
  // Toast notifications
552
549
  "sonner",
550
+ // Theme
551
+ "next-themes",
552
+ // Animations
553
+ "tw-animate-css",
553
554
  // Validation
554
555
  "zod",
555
556
  // Supabase client
@@ -577,7 +578,7 @@ async function installDependencies(projectPath) {
577
578
  }
578
579
 
579
580
  // src/steps/create-env.ts
580
- import { writeFile as writeFile2, readFile as readFile2, appendFile } from "fs/promises";
581
+ import { writeFile, readFile, appendFile } from "fs/promises";
581
582
  import path3 from "path";
582
583
  async function createEnvFile(projectPath, supabaseKeys) {
583
584
  await withSpinner(
@@ -588,18 +589,18 @@ NEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}
588
589
  NEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}
589
590
  SUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}
590
591
  `;
591
- await writeFile2(
592
+ await writeFile(
592
593
  path3.join(projectPath, ".env.local"),
593
594
  envContent
594
595
  );
595
596
  const gitignorePath = path3.join(projectPath, ".gitignore");
596
597
  try {
597
- const gitignore = await readFile2(gitignorePath, "utf-8");
598
+ const gitignore = await readFile(gitignorePath, "utf-8");
598
599
  if (!gitignore.includes(".env.local")) {
599
600
  await appendFile(gitignorePath, "\n# Environment variables\n.env.local\n.env*.local\n");
600
601
  }
601
602
  } catch {
602
- await writeFile2(gitignorePath, "# Environment variables\n.env.local\n.env*.local\n");
603
+ await writeFile(gitignorePath, "# Environment variables\n.env.local\n.env*.local\n");
603
604
  }
604
605
  },
605
606
  "Archivo .env.local creado con credenciales de Supabase"
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.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","import { existsSync, readFileSync } from 'fs';\n\n// Variable para almacenar la ruta del config\nlet configFilePath: string = '';\n\ninterface ConfigFile {\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// Cache de la configuración cargada\nlet loadedConfig: ConfigFile | 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;\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 * Carga la configuración desde el archivo JSON\n */\nfunction loadConfigFromFile(): ConfigFile | null {\n if (loadedConfig) {\n return loadedConfig;\n }\n\n if (!configFilePath || !existsSync(configFilePath)) {\n return null;\n }\n\n try {\n const content = readFileSync(configFilePath, 'utf-8');\n const parsed = JSON.parse(content);\n\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 null;\n }\n}\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 const config = loadConfigFromFile();\n\n if (!config) {\n throw new Error('No se pudo cargar la configuración');\n }\n\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: config.github.token,\n username: config.github.username,\n },\n supabase: {\n accessToken: config.supabase.token,\n organizationId: config.supabase.orgId,\n },\n jira: {\n email: config.jira.email,\n apiToken: config.jira.token,\n domain: config.jira.domain,\n },\n },\n defaults: {\n githubOrg: config.github.org || undefined,\n supabaseRegion: config.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n const config = loadConfigFromFile();\n\n if (!config) {\n return false;\n }\n\n return (\n config.github.token !== '' &&\n config.supabase.token !== '' &&\n 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"]}
1
+ {"version":3,"sources":["../../src/index.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","import { existsSync, readFileSync } from 'fs';\n\n// Variable para almacenar la ruta del config\nlet configFilePath: string = '';\n\ninterface ConfigFile {\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// Cache de la configuración cargada\nlet loadedConfig: ConfigFile | 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;\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 * Carga la configuración desde el archivo JSON\n */\nfunction loadConfigFromFile(): ConfigFile | null {\n if (loadedConfig) {\n return loadedConfig;\n }\n\n if (!configFilePath || !existsSync(configFilePath)) {\n return null;\n }\n\n try {\n const content = readFileSync(configFilePath, 'utf-8');\n const parsed = JSON.parse(content);\n\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 null;\n }\n}\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 const config = loadConfigFromFile();\n\n if (!config) {\n throw new Error('No se pudo cargar la configuración');\n }\n\n return {\n version: '1.0.0',\n credentials: {\n github: {\n token: config.github.token,\n username: config.github.username,\n },\n supabase: {\n accessToken: config.supabase.token,\n organizationId: config.supabase.orgId,\n },\n jira: {\n email: config.jira.email,\n apiToken: config.jira.token,\n domain: config.jira.domain,\n },\n },\n defaults: {\n githubOrg: config.github.org || undefined,\n supabaseRegion: config.supabase.region,\n jiraProjectType: 'software',\n },\n };\n}\n\nexport async function hasConfig(): Promise<boolean> {\n const config = loadConfigFromFile();\n\n if (!config) {\n return false;\n }\n\n return (\n config.github.token !== '' &&\n config.supabase.token !== '' &&\n 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 } 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 + supabase)\n await cp(\n path.join(templatesDir, 'lib'),\n path.join(srcDir, 'lib'),\n { recursive: true }\n );\n\n // Copiar modules (auth actions)\n await cp(\n path.join(templatesDir, 'modules'),\n path.join(srcDir, 'modules'),\n { recursive: true }\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 // Reemplazar globals.css con el completo del template\n await cp(\n path.join(templatesDir, 'app', 'globals.css'),\n path.join(srcDir, 'app', 'globals.css')\n );\n },\n 'Template LFT copiado (47 componentes + páginas)'\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 // Theme\n 'next-themes',\n\n // Animations\n 'tw-animate-css',\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","path","path","chalk","chalk","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@create-lft-app/cli",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "CLI para crear proyectos LFT con Next.js, GitHub, Supabase y Jira",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,68 +1,249 @@
1
- /* LFT Custom Styles */
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+
6
+ @theme inline {
7
+ --color-background: var(--background);
8
+ --color-foreground: var(--foreground);
9
+ --font-sans: var(--font-geist-sans);
10
+ --font-mono: var(--font-geist-mono);
11
+ --color-sidebar-ring: var(--sidebar-ring);
12
+ --color-sidebar-border: var(--sidebar-border);
13
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
14
+ --color-sidebar-accent: var(--sidebar-accent);
15
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
16
+ --color-sidebar-primary: var(--sidebar-primary);
17
+ --color-sidebar-foreground: var(--sidebar-foreground);
18
+ --color-sidebar: var(--sidebar);
19
+ --color-chart-5: var(--chart-5);
20
+ --color-chart-4: var(--chart-4);
21
+ --color-chart-3: var(--chart-3);
22
+ --color-chart-2: var(--chart-2);
23
+ --color-chart-1: var(--chart-1);
24
+ --color-ring: var(--ring);
25
+ --color-input: var(--input);
26
+ --color-border: var(--border);
27
+ --color-destructive: var(--destructive);
28
+ --color-accent-foreground: var(--accent-foreground);
29
+ --color-accent: var(--accent);
30
+ --color-muted-foreground: var(--muted-foreground);
31
+ --color-muted: var(--muted);
32
+ --color-secondary-foreground: var(--secondary-foreground);
33
+ --color-secondary: var(--secondary);
34
+ --color-primary-foreground: var(--primary-foreground);
35
+ --color-primary: var(--primary);
36
+ --color-popover-foreground: var(--popover-foreground);
37
+ --color-popover: var(--popover);
38
+ --color-card-foreground: var(--card-foreground);
39
+ --color-card: var(--card);
40
+ --radius-sm: calc(var(--radius) - 4px);
41
+ --radius-md: calc(var(--radius) - 2px);
42
+ --radius-lg: var(--radius);
43
+ --radius-xl: calc(var(--radius) + 4px);
44
+ --radius-2xl: calc(var(--radius) + 8px);
45
+ --radius-3xl: calc(var(--radius) + 12px);
46
+ --radius-4xl: calc(var(--radius) + 16px);
47
+ }
48
+
49
+ /* ========================================
50
+ MIDDAY DESIGN SYSTEM - Color Palette
51
+ ======================================== */
2
52
 
3
- /* Sidebar custom colors */
4
53
  :root {
5
- --sidebar-background: 0 0% 98%;
6
- --sidebar-foreground: 240 5.3% 26.1%;
7
- --sidebar-primary: 240 5.9% 10%;
8
- --sidebar-primary-foreground: 0 0% 98%;
9
- --sidebar-accent: 240 4.8% 95.9%;
10
- --sidebar-accent-foreground: 240 5.9% 10%;
11
- --sidebar-border: 220 13% 91%;
12
- --sidebar-ring: 217.2 91.2% 59.8%;
54
+ --radius: 0.5rem;
55
+
56
+ /* Midday Dark Theme - Pure blacks (DEFAULT) */
57
+ --background: hsl(0 0% 5%);
58
+ --foreground: hsl(0 0% 98%);
59
+
60
+ --card: hsl(0 0% 7%);
61
+ --card-foreground: hsl(0 0% 98%);
62
+
63
+ --popover: hsl(0 0% 4%);
64
+ --popover-foreground: hsl(0 0% 98%);
65
+
66
+ --primary: hsl(0 0% 98%);
67
+ --primary-foreground: hsl(0 0% 9%);
68
+
69
+ --secondary: hsl(0 0% 11%);
70
+ --secondary-foreground: hsl(0 0% 98%);
71
+
72
+ --muted: hsl(0 0% 11%);
73
+ --muted-foreground: hsl(0 0% 64%);
74
+
75
+ --accent: hsl(0 0% 11%);
76
+ --accent-foreground: hsl(0 0% 98%);
77
+
78
+ --destructive: hsl(0 63% 31%);
79
+ --destructive-foreground: hsl(0 0% 98%);
80
+
81
+ --border: hsl(0 0% 11%);
82
+ --input: hsl(0 0% 15%);
83
+ --ring: hsl(0 0% 83%);
84
+
85
+ /* Chart colors dark */
86
+ --chart-1: hsl(220 70% 50%);
87
+ --chart-2: hsl(160 60% 45%);
88
+ --chart-3: hsl(30 80% 55%);
89
+ --chart-4: hsl(280 65% 60%);
90
+ --chart-5: hsl(340 75% 55%);
91
+
92
+ /* Sidebar dark */
93
+ --sidebar: hsl(0 0% 7%);
94
+ --sidebar-foreground: hsl(0 0% 98%);
95
+ --sidebar-primary: hsl(0 0% 98%);
96
+ --sidebar-primary-foreground: hsl(0 0% 9%);
97
+ --sidebar-accent: hsl(0 0% 11%);
98
+ --sidebar-accent-foreground: hsl(0 0% 98%);
99
+ --sidebar-border: hsl(0 0% 11%);
100
+ --sidebar-ring: hsl(0 0% 83%);
101
+ }
102
+
103
+ .light {
104
+ /* Midday Light Theme - Warm beige/neutral palette */
105
+ --background: hsl(0 0% 100%);
106
+ --foreground: hsl(0 0% 7%);
107
+
108
+ --card: hsl(45 18% 96%);
109
+ --card-foreground: hsl(0 0% 4%);
110
+
111
+ --popover: hsl(0 0% 100%);
112
+ --popover-foreground: hsl(0 0% 4%);
113
+
114
+ --primary: hsl(240 6% 10%);
115
+ --primary-foreground: hsl(0 0% 98%);
116
+
117
+ --secondary: hsl(40 11% 89%);
118
+ --secondary-foreground: hsl(0 0% 9%);
119
+
120
+ --muted: hsl(40 11% 89%);
121
+ --muted-foreground: hsl(0 0% 38%);
122
+
123
+ --accent: hsl(40 10% 94%);
124
+ --accent-foreground: hsl(0 0% 9%);
125
+
126
+ --destructive: hsl(0 84% 60%);
127
+ --destructive-foreground: hsl(0 0% 98%);
128
+
129
+ --border: hsl(45 5% 85%);
130
+ --input: hsl(0 0% 90%);
131
+ --ring: hsl(0 0% 4%);
132
+
133
+ /* Chart colors */
134
+ --chart-1: hsl(12 76% 61%);
135
+ --chart-2: hsl(173 58% 39%);
136
+ --chart-3: hsl(197 37% 24%);
137
+ --chart-4: hsl(43 74% 66%);
138
+ --chart-5: hsl(27 87% 67%);
139
+
140
+ /* Sidebar - Midday style */
141
+ --sidebar: hsl(0 0% 99%);
142
+ --sidebar-foreground: hsl(0 0% 7%);
143
+ --sidebar-primary: hsl(240 6% 10%);
144
+ --sidebar-primary-foreground: hsl(0 0% 98%);
145
+ --sidebar-accent: hsl(40 10% 97%);
146
+ --sidebar-accent-foreground: hsl(0 0% 9%);
147
+ --sidebar-border: hsl(45 5% 85%);
148
+ --sidebar-ring: hsl(0 0% 4%);
149
+ }
150
+
151
+ @layer base {
152
+ * {
153
+ @apply border-border outline-ring/50;
154
+ }
155
+ body {
156
+ @apply bg-background text-foreground;
157
+ }
158
+ }
159
+
160
+ /* ========================================
161
+ MIDDAY UTILITIES
162
+ ======================================== */
163
+
164
+ /* Scrollbar hide utility */
165
+ .scrollbar-hide {
166
+ -ms-overflow-style: none;
167
+ scrollbar-width: none;
13
168
  }
169
+ .scrollbar-hide::-webkit-scrollbar {
170
+ display: none;
171
+ }
172
+
173
+ /* ========================================
174
+ MIDDAY ANIMATIONS
175
+ ======================================== */
14
176
 
15
- .dark {
16
- --sidebar-background: 240 5.9% 10%;
17
- --sidebar-foreground: 240 4.8% 95.9%;
18
- --sidebar-primary: 0 0% 98%;
19
- --sidebar-primary-foreground: 240 5.9% 10%;
20
- --sidebar-accent: 240 3.7% 15.9%;
21
- --sidebar-accent-foreground: 240 4.8% 95.9%;
22
- --sidebar-border: 240 3.7% 15.9%;
23
- --sidebar-ring: 217.2 91.2% 59.8%;
177
+ @keyframes shimmer {
178
+ 0% {
179
+ transform: translateX(-100%);
180
+ }
181
+ 100% {
182
+ transform: translateX(100%);
183
+ }
24
184
  }
25
185
 
26
- /* Scrollbar styling */
27
- ::-webkit-scrollbar {
28
- width: 8px;
29
- height: 8px;
186
+ @keyframes accordion-down {
187
+ from {
188
+ height: 0;
189
+ }
190
+ to {
191
+ height: var(--radix-accordion-content-height);
192
+ }
30
193
  }
31
194
 
32
- ::-webkit-scrollbar-track {
33
- background: transparent;
195
+ @keyframes accordion-up {
196
+ from {
197
+ height: var(--radix-accordion-content-height);
198
+ }
199
+ to {
200
+ height: 0;
201
+ }
34
202
  }
35
203
 
36
- ::-webkit-scrollbar-thumb {
37
- background: hsl(var(--muted-foreground) / 0.3);
38
- border-radius: 4px;
204
+ @keyframes dialog-overlay-show {
205
+ from {
206
+ opacity: 0;
207
+ }
208
+ to {
209
+ opacity: 1;
210
+ }
39
211
  }
40
212
 
41
- ::-webkit-scrollbar-thumb:hover {
42
- background: hsl(var(--muted-foreground) / 0.5);
213
+ @keyframes dialog-content-show {
214
+ from {
215
+ opacity: 0;
216
+ transform: translate(-50%, -50%) scale(0.97);
217
+ }
218
+ to {
219
+ opacity: 1;
220
+ transform: translate(-50%, -50%) scale(1);
221
+ }
43
222
  }
44
223
 
45
- /* Focus visible improvements */
46
- *:focus-visible {
47
- outline: 2px solid hsl(var(--ring));
48
- outline-offset: 2px;
224
+ @keyframes caret-blink {
225
+ 0%, 70%, 100% {
226
+ opacity: 1;
227
+ }
228
+ 20%, 50% {
229
+ opacity: 0;
230
+ }
49
231
  }
50
232
 
51
- /* Smooth transitions */
52
- * {
53
- transition-property: background-color, border-color, color, fill, stroke;
54
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
55
- transition-duration: 150ms;
233
+ /* Loading ellipsis animation */
234
+ @keyframes loading-ellipsis {
235
+ 0% { content: ''; }
236
+ 25% { content: '.'; }
237
+ 50% { content: '..'; }
238
+ 75% { content: '...'; }
56
239
  }
57
240
 
58
- /* Widget animations */
59
- .widget-enter {
60
- opacity: 0;
61
- transform: translateY(10px);
241
+ .loading-ellipsis::after {
242
+ content: '';
243
+ animation: loading-ellipsis 1.5s infinite;
62
244
  }
63
245
 
64
- .widget-enter-active {
65
- opacity: 1;
66
- transform: translateY(0);
67
- transition: opacity 300ms, transform 300ms;
246
+ /* Animate shimmer class */
247
+ .animate-shimmer {
248
+ animation: shimmer 2.5s linear infinite;
68
249
  }
@@ -25,8 +25,8 @@ export default function RootLayout({
25
25
  }
26
26
 
27
27
  return (
28
- <html lang="es" suppressHydrationWarning>
29
- <body className={inter.className}>
28
+ <html lang="es" className="dark" suppressHydrationWarning>
29
+ <body className={`${inter.className} font-sans antialiased`}>
30
30
  <SidebarProvider>
31
31
  <AdminSidebar user={user} />
32
32
  <SidebarInset>
@@ -0,0 +1,8 @@
1
+ import { createBrowserClient } from '@supabase/ssr'
2
+
3
+ export function createClient() {
4
+ return createBrowserClient(
5
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
6
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
7
+ )
8
+ }
@@ -0,0 +1,29 @@
1
+ import { createServerClient } from '@supabase/ssr'
2
+ import { cookies } from 'next/headers'
3
+
4
+ export async function createClient() {
5
+ const cookieStore = await cookies()
6
+
7
+ return createServerClient(
8
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
9
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
10
+ {
11
+ cookies: {
12
+ getAll() {
13
+ return cookieStore.getAll()
14
+ },
15
+ setAll(cookiesToSet) {
16
+ try {
17
+ cookiesToSet.forEach(({ name, value, options }) =>
18
+ cookieStore.set(name, value, options)
19
+ )
20
+ } catch {
21
+ // The `setAll` method was called from a Server Component.
22
+ // This can be ignored if you have middleware refreshing
23
+ // user sessions.
24
+ }
25
+ },
26
+ },
27
+ }
28
+ )
29
+ }
@@ -0,0 +1,12 @@
1
+ 'use server'
2
+
3
+ import { createClient } from '@/lib/supabase/server'
4
+ import { redirect } from 'next/navigation'
5
+
6
+ export async function logout() {
7
+ const supabase = await createClient()
8
+ await supabase.auth.signOut()
9
+ redirect('/auth/login')
10
+ }
11
+
12
+ export const logoutAction = logout
@@ -1,36 +0,0 @@
1
- 'use client'
2
-
3
- import { Shield, X } from 'lucide-react'
4
- import { Button } from '@/components/ui/button'
5
- import { stopImpersonation } from '@/app/(admin)/admin/organizations/impersonation-actions'
6
-
7
- interface ImpersonationBannerProps {
8
- organization: {
9
- id: string
10
- name: string
11
- slug: string
12
- }
13
- }
14
-
15
- export function ImpersonationBanner({ organization }: ImpersonationBannerProps) {
16
- return (
17
- <div className="bg-[#1a1a1a] border-b border-[#2a2a2a] text-[#878787] px-4 py-1.5 flex items-center justify-between md:pl-[86px]">
18
- <div className="flex items-center gap-2">
19
- <Shield className="h-3.5 w-3.5 text-yellow-500" />
20
- <span className="text-xs">
21
- Viendo como: <strong className="text-foreground">{organization.name}</strong>
22
- </span>
23
- <span className="text-xs opacity-60">({organization.slug})</span>
24
- </div>
25
- <Button
26
- variant="ghost"
27
- size="sm"
28
- onClick={() => stopImpersonation()}
29
- className="h-6 px-2 text-xs text-[#878787] hover:text-foreground hover:bg-[#2a2a2a]"
30
- >
31
- <X className="h-3.5 w-3.5 mr-1" />
32
- Salir
33
- </Button>
34
- </div>
35
- )
36
- }