@icarusmx/creta 1.5.4 → 1.5.7

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.
Files changed (37) hide show
  1. package/bin/creta.js +44 -3
  2. package/lib/aws-guide-viewer.js +179 -0
  3. package/lib/builders/MenuBuilder.js +23 -4
  4. package/lib/executors/ExercisesExecutor.js +8 -0
  5. package/lib/exercises/array-object-manipulation.md +1281 -0
  6. package/lib/exercises/aws-billing-detective.md +588 -0
  7. package/lib/exercises/git-stash-workflow.md +426 -0
  8. package/lib/exercises/iterm2-pane-navigation.md +504 -0
  9. package/lib/exercises/railway-deployment.md +1185 -0
  10. package/lib/papers/bitcoin/bitcoin.md +92 -0
  11. package/lib/papers/mapreduce/mapreduce.md +476 -0
  12. package/lib/papers/spark/spark.md +49 -0
  13. package/lib/vim-setup-tutorial.js +367 -0
  14. package/package.json +5 -1
  15. package/ascii-logo.txt +0 -8
  16. package/codex-refactor.txt +0 -13
  17. package/docs/diagrams/README.md +0 -131
  18. package/docs/diagrams/architecture-overview.mmd +0 -71
  19. package/docs/diagrams/architecture.svg +0 -1
  20. package/docs/diagrams/ecosystem-integration.mmd +0 -49
  21. package/docs/diagrams/evolution-phases.mmd +0 -49
  22. package/docs/diagrams/output.svg +0 -1
  23. package/docs/diagrams/phase2-command-help-flow.mmd +0 -51
  24. package/docs/diagrams/user-journey.mmd +0 -78
  25. package/ejemplo.sh +0 -3
  26. package/refactor.txt +0 -581
  27. package/templates/sveltekit-portfolio/package.json +0 -20
  28. package/templates/sveltekit-portfolio/src/app.css +0 -51
  29. package/templates/sveltekit-portfolio/src/app.html +0 -12
  30. package/templates/sveltekit-portfolio/src/routes/+layout.svelte +0 -108
  31. package/templates/sveltekit-portfolio/src/routes/+page.svelte +0 -79
  32. package/templates/sveltekit-portfolio/static/favicon.png +0 -0
  33. package/templates/sveltekit-portfolio/svelte.config.js +0 -10
  34. package/templates/sveltekit-portfolio/vite.config.js +0 -10
  35. package/test/enunciados.test.js +0 -72
  36. package/test/sintaxis-menu.test.js +0 -45
  37. package/wea-fome-qlia.sh +0 -92
package/bin/creta.js CHANGED
@@ -7,6 +7,8 @@ import path from 'path'
7
7
  import { fileURLToPath } from 'url'
8
8
  import { CretaCodeSession } from '../lib/session.js'
9
9
  import { PullRequestTutorial } from '../lib/pr-tutorial.js'
10
+ import { VimSetupTutorial } from '../lib/vim-setup-tutorial.js'
11
+ import { AWSGuideViewer } from '../lib/aws-guide-viewer.js'
10
12
  import { CommandHelpExecutor } from '../lib/executors/CommandHelpExecutor.js'
11
13
  import { PapersExecutor } from '../lib/papers/PapersExecutor.js'
12
14
  import { ExercisesExecutor } from '../lib/executors/ExercisesExecutor.js'
