@icarusmx/creta 1.4.18 → 1.5.1
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/README.md +395 -0
- package/bin/creta.js +1645 -25
- package/docs/diagrams/README.md +131 -0
- package/docs/diagrams/architecture-overview.mmd +71 -0
- package/docs/diagrams/architecture.svg +1 -0
- package/docs/diagrams/ecosystem-integration.mmd +49 -0
- package/docs/diagrams/evolution-phases.mmd +49 -0
- package/docs/diagrams/output.svg +1 -0
- package/docs/diagrams/phase2-command-help-flow.mmd +51 -0
- package/docs/diagrams/user-journey.mmd +78 -0
- package/lib/cli/index.js +6 -0
- package/lib/customizers/TerminalCustomizer.js +186 -15
- package/lib/data/command-help/cd.js +47 -0
- package/lib/data/command-help/git-add.js +43 -0
- package/lib/data/command-help/git-commit.js +39 -0
- package/lib/data/command-help/git-log.js +47 -0
- package/lib/data/command-help/git-push.js +35 -0
- package/lib/data/command-help/git-status.js +31 -0
- package/lib/data/command-help/index.js +30 -0
- package/lib/data/command-help/ls.js +51 -0
- package/lib/data/command-help/mkdir.js +31 -0
- package/lib/data/command-help/touch.js +26 -0
- package/lib/data/command-help/wc.js +43 -0
- package/lib/data/messages.js +16 -4
- package/lib/executors/CommandHelpExecutor.js +93 -0
- package/lib/papers/AccessControl.js +121 -0
- package/lib/papers/PapersExecutor.js +276 -0
- package/package.json +1 -4
package/bin/creta.js
CHANGED
|
@@ -1,40 +1,1660 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { createInterface } from 'readline'
|
|
4
|
+
import { execSync } from 'child_process'
|
|
5
|
+
import fs from 'fs'
|
|
6
|
+
import path from 'path'
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
8
|
+
import { CretaCodeSession } from '../lib/session.js'
|
|
9
|
+
import { PullRequestTutorial } from '../lib/pr-tutorial.js'
|
|
10
|
+
import { CommandHelpExecutor } from '../lib/executors/CommandHelpExecutor.js'
|
|
11
|
+
import { PapersExecutor } from '../lib/papers/PapersExecutor.js'
|
|
12
|
+
import { Lesson1SystemDecomposition } from '../lessons/lesson1-system-decomposition.js'
|
|
13
|
+
import { Lesson2ObjectRequests } from '../lessons/lesson2-object-requests.js'
|
|
14
|
+
import { Lesson3OnlyWay } from '../lessons/lesson3-only-way.js'
|
|
15
|
+
import { Lesson4OperationSignatures } from '../lessons/lesson4-operation-signatures.js'
|
|
16
|
+
import { Lesson5InterfaceSet } from '../lessons/lesson5-interface-set.js'
|
|
17
|
+
import { Lesson6InterfaceDesign } from '../lessons/lesson6-interface-design.js'
|
|
18
|
+
import { Lesson7ObjectDefinition } from '../lessons/lesson7-object-definition.js'
|
|
4
19
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
20
|
+
const ENUNCIADOS = [
|
|
21
|
+
{
|
|
22
|
+
id: 1,
|
|
23
|
+
texto: "La parte difícil del diseño orientado a objetos es descomponer un sistema como un conjunto de objetos que interactúan entre sí.",
|
|
24
|
+
nivel: "Fundacional",
|
|
25
|
+
enfoque: "Descomposición de sistemas"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 2,
|
|
29
|
+
texto: "Los objetos interactúan entre sí a través de solicitudes.",
|
|
30
|
+
nivel: "Interacción",
|
|
31
|
+
enfoque: "Comunicación entre objetos"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 3,
|
|
35
|
+
texto: "Las solicitudes son la única forma de conseguir que un objeto lleve a cabo una operación.",
|
|
36
|
+
nivel: "Operaciones",
|
|
37
|
+
enfoque: "Mecanismo de ejecución"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 4,
|
|
41
|
+
texto: "Cada operación declarada por un objeto debe incluir:\na) nombre de la operación\nb) insumos necesarios para realizar la operación\nc) el valor que regresa tras ejecutar la operación\n\nEstos tres elementos constituyen la firma de operación.",
|
|
42
|
+
nivel: "Firmas",
|
|
43
|
+
enfoque: "Contratos de operación"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 5,
|
|
47
|
+
texto: "La interfaz de un objeto es el conjunto de todas sus firmas de operación.",
|
|
48
|
+
nivel: "Interfaces",
|
|
49
|
+
enfoque: "Definición de contratos"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 6,
|
|
53
|
+
texto: "El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces.",
|
|
54
|
+
nivel: "Diseño",
|
|
55
|
+
enfoque: "Metodología de desarrollo"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 7,
|
|
59
|
+
texto: "Un objeto es un conjunto de datos y procedimientos que operan sobre esos datos.",
|
|
60
|
+
nivel: "Definición",
|
|
61
|
+
enfoque: "Naturaleza del objeto"
|
|
10
62
|
}
|
|
63
|
+
]
|
|
11
64
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
65
|
+
const args = process.argv.slice(2)
|
|
66
|
+
const command = args[0]
|
|
67
|
+
|
|
68
|
+
// Check if this is a command help request (Phase 2: Desarrollador mode)
|
|
69
|
+
if (command && isCommandHelpRequest(args)) {
|
|
70
|
+
const executor = new CommandHelpExecutor(args)
|
|
71
|
+
await executor.execute()
|
|
72
|
+
process.exit(0)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ASCII Logo
|
|
76
|
+
console.log(`
|
|
77
|
+
█████████████████████████
|
|
78
|
+
█ █ █ █ █ █ █
|
|
79
|
+
█ C █ R █ E █ T █ A █ █ █
|
|
80
|
+
█ █ █ █ █ █ █
|
|
81
|
+
█████████████████████████
|
|
82
|
+
|
|
83
|
+
Bienvenido a la escuela de software de icarus.mx
|
|
84
|
+
Salgamos de este laberinto 🏛️
|
|
85
|
+
`)
|
|
86
|
+
|
|
87
|
+
if (!command) {
|
|
88
|
+
// Default behavior: show main menu
|
|
89
|
+
await startMainMenu()
|
|
90
|
+
process.exit(0)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (command.startsWith('portafolio')) {
|
|
94
|
+
const level = command === 'portafolio' ? 0 : parseInt(command.split('-')[1]) || 0
|
|
95
|
+
|
|
96
|
+
// Check if we're in an existing Creta project
|
|
97
|
+
if (level > 0 && isInCretaProject()) {
|
|
98
|
+
await unstuckProject(level)
|
|
99
|
+
} else {
|
|
100
|
+
await createPortfolioProject(level)
|
|
101
|
+
}
|
|
102
|
+
} else if (command === 'enunciados') {
|
|
103
|
+
// Start enunciados selector
|
|
104
|
+
await startEnunciadosSelector()
|
|
105
|
+
} else if (command === 'code') {
|
|
106
|
+
// Start interactive coding session
|
|
107
|
+
const session = new CretaCodeSession()
|
|
108
|
+
await session.start()
|
|
109
|
+
} else if (command === 'papers') {
|
|
110
|
+
// Start papers selector
|
|
111
|
+
const executor = new PapersExecutor()
|
|
112
|
+
await executor.execute()
|
|
113
|
+
} else if (command === 'help' || command === 'ayuda') {
|
|
114
|
+
// Show available commands
|
|
115
|
+
showHelp()
|
|
116
|
+
} else {
|
|
117
|
+
console.log(`Comando no reconocido: ${command}`)
|
|
118
|
+
console.log("Escribe 'creta help' para ver comandos disponibles")
|
|
119
|
+
process.exit(1)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function createPortfolioProject(level) {
|
|
123
|
+
const rl = createInterface({
|
|
124
|
+
input: process.stdin,
|
|
125
|
+
output: process.stdout
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const askQuestion = (question) => {
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
rl.question(question, resolve)
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const name = await askQuestion("¿Cuál es tu nombre? ")
|
|
136
|
+
const projectName = `${name.toLowerCase().replace(/\s+/g, '-')}-portafolio`
|
|
137
|
+
|
|
138
|
+
console.log(`\n🚀 Creando proyecto: ${projectName}`)
|
|
139
|
+
console.log(`📚 Nivel: ${level === 0 ? 'Reto completo' : `Con ${getLevelDescription(level)} completado`}`)
|
|
140
|
+
|
|
141
|
+
await createProjectFiles(projectName, name, level)
|
|
142
|
+
|
|
143
|
+
console.log(`\n✨ ¡Proyecto creado exitosamente!`)
|
|
144
|
+
console.log(`\n📁 Ingresa a tu proyecto: cd ${projectName}`)
|
|
145
|
+
console.log(`📦 Instala dependencias: npm install`)
|
|
146
|
+
console.log(`🚀 Inicia el servidor: npm run dev`)
|
|
147
|
+
console.log(`\n💡 Lee los comentarios en los archivos para saber qué hacer`)
|
|
148
|
+
|
|
149
|
+
rl.close()
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Error:', error.message)
|
|
152
|
+
rl.close()
|
|
153
|
+
process.exit(1)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function createProjectFiles(projectName, studentName, level) {
|
|
158
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
159
|
+
const __dirname = path.dirname(__filename)
|
|
160
|
+
const templatePath = path.join(__dirname, '../templates/sveltekit-portfolio')
|
|
161
|
+
const targetPath = path.join(process.cwd(), projectName)
|
|
162
|
+
|
|
163
|
+
// Check if template exists
|
|
164
|
+
if (!fs.existsSync(templatePath)) {
|
|
165
|
+
console.error(`Debug info:`)
|
|
166
|
+
console.error(` - CLI location: ${__filename}`)
|
|
167
|
+
console.error(` - Template path: ${templatePath}`)
|
|
168
|
+
console.error(` - Template exists: ${fs.existsSync(templatePath)}`)
|
|
169
|
+
throw new Error('Template no encontrado. Es posible que necesites reinstalar el paquete: npm uninstall -g @icarusmx/creta && npm install -g @icarusmx/creta')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Create target directory
|
|
173
|
+
if (fs.existsSync(targetPath)) {
|
|
174
|
+
throw new Error(`El directorio ${projectName} ya existe`)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fs.mkdirSync(targetPath, { recursive: true })
|
|
178
|
+
|
|
179
|
+
// Copy template files
|
|
180
|
+
await copyTemplate(templatePath, targetPath, projectName, studentName, level)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function copyTemplate(src, dest, projectName, studentName, level) {
|
|
184
|
+
const items = fs.readdirSync(src)
|
|
185
|
+
|
|
186
|
+
for (const item of items) {
|
|
187
|
+
const srcPath = path.join(src, item)
|
|
188
|
+
const destPath = path.join(dest, item)
|
|
189
|
+
|
|
190
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
191
|
+
fs.mkdirSync(destPath, { recursive: true })
|
|
192
|
+
await copyTemplate(srcPath, destPath, projectName, studentName, level)
|
|
193
|
+
} else {
|
|
194
|
+
// Check if this is a binary file
|
|
195
|
+
const binaryExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.woff', '.woff2', '.ttf', '.eot']
|
|
196
|
+
const ext = path.extname(srcPath).toLowerCase()
|
|
197
|
+
|
|
198
|
+
if (binaryExtensions.includes(ext)) {
|
|
199
|
+
// Copy binary files directly without text processing
|
|
200
|
+
fs.copyFileSync(srcPath, destPath)
|
|
201
|
+
} else {
|
|
202
|
+
// Process text files with placeholders
|
|
203
|
+
let content = fs.readFileSync(srcPath, 'utf8')
|
|
204
|
+
|
|
205
|
+
// Apply level-specific modifications first
|
|
206
|
+
if (level > 0) {
|
|
207
|
+
content = applyLevelModifications(content, item, level)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Then replace placeholders
|
|
211
|
+
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName)
|
|
212
|
+
content = content.replace(/\{\{STUDENT_NAME\}\}/g, studentName)
|
|
213
|
+
|
|
214
|
+
fs.writeFileSync(destPath, content)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function applyLevelModifications(content, filename, level) {
|
|
221
|
+
if (filename === '+layout.svelte') {
|
|
222
|
+
return applyLayoutModifications(content, level)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (filename === '+page.svelte') {
|
|
226
|
+
return applyPageModifications(content, level)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return content
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function applyLayoutModifications(content, level) {
|
|
233
|
+
if (level >= 1) {
|
|
234
|
+
// Replace navbar placeholder with complete solution
|
|
235
|
+
content = content.replace(
|
|
236
|
+
'<nav class="bg-white shadow-sm">\n <!-- ⚠️ COMPLETA AQUÍ LA NAVEGACIÓN -->\n</nav>',
|
|
237
|
+
`<nav class="bg-white shadow-sm">
|
|
238
|
+
<div class="max-w-7xl mx-auto px-4">
|
|
239
|
+
<div class="flex justify-between items-center py-3">
|
|
240
|
+
<div class="flex items-center space-x-3">
|
|
241
|
+
<img src="https://icarus.mx/logo.png" alt="Logo" class="w-8 h-8">
|
|
242
|
+
<span class="text-xl font-bold text-gray-900">{{STUDENT_NAME}}</span>
|
|
243
|
+
</div>
|
|
244
|
+
<div class="hidden md:flex space-x-6">
|
|
245
|
+
<a href="#inicio" class="text-gray-600 hover:text-blue-600">Inicio</a>
|
|
246
|
+
<a href="#sobre-mi" class="text-gray-600 hover:text-blue-600">Sobre mí</a>
|
|
247
|
+
<a href="#proyectos" class="text-gray-600 hover:text-blue-600">Proyectos</a>
|
|
248
|
+
<a href="#contacto" class="text-gray-600 hover:text-blue-600">Contacto</a>
|
|
249
|
+
</div>
|
|
250
|
+
<button class="md:hidden">
|
|
251
|
+
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
252
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
|
253
|
+
</svg>
|
|
254
|
+
</button>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</nav>`
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (level >= 3) {
|
|
262
|
+
// Replace footer placeholder with complete solution
|
|
263
|
+
content = content.replace(
|
|
264
|
+
'<footer class="bg-gray-50 border-t">\n <!-- ⚠️ COMPLETA AQUÍ EL FOOTER -->\n</footer>',
|
|
265
|
+
`<footer class="bg-gray-50 border-t">
|
|
266
|
+
<div class="max-w-7xl mx-auto py-8 px-4">
|
|
267
|
+
<div class="text-center text-gray-600 text-sm space-y-2">
|
|
268
|
+
<p>© ${new Date().getFullYear()} {{STUDENT_NAME}}. Todos los derechos reservados.</p>
|
|
269
|
+
<p>Hecho con ❤️ en <a href="https://creta.school" class="text-blue-600 hover:underline">Creta</a></p>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
</footer>`
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return content
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function applyPageModifications(content, level) {
|
|
280
|
+
if (level >= 2) {
|
|
281
|
+
// Replace hero placeholder with complete solution
|
|
282
|
+
content = content.replace(
|
|
283
|
+
`<section class="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100">
|
|
284
|
+
<!-- ⚠️ COMPLETA AQUÍ LA SECCIÓN HERO -->
|
|
285
|
+
<div class="max-w-4xl mx-auto px-4 text-center">
|
|
286
|
+
<h1 class="text-4xl md:text-6xl font-bold text-gray-900 mb-6">
|
|
287
|
+
Gracias por seguir aquí
|
|
288
|
+
</h1>
|
|
289
|
+
<p class="text-lg text-gray-600 mb-8">
|
|
290
|
+
Abre el proyecto usando <code>code .</code> y sigue las instrucciones. Si tienes dudas, apóyate en el equipo
|
|
291
|
+
</p>
|
|
292
|
+
</div>
|
|
293
|
+
</section>`,
|
|
294
|
+
`<section id="inicio" class="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100">
|
|
295
|
+
<div class="max-w-4xl mx-auto px-4 text-center">
|
|
296
|
+
<div class="animate-fade-in">
|
|
297
|
+
<h1 class="text-4xl md:text-6xl font-bold text-gray-900 mb-6">
|
|
298
|
+
Hola, soy {{STUDENT_NAME}}
|
|
299
|
+
</h1>
|
|
300
|
+
<p class="text-lg text-gray-600 mb-8 max-w-2xl mx-auto">
|
|
301
|
+
Soy un desarrollador apasionado por crear productos digitales que impacten positivamente.
|
|
302
|
+
Aprendo construyendo y siempre busco nuevos desafíos.
|
|
303
|
+
</p>
|
|
304
|
+
<div class="flex justify-center space-x-4">
|
|
305
|
+
<a href="#proyectos" class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded-lg transition-colors duration-200 font-medium">
|
|
306
|
+
Ver proyectos
|
|
307
|
+
</a>
|
|
308
|
+
<a href="#contacto" class="border border-blue-600 text-blue-600 hover:bg-blue-50 px-8 py-3 rounded-lg transition-colors duration-200 font-medium">
|
|
309
|
+
Contáctame
|
|
310
|
+
</a>
|
|
311
|
+
</div>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
</section>`
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (level >= 3) {
|
|
319
|
+
// Add complete sections for level 3
|
|
320
|
+
content = content.replace(
|
|
321
|
+
`<!-- ⚠️ AQUÍ VAN LAS DEMÁS SECCIONES (SOBRE MÍ, PROYECTOS, CONTACTO) -->
|
|
322
|
+
<!-- Revisa los comentarios arriba para saber qué crear -->`,
|
|
323
|
+
`<!-- Sobre mí -->
|
|
324
|
+
<section id="sobre-mi" class="py-20 bg-white">
|
|
325
|
+
<div class="max-w-4xl mx-auto px-4">
|
|
326
|
+
<div class="text-center mb-16">
|
|
327
|
+
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 mb-6">Sobre mí</h2>
|
|
328
|
+
<div class="w-20 h-1 bg-blue-600 mx-auto mb-8"></div>
|
|
329
|
+
</div>
|
|
330
|
+
|
|
331
|
+
<div class="grid md:grid-cols-2 gap-12 items-center">
|
|
332
|
+
<div>
|
|
333
|
+
<div class="bg-gray-100 aspect-square rounded-lg flex items-center justify-center mb-6 md:mb-0">
|
|
334
|
+
<span class="text-gray-500 text-lg">Tu foto aquí</span>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
<div>
|
|
338
|
+
<p class="text-lg text-gray-600 mb-6 leading-relaxed">
|
|
339
|
+
Soy un desarrollador apasionado por crear productos digitales que impacten positivamente.
|
|
340
|
+
Aprendo construyendo y siempre busco nuevos desafíos que me permitan crecer profesionalmente.
|
|
341
|
+
</p>
|
|
342
|
+
<div class="grid grid-cols-2 gap-4">
|
|
343
|
+
<div class="bg-blue-50 p-4 rounded-lg text-center">
|
|
344
|
+
<div class="text-2xl font-bold text-blue-600">2+</div>
|
|
345
|
+
<div class="text-sm text-gray-600">Años aprendiendo</div>
|
|
346
|
+
</div>
|
|
347
|
+
<div class="bg-green-50 p-4 rounded-lg text-center">
|
|
348
|
+
<div class="text-2xl font-bold text-green-600">5+</div>
|
|
349
|
+
<div class="text-sm text-gray-600">Proyectos</div>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
</section>
|
|
356
|
+
|
|
357
|
+
<!-- Proyectos -->
|
|
358
|
+
<section id="proyectos" class="py-20 bg-gray-50">
|
|
359
|
+
<div class="max-w-6xl mx-auto px-4">
|
|
360
|
+
<div class="text-center mb-16">
|
|
361
|
+
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 mb-6">Mis Proyectos</h2>
|
|
362
|
+
<div class="w-20 h-1 bg-blue-600 mx-auto mb-8"></div>
|
|
363
|
+
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
|
|
364
|
+
Algunos de los proyectos en los que he trabajado y que demuestran mis habilidades
|
|
365
|
+
</p>
|
|
366
|
+
</div>
|
|
367
|
+
|
|
368
|
+
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
369
|
+
<!-- Proyecto 1 -->
|
|
370
|
+
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-200 project-card">
|
|
371
|
+
<div class="bg-gradient-to-br from-blue-400 to-blue-600 h-48 flex items-center justify-center">
|
|
372
|
+
<span class="text-white text-lg font-medium">Proyecto 1</span>
|
|
373
|
+
</div>
|
|
374
|
+
<div class="p-6">
|
|
375
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Nombre del Proyecto</h3>
|
|
376
|
+
<p class="text-gray-600 mb-4">Descripción breve del proyecto y las tecnologías utilizadas.</p>
|
|
377
|
+
<div class="flex space-x-3">
|
|
378
|
+
<a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">Ver código</a>
|
|
379
|
+
<a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">Ver demo</a>
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
|
|
384
|
+
<!-- Proyecto 2 -->
|
|
385
|
+
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-200 project-card">
|
|
386
|
+
<div class="bg-gradient-to-br from-green-400 to-green-600 h-48 flex items-center justify-center">
|
|
387
|
+
<span class="text-white text-lg font-medium">Proyecto 2</span>
|
|
388
|
+
</div>
|
|
389
|
+
<div class="p-6">
|
|
390
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Nombre del Proyecto</h3>
|
|
391
|
+
<p class="text-gray-600 mb-4">Descripción breve del proyecto y las tecnologías utilizadas.</p>
|
|
392
|
+
<div class="flex space-x-3">
|
|
393
|
+
<a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">Ver código</a>
|
|
394
|
+
<a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">Ver demo</a>
|
|
395
|
+
</div>
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
<!-- Proyecto 3 -->
|
|
400
|
+
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-200 project-card">
|
|
401
|
+
<div class="bg-gradient-to-br from-purple-400 to-purple-600 h-48 flex items-center justify-center">
|
|
402
|
+
<span class="text-white text-lg font-medium">Proyecto 3</span>
|
|
403
|
+
</div>
|
|
404
|
+
<div class="p-6">
|
|
405
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Nombre del Proyecto</h3>
|
|
406
|
+
<p class="text-gray-600 mb-4">Descripción breve del proyecto y las tecnologías utilizadas.</p>
|
|
407
|
+
<div class="flex space-x-3">
|
|
408
|
+
<a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">Ver código</a>
|
|
409
|
+
<a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">Ver demo</a>
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
</section>
|
|
416
|
+
|
|
417
|
+
<!-- Contacto -->
|
|
418
|
+
<section id="contacto" class="py-20 bg-white">
|
|
419
|
+
<div class="max-w-4xl mx-auto px-4">
|
|
420
|
+
<div class="text-center mb-16">
|
|
421
|
+
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 mb-6">Contacto</h2>
|
|
422
|
+
<div class="w-20 h-1 bg-blue-600 mx-auto mb-8"></div>
|
|
423
|
+
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
|
|
424
|
+
¿Tienes un proyecto en mente? ¡Hablemos y veamos cómo puedo ayudarte!
|
|
425
|
+
</p>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<div class="grid md:grid-cols-2 gap-12">
|
|
429
|
+
<div>
|
|
430
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-6">Información de contacto</h3>
|
|
431
|
+
<div class="space-y-4">
|
|
432
|
+
<div class="flex items-center space-x-3">
|
|
433
|
+
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
434
|
+
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
435
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
|
|
436
|
+
</svg>
|
|
437
|
+
</div>
|
|
438
|
+
<div>
|
|
439
|
+
<p class="text-gray-900 font-medium">Email</p>
|
|
440
|
+
<p class="text-gray-600">tu.email@ejemplo.com</p>
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
|
|
444
|
+
<div class="flex items-center space-x-3">
|
|
445
|
+
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
446
|
+
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
447
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path>
|
|
448
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
449
|
+
</svg>
|
|
450
|
+
</div>
|
|
451
|
+
<div>
|
|
452
|
+
<p class="text-gray-900 font-medium">Ubicación</p>
|
|
453
|
+
<p class="text-gray-600">Tu ciudad, País</p>
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
|
|
458
|
+
<div class="mt-8">
|
|
459
|
+
<h4 class="text-lg font-medium text-gray-900 mb-4">Sígueme</h4>
|
|
460
|
+
<div class="flex space-x-4">
|
|
461
|
+
<a href="#" class="w-10 h-10 bg-gray-100 hover:bg-blue-100 rounded-lg flex items-center justify-center transition-colors duration-200">
|
|
462
|
+
<span class="text-gray-600 hover:text-blue-600">LI</span>
|
|
463
|
+
</a>
|
|
464
|
+
<a href="#" class="w-10 h-10 bg-gray-100 hover:bg-blue-100 rounded-lg flex items-center justify-center transition-colors duration-200">
|
|
465
|
+
<span class="text-gray-600 hover:text-blue-600">GH</span>
|
|
466
|
+
</a>
|
|
467
|
+
<a href="#" class="w-10 h-10 bg-gray-100 hover:bg-blue-100 rounded-lg flex items-center justify-center transition-colors duration-200">
|
|
468
|
+
<span class="text-gray-600 hover:text-blue-600">TW</span>
|
|
469
|
+
</a>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
|
|
474
|
+
<div>
|
|
475
|
+
<form class="space-y-6">
|
|
476
|
+
<div>
|
|
477
|
+
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">Nombre</label>
|
|
478
|
+
<input type="text" id="name" name="name" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:border-transparent">
|
|
479
|
+
</div>
|
|
480
|
+
<div>
|
|
481
|
+
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">Email</label>
|
|
482
|
+
<input type="email" id="email" name="email" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:border-transparent">
|
|
483
|
+
</div>
|
|
484
|
+
<div>
|
|
485
|
+
<label for="message" class="block text-sm font-medium text-gray-700 mb-2">Mensaje</label>
|
|
486
|
+
<textarea id="message" name="message" rows="4" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:border-transparent"></textarea>
|
|
487
|
+
</div>
|
|
488
|
+
<button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded-lg transition-colors duration-200 font-medium">
|
|
489
|
+
Enviar mensaje
|
|
490
|
+
</button>
|
|
491
|
+
</form>
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
</div>
|
|
495
|
+
</section>`
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return content
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function getLevelDescription(level) {
|
|
503
|
+
const descriptions = {
|
|
504
|
+
1: 'navbar',
|
|
505
|
+
2: 'navbar + hero',
|
|
506
|
+
3: 'todo el portafolio'
|
|
507
|
+
}
|
|
508
|
+
return descriptions[level] || 'nivel desconocido'
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function isInCretaProject() {
|
|
512
|
+
// Check if we're in a Creta project by looking for key files
|
|
513
|
+
let currentDir
|
|
514
|
+
try {
|
|
515
|
+
currentDir = process.cwd()
|
|
516
|
+
} catch (error) {
|
|
517
|
+
// If we can't get the current directory, we're definitely not in a Creta project
|
|
518
|
+
console.error('Error: No se puede acceder al directorio actual. Asegúrate de estar en un directorio válido.')
|
|
519
|
+
return false
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const packageJsonPath = path.join(currentDir, 'package.json')
|
|
523
|
+
const layoutPath = path.join(currentDir, 'src/routes/+layout.svelte')
|
|
524
|
+
const pagePath = path.join(currentDir, 'src/routes/+page.svelte')
|
|
525
|
+
|
|
526
|
+
// Must have package.json and SvelteKit structure
|
|
527
|
+
if (!fs.existsSync(packageJsonPath) || !fs.existsSync(layoutPath) || !fs.existsSync(pagePath)) {
|
|
528
|
+
return false
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Check if layout contains Creta comments
|
|
532
|
+
try {
|
|
533
|
+
const layoutContent = fs.readFileSync(layoutPath, 'utf8')
|
|
534
|
+
return layoutContent.includes('RETO CRETA') || layoutContent.includes('🧭 RETO 1: NAVBAR')
|
|
535
|
+
} catch (error) {
|
|
536
|
+
return false
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async function unstuckProject(level) {
|
|
541
|
+
console.log(`\n🔓 ¡Te ayudo a desbloquear el nivel ${level}!`)
|
|
542
|
+
console.log(`📚 Agregando código para: ${getLevelDescription(level)}`)
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
let currentDir
|
|
546
|
+
try {
|
|
547
|
+
currentDir = process.cwd()
|
|
548
|
+
} catch (error) {
|
|
549
|
+
console.error('Error: No se puede acceder al directorio actual. Asegúrate de estar en un directorio válido.')
|
|
550
|
+
process.exit(1)
|
|
551
|
+
}
|
|
552
|
+
const layoutPath = path.join(currentDir, 'src/routes/+layout.svelte')
|
|
553
|
+
const pagePath = path.join(currentDir, 'src/routes/+page.svelte')
|
|
554
|
+
|
|
555
|
+
// Get student name from package.json title if possible
|
|
556
|
+
let studentName = 'Tu nombre'
|
|
557
|
+
try {
|
|
558
|
+
const packageJsonPath = path.join(currentDir, 'package.json')
|
|
559
|
+
const packageContent = fs.readFileSync(packageJsonPath, 'utf8')
|
|
560
|
+
const packageJson = JSON.parse(packageContent)
|
|
561
|
+
if (packageJson.name && packageJson.name.includes('-portafolio')) {
|
|
562
|
+
studentName = packageJson.name.replace('-portafolio', '').split('-').map(word =>
|
|
563
|
+
word.charAt(0).toUpperCase() + word.slice(1)
|
|
564
|
+
).join(' ')
|
|
565
|
+
}
|
|
566
|
+
} catch (error) {
|
|
567
|
+
// Use default if can't parse
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Apply modifications to existing files
|
|
571
|
+
if (fs.existsSync(layoutPath)) {
|
|
572
|
+
let layoutContent = fs.readFileSync(layoutPath, 'utf8')
|
|
573
|
+
layoutContent = applyLayoutModifications(layoutContent, level)
|
|
574
|
+
// Replace placeholders in layout
|
|
575
|
+
layoutContent = layoutContent.replace(/\{\{STUDENT_NAME\}\}/g, studentName)
|
|
576
|
+
layoutContent = layoutContent.replace(/\{\{PROJECT_NAME\}\}/g, `${studentName.toLowerCase().replace(/\s+/g, '-')}-portafolio`)
|
|
577
|
+
fs.writeFileSync(layoutPath, layoutContent)
|
|
578
|
+
console.log(`✅ Actualizado: src/routes/+layout.svelte`)
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (fs.existsSync(pagePath)) {
|
|
582
|
+
let pageContent = fs.readFileSync(pagePath, 'utf8')
|
|
583
|
+
pageContent = applyPageModifications(pageContent, level)
|
|
584
|
+
// Replace placeholders in page
|
|
585
|
+
pageContent = pageContent.replace(/\{\{STUDENT_NAME\}\}/g, studentName)
|
|
586
|
+
pageContent = pageContent.replace(/\{\{PROJECT_NAME\}\}/g, `${studentName.toLowerCase().replace(/\s+/g, '-')}-portafolio`)
|
|
587
|
+
fs.writeFileSync(pagePath, pageContent)
|
|
588
|
+
console.log(`✅ Actualizado: src/routes/+page.svelte`)
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
console.log(`\n🎉 ¡Listo! Ahora tienes el código del nivel ${level}`)
|
|
592
|
+
console.log(`💡 Revisa los archivos actualizados para ver qué se agregó`)
|
|
593
|
+
console.log(`🚀 Continúa con: npm run dev`)
|
|
594
|
+
|
|
595
|
+
} catch (error) {
|
|
596
|
+
console.error('Error al actualizar el proyecto:', error.message)
|
|
597
|
+
process.exit(1)
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function showHelp() {
|
|
602
|
+
console.log("\n📚 Comandos disponibles:")
|
|
603
|
+
console.log(" creta - Explora los 7 enunciados fundamentales (comando principal) 🧠")
|
|
604
|
+
console.log(" creta enunciados - Explora los 7 enunciados fundamentales 🧠")
|
|
605
|
+
console.log(" creta portafolio - Crea tu portafolio personal (reto completo)")
|
|
606
|
+
console.log(" creta portafolio-1 - Desbloquea nivel 1 (navbar) 🔓")
|
|
607
|
+
console.log(" creta portafolio-2 - Desbloquea nivel 2 (navbar + hero) 🔓")
|
|
608
|
+
console.log(" creta portafolio-3 - Desbloquea nivel 3 (solución completa) 🔓")
|
|
609
|
+
console.log(" creta code - Inicia sesión interactiva de programación 🤖")
|
|
610
|
+
console.log(" creta help - Muestra esta ayuda")
|
|
611
|
+
console.log("\n💡 Tip: Si estás dentro de un proyecto existente, los comandos")
|
|
612
|
+
console.log(" portafolio-1/2/3 actualizarán tus archivos directamente")
|
|
613
|
+
console.log("\n🎯 La filosofía Creta: partir de enunciados que generan 'ruido' para")
|
|
614
|
+
console.log(" construir comprensión real, no solo sintaxis.")
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
async function startMainMenu() {
|
|
618
|
+
// Always try interactive mode first, fall back only if it fails
|
|
619
|
+
try {
|
|
620
|
+
return await startMainMenuInteractive()
|
|
621
|
+
} catch (error) {
|
|
622
|
+
// If interactive mode fails, fall back to numbered selection
|
|
623
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
624
|
+
return await startMainMenuFallback()
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
async function startMainMenuInteractive() {
|
|
629
|
+
// Check if setRawMode is available before trying to use it
|
|
630
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
631
|
+
throw new Error('setRawMode not available')
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
console.log("Te ofrecemos las siguientes opciones:")
|
|
635
|
+
|
|
636
|
+
const options = [
|
|
637
|
+
{ id: 1, title: "Aprender sintaxis" },
|
|
638
|
+
{ id: 2, title: "Aprender conceptos de diseño" },
|
|
639
|
+
{ id: 3, title: "Construir proyectos" },
|
|
640
|
+
{ id: 4, title: "📄 Recrear papers clásicos" }
|
|
641
|
+
]
|
|
642
|
+
|
|
643
|
+
let selectedIndex = 0
|
|
644
|
+
|
|
645
|
+
// Enable raw mode to capture arrow keys
|
|
646
|
+
try {
|
|
647
|
+
process.stdin.setRawMode(true)
|
|
648
|
+
process.stdin.resume()
|
|
649
|
+
process.stdin.setEncoding('utf8')
|
|
650
|
+
} catch (error) {
|
|
651
|
+
throw new Error('Failed to enable raw mode: ' + error.message)
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const renderOptions = () => {
|
|
655
|
+
// Clear previous output and move cursor to top
|
|
656
|
+
process.stdout.write('\x1b[2J')
|
|
657
|
+
process.stdout.write('\x1b[H')
|
|
658
|
+
|
|
659
|
+
console.log(`
|
|
660
|
+
█████████████████████████
|
|
661
|
+
█ █ █ █ █ █ █
|
|
662
|
+
█ C █ R █ E █ T █ A █ █ █
|
|
663
|
+
█ █ █ █ █ █ █
|
|
664
|
+
█████████████████████████
|
|
665
|
+
|
|
666
|
+
Bienvenido a la escuela de software de icarus.mx
|
|
667
|
+
Salgamos de este laberinto 🏛️
|
|
668
|
+
`)
|
|
669
|
+
console.log("Te ofrecemos las siguientes opciones:")
|
|
670
|
+
|
|
671
|
+
options.forEach((option, index) => {
|
|
672
|
+
const isSelected = index === selectedIndex
|
|
673
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
674
|
+
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
675
|
+
const reset = '\x1b[0m'
|
|
676
|
+
|
|
677
|
+
console.log(`${highlight}${prefix}${index + 1}. ${option.title}${reset}`)
|
|
678
|
+
console.log("")
|
|
679
|
+
})
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return new Promise((resolve) => {
|
|
683
|
+
renderOptions()
|
|
684
|
+
|
|
685
|
+
const onKeyPress = (key) => {
|
|
686
|
+
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
687
|
+
process.stdin.setRawMode(false)
|
|
688
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
689
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
690
|
+
resolve()
|
|
691
|
+
return
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if (key === '\r' || key === '\n') { // Enter
|
|
695
|
+
process.stdin.setRawMode(false)
|
|
696
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
697
|
+
|
|
698
|
+
const selectedOption = options[selectedIndex]
|
|
699
|
+
|
|
700
|
+
// Clear screen
|
|
701
|
+
process.stdout.write('\x1b[2J')
|
|
702
|
+
process.stdout.write('\x1b[H')
|
|
703
|
+
|
|
704
|
+
if (selectedOption.id === 1) {
|
|
705
|
+
startSintaxisSelector().then(resolve)
|
|
706
|
+
} else if (selectedOption.id === 2) {
|
|
707
|
+
startEnunciadosSelector().then(resolve)
|
|
708
|
+
} else if (selectedOption.id === 3) {
|
|
709
|
+
startProyectosSelector().then(resolve)
|
|
710
|
+
} else if (selectedOption.id === 4) {
|
|
711
|
+
const executor = new PapersExecutor()
|
|
712
|
+
executor.execute().then(resolve)
|
|
713
|
+
}
|
|
714
|
+
return
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Handle arrow keys (escape sequences)
|
|
718
|
+
if (key === '\u001b[A') { // Up arrow
|
|
719
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : options.length - 1
|
|
720
|
+
renderOptions()
|
|
721
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
722
|
+
selectedIndex = selectedIndex < options.length - 1 ? selectedIndex + 1 : 0
|
|
723
|
+
renderOptions()
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
process.stdin.on('data', onKeyPress)
|
|
16
728
|
})
|
|
729
|
+
}
|
|
17
730
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
process.
|
|
731
|
+
async function startMainMenuFallback() {
|
|
732
|
+
const rl = createInterface({
|
|
733
|
+
input: process.stdin,
|
|
734
|
+
output: process.stdout
|
|
22
735
|
})
|
|
23
736
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
737
|
+
const askQuestion = (question) => {
|
|
738
|
+
return new Promise((resolve) => {
|
|
739
|
+
rl.question(question, resolve)
|
|
740
|
+
})
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
try {
|
|
744
|
+
console.log("Te ofrecemos las siguientes opciones:")
|
|
745
|
+
console.log("")
|
|
746
|
+
console.log("1. Aprender sintaxis")
|
|
747
|
+
console.log("2. Aprender conceptos de diseño")
|
|
748
|
+
console.log("3. Construir proyectos")
|
|
749
|
+
console.log("4. 📄 Recrear papers clásicos")
|
|
750
|
+
console.log("")
|
|
751
|
+
|
|
752
|
+
const respuesta = await askQuestion("Elige una opción (1-4) o 'q' para salir: ")
|
|
753
|
+
|
|
754
|
+
if (respuesta.toLowerCase() === 'q') {
|
|
755
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
756
|
+
rl.close()
|
|
757
|
+
return
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const opcionSeleccionada = parseInt(respuesta)
|
|
761
|
+
|
|
762
|
+
if (opcionSeleccionada === 1) {
|
|
763
|
+
rl.close()
|
|
764
|
+
await startSintaxisSelector()
|
|
765
|
+
} else if (opcionSeleccionada === 2) {
|
|
766
|
+
rl.close()
|
|
767
|
+
await startEnunciadosSelector()
|
|
768
|
+
} else if (opcionSeleccionada === 3) {
|
|
769
|
+
rl.close()
|
|
770
|
+
await startProyectosSelector()
|
|
771
|
+
} else if (opcionSeleccionada === 4) {
|
|
772
|
+
rl.close()
|
|
773
|
+
const executor = new PapersExecutor()
|
|
774
|
+
await executor.execute()
|
|
775
|
+
} else {
|
|
776
|
+
console.log("❌ Opción no válida. Elige 1, 2, 3 o 4.")
|
|
777
|
+
rl.close()
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
} catch (error) {
|
|
781
|
+
console.error('Error:', error.message)
|
|
782
|
+
rl.close()
|
|
28
783
|
process.exit(1)
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
async function startEnunciadosSelector() {
|
|
788
|
+
// Always try interactive mode first, fall back only if it fails
|
|
789
|
+
try {
|
|
790
|
+
return await startEnunciadosSelectorInteractive()
|
|
791
|
+
} catch (error) {
|
|
792
|
+
// If interactive mode fails, fall back to numbered selection
|
|
793
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
794
|
+
return await startEnunciadosSelectorFallback()
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
async function startEnunciadosSelectorInteractive() {
|
|
799
|
+
// Check if setRawMode is available before trying to use it
|
|
800
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
801
|
+
throw new Error('setRawMode not available')
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
console.log("Los enunciados fundamentales son un conjunto de afirmaciones que tienen el propósito de ejercitar el pensamiento orientado a objetos de los estudiantes de Creta.")
|
|
805
|
+
console.log("")
|
|
806
|
+
console.log("Escogimos estos enunciados porque creemos que exhaustan los conceptos mínimos necesarios para entender el paradigma de la programación orientada a objetos.")
|
|
807
|
+
|
|
808
|
+
// Wait for user to press Enter before showing the list
|
|
809
|
+
const rl = createInterface({
|
|
810
|
+
input: process.stdin,
|
|
811
|
+
output: process.stdout
|
|
812
|
+
})
|
|
813
|
+
|
|
814
|
+
await new Promise((resolve) => {
|
|
815
|
+
rl.question("\nPresiona Enter para comenzar...", () => {
|
|
816
|
+
rl.close()
|
|
817
|
+
resolve()
|
|
818
|
+
})
|
|
819
|
+
})
|
|
820
|
+
|
|
821
|
+
console.log("\n\n")
|
|
822
|
+
console.log("Elige qué enunciado te gustaría explorar:")
|
|
823
|
+
console.log("")
|
|
824
|
+
|
|
825
|
+
let selectedIndex = 0
|
|
826
|
+
let running = true
|
|
827
|
+
|
|
828
|
+
// Enable raw mode to capture arrow keys
|
|
829
|
+
try {
|
|
830
|
+
process.stdin.setRawMode(true)
|
|
831
|
+
process.stdin.resume()
|
|
832
|
+
process.stdin.setEncoding('utf8')
|
|
833
|
+
} catch (error) {
|
|
834
|
+
throw new Error('Failed to enable raw mode: ' + error.message)
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const renderOptions = () => {
|
|
838
|
+
// Clear previous output and move cursor to top
|
|
839
|
+
process.stdout.write('\x1b[2J')
|
|
840
|
+
process.stdout.write('\x1b[H')
|
|
841
|
+
|
|
842
|
+
console.log("Los enunciados fundamentales son un conjunto de afirmaciones que tienen el propósito de ejercitar el pensamiento orientado a objetos de los estudiantes de Creta.")
|
|
843
|
+
console.log("")
|
|
844
|
+
console.log("Escogimos estos enunciados porque creemos que exhaustan los conceptos mínimos necesarios para entender el paradigma de la programación orientada a objetos.")
|
|
845
|
+
console.log("")
|
|
846
|
+
console.log("Elige qué enunciado te gustaría explorar:")
|
|
847
|
+
console.log("")
|
|
848
|
+
|
|
849
|
+
ENUNCIADOS.forEach((enunciado, index) => {
|
|
850
|
+
const isSelected = index === selectedIndex
|
|
851
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
852
|
+
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
853
|
+
const reset = '\x1b[0m'
|
|
854
|
+
|
|
855
|
+
// Format the enunciado text with proper indentation for lists
|
|
856
|
+
let formattedText = enunciado.texto
|
|
857
|
+
if (enunciado.id === 4) {
|
|
858
|
+
// Special formatting for enunciado 4 with list items
|
|
859
|
+
formattedText = formattedText.replace(/\n([abc])\)/g, '\n $1)')
|
|
860
|
+
formattedText = formattedText.replace(/\n\nEstos tres elementos/g, '\n\n Estos tres elementos')
|
|
861
|
+
}
|
|
862
|
+
console.log(`${highlight}${prefix}${index + 1}. ${formattedText}${reset}`)
|
|
863
|
+
console.log("")
|
|
864
|
+
})
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return new Promise((resolve) => {
|
|
868
|
+
renderOptions()
|
|
869
|
+
|
|
870
|
+
const onKeyPress = async (key) => {
|
|
871
|
+
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
872
|
+
process.stdin.setRawMode(false)
|
|
873
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
874
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
875
|
+
resolve()
|
|
876
|
+
return
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
if (key === '\r' || key === '\n') { // Enter
|
|
880
|
+
process.stdin.setRawMode(false)
|
|
881
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
882
|
+
|
|
883
|
+
const enunciadoSeleccionado = ENUNCIADOS[selectedIndex]
|
|
884
|
+
|
|
885
|
+
// Clear screen and show selection
|
|
886
|
+
process.stdout.write('\x1b[2J')
|
|
887
|
+
process.stdout.write('\x1b[H')
|
|
888
|
+
|
|
889
|
+
// Check if we have a lesson implementation for this enunciado
|
|
890
|
+
if (enunciadoSeleccionado.id === 1) {
|
|
891
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
892
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
893
|
+
|
|
894
|
+
try {
|
|
895
|
+
const lesson1 = new Lesson1SystemDecomposition()
|
|
896
|
+
await lesson1.start()
|
|
897
|
+
await returnToMainMenu()
|
|
898
|
+
} catch (error) {
|
|
899
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
900
|
+
console.log("\n🚀 Próximamente:")
|
|
901
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
902
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
903
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
904
|
+
await returnToMainMenu()
|
|
905
|
+
}
|
|
906
|
+
} else if (enunciadoSeleccionado.id === 1) {
|
|
907
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
908
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
909
|
+
|
|
910
|
+
try {
|
|
911
|
+
const lesson1 = new Lesson1SystemDecomposition()
|
|
912
|
+
await lesson1.start()
|
|
913
|
+
await returnToMainMenu()
|
|
914
|
+
} catch (error) {
|
|
915
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
916
|
+
console.log("\n🚀 Próximamente:")
|
|
917
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
918
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
919
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
920
|
+
await returnToMainMenu()
|
|
921
|
+
}
|
|
922
|
+
} else if (enunciadoSeleccionado.id === 2) {
|
|
923
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
924
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
925
|
+
|
|
926
|
+
try {
|
|
927
|
+
const lesson2 = new Lesson2ObjectRequests()
|
|
928
|
+
await lesson2.start()
|
|
929
|
+
await returnToMainMenu()
|
|
930
|
+
} catch (error) {
|
|
931
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
932
|
+
console.log("\n🚀 Próximamente:")
|
|
933
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
934
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
935
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
936
|
+
await returnToMainMenu()
|
|
937
|
+
}
|
|
938
|
+
} else if (enunciadoSeleccionado.id === 3) {
|
|
939
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
940
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
941
|
+
|
|
942
|
+
try {
|
|
943
|
+
const lesson3 = new Lesson3OnlyWay()
|
|
944
|
+
await lesson3.start()
|
|
945
|
+
await returnToMainMenu()
|
|
946
|
+
} catch (error) {
|
|
947
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
948
|
+
console.log("\n🚀 Próximamente:")
|
|
949
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
950
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
951
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
952
|
+
await returnToMainMenu()
|
|
953
|
+
}
|
|
954
|
+
} else if (enunciadoSeleccionado.id === 4) {
|
|
955
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
956
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
957
|
+
|
|
958
|
+
try {
|
|
959
|
+
const lesson4 = new Lesson4OperationSignatures()
|
|
960
|
+
await lesson4.start()
|
|
961
|
+
await returnToMainMenu()
|
|
962
|
+
} catch (error) {
|
|
963
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
964
|
+
console.log("\n🚀 Próximamente:")
|
|
965
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
966
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
967
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
968
|
+
await returnToMainMenu()
|
|
969
|
+
}
|
|
970
|
+
} else if (enunciadoSeleccionado.id === 5) {
|
|
971
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
972
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
973
|
+
|
|
974
|
+
try {
|
|
975
|
+
const lesson5 = new Lesson5InterfaceSet()
|
|
976
|
+
await lesson5.start()
|
|
977
|
+
await returnToMainMenu()
|
|
978
|
+
} catch (error) {
|
|
979
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
980
|
+
console.log("\n🚀 Próximamente:")
|
|
981
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
982
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
983
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
984
|
+
await returnToMainMenu()
|
|
985
|
+
}
|
|
986
|
+
} else if (enunciadoSeleccionado.id === 6) {
|
|
987
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
988
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
989
|
+
|
|
990
|
+
try {
|
|
991
|
+
const lesson6 = new Lesson6InterfaceDesign()
|
|
992
|
+
await lesson6.start()
|
|
993
|
+
await returnToMainMenu()
|
|
994
|
+
} catch (error) {
|
|
995
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
996
|
+
console.log("\n🚀 Próximamente:")
|
|
997
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
998
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
999
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1000
|
+
await returnToMainMenu()
|
|
1001
|
+
}
|
|
1002
|
+
} else if (enunciadoSeleccionado.id === 7) {
|
|
1003
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1004
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1005
|
+
|
|
1006
|
+
try {
|
|
1007
|
+
const lesson7 = new Lesson7ObjectDefinition()
|
|
1008
|
+
await lesson7.start()
|
|
1009
|
+
await returnToMainMenu()
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1012
|
+
console.log("\n🚀 Próximamente:")
|
|
1013
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1014
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1015
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1016
|
+
await returnToMainMenu()
|
|
1017
|
+
}
|
|
1018
|
+
} else {
|
|
1019
|
+
console.log("\n🚀 Próximamente:")
|
|
1020
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1021
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1022
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1023
|
+
|
|
1024
|
+
console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
|
|
1025
|
+
console.log(" te genera más curiosidad o confusión?")
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
resolve()
|
|
1029
|
+
return
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// Handle arrow keys (escape sequences)
|
|
1033
|
+
if (key === '\u001b[A') { // Up arrow
|
|
1034
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : ENUNCIADOS.length - 1
|
|
1035
|
+
renderOptions()
|
|
1036
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
1037
|
+
selectedIndex = selectedIndex < ENUNCIADOS.length - 1 ? selectedIndex + 1 : 0
|
|
1038
|
+
renderOptions()
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
process.stdin.on('data', onKeyPress)
|
|
29
1043
|
})
|
|
30
1044
|
}
|
|
31
1045
|
|
|
32
|
-
|
|
1046
|
+
async function startEnunciadosSelectorFallback() {
|
|
1047
|
+
const rl = createInterface({
|
|
1048
|
+
input: process.stdin,
|
|
1049
|
+
output: process.stdout
|
|
1050
|
+
})
|
|
33
1051
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
1052
|
+
const askQuestion = (question) => {
|
|
1053
|
+
return new Promise((resolve) => {
|
|
1054
|
+
rl.question(question, resolve)
|
|
1055
|
+
})
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
try {
|
|
1059
|
+
console.log("Los enunciados fundamentales son un conjunto de afirmaciones que tienen el propósito de ejercitar el pensamiento orientado a objetos de los estudiantes de Creta.")
|
|
1060
|
+
console.log("")
|
|
1061
|
+
console.log("Escogimos estos enunciados porque creemos que exhaustan los conceptos mínimos necesarios para entender el paradigma de la programación orientada a objetos.")
|
|
1062
|
+
|
|
1063
|
+
await askQuestion("\nPresiona Enter para comenzar...")
|
|
1064
|
+
|
|
1065
|
+
console.log("\n\n")
|
|
1066
|
+
console.log("Elige qué enunciado te gustaría explorar:")
|
|
1067
|
+
console.log("")
|
|
1068
|
+
|
|
1069
|
+
ENUNCIADOS.forEach((enunciado, index) => {
|
|
1070
|
+
// Format the enunciado text with proper indentation for lists
|
|
1071
|
+
let formattedText = enunciado.texto
|
|
1072
|
+
if (enunciado.id === 4) {
|
|
1073
|
+
// Special formatting for enunciado 4 with list items
|
|
1074
|
+
formattedText = formattedText.replace(/\n([abc])\)/g, '\n $1)')
|
|
1075
|
+
formattedText = formattedText.replace(/\n\nEstos tres elementos/g, '\n\n Estos tres elementos')
|
|
1076
|
+
}
|
|
1077
|
+
console.log(`${index + 1}. ${formattedText}`)
|
|
1078
|
+
console.log("")
|
|
1079
|
+
})
|
|
1080
|
+
|
|
1081
|
+
const respuesta = await askQuestion("Elige un número (1-7) o 'q' para salir: ")
|
|
1082
|
+
|
|
1083
|
+
if (respuesta.toLowerCase() === 'q') {
|
|
1084
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
1085
|
+
rl.close()
|
|
1086
|
+
return
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
const numeroSeleccionado = parseInt(respuesta)
|
|
1090
|
+
|
|
1091
|
+
if (numeroSeleccionado >= 1 && numeroSeleccionado <= 7) {
|
|
1092
|
+
const enunciadoSeleccionado = ENUNCIADOS[numeroSeleccionado - 1]
|
|
1093
|
+
|
|
1094
|
+
// Check if we have a lesson implementation for this enunciado
|
|
1095
|
+
if (enunciadoSeleccionado.id === 1) {
|
|
1096
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1097
|
+
rl.close()
|
|
1098
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1099
|
+
|
|
1100
|
+
try {
|
|
1101
|
+
const lesson1 = new Lesson1SystemDecomposition()
|
|
1102
|
+
await lesson1.start()
|
|
1103
|
+
} catch (error) {
|
|
1104
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1105
|
+
console.log("\n🚀 Próximamente:")
|
|
1106
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1107
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1108
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1109
|
+
}
|
|
1110
|
+
return
|
|
1111
|
+
} else if (enunciadoSeleccionado.id === 1) {
|
|
1112
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1113
|
+
rl.close()
|
|
1114
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1115
|
+
|
|
1116
|
+
try {
|
|
1117
|
+
const lesson1 = new Lesson1SystemDecomposition()
|
|
1118
|
+
await lesson1.start()
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1121
|
+
console.log("\n🚀 Próximamente:")
|
|
1122
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1123
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1124
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1125
|
+
}
|
|
1126
|
+
return
|
|
1127
|
+
} else if (enunciadoSeleccionado.id === 2) {
|
|
1128
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1129
|
+
rl.close()
|
|
1130
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1131
|
+
|
|
1132
|
+
try {
|
|
1133
|
+
const lesson2 = new Lesson2ObjectRequests()
|
|
1134
|
+
await lesson2.start()
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1137
|
+
console.log("\n🚀 Próximamente:")
|
|
1138
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1139
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1140
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1141
|
+
}
|
|
1142
|
+
return
|
|
1143
|
+
} else if (enunciadoSeleccionado.id === 3) {
|
|
1144
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1145
|
+
rl.close()
|
|
1146
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1147
|
+
|
|
1148
|
+
try {
|
|
1149
|
+
const lesson3 = new Lesson3OnlyWay()
|
|
1150
|
+
await lesson3.start()
|
|
1151
|
+
} catch (error) {
|
|
1152
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1153
|
+
console.log("\n🚀 Próximamente:")
|
|
1154
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1155
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1156
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1157
|
+
}
|
|
1158
|
+
return
|
|
1159
|
+
} else if (enunciadoSeleccionado.id === 4) {
|
|
1160
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1161
|
+
rl.close()
|
|
1162
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1163
|
+
|
|
1164
|
+
try {
|
|
1165
|
+
const lesson4 = new Lesson4OperationSignatures()
|
|
1166
|
+
await lesson4.start()
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1169
|
+
console.log("\n🚀 Próximamente:")
|
|
1170
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1171
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1172
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1173
|
+
}
|
|
1174
|
+
return
|
|
1175
|
+
} else if (enunciadoSeleccionado.id === 5) {
|
|
1176
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1177
|
+
rl.close()
|
|
1178
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1179
|
+
|
|
1180
|
+
try {
|
|
1181
|
+
const lesson5 = new Lesson5InterfaceSet()
|
|
1182
|
+
await lesson5.start()
|
|
1183
|
+
} catch (error) {
|
|
1184
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1185
|
+
console.log("\n🚀 Próximamente:")
|
|
1186
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1187
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1188
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1189
|
+
}
|
|
1190
|
+
return
|
|
1191
|
+
} else if (enunciadoSeleccionado.id === 6) {
|
|
1192
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1193
|
+
rl.close()
|
|
1194
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1195
|
+
|
|
1196
|
+
try {
|
|
1197
|
+
const lesson6 = new Lesson6InterfaceDesign()
|
|
1198
|
+
await lesson6.start()
|
|
1199
|
+
} catch (error) {
|
|
1200
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1201
|
+
console.log("\n🚀 Próximamente:")
|
|
1202
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1203
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1204
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1205
|
+
}
|
|
1206
|
+
return
|
|
1207
|
+
} else if (enunciadoSeleccionado.id === 7) {
|
|
1208
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1209
|
+
rl.close()
|
|
1210
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1211
|
+
|
|
1212
|
+
try {
|
|
1213
|
+
const lesson7 = new Lesson7ObjectDefinition()
|
|
1214
|
+
await lesson7.start()
|
|
1215
|
+
} catch (error) {
|
|
1216
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1217
|
+
console.log("\n🚀 Próximamente:")
|
|
1218
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1219
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1220
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1221
|
+
}
|
|
1222
|
+
return
|
|
1223
|
+
} else {
|
|
1224
|
+
console.log("\n🚀 Próximamente:")
|
|
1225
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1226
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1227
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1228
|
+
|
|
1229
|
+
console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
|
|
1230
|
+
console.log(" te genera más curiosidad o confusión?")
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
} else {
|
|
1234
|
+
console.log("❌ Opción no válida. Elige un número entre 1 y 7.")
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
rl.close()
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
console.error('Error:', error.message)
|
|
1240
|
+
rl.close()
|
|
1241
|
+
process.exit(1)
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
async function startSintaxisSelector() {
|
|
1247
|
+
const rl = createInterface({
|
|
1248
|
+
input: process.stdin,
|
|
1249
|
+
output: process.stdout
|
|
1250
|
+
})
|
|
1251
|
+
|
|
1252
|
+
console.log("Sintaxis: estudia el modo en que se combinan las palabras y los distintos grupos que forman para expresar significado.")
|
|
1253
|
+
|
|
1254
|
+
await new Promise((resolve) => {
|
|
1255
|
+
rl.question("\nPresiona Enter para comenzar...", () => {
|
|
1256
|
+
rl.close()
|
|
1257
|
+
resolve()
|
|
1258
|
+
})
|
|
1259
|
+
})
|
|
1260
|
+
|
|
1261
|
+
console.log("\nEn esta sección aprenderemos algo más que palabras, aprenderemos comandos.")
|
|
1262
|
+
console.log("")
|
|
1263
|
+
console.log("Al final del día un comando es una palabra, la diferencia es que está dotada de un significado que tu computadora entiende.")
|
|
1264
|
+
console.log("")
|
|
1265
|
+
console.log("🚀 Próximamente:")
|
|
1266
|
+
console.log("- Terminal básico (pwd, ls, cd, mkdir, touch, cat)")
|
|
1267
|
+
console.log("- Git básico (init, status, add, commit)")
|
|
1268
|
+
console.log("- Git colaboración (remote, push, pull, clone)")
|
|
1269
|
+
console.log("- Git avanzado (branch, checkout, merge)")
|
|
1270
|
+
console.log("")
|
|
1271
|
+
console.log("Este es tu primer comando: ls")
|
|
1272
|
+
console.log("")
|
|
1273
|
+
console.log("Presiona ctrl + c para terminar esta sesión y después ejecuta el comando ls en tu terminal")
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
async function startProyectosSelector() {
|
|
1277
|
+
// Always try interactive mode first, fall back only if it fails
|
|
1278
|
+
try {
|
|
1279
|
+
return await startProyectosSelectorInteractive()
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
// If interactive mode fails, fall back to numbered selection
|
|
1282
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
1283
|
+
return await startProyectosSelectorFallback()
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
async function startProyectosSelectorInteractive() {
|
|
1288
|
+
// Check if setRawMode is available before trying to use it
|
|
1289
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
1290
|
+
throw new Error('setRawMode not available')
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
console.log("\n🚀 Construir Proyectos")
|
|
1294
|
+
console.log("Elige qué proyecto quieres construir:")
|
|
1295
|
+
|
|
1296
|
+
const projects = [
|
|
1297
|
+
{ id: 1, title: "🔀 Construye una pull-request", type: 'pr' },
|
|
1298
|
+
{ id: 2, title: "🎨 Construye tu portafolio", type: 'portfolio' }
|
|
1299
|
+
]
|
|
1300
|
+
|
|
1301
|
+
let selectedIndex = 0
|
|
1302
|
+
|
|
1303
|
+
// Enable raw mode to capture arrow keys
|
|
1304
|
+
try {
|
|
1305
|
+
process.stdin.setRawMode(true)
|
|
1306
|
+
process.stdin.resume()
|
|
1307
|
+
process.stdin.setEncoding('utf8')
|
|
1308
|
+
} catch (error) {
|
|
1309
|
+
throw new Error('Failed to enable raw mode: ' + error.message)
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
const renderOptions = () => {
|
|
1313
|
+
// Clear previous output and move cursor to top
|
|
1314
|
+
process.stdout.write('\x1b[2J')
|
|
1315
|
+
process.stdout.write('\x1b[H')
|
|
1316
|
+
|
|
1317
|
+
console.log("🚀 Construir Proyectos")
|
|
1318
|
+
console.log("Elige qué proyecto quieres construir:")
|
|
1319
|
+
|
|
1320
|
+
projects.forEach((project, index) => {
|
|
1321
|
+
const isSelected = index === selectedIndex
|
|
1322
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
1323
|
+
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
1324
|
+
const reset = '\x1b[0m'
|
|
1325
|
+
|
|
1326
|
+
console.log(`${highlight}${prefix}${project.title}${reset}`)
|
|
1327
|
+
console.log("")
|
|
1328
|
+
})
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
return new Promise((resolve) => {
|
|
1332
|
+
renderOptions()
|
|
1333
|
+
|
|
1334
|
+
const onKeyPress = (key) => {
|
|
1335
|
+
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
1336
|
+
process.stdin.setRawMode(false)
|
|
1337
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
1338
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
1339
|
+
resolve()
|
|
1340
|
+
return
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
if (key === '\r' || key === '\n') { // Enter
|
|
1344
|
+
process.stdin.setRawMode(false)
|
|
1345
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
1346
|
+
|
|
1347
|
+
const selectedProject = projects[selectedIndex]
|
|
1348
|
+
|
|
1349
|
+
// Clear screen
|
|
1350
|
+
process.stdout.write('\x1b[2J')
|
|
1351
|
+
process.stdout.write('\x1b[H')
|
|
1352
|
+
|
|
1353
|
+
if (selectedProject.type === 'pr') {
|
|
1354
|
+
startPullRequestTutorial().then(resolve)
|
|
1355
|
+
} else if (selectedProject.type === 'portfolio') {
|
|
1356
|
+
startPortfolioSelector().then(resolve)
|
|
1357
|
+
}
|
|
1358
|
+
return
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// Handle arrow keys (escape sequences)
|
|
1362
|
+
if (key === '\u001b[A') { // Up arrow
|
|
1363
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : projects.length - 1
|
|
1364
|
+
renderOptions()
|
|
1365
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
1366
|
+
selectedIndex = selectedIndex < projects.length - 1 ? selectedIndex + 1 : 0
|
|
1367
|
+
renderOptions()
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
process.stdin.on('data', onKeyPress)
|
|
1372
|
+
})
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
async function returnToMainMenu() {
|
|
1376
|
+
const rl = createInterface({
|
|
1377
|
+
input: process.stdin,
|
|
1378
|
+
output: process.stdout
|
|
1379
|
+
})
|
|
1380
|
+
|
|
1381
|
+
const askQuestion = (question) => {
|
|
1382
|
+
return new Promise((resolve) => {
|
|
1383
|
+
rl.question(question, resolve)
|
|
1384
|
+
})
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
console.log("\n🏠 ¿Qué te gustaría hacer ahora?")
|
|
1388
|
+
console.log("1. Volver al menú principal")
|
|
1389
|
+
console.log("2. Salir")
|
|
1390
|
+
|
|
1391
|
+
const respuesta = await askQuestion("\nElige una opción (1-2): ")
|
|
1392
|
+
|
|
1393
|
+
if (respuesta === '1') {
|
|
1394
|
+
rl.close()
|
|
1395
|
+
console.clear()
|
|
1396
|
+
await startMainMenu()
|
|
1397
|
+
} else {
|
|
1398
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
1399
|
+
rl.close()
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
async function startProyectosSelectorFallback() {
|
|
1404
|
+
const rl = createInterface({
|
|
1405
|
+
input: process.stdin,
|
|
1406
|
+
output: process.stdout
|
|
1407
|
+
})
|
|
1408
|
+
|
|
1409
|
+
const askQuestion = (question) => {
|
|
1410
|
+
return new Promise((resolve) => {
|
|
1411
|
+
rl.question(question, resolve)
|
|
1412
|
+
})
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
try {
|
|
1416
|
+
console.log("\n🚀 Construir Proyectos")
|
|
1417
|
+
console.log("Elige qué proyecto quieres construir:")
|
|
1418
|
+
console.log("")
|
|
1419
|
+
console.log("1. 🔀 Construye una pull-request")
|
|
1420
|
+
console.log("2. 🎨 Construye tu portafolio")
|
|
1421
|
+
console.log("")
|
|
1422
|
+
|
|
1423
|
+
const respuesta = await askQuestion("Elige una opción (1-2) o 'q' para salir: ")
|
|
1424
|
+
|
|
1425
|
+
if (respuesta.toLowerCase() === 'q') {
|
|
1426
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
1427
|
+
rl.close()
|
|
1428
|
+
return
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const opcionSeleccionada = parseInt(respuesta)
|
|
1432
|
+
|
|
1433
|
+
if (opcionSeleccionada === 1) {
|
|
1434
|
+
rl.close()
|
|
1435
|
+
await startPullRequestTutorial()
|
|
1436
|
+
} else if (opcionSeleccionada === 2) {
|
|
1437
|
+
rl.close()
|
|
1438
|
+
await startPortfolioSelector()
|
|
1439
|
+
} else {
|
|
1440
|
+
console.log("❌ Opción no válida. Elige 1 o 2.")
|
|
1441
|
+
rl.close()
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
console.error('Error:', error.message)
|
|
1446
|
+
rl.close()
|
|
1447
|
+
process.exit(1)
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
async function startPortfolioSelector() {
|
|
1452
|
+
// Always try interactive mode first, fall back only if it fails
|
|
1453
|
+
try {
|
|
1454
|
+
return await startPortfolioSelectorInteractive()
|
|
1455
|
+
} catch (error) {
|
|
1456
|
+
// If interactive mode fails, fall back to numbered selection
|
|
1457
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
1458
|
+
return await startPortfolioSelectorFallback()
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
async function startPortfolioSelectorInteractive() {
|
|
1463
|
+
// Check if setRawMode is available before trying to use it
|
|
1464
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
1465
|
+
throw new Error('setRawMode not available')
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
console.log("\n🎨 Construye tu Portafolio")
|
|
1469
|
+
console.log("Elige el nivel:")
|
|
1470
|
+
|
|
1471
|
+
const projects = [
|
|
1472
|
+
{ id: 1, title: "🎨 Portafolio Personal", description: "Reto completo", level: 0 },
|
|
1473
|
+
{ id: 2, title: "🔓 Portafolio Nivel 1", description: "Solo navbar", level: 1 },
|
|
1474
|
+
{ id: 3, title: "🔓 Portafolio Nivel 2", description: "Navbar + hero", level: 2 },
|
|
1475
|
+
{ id: 4, title: "🔓 Portafolio Nivel 3", description: "Solución completa", level: 3 }
|
|
1476
|
+
]
|
|
1477
|
+
|
|
1478
|
+
let selectedIndex = 0
|
|
1479
|
+
|
|
1480
|
+
// Enable raw mode to capture arrow keys
|
|
1481
|
+
try {
|
|
1482
|
+
process.stdin.setRawMode(true)
|
|
1483
|
+
process.stdin.resume()
|
|
1484
|
+
process.stdin.setEncoding('utf8')
|
|
1485
|
+
} catch (error) {
|
|
1486
|
+
throw new Error('Failed to enable raw mode: ' + error.message)
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
const renderOptions = () => {
|
|
1490
|
+
// Clear previous output and move cursor to top
|
|
1491
|
+
process.stdout.write('\x1b[2J')
|
|
1492
|
+
process.stdout.write('\x1b[H')
|
|
1493
|
+
|
|
1494
|
+
console.log("🎨 Construye tu Portafolio")
|
|
1495
|
+
console.log("Elige el nivel:")
|
|
1496
|
+
|
|
1497
|
+
projects.forEach((project, index) => {
|
|
1498
|
+
const isSelected = index === selectedIndex
|
|
1499
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
1500
|
+
const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
|
|
1501
|
+
const reset = '\x1b[0m'
|
|
1502
|
+
|
|
1503
|
+
console.log(`${highlight}${prefix}${project.title}${reset}`)
|
|
1504
|
+
if (isSelected) {
|
|
1505
|
+
console.log(`${highlight} ${project.description}${reset}`)
|
|
1506
|
+
}
|
|
1507
|
+
console.log("")
|
|
1508
|
+
})
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
return new Promise((resolve) => {
|
|
1512
|
+
renderOptions()
|
|
1513
|
+
|
|
1514
|
+
const onKeyPress = (key) => {
|
|
1515
|
+
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
1516
|
+
process.stdin.setRawMode(false)
|
|
1517
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
1518
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
1519
|
+
resolve()
|
|
1520
|
+
return
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
if (key === '\r' || key === '\n') { // Enter
|
|
1524
|
+
process.stdin.setRawMode(false)
|
|
1525
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
1526
|
+
|
|
1527
|
+
const selectedProject = projects[selectedIndex]
|
|
1528
|
+
const level = selectedProject.level
|
|
1529
|
+
|
|
1530
|
+
// Clear screen
|
|
1531
|
+
process.stdout.write('\x1b[2J')
|
|
1532
|
+
process.stdout.write('\x1b[H')
|
|
1533
|
+
|
|
1534
|
+
// Check if we're in an existing Creta project
|
|
1535
|
+
if (level > 0 && isInCretaProject()) {
|
|
1536
|
+
unstuckProject(level).then(resolve)
|
|
1537
|
+
} else {
|
|
1538
|
+
createPortfolioProject(level).then(resolve)
|
|
1539
|
+
}
|
|
1540
|
+
return
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// Handle arrow keys (escape sequences)
|
|
1544
|
+
if (key === '\u001b[A') { // Up arrow
|
|
1545
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : projects.length - 1
|
|
1546
|
+
renderOptions()
|
|
1547
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
1548
|
+
selectedIndex = selectedIndex < projects.length - 1 ? selectedIndex + 1 : 0
|
|
1549
|
+
renderOptions()
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
process.stdin.on('data', onKeyPress)
|
|
1554
|
+
})
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
async function startPortfolioSelectorFallback() {
|
|
1558
|
+
const rl = createInterface({
|
|
1559
|
+
input: process.stdin,
|
|
1560
|
+
output: process.stdout
|
|
1561
|
+
})
|
|
1562
|
+
|
|
1563
|
+
const askQuestion = (question) => {
|
|
1564
|
+
return new Promise((resolve) => {
|
|
1565
|
+
rl.question(question, resolve)
|
|
1566
|
+
})
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
try {
|
|
1570
|
+
console.log("\n🎨 Construye tu Portafolio")
|
|
1571
|
+
console.log("Elige el nivel:")
|
|
1572
|
+
console.log("")
|
|
1573
|
+
console.log("1. 🎨 Portafolio Personal - Reto completo")
|
|
1574
|
+
console.log("2. 🔓 Portafolio Nivel 1 - Solo navbar")
|
|
1575
|
+
console.log("3. 🔓 Portafolio Nivel 2 - Navbar + hero")
|
|
1576
|
+
console.log("4. 🔓 Portafolio Nivel 3 - Solución completa")
|
|
1577
|
+
console.log("")
|
|
1578
|
+
|
|
1579
|
+
const respuesta = await askQuestion("Elige una opción (1-4) o 'q' para salir: ")
|
|
1580
|
+
|
|
1581
|
+
if (respuesta.toLowerCase() === 'q') {
|
|
1582
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
1583
|
+
rl.close()
|
|
1584
|
+
return
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
const opcionSeleccionada = parseInt(respuesta)
|
|
1588
|
+
|
|
1589
|
+
if (opcionSeleccionada >= 1 && opcionSeleccionada <= 4) {
|
|
1590
|
+
rl.close()
|
|
1591
|
+
|
|
1592
|
+
// Map selection to portfolio level
|
|
1593
|
+
const level = opcionSeleccionada === 1 ? 0 : opcionSeleccionada - 1
|
|
1594
|
+
|
|
1595
|
+
// Check if we're in an existing Creta project
|
|
1596
|
+
if (level > 0 && isInCretaProject()) {
|
|
1597
|
+
await unstuckProject(level)
|
|
1598
|
+
} else {
|
|
1599
|
+
await createPortfolioProject(level)
|
|
1600
|
+
}
|
|
1601
|
+
} else {
|
|
1602
|
+
console.log("❌ Opción no válida. Elige un número entre 1 y 4.")
|
|
1603
|
+
rl.close()
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
} catch (error) {
|
|
1607
|
+
console.error('Error:', error.message)
|
|
1608
|
+
rl.close()
|
|
1609
|
+
process.exit(1)
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
async function startPullRequestTutorial() {
|
|
1614
|
+
try {
|
|
1615
|
+
const tutorial = new PullRequestTutorial()
|
|
1616
|
+
await tutorial.start()
|
|
1617
|
+
|
|
1618
|
+
// Volver al menú principal después de completar el tutorial
|
|
1619
|
+
await returnToMainMenu()
|
|
1620
|
+
} catch (error) {
|
|
1621
|
+
console.error("\n❌ Error al ejecutar el tutorial:", error.message)
|
|
1622
|
+
console.log("\nSi el problema persiste, contacta al equipo de Creta.")
|
|
1623
|
+
|
|
1624
|
+
const rl = createInterface({
|
|
1625
|
+
input: process.stdin,
|
|
1626
|
+
output: process.stdout
|
|
1627
|
+
})
|
|
1628
|
+
|
|
1629
|
+
await new Promise((resolve) => {
|
|
1630
|
+
rl.question("\nPresiona Enter para volver al menú principal...", () => {
|
|
1631
|
+
rl.close()
|
|
1632
|
+
resolve()
|
|
1633
|
+
})
|
|
1634
|
+
})
|
|
1635
|
+
|
|
1636
|
+
await startMainMenu()
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
// Helper function to detect command help requests
|
|
1641
|
+
function isCommandHelpRequest(args) {
|
|
1642
|
+
// List of supported commands for help
|
|
1643
|
+
const basicCommands = ['ls', 'cd', 'mkdir', 'touch', 'wc']
|
|
1644
|
+
const gitCommands = ['git status', 'git add', 'git commit', 'git push', 'git log']
|
|
1645
|
+
|
|
1646
|
+
const commandString = args.join(' ')
|
|
1647
|
+
|
|
1648
|
+
// Check basic commands
|
|
1649
|
+
if (basicCommands.includes(args[0])) {
|
|
1650
|
+
return true
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
// Check git commands (two words)
|
|
1654
|
+
if (args[0] === 'git' && args.length >= 2) {
|
|
1655
|
+
const gitCommand = `${args[0]} ${args[1]}`
|
|
1656
|
+
return gitCommands.includes(gitCommand)
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
return false
|
|
40
1660
|
}
|