@create-lft-app/cli 1.0.13 → 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);
@@ -509,22 +509,14 @@ async function copyTemplate(projectPath) {
509
509
  path2.join(templatesDir, "app", "auth", "login", "page.tsx"),
510
510
  path2.join(srcDir, "app", "auth", "login", "page.tsx")
511
511
  );
512
- await mergeGlobalStyles(projectPath, templatesDir);
512
+ await cp(
513
+ path2.join(templatesDir, "app", "globals.css"),
514
+ path2.join(srcDir, "app", "globals.css")
515
+ );
513
516
  },
514
517
  "Template LFT copiado (47 componentes + p\xE1ginas)"
515
518
  );
516
519
  }
517
- async function mergeGlobalStyles(projectPath, templatesDir) {
518
- const templateCssPath = path2.join(templatesDir, "app", "globals.css");
519
- const projectCssPath = path2.join(projectPath, "src", "app", "globals.css");
520
- try {
521
- const templateCss = await readFile(templateCssPath, "utf-8");
522
- const existingCss = await readFile(projectCssPath, "utf-8");
523
- const merged = existingCss + "\n\n/* LFT Custom Styles */\n" + templateCss;
524
- await writeFile(projectCssPath, merged);
525
- } catch {
526
- }
527
- }
528
520
 
529
521
  // src/steps/install-deps.ts
530
522
  import { execa as execa2 } from "execa";
@@ -567,6 +559,8 @@ var TEMPLATE_DEPENDENCIES = [
567
559
  "sonner",
568
560
  // Theme
569
561
  "next-themes",
562
+ // Animations
563
+ "tw-animate-css",
570
564
  // Validation
571
565
  "zod",
572
566
  // Supabase client
@@ -594,7 +588,7 @@ async function installDependencies(projectPath) {
594
588
  }
595
589
 
596
590
  // src/steps/create-env.ts
597
- import { writeFile as writeFile2, readFile as readFile2, appendFile } from "fs/promises";
591
+ import { writeFile, readFile, appendFile } from "fs/promises";
598
592
  import path3 from "path";
599
593
  async function createEnvFile(projectPath, supabaseKeys) {
600
594
  await withSpinner(
@@ -605,18 +599,18 @@ NEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}
605
599
  NEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}
606
600
  SUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}
607
601
  `;
608
- await writeFile2(
602
+ await writeFile(
609
603
  path3.join(projectPath, ".env.local"),
610
604
  envContent
611
605
  );
612
606
  const gitignorePath = path3.join(projectPath, ".gitignore");
613
607
  try {
614
- const gitignore = await readFile2(gitignorePath, "utf-8");
608
+ const gitignore = await readFile(gitignorePath, "utf-8");
615
609
  if (!gitignore.includes(".env.local")) {
616
610
  await appendFile(gitignorePath, "\n# Environment variables\n.env.local\n.env*.local\n");
617
611
  }
618
612
  } catch {
619
- 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");
620
614
  }
621
615
  },
622
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 + 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 // 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 // Theme\n 'next-themes',\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);
@@ -499,22 +499,14 @@ async function copyTemplate(projectPath) {
499
499
  path2.join(templatesDir, "app", "auth", "login", "page.tsx"),
500
500
  path2.join(srcDir, "app", "auth", "login", "page.tsx")
501
501
  );
502
- await mergeGlobalStyles(projectPath, templatesDir);
502
+ await cp(
503
+ path2.join(templatesDir, "app", "globals.css"),
504
+ path2.join(srcDir, "app", "globals.css")
505
+ );
503
506
  },
504
507
  "Template LFT copiado (47 componentes + p\xE1ginas)"
505
508
  );
506
509
  }
507
- async function mergeGlobalStyles(projectPath, templatesDir) {
508
- const templateCssPath = path2.join(templatesDir, "app", "globals.css");
509
- const projectCssPath = path2.join(projectPath, "src", "app", "globals.css");
510
- try {
511
- const templateCss = await readFile(templateCssPath, "utf-8");
512
- const existingCss = await readFile(projectCssPath, "utf-8");
513
- const merged = existingCss + "\n\n/* LFT Custom Styles */\n" + templateCss;
514
- await writeFile(projectCssPath, merged);
515
- } catch {
516
- }
517
- }
518
510
 
519
511
  // src/steps/install-deps.ts
520
512
  import { execa as execa2 } from "execa";
@@ -557,6 +549,8 @@ var TEMPLATE_DEPENDENCIES = [
557
549
  "sonner",
558
550
  // Theme
559
551
  "next-themes",
552
+ // Animations
553
+ "tw-animate-css",
560
554
  // Validation
561
555
  "zod",
562
556
  // Supabase client
@@ -584,7 +578,7 @@ async function installDependencies(projectPath) {
584
578
  }
585
579
 
586
580
  // src/steps/create-env.ts
587
- import { writeFile as writeFile2, readFile as readFile2, appendFile } from "fs/promises";
581
+ import { writeFile, readFile, appendFile } from "fs/promises";
588
582
  import path3 from "path";
589
583
  async function createEnvFile(projectPath, supabaseKeys) {
590
584
  await withSpinner(
@@ -595,18 +589,18 @@ NEXT_PUBLIC_SUPABASE_URL=${supabaseKeys.url}
595
589
  NEXT_PUBLIC_SUPABASE_ANON_KEY=${supabaseKeys.anonKey}
596
590
  SUPABASE_SERVICE_ROLE_KEY=${supabaseKeys.serviceKey}
597
591
  `;
598
- await writeFile2(
592
+ await writeFile(
599
593
  path3.join(projectPath, ".env.local"),
600
594
  envContent
601
595
  );
602
596
  const gitignorePath = path3.join(projectPath, ".gitignore");
603
597
  try {
604
- const gitignore = await readFile2(gitignorePath, "utf-8");
598
+ const gitignore = await readFile(gitignorePath, "utf-8");
605
599
  if (!gitignore.includes(".env.local")) {
606
600
  await appendFile(gitignorePath, "\n# Environment variables\n.env.local\n.env*.local\n");
607
601
  }
608
602
  } catch {
609
- 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");
610
604
  }
611
605
  },
612
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 + 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 // 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 // Theme\n 'next-themes',\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.13",
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>