@@ -112,6 +114,10 @@ if (command.startsWith('portafolio')) {
112
114
  // Start papers selector
113
115
  const executor = new PapersExecutor()
114
116
  await executor.execute()
117
+ } else if (command === 'aws') {
118
+ // Show AWS billing detective guide
119
+ const viewer = new AWSGuideViewer()
120
+ await viewer.start()
115
121
  } else if (command === 'help' || command === 'ayuda') {
116
122
  // Show available commands
117
123
  showHelp()
@@ -609,6 +615,7 @@ function showHelp() {
609
615
  console.log(" creta portafolio-2 - Desbloquea nivel 2 (navbar + hero) 🔓")
610
616
  console.log(" creta portafolio-3 - Desbloquea nivel 3 (solución completa) 🔓")
611
617
  console.log(" creta code - Inicia sesión interactiva de programación 🤖")
618
+ console.log(" creta aws - Guía de AWS Billing Detective 🕵️")
612
619
  console.log(" creta help - Muestra esta ayuda")
613
620
  console.log("\n💡 Tip: Si estás dentro de un proyecto existente, los comandos")
614
621
  console.log(" portafolio-1/2/3 actualizarán tus archivos directamente")
@@ -1306,7 +1313,8 @@ async function startProyectosSelectorInteractive() {
1306
1313
 
1307
1314
  const projects = [
1308
1315
  { id: 1, title: "🔀 Construye una pull-request", type: 'pr' },
1309
- { id: 2, title: "🎨 Construye tu portafolio", type: 'portfolio' }
1316
+ { id: 2, title: "🎨 Construye tu portafolio", type: 'portfolio' },
1317
+ { id: 3, title: "⌨️ Configura Creta Vim", type: 'vim' }
1310
1318
  ]
1311
1319
 
1312
1320
  let selectedIndex = 0
@@ -1365,6 +1373,8 @@ async function startProyectosSelectorInteractive() {
1365
1373
  startPullRequestTutorial().then(resolve)
1366
1374
  } else if (selectedProject.type === 'portfolio') {
1367
1375
  startPortfolioSelector().then(resolve)
1376
+ } else if (selectedProject.type === 'vim') {
1377
+ startVimSetupTutorial().then(resolve)
1368
1378
  }
1369
1379
  return
1370
1380
  }
@@ -1429,9 +1439,10 @@ async function startProyectosSelectorFallback() {
1429
1439
  console.log("")
1430
1440
  console.log("1. 🔀 Construye una pull-request")
1431
1441
  console.log("2. 🎨 Construye tu portafolio")
1442
+ console.log("3. ⌨️ Configura Creta Vim")
1432
1443
  console.log("")
1433
1444
 
1434
- const respuesta = await askQuestion("Elige una opción (1-2) o 'q' para salir: ")
1445
+ const respuesta = await askQuestion("Elige una opción (1-3) o 'q' para salir: ")
1435
1446
 
1436
1447
  if (respuesta.toLowerCase() === 'q') {
1437
1448
  console.log("Hecho con <3 por icarus.mx")
@@ -1447,8 +1458,11 @@ async function startProyectosSelectorFallback() {
1447
1458
  } else if (opcionSeleccionada === 2) {
1448
1459
  rl.close()
1449
1460
  await startPortfolioSelector()
1461
+ } else if (opcionSeleccionada === 3) {
1462
+ rl.close()
1463
+ await startVimSetupTutorial()
1450
1464
  } else {
1451
- console.log("❌ Opción no válida. Elige 1 o 2.")
1465
+ console.log("❌ Opción no válida. Elige 1, 2 o 3.")
1452
1466
  rl.close()
1453
1467
  }
1454
1468
 
@@ -1648,6 +1662,33 @@ async function startPullRequestTutorial() {
1648
1662
  }
1649
1663
  }
1650
1664
 
1665
+ async function startVimSetupTutorial() {
1666
+ try {
1667
+ const tutorial = new VimSetupTutorial()
1668
+ await tutorial.start()
1669
+
1670
+ // Volver al menú principal después de completar el tutorial
1671
+ await returnToMainMenu()
1672
+ } catch (error) {
1673
+ console.error("\n❌ Error al ejecutar el tutorial:", error.message)
1674
+ console.log("\nSi el problema persiste, contacta al equipo de Creta.")
1675
+
1676
+ const rl = createInterface({
1677
+ input: process.stdin,
1678
+ output: process.stdout
1679
+ })
1680
+
1681
+ await new Promise((resolve) => {
1682
+ rl.question("\nPresiona Enter para volver al menú principal...", () => {
1683
+ rl.close()
1684
+ resolve()
1685
+ })
1686
+ })
1687
+
1688
+ await startMainMenu()
1689
+ }
1690
+ }
1691
+
1651
1692
  // Helper function to detect command help requests
1652
1693
  function isCommandHelpRequest(args) {
1653
1694
  // List of supported commands for help
@@ -0,0 +1,179 @@
1
+ import { createInterface } from 'readline'
2
+ import { execSync } from 'child_process'
3
+ import fs from 'fs'
4
+ import path from 'path'
5
+ import { fileURLToPath } from 'url'
6
+ import chalk from 'chalk'
7
+
8
+ const __filename = fileURLToPath(import.meta.url)
9
+ const __dirname = path.dirname(__filename)
10
+
11
+ export class AWSGuideViewer {
12
+ constructor() {
13
+ this.guidePath = path.join(__dirname, 'exercises', 'aws-billing-detective.md')
14
+ }
15
+
16
+ async start() {
17
+ console.clear()
18
+ this.showWelcome()
19
+ await this.showOptions()
20
+ }
21
+
22
+ showWelcome() {
23
+ console.log(chalk.cyan('\n🕵️ AWS Billing Detective'))
24
+ console.log(chalk.gray('═'.repeat(60)))
25
+ console.log('\n' + chalk.bold('El misterio: "Apagué todo pero AWS me sigue cobrando"'))
26
+ console.log('\nGuía completa para encontrar cargos ocultos de AWS:')
27
+ console.log(' • Obtener credenciales de AWS (IAM)')
28
+ console.log(' • Instalar y configurar AWS CLI')
29
+ console.log(' • Comandos de auditoría región por región')
30
+ console.log(' • Los sospechosos habituales (EBS, Elastic IPs, NAT Gateways)')
31
+ console.log(' • Scripts de prevención')
32
+ console.log('\n' + chalk.yellow('📍 Ubicación: ') + this.guidePath)
33
+ console.log(chalk.gray('\n588 líneas de guía paso a paso\n'))
34
+ }
35
+
36
+ async showOptions() {
37
+ const rl = createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout
40
+ })
41
+
42
+ const askQuestion = (question) => {
43
+ return new Promise((resolve) => {
44
+ rl.question(question, resolve)
45
+ })
46
+ }
47
+
48
+ // Check if file exists
49
+ if (!fs.existsSync(this.guidePath)) {
50
+ console.log(chalk.red('❌ Error: No se encontró la guía de AWS'))
51
+ console.log(chalk.gray('\nAsegúrate de estar ejecutando Creta desde el directorio correcto'))
52
+ rl.close()
53
+ return
54
+ }
55
+
56
+ console.log(chalk.bold('📚 Opciones:'))
57
+ console.log('')
58
+ console.log('1. Abrir con nvim ' + chalk.gray('(recomendado, usa fold markers)'))
59
+ console.log('2. Mostrar la ruta ' + chalk.gray('(para copiar)'))
60
+ console.log('3. Ver primeros 30 líneas ' + chalk.gray('(preview)'))
61
+ console.log('4. Ver tabla de contenido')
62
+ console.log('')
63
+
64
+ const choice = await askQuestion(chalk.cyan('Elige una opción (1-4) o Enter para nvim: '))
65
+ rl.close()
66
+
67
+ if (choice === '' || choice === '1') {
68
+ await this.openWithNvim()
69
+ } else if (choice === '2') {
70
+ this.showPath()
71
+ } else if (choice === '3') {
72
+ this.showPreview()
73
+ } else if (choice === '4') {
74
+ this.showTableOfContents()
75
+ }
76
+ }
77
+
78
+ async openWithNvim() {
79
+ console.log('\n' + chalk.cyan('🚀 Abriendo con nvim...'))
80
+ console.log(chalk.gray('💡 Tip: Usa ') + chalk.yellow('zM') + chalk.gray(' para cerrar todos los folds'))
81
+ console.log(chalk.gray(' Usa ') + chalk.yellow('zR') + chalk.gray(' para abrir todos los folds'))
82
+ console.log(chalk.gray(' Usa ') + chalk.yellow('za') + chalk.gray(' para toggle fold en la línea actual'))
83
+ console.log('')
84
+
85
+ try {
86
+ execSync(`nvim "${this.guidePath}"`, { stdio: 'inherit' })
87
+ } catch (error) {
88
+ console.log('\n' + chalk.yellow('⚠️ No se pudo abrir nvim. Intentando con el editor por defecto...'))
89
+ try {
90
+ execSync(`$EDITOR "${this.guidePath}" || vi "${this.guidePath}"`, { stdio: 'inherit' })
91
+ } catch (fallbackError) {
92
+ console.log('\n' + chalk.red('❌ No se pudo abrir ningún editor.'))
93
+ console.log(chalk.yellow('📍 Abre manualmente: ') + this.guidePath)
94
+ }
95
+ }
96
+ }
97
+
98
+ showPath() {
99
+ console.log('\n' + chalk.cyan('📋 Ruta del archivo:'))
100
+ console.log(chalk.yellow(this.guidePath))
101
+ console.log('')
102
+ console.log(chalk.gray('💡 Tip: Usa este comando para abrirlo:'))
103
+ console.log(chalk.yellow(` nvim "${this.guidePath}"`))
104
+ console.log('')
105
+
106
+ // Try to copy to clipboard (macOS)
107
+ try {
108
+ execSync(`echo "${this.guidePath}" | pbcopy`, { stdio: 'ignore' })
109
+ console.log(chalk.green('✓ Ruta copiada al portapapeles (macOS)'))
110
+ } catch (error) {
111
+ // Silently fail if pbcopy not available
112
+ }
113
+ console.log('')
114
+ }
115
+
116
+ showPreview() {
117
+ console.log('\n' + chalk.cyan('📄 Primeras 30 líneas:'))
118
+ console.log(chalk.gray('═'.repeat(60)))
119
+ try {
120
+ const preview = execSync(`head -30 "${this.guidePath}"`, { encoding: 'utf8' })
121
+ console.log(preview)
122
+ } catch (error) {
123
+ console.log(chalk.red('❌ Error al leer el archivo'))
124
+ }
125
+ console.log(chalk.gray('═'.repeat(60)))
126
+ console.log('')
127
+ console.log(chalk.gray('💡 Abre el archivo completo con: ') + chalk.yellow(`creta aws`))
128
+ console.log(chalk.gray(' O directamente: ') + chalk.yellow(`nvim "${this.guidePath}"`))
129
+ console.log('')
130
+ }
131
+
132
+ showTableOfContents() {
133
+ console.log('\n' + chalk.cyan('📚 Tabla de Contenido'))
134
+ console.log(chalk.gray('═'.repeat(60)))
135
+ console.log('')
136
+
137
+ const toc = [
138
+ { section: 'El Misterio', description: 'Por qué AWS cobra después de apagar todo' },
139
+ { section: 'Parte 1', description: 'Obtener tus AWS Access Keys del console' },
140
+ { section: 'Parte 2', description: 'Instalar y configurar AWS CLI' },
141
+ { section: 'Parte 3', description: 'Auditoría completa de billing' },
142
+ { section: '', description: ' • EC2 instances' },
143
+ { section: '', description: ' • EBS volumes (el culpable #1)' },
144
+ { section: '', description: ' • Elastic IPs ($3.60/mes cada una)' },
145
+ { section: '', description: ' • NAT Gateways ($32/mes cada uno!)' },
146
+ { section: '', description: ' • Load Balancers' },
147
+ { section: '', description: ' • RDS databases' },
148
+ { section: '', description: ' • Snapshots' },
149
+ { section: '', description: ' • S3 buckets' },
150
+ { section: '', description: ' • CloudWatch logs' },
151
+ { section: 'Parte 4', description: 'Script de auditoría multi-región' },
152
+ { section: 'Parte 5', description: 'Cost Explorer (interfaz web)' },
153
+ { section: 'Parte 6', description: 'Alertas de billing (prevención)' },
154
+ { section: 'Quick Reference', description: 'Comandos más comunes' },
155
+ { section: 'Troubleshooting', description: 'Solución de problemas' },
156
+ { section: 'Checklist', description: 'Lista de prevención' },
157
+ ]
158
+
159
+ toc.forEach(({ section, description }) => {
160
+ if (section) {
161
+ console.log(chalk.bold(section.padEnd(15)) + chalk.gray(description))
162
+ } else {
163
+ console.log(chalk.gray(description))
164
+ }
165
+ })
166
+
167
+ console.log('')
168
+ console.log(chalk.gray('─'.repeat(60)))
169
+ console.log('')
170
+ console.log(chalk.yellow('💡 La guía completa tiene 588 líneas con:'))
171
+ console.log(' • Comandos copy-paste listos para usar')
172
+ console.log(' • Explicaciones de qué hace cada servicio')
173
+ console.log(' • Estimaciones de costo por servicio')
174
+ console.log(' • Scripts para automatizar la auditoría')
175
+ console.log('')
176
+ console.log(chalk.gray('Abre con: ') + chalk.yellow('nvim "' + this.guidePath + '"'))
177
+ console.log('')
178
+ }
179
+ }
@@ -53,12 +53,13 @@ export class MenuBuilder {
53
53
 
54
54
  renderOption(option, isSelected, index) {
55
55
  const prefix = isSelected ? '▶ ' : ' '
56
+ const number = `${index + 1}.`
56
57
  const label = option.title || option.label || `Opción ${index + 1}`
57
58
 
58
59
  if (isSelected) {
59
- console.log(`\x1b[36m${prefix}${label}\x1b[0m`)
60
+ console.log(`\x1b[36m${prefix}${number} ${label}\x1b[0m`)
60
61
  } else {
61
- console.log(`${prefix}${label}`)
62
+ console.log(`${prefix}${number} ${label}`)
62
63
  }
63
64
 
64
65
  if (option.description) {
@@ -117,10 +118,28 @@ export class MenuBuilder {
117
118
  return
118
119
  }
119
120
 
120
- if (key === '\u001b[A') {
121
+ // Handle number keys (1-9)
122
+ const numberMatch = key.match(/^[1-9]$/)
123
+ if (numberMatch) {
124
+ const num = parseInt(key, 10)
125
+ const targetIndex = num - 1
126
+
127
+ // Check if the number is within range
128
+ if (targetIndex >= 0 && targetIndex < this.config.options.length) {
129
+ const choice = this.config.options[targetIndex]
130
+ cleanup()
131
+ resolve(choice)
132
+ return
133
+ }
134
+ }
135
+
136
+ // Arrow keys or vim-style navigation
137
+ if (key === '\u001b[A' || key === 'k') {
138
+ // Up arrow or 'k'
121
139
  selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : this.config.options.length - 1
122
140
  render()
123
- } else if (key === '\u001b[B') {
141
+ } else if (key === '\u001b[B' || key === 'j') {
142
+ // Down arrow or 'j'
124
143
  selectedIndex = selectedIndex < this.config.options.length - 1 ? selectedIndex + 1 : 0
125
144
  render()
126
145
  }
@@ -33,6 +33,14 @@ export class ExercisesExecutor {
33
33
  file: "railway-deployment.md",
34
34
  lines: 500,
35
35
  topics: ["Railway", "Deployment", "Node.js", "DevOps"]
36
+ },
37
+ {
38
+ id: 4,
39
+ title: "AWS Billing Detective",
40
+ description: "Hunt down AWS charges and prevent surprises",
41
+ file: "aws-billing-detective.md",
42
+ lines: 588,
43
+ topics: ["AWS", "CLI", "Cost Management", "DevOps"]
36
44
  }
37
45
  ]
38
46
  }