@icarusmx/creta 0.2.2 → 0.3.0
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.md +101 -8
- package/bin/creta.js +92 -6
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -4,22 +4,115 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
4
4
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
|
-
This is "@icarusmx/creta" - a
|
|
7
|
+
This is "@icarusmx/creta" - a CLI tool for the Icarus software school that helps reconnect with former students by providing them with guided challenges to build personal portfolios. The tool generates SvelteKit 5 + Tailwind CSS 4 boilerplates with instructional comments in Spanish.
|
|
8
|
+
|
|
9
|
+
## Purpose and Mission
|
|
10
|
+
|
|
11
|
+
Creta is a Spanish-speaking software school focused on learn-by-building approach. This CLI tool serves as a reconnection mechanism with former students, encouraging them to complete their education by building personal websites. The tool provides progressive difficulty levels where students can skip ahead or get solutions for different components.
|
|
8
12
|
|
|
9
13
|
## Architecture
|
|
10
14
|
|
|
11
|
-
- **Entry point**: `bin/creta.js` -
|
|
12
|
-
- **Package**: Published as `@icarusmx/creta` on npm with public access
|
|
13
|
-
- **Language**: JavaScript (no TypeScript)
|
|
15
|
+
- **Entry point**: `bin/creta.js` - Interactive Node.js CLI that collects student names and generates projects
|
|
16
|
+
- **Package**: Published as `@icarusmx/creta` on npm with public access (current version: 0.2.2)
|
|
17
|
+
- **Language**: JavaScript ES modules (no TypeScript)
|
|
18
|
+
- **Templates**: SvelteKit 5 + Tailwind CSS 4 portfolio boilerplate in `/templates/sveltekit-portfolio/`
|
|
14
19
|
|
|
15
|
-
##
|
|
20
|
+
## Available Commands
|
|
21
|
+
|
|
22
|
+
- `creta portafolio` - Full challenge with instructional comments (level 0)
|
|
23
|
+
- `creta portafolio-1` - Navbar completed (level 1)
|
|
24
|
+
- `creta portafolio-2` - Navbar + hero completed (level 2)
|
|
25
|
+
- `creta portafolio-3` - Complete solution (level 3)
|
|
26
|
+
|
|
27
|
+
## Technology Stack
|
|
28
|
+
|
|
29
|
+
### Frontend Template
|
|
30
|
+
- **SvelteKit 5**: Using new syntax with `{@render children?.()}` instead of `<slot />`
|
|
31
|
+
- **Tailwind CSS 4**: Using `@tailwindcss/vite` plugin (no config files needed)
|
|
32
|
+
- **Vite**: Build tool and dev server
|
|
33
|
+
|
|
34
|
+
### Template Structure
|
|
35
|
+
```
|
|
36
|
+
templates/sveltekit-portfolio/
|
|
37
|
+
├── package.json # SvelteKit 5 + Tailwind 4 dependencies
|
|
38
|
+
├── vite.config.js # Vite config with Tailwind plugin
|
|
39
|
+
├── svelte.config.js # SvelteKit configuration
|
|
40
|
+
├── src/
|
|
41
|
+
│ ├── app.html # HTML template
|
|
42
|
+
│ ├── app.css # Tailwind directives
|
|
43
|
+
│ └── routes/
|
|
44
|
+
│ ├── +layout.svelte # Layout with navbar/footer challenges
|
|
45
|
+
│ └── +page.svelte # Hero section challenge
|
|
46
|
+
└── static/
|
|
47
|
+
└── favicon.png
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Key Features
|
|
51
|
+
|
|
52
|
+
### Interactive Project Generation
|
|
53
|
+
- Prompts for student name using readline interface
|
|
54
|
+
- Generates project directory named `{name}-portafolio`
|
|
55
|
+
- Replaces `{{STUDENT_NAME}}` and `{{PROJECT_NAME}}` placeholders
|
|
56
|
+
- Copies template files with level-specific modifications
|
|
16
57
|
|
|
17
|
-
|
|
58
|
+
### Progressive Difficulty System
|
|
59
|
+
The `applyLevelModifications()` function provides solutions based on level:
|
|
60
|
+
- **Level 1+**: Complete navbar with navigation links
|
|
61
|
+
- **Level 2+**: Complete hero section with student's name
|
|
62
|
+
- **Level 3+**: Complete footer with copyright and Creta attribution
|
|
63
|
+
|
|
64
|
+
### Spanish Instructional Design
|
|
65
|
+
- All comments and instructions in Spanish
|
|
66
|
+
- Detailed Tailwind CSS patterns and tips
|
|
67
|
+
- Encouraging messages for returning students
|
|
68
|
+
- HTML structure examples in code blocks (using `[placeholders]` to avoid parsing issues)
|
|
69
|
+
|
|
70
|
+
## Development Commands
|
|
18
71
|
|
|
19
72
|
```bash
|
|
73
|
+
# Test CLI locally
|
|
20
74
|
node bin/creta.js
|
|
75
|
+
|
|
76
|
+
# Test specific commands
|
|
77
|
+
node bin/creta.js portafolio
|
|
78
|
+
node bin/creta.js portafolio-1
|
|
79
|
+
|
|
80
|
+
# Publish to npm (increment version first)
|
|
81
|
+
npm publish
|
|
21
82
|
```
|
|
22
83
|
|
|
23
|
-
## Current State
|
|
84
|
+
## Current State (v0.2.2)
|
|
85
|
+
|
|
86
|
+
The CLI is fully functional with:
|
|
87
|
+
- ✅ Interactive name collection
|
|
88
|
+
- ✅ SvelteKit 5 + Tailwind 4 template generation
|
|
89
|
+
- ✅ Progressive difficulty levels (0-3)
|
|
90
|
+
- ✅ Spanish instructional comments
|
|
91
|
+
- ✅ Proper Svelte 5 syntax (`{@render children?.()}`)
|
|
92
|
+
- ✅ HTML parsing issue fixes
|
|
93
|
+
- ✅ Encouraging welcome message for returning students
|
|
94
|
+
|
|
95
|
+
## Recent Fixes and Updates
|
|
96
|
+
|
|
97
|
+
### Version History
|
|
98
|
+
- **0.2.2**: Fixed Svelte 5 syntax and updated welcome message
|
|
99
|
+
- **0.2.1**: Fixed HTML comment parsing errors in Svelte templates
|
|
100
|
+
- **0.2.0**: Updated to Tailwind 4, changed command to "portafolio", new greeting
|
|
101
|
+
- **0.1.1**: Fixed template path resolution for global installs
|
|
102
|
+
- **0.1.0**: Initial working version with template generation
|
|
103
|
+
- **0.0.2**: Basic CLI structure
|
|
104
|
+
|
|
105
|
+
### Known Issues Resolved
|
|
106
|
+
- ✅ HTML comments in code examples causing Svelte parsing errors (fixed by using `[placeholders]`)
|
|
107
|
+
- ✅ Svelte 5 syntax compatibility (`<slot />` → `{@render children?.()}`)
|
|
108
|
+
- ✅ Tailwind 4 migration (removed config files, updated to Vite plugin)
|
|
109
|
+
- ✅ Template path resolution for global npm installs
|
|
110
|
+
|
|
111
|
+
## Message and Tone
|
|
112
|
+
|
|
113
|
+
The CLI uses encouraging Spanish messages:
|
|
114
|
+
- Welcome: "¡Bienvenido de vuelta! 🏛️"
|
|
115
|
+
- Mission: "Retomemos desde donde nos quedamos: hagamos tu portafolio."
|
|
116
|
+
- Hero message: "Gracias por seguir aquí. Abre el proyecto usando `code .` y sigue las instrucciones. Si tienes dudas, apóyate en el equipo"
|
|
24
117
|
|
|
25
|
-
|
|
118
|
+
This reflects Creta's supportive approach to bringing students back to complete their learning journey.
|
package/bin/creta.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createInterface } from 'readline'
|
|
|
4
4
|
import { execSync } from 'child_process'
|
|
5
5
|
import fs from 'fs'
|
|
6
6
|
import path from 'path'
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
7
8
|
|
|
8
9
|
const args = process.argv.slice(2)
|
|
9
10
|
const command = args[0]
|
|
@@ -14,15 +15,23 @@ console.log("Retomemos desde donde nos quedamos: hagamos tu portafolio.\n")
|
|
|
14
15
|
if (!command) {
|
|
15
16
|
console.log("Comandos disponibles:")
|
|
16
17
|
console.log(" creta portafolio - Crea tu portafolio personal (reto completo)")
|
|
17
|
-
console.log(" creta portafolio-1 -
|
|
18
|
-
console.log(" creta portafolio-2 -
|
|
19
|
-
console.log(" creta portafolio-3 -
|
|
18
|
+
console.log(" creta portafolio-1 - Desbloquea nivel 1 (navbar) 🔓")
|
|
19
|
+
console.log(" creta portafolio-2 - Desbloquea nivel 2 (navbar + hero) 🔓")
|
|
20
|
+
console.log(" creta portafolio-3 - Desbloquea nivel 3 (solución completa) 🔓")
|
|
21
|
+
console.log("\n💡 Tip: Si estás dentro de un proyecto existente, los comandos")
|
|
22
|
+
console.log(" portafolio-1/2/3 actualizarán tus archivos directamente")
|
|
20
23
|
process.exit(0)
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
if (command.startsWith('portafolio')) {
|
|
24
27
|
const level = command === 'portafolio' ? 0 : parseInt(command.split('-')[1]) || 0
|
|
25
|
-
|
|
28
|
+
|
|
29
|
+
// Check if we're in an existing Creta project
|
|
30
|
+
if (level > 0 && isInCretaProject()) {
|
|
31
|
+
await unstuckProject(level)
|
|
32
|
+
} else {
|
|
33
|
+
await createPortfolioProject(level)
|
|
34
|
+
}
|
|
26
35
|
} else {
|
|
27
36
|
console.log(`Comando no reconocido: ${command}`)
|
|
28
37
|
process.exit(1)
|
|
@@ -64,13 +73,18 @@ async function createPortfolioProject(level) {
|
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
async function createProjectFiles(projectName, studentName, level) {
|
|
67
|
-
const
|
|
76
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
77
|
+
const __dirname = path.dirname(__filename)
|
|
68
78
|
const templatePath = path.join(__dirname, '../templates/sveltekit-portfolio')
|
|
69
79
|
const targetPath = path.join(process.cwd(), projectName)
|
|
70
80
|
|
|
71
81
|
// Check if template exists
|
|
72
82
|
if (!fs.existsSync(templatePath)) {
|
|
73
|
-
|
|
83
|
+
console.error(`Debug info:`)
|
|
84
|
+
console.error(` - CLI location: ${__filename}`)
|
|
85
|
+
console.error(` - Template path: ${templatePath}`)
|
|
86
|
+
console.error(` - Template exists: ${fs.existsSync(templatePath)}`)
|
|
87
|
+
throw new Error('Template no encontrado. Es posible que necesites reinstalar el paquete: npm uninstall -g @icarusmx/creta && npm install -g @icarusmx/creta')
|
|
74
88
|
}
|
|
75
89
|
|
|
76
90
|
// Create target directory
|
|
@@ -215,3 +229,75 @@ function getLevelDescription(level) {
|
|
|
215
229
|
}
|
|
216
230
|
return descriptions[level] || 'nivel desconocido'
|
|
217
231
|
}
|
|
232
|
+
|
|
233
|
+
function isInCretaProject() {
|
|
234
|
+
// Check if we're in a Creta project by looking for key files
|
|
235
|
+
const currentDir = process.cwd()
|
|
236
|
+
const packageJsonPath = path.join(currentDir, 'package.json')
|
|
237
|
+
const layoutPath = path.join(currentDir, 'src/routes/+layout.svelte')
|
|
238
|
+
const pagePath = path.join(currentDir, 'src/routes/+page.svelte')
|
|
239
|
+
|
|
240
|
+
// Must have package.json and SvelteKit structure
|
|
241
|
+
if (!fs.existsSync(packageJsonPath) || !fs.existsSync(layoutPath) || !fs.existsSync(pagePath)) {
|
|
242
|
+
return false
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Check if layout contains Creta comments
|
|
246
|
+
try {
|
|
247
|
+
const layoutContent = fs.readFileSync(layoutPath, 'utf8')
|
|
248
|
+
return layoutContent.includes('RETO CRETA') || layoutContent.includes('🧭 RETO 1: NAVBAR')
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return false
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function unstuckProject(level) {
|
|
255
|
+
console.log(`\n🔓 ¡Te ayudo a desbloquear el nivel ${level}!`)
|
|
256
|
+
console.log(`📚 Agregando código para: ${getLevelDescription(level)}`)
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const currentDir = process.cwd()
|
|
260
|
+
const layoutPath = path.join(currentDir, 'src/routes/+layout.svelte')
|
|
261
|
+
const pagePath = path.join(currentDir, 'src/routes/+page.svelte')
|
|
262
|
+
|
|
263
|
+
// Get student name from package.json title if possible
|
|
264
|
+
let studentName = 'Tu nombre'
|
|
265
|
+
try {
|
|
266
|
+
const packageJsonPath = path.join(currentDir, 'package.json')
|
|
267
|
+
const packageContent = fs.readFileSync(packageJsonPath, 'utf8')
|
|
268
|
+
const packageJson = JSON.parse(packageContent)
|
|
269
|
+
if (packageJson.name && packageJson.name.includes('-portafolio')) {
|
|
270
|
+
studentName = packageJson.name.replace('-portafolio', '').split('-').map(word =>
|
|
271
|
+
word.charAt(0).toUpperCase() + word.slice(1)
|
|
272
|
+
).join(' ')
|
|
273
|
+
}
|
|
274
|
+
} catch (error) {
|
|
275
|
+
// Use default if can't parse
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Apply modifications to existing files
|
|
279
|
+
if (fs.existsSync(layoutPath)) {
|
|
280
|
+
let layoutContent = fs.readFileSync(layoutPath, 'utf8')
|
|
281
|
+
layoutContent = applyLayoutModifications(layoutContent, level)
|
|
282
|
+
fs.writeFileSync(layoutPath, layoutContent)
|
|
283
|
+
console.log(`✅ Actualizado: src/routes/+layout.svelte`)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (fs.existsSync(pagePath)) {
|
|
287
|
+
let pageContent = fs.readFileSync(pagePath, 'utf8')
|
|
288
|
+
pageContent = applyPageModifications(pageContent, level)
|
|
289
|
+
// Replace student name placeholder
|
|
290
|
+
pageContent = pageContent.replace(/\{\{STUDENT_NAME\}\}/g, studentName)
|
|
291
|
+
fs.writeFileSync(pagePath, pageContent)
|
|
292
|
+
console.log(`✅ Actualizado: src/routes/+page.svelte`)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
console.log(`\n🎉 ¡Listo! Ahora tienes el código del nivel ${level}`)
|
|
296
|
+
console.log(`💡 Revisa los archivos actualizados para ver qué se agregó`)
|
|
297
|
+
console.log(`🚀 Continúa con: npm run dev`)
|
|
298
|
+
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error('Error al actualizar el proyecto:', error.message)
|
|
301
|
+
process.exit(1)
|
|
302
|
+
}
|
|
303
|
+
}
|