@icarusmx/creta 0.8.0 → 0.8.2
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/.claude/settings.local.json +2 -1
- package/bin/creta.js +217 -26
- package/package.json +1 -1
package/bin/creta.js
CHANGED
|
@@ -580,6 +580,110 @@ function showHelp() {
|
|
|
580
580
|
}
|
|
581
581
|
|
|
582
582
|
async function startMainMenu() {
|
|
583
|
+
// Always try interactive mode first, fall back only if it fails
|
|
584
|
+
try {
|
|
585
|
+
return await startMainMenuInteractive()
|
|
586
|
+
} catch (error) {
|
|
587
|
+
// If interactive mode fails, fall back to numbered selection
|
|
588
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
589
|
+
return await startMainMenuFallback()
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async function startMainMenuInteractive() {
|
|
594
|
+
// Check if setRawMode is available before trying to use it
|
|
595
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
596
|
+
throw new Error('setRawMode not available')
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
console.log("Te ofrecemos las siguientes opciones")
|
|
600
|
+
console.log("Usa ↑/↓ para navegar, Enter para seleccionar, 'q' para salir\n")
|
|
601
|
+
|
|
602
|
+
const options = [
|
|
603
|
+
{ id: 1, title: "🧠 Aprender conceptos", description: "Explora los enunciados fundamentales" },
|
|
604
|
+
{ id: 2, title: "🚀 Construir proyectos", description: "Crea tu portafolio personal" }
|
|
605
|
+
]
|
|
606
|
+
|
|
607
|
+
let selectedIndex = 0
|
|
608
|
+
|
|
609
|
+
// Enable raw mode to capture arrow keys
|
|
610
|
+
try {
|
|
611
|
+
process.stdin.setRawMode(true)
|
|
612
|
+
process.stdin.resume()
|
|
613
|
+
process.stdin.setEncoding('utf8')
|
|
614
|
+
} catch (error) {
|
|
615
|
+
throw new Error('Failed to enable raw mode: ' + error.message)
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const renderOptions = () => {
|
|
619
|
+
// Clear previous output and move cursor to top
|
|
620
|
+
process.stdout.write('\x1b[2J')
|
|
621
|
+
process.stdout.write('\x1b[H')
|
|
622
|
+
|
|
623
|
+
console.log("🏛️ Bienvenido a Creta")
|
|
624
|
+
console.log("La escuela de software de icarus.mx\n")
|
|
625
|
+
console.log("Te ofrecemos las siguientes opciones")
|
|
626
|
+
console.log("Usa ↑/↓ para navegar, Enter para seleccionar, 'q' para salir\n")
|
|
627
|
+
|
|
628
|
+
options.forEach((option, index) => {
|
|
629
|
+
const isSelected = index === selectedIndex
|
|
630
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
631
|
+
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
632
|
+
const reset = '\x1b[0m'
|
|
633
|
+
|
|
634
|
+
console.log(`${highlight}${prefix}${option.title}${reset}`)
|
|
635
|
+
if (isSelected) {
|
|
636
|
+
console.log(`${highlight} ${option.description}${reset}`)
|
|
637
|
+
}
|
|
638
|
+
console.log("")
|
|
639
|
+
})
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return new Promise((resolve) => {
|
|
643
|
+
renderOptions()
|
|
644
|
+
|
|
645
|
+
const onKeyPress = (key) => {
|
|
646
|
+
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
647
|
+
process.stdin.setRawMode(false)
|
|
648
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
649
|
+
console.log("\n¡Hasta la vista! 👋")
|
|
650
|
+
resolve()
|
|
651
|
+
return
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (key === '\r' || key === '\n') { // Enter
|
|
655
|
+
process.stdin.setRawMode(false)
|
|
656
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
657
|
+
|
|
658
|
+
const selectedOption = options[selectedIndex]
|
|
659
|
+
|
|
660
|
+
// Clear screen
|
|
661
|
+
process.stdout.write('\x1b[2J')
|
|
662
|
+
process.stdout.write('\x1b[H')
|
|
663
|
+
|
|
664
|
+
if (selectedOption.id === 1) {
|
|
665
|
+
startEnunciadosSelector().then(resolve)
|
|
666
|
+
} else if (selectedOption.id === 2) {
|
|
667
|
+
startProyectosSelector().then(resolve)
|
|
668
|
+
}
|
|
669
|
+
return
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Handle arrow keys (escape sequences)
|
|
673
|
+
if (key === '\u001b[A') { // Up arrow
|
|
674
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : options.length - 1
|
|
675
|
+
renderOptions()
|
|
676
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
677
|
+
selectedIndex = selectedIndex < options.length - 1 ? selectedIndex + 1 : 0
|
|
678
|
+
renderOptions()
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
process.stdin.on('data', onKeyPress)
|
|
683
|
+
})
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
async function startMainMenuFallback() {
|
|
583
687
|
const rl = createInterface({
|
|
584
688
|
input: process.stdin,
|
|
585
689
|
output: process.stdout
|
|
@@ -592,10 +696,10 @@ async function startMainMenu() {
|
|
|
592
696
|
}
|
|
593
697
|
|
|
594
698
|
try {
|
|
595
|
-
console.log("
|
|
699
|
+
console.log("Te ofrecemos las siguientes opciones")
|
|
596
700
|
console.log("")
|
|
597
|
-
console.log("1. 🧠
|
|
598
|
-
console.log("2. 🚀
|
|
701
|
+
console.log("1. 🧠 Aprender conceptos - Explora los enunciados fundamentales")
|
|
702
|
+
console.log("2. 🚀 Construir proyectos - Crea tu portafolio personal")
|
|
599
703
|
console.log("")
|
|
600
704
|
|
|
601
705
|
const respuesta = await askQuestion("Elige una opción (1-2) o 'q' para salir: ")
|
|
@@ -674,27 +778,7 @@ async function startEnunciadosSelectorInteractive() {
|
|
|
674
778
|
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
675
779
|
const reset = '\x1b[0m'
|
|
676
780
|
|
|
677
|
-
console.log(`${highlight}${prefix}${index + 1}.
|
|
678
|
-
|
|
679
|
-
if (isSelected) {
|
|
680
|
-
// Show full text for selected option with word wrapping
|
|
681
|
-
const maxWidth = 66
|
|
682
|
-
const words = enunciado.texto.split(' ')
|
|
683
|
-
let currentLine = ' "'
|
|
684
|
-
|
|
685
|
-
words.forEach(word => {
|
|
686
|
-
if (currentLine.length + word.length + 1 <= maxWidth) {
|
|
687
|
-
currentLine += (currentLine === ' "' ? '' : ' ') + word
|
|
688
|
-
} else {
|
|
689
|
-
console.log(`${highlight}${currentLine}${reset}`)
|
|
690
|
-
currentLine = ' ' + word
|
|
691
|
-
}
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
if (currentLine.length > 6) {
|
|
695
|
-
console.log(`${highlight}${currentLine}"${reset}`)
|
|
696
|
-
}
|
|
697
|
-
}
|
|
781
|
+
console.log(`${highlight}${prefix}${index + 1}. ${enunciado.texto}${reset}`)
|
|
698
782
|
console.log("")
|
|
699
783
|
})
|
|
700
784
|
}
|
|
@@ -770,8 +854,7 @@ async function startEnunciadosSelectorFallback() {
|
|
|
770
854
|
console.log("")
|
|
771
855
|
|
|
772
856
|
ENUNCIADOS.forEach((enunciado, index) => {
|
|
773
|
-
console.log(`${index + 1}.
|
|
774
|
-
console.log(` "${enunciado.texto}"`)
|
|
857
|
+
console.log(`${index + 1}. ${enunciado.texto}`)
|
|
775
858
|
console.log("")
|
|
776
859
|
})
|
|
777
860
|
|
|
@@ -815,6 +898,114 @@ async function startEnunciadosSelectorFallback() {
|
|
|
815
898
|
|
|
816
899
|
|
|
817
900
|
async function startProyectosSelector() {
|
|
901
|
+
// Always try interactive mode first, fall back only if it fails
|
|
902
|
+
try {
|
|
903
|
+
return await startProyectosSelectorInteractive()
|
|
904
|
+
} catch (error) {
|
|
905
|
+
// If interactive mode fails, fall back to numbered selection
|
|
906
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
907
|
+
return await startProyectosSelectorFallback()
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
async function startProyectosSelectorInteractive() {
|
|
912
|
+
// Check if setRawMode is available before trying to use it
|
|
913
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
914
|
+
throw new Error('setRawMode not available')
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
console.log("\n🚀 Proyectos Disponibles")
|
|
918
|
+
console.log("¿Qué proyecto quieres crear?")
|
|
919
|
+
console.log("Usa ↑/↓ para navegar, Enter para seleccionar, 'q' para salir\n")
|
|
920
|
+
|
|
921
|
+
const projects = [
|
|
922
|
+
{ id: 1, title: "🎨 Portafolio Personal", description: "Reto completo", level: 0 },
|
|
923
|
+
{ id: 2, title: "🔓 Portafolio Nivel 1", description: "Solo navbar", level: 1 },
|
|
924
|
+
{ id: 3, title: "🔓 Portafolio Nivel 2", description: "Navbar + hero", level: 2 },
|
|
925
|
+
{ id: 4, title: "🔓 Portafolio Nivel 3", description: "Solución completa", level: 3 }
|
|
926
|
+
]
|
|
927
|
+
|
|
928
|
+
let selectedIndex = 0
|
|
929
|
+
|
|
930
|
+
// Enable raw mode to capture arrow keys
|
|
931
|
+
try {
|
|
932
|
+
process.stdin.setRawMode(true)
|
|
933
|
+
process.stdin.resume()
|
|
934
|
+
process.stdin.setEncoding('utf8')
|
|
935
|
+
} catch (error) {
|
|
936
|
+
throw new Error('Failed to enable raw mode: ' + error.message)
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const renderOptions = () => {
|
|
940
|
+
// Clear previous output and move cursor to top
|
|
941
|
+
process.stdout.write('\x1b[2J')
|
|
942
|
+
process.stdout.write('\x1b[H')
|
|
943
|
+
|
|
944
|
+
console.log("🚀 Proyectos Disponibles")
|
|
945
|
+
console.log("¿Qué proyecto quieres crear?")
|
|
946
|
+
console.log("Usa ↑/↓ para navegar, Enter para seleccionar, 'q' para salir\n")
|
|
947
|
+
|
|
948
|
+
projects.forEach((project, index) => {
|
|
949
|
+
const isSelected = index === selectedIndex
|
|
950
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
951
|
+
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
952
|
+
const reset = '\x1b[0m'
|
|
953
|
+
|
|
954
|
+
console.log(`${highlight}${prefix}${project.title}${reset}`)
|
|
955
|
+
if (isSelected) {
|
|
956
|
+
console.log(`${highlight} ${project.description}${reset}`)
|
|
957
|
+
}
|
|
958
|
+
console.log("")
|
|
959
|
+
})
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
return new Promise((resolve) => {
|
|
963
|
+
renderOptions()
|
|
964
|
+
|
|
965
|
+
const onKeyPress = (key) => {
|
|
966
|
+
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
967
|
+
process.stdin.setRawMode(false)
|
|
968
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
969
|
+
console.log("\n¡Hasta la vista! 👋")
|
|
970
|
+
resolve()
|
|
971
|
+
return
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (key === '\r' || key === '\n') { // Enter
|
|
975
|
+
process.stdin.setRawMode(false)
|
|
976
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
977
|
+
|
|
978
|
+
const selectedProject = projects[selectedIndex]
|
|
979
|
+
const level = selectedProject.level
|
|
980
|
+
|
|
981
|
+
// Clear screen
|
|
982
|
+
process.stdout.write('\x1b[2J')
|
|
983
|
+
process.stdout.write('\x1b[H')
|
|
984
|
+
|
|
985
|
+
// Check if we're in an existing Creta project
|
|
986
|
+
if (level > 0 && isInCretaProject()) {
|
|
987
|
+
unstuckProject(level).then(resolve)
|
|
988
|
+
} else {
|
|
989
|
+
createPortfolioProject(level).then(resolve)
|
|
990
|
+
}
|
|
991
|
+
return
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// Handle arrow keys (escape sequences)
|
|
995
|
+
if (key === '\u001b[A') { // Up arrow
|
|
996
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : projects.length - 1
|
|
997
|
+
renderOptions()
|
|
998
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
999
|
+
selectedIndex = selectedIndex < projects.length - 1 ? selectedIndex + 1 : 0
|
|
1000
|
+
renderOptions()
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
process.stdin.on('data', onKeyPress)
|
|
1005
|
+
})
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
async function startProyectosSelectorFallback() {
|
|
818
1009
|
const rl = createInterface({
|
|
819
1010
|
input: process.stdin,
|
|
820
1011
|
output: process.stdout
|