@icarusmx/creta 1.4.17 → 1.4.19

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/lib/cli/index.js CHANGED
@@ -8,6 +8,7 @@ import { showHelp } from '../commands/help.js'
8
8
  import { CretaCodeSession } from '../session.js'
9
9
  import { greetUser } from '../utils/greeting.js'
10
10
  import { SandboxManager } from '../sandbox/SandboxManager.js'
11
+ import TerminalCustomizer from '../customizers/TerminalCustomizer.js'
11
12
 
12
13
  async function executeMainMenu() {
13
14
  const menu = new MenuBuilder(getMainMenuConfig())
@@ -40,6 +41,16 @@ async function resetUserState() {
40
41
  console.log('✅ Estado de usuario reiniciado. La próxima vez que ejecutes creta, se te pedirá tu nombre de nuevo.')
41
42
  }
42
43
 
44
+ async function customizeTerminal() {
45
+ const customizer = new TerminalCustomizer()
46
+ await customizer.customize()
47
+ }
48
+
49
+ async function revertTerminal() {
50
+ const customizer = new TerminalCustomizer()
51
+ await customizer.revert()
52
+ }
53
+
43
54
  const COMMANDS = new Map([
44
55
  ['enunciados', () => executeEnunciados()],
45
56
  ['sintaxis', () => executeSintaxis()],
@@ -47,6 +58,8 @@ const COMMANDS = new Map([
47
58
  ['portafolio', () => executePortfolio(0)],
48
59
  ['code', () => runCodeSession()],
49
60
  ['reset', () => resetUserState()],
61
+ ['icarus-terminal', () => customizeTerminal()],
62
+ ['revert-terminal', () => revertTerminal()],
50
63
  ['help', () => showHelp()],
51
64
  ['ayuda', () => showHelp()]
52
65
  ])
@@ -0,0 +1,275 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { execSync } from 'child_process';
5
+ import { UserState } from '../utils/user-state.js';
6
+
7
+ class TerminalCustomizer {
8
+ constructor() {
9
+ this.homeDir = os.homedir();
10
+ this.zshrcPath = path.join(this.homeDir, '.zshrc');
11
+ this.icarusZshPath = path.join(this.homeDir, '.icarus-zsh');
12
+ this.tips = this.initializeTips();
13
+ }
14
+
15
+ initializeTips() {
16
+ return {
17
+ 'terminal-basico': [
18
+ '💡 Usa "cd -" para volver al directorio anterior',
19
+ '💡 "pwd" muestra tu ubicación actual en el sistema',
20
+ '💡 "ls -la" muestra archivos ocultos y permisos',
21
+ '💡 Usa Tab para autocompletar nombres de archivos'
22
+ ],
23
+ 'git-basico': [
24
+ '💡 Siempre usa "git status" antes de hacer commit',
25
+ '💡 "git log --oneline" muestra el historial compacto',
26
+ '💡 "git diff" te muestra los cambios antes de commit',
27
+ '💡 Commits frecuentes = mejor historial'
28
+ ],
29
+ 'piping-redireccion': [
30
+ '💡 El pipe "|" conecta la salida de un comando con otro',
31
+ '💡 ">" sobrescribe archivos, ">>" agrega al final',
32
+ '💡 "grep" es tu mejor amigo para buscar en texto'
33
+ ],
34
+ 'bash-scripts': [
35
+ '💡 Usa "chmod +x script.sh" para hacer ejecutable tu script',
36
+ '💡 Siempre empieza con "#!/bin/bash" en la primera línea',
37
+ '💡 "$?" te dice el código de salida del último comando'
38
+ ],
39
+ 'portafolio': [
40
+ '💡 "npm run dev" para ver cambios en tiempo real',
41
+ '💡 Tailwind CSS usa clases utilitarias, no CSS custom',
42
+ '💡 Usa "md:" para breakpoints responsive en Tailwind',
43
+ '💡 SvelteKit recarga automáticamente al guardar cambios'
44
+ ],
45
+ 'general': [
46
+ '💡 Lee los errores completos, suelen decirte qué hacer',
47
+ '💡 Google es tu amigo, pero StackOverflow más',
48
+ '💡 Commits pequeños y frecuentes > commits gigantes',
49
+ '💡 Comenta tu código como si fueras a olvidarlo mañana'
50
+ ]
51
+ };
52
+ }
53
+
54
+ getContextualTip() {
55
+ const userState = UserState.get();
56
+ const recentLessons = userState.lessonsCompleted.slice(-3);
57
+
58
+ // Try to get a tip from recently completed lessons
59
+ for (const lesson of recentLessons.reverse()) {
60
+ const lessonId = typeof lesson === 'object' ? lesson.id : lesson;
61
+ if (this.tips[lessonId] && this.tips[lessonId].length > 0) {
62
+ const tips = this.tips[lessonId];
63
+ return tips[Math.floor(Math.random() * tips.length)];
64
+ }
65
+ }
66
+
67
+ // Fallback to general tips
68
+ const generalTips = this.tips.general;
69
+ return generalTips[Math.floor(Math.random() * generalTips.length)];
70
+ }
71
+
72
+ async customize() {
73
+ console.log('\n🏛️ Configurando tu terminal Creta...\n');
74
+
75
+ try {
76
+ // Backup existing .zshrc if it exists
77
+ if (fs.existsSync(this.zshrcPath)) {
78
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
79
+ const backupPath = `${this.zshrcPath}.backup.${timestamp}`;
80
+ fs.copyFileSync(this.zshrcPath, backupPath);
81
+ console.log(`✅ Backup creado: ${backupPath}`);
82
+ }
83
+
84
+ // Create ~/.icarus-zsh with custom configuration
85
+ this.createIcarusZsh();
86
+ console.log(`✅ Configuración creada: ${this.icarusZshPath}`);
87
+
88
+ // Add source line to .zshrc if not already present
89
+ this.updateZshrc();
90
+ console.log(`✅ Terminal configurado`);
91
+
92
+ // Apply changes instantly
93
+ this.applyChanges();
94
+
95
+ console.log('\n🎉 ¡Terminal Creta configurado exitosamente!');
96
+ console.log('💡 Reinicia tu terminal o ejecuta: source ~/.zshrc\n');
97
+
98
+ } catch (error) {
99
+ console.error('❌ Error al configurar el terminal:', error.message);
100
+ throw error;
101
+ }
102
+ }
103
+
104
+ createIcarusZsh() {
105
+ const tip = this.getContextualTip();
106
+ const roadmapHint = this.getRoadmapHint();
107
+
108
+ // Use template literal with escaped $ to prevent Node.js interpolation
109
+ const config = `# ========================================
110
+ # 🏛️ Creta Terminal Configuration
111
+ # ========================================
112
+
113
+ # Custom prompt with color #007acc
114
+ autoload -U colors && colors
115
+ setopt PROMPT_SUBST
116
+
117
+ # Prompt color codes
118
+ CRETA_BLUE='%F{39}'
119
+ RESET='%f'
120
+ GIT_BRANCH_COLOR='%F{245}' # Gray for branch
121
+
122
+ # Git branch detection function
123
+ function git_branch_name() {
124
+ git symbolic-ref --short HEAD 2>/dev/null || echo ""
125
+ }
126
+
127
+ function git_prompt_info() {
128
+ local branch=\$(git_branch_name)
129
+ if [[ -n "\$branch" ]]; then
130
+ echo " | \${branch}"
131
+ fi
132
+ }
133
+
134
+ # Custom prompt: [🏛️ creta | branch] ~/path $
135
+ PROMPT="\${CRETA_BLUE}[🏛️ creta\${GIT_BRANCH_COLOR}\$(git_prompt_info)\${CRETA_BLUE}]\${RESET} %~ $ "
136
+
137
+ # Welcome message function
138
+ function creta_welcome() {
139
+ print ""
140
+ print -P "\${CRETA_BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\${RESET}"
141
+ print -P "\${CRETA_BLUE} 🏛️ Bienvenido a Creta Terminal\${RESET}"
142
+ print -P "\${CRETA_BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\${RESET}"
143
+ print ""
144
+
145
+ # Show contextual tip
146
+ echo "${tip.replace(/"/g, '\\"')}"
147
+
148
+ # Show roadmap hint if available
149
+ if [[ -f "roadmap.txt" ]]; then
150
+ local next_item=\$(grep -v "^#" roadmap.txt | head -n 1)
151
+ if [[ -n "\$next_item" ]]; then
152
+ echo ""
153
+ echo "📋 Siguiente en roadmap: \$next_item"
154
+ fi
155
+ fi
156
+
157
+ print ""
158
+ }
159
+
160
+ # Show welcome message
161
+ creta_welcome
162
+ `;
163
+
164
+ fs.writeFileSync(this.icarusZshPath, config, 'utf8');
165
+ }
166
+
167
+ getRoadmapHint() {
168
+ // This is a placeholder - actual parsing happens in the shell script
169
+ // We could potentially read roadmap.txt here if we want to customize the message
170
+ return null;
171
+ }
172
+
173
+ updateZshrc() {
174
+ const sourceLine = '\n# Source Creta terminal configuration\n[ -f ~/.icarus-zsh ] && source ~/.icarus-zsh\n';
175
+
176
+ // Create .zshrc if it doesn't exist
177
+ if (!fs.existsSync(this.zshrcPath)) {
178
+ fs.writeFileSync(this.zshrcPath, sourceLine, 'utf8');
179
+ return;
180
+ }
181
+
182
+ // Check if already sourced
183
+ const currentContent = fs.readFileSync(this.zshrcPath, 'utf8');
184
+ if (currentContent.includes('source ~/.icarus-zsh') || currentContent.includes('. ~/.icarus-zsh')) {
185
+ console.log('⚠️ Creta ya estaba configurado en .zshrc (actualizando)');
186
+ return;
187
+ }
188
+
189
+ // Append source line
190
+ fs.appendFileSync(this.zshrcPath, sourceLine, 'utf8');
191
+ }
192
+
193
+ applyChanges() {
194
+ try {
195
+ // Note: This won't change the current terminal session's prompt,
196
+ // but it will be applied in new sessions
197
+ execSync('source ~/.zshrc', { shell: '/bin/zsh', stdio: 'inherit' });
198
+ } catch (error) {
199
+ // Source command may fail in some contexts, but config is still written
200
+ // User can manually source or restart terminal
201
+ }
202
+ }
203
+
204
+ async revert() {
205
+ console.log('\n🔄 Revirtiendo configuración de Creta Terminal...\n');
206
+
207
+ try {
208
+ let changesMade = false;
209
+
210
+ // Remove ~/.icarus-zsh if it exists
211
+ if (fs.existsSync(this.icarusZshPath)) {
212
+ fs.unlinkSync(this.icarusZshPath);
213
+ console.log('✅ Archivo ~/.icarus-zsh eliminado');
214
+ changesMade = true;
215
+ }
216
+
217
+ // Remove source line from .zshrc
218
+ if (fs.existsSync(this.zshrcPath)) {
219
+ const currentContent = fs.readFileSync(this.zshrcPath, 'utf8');
220
+
221
+ if (currentContent.includes('source ~/.icarus-zsh') || currentContent.includes('. ~/.icarus-zsh')) {
222
+ // Remove the entire Creta block (comment + source line)
223
+ const cleanedContent = currentContent
224
+ .replace(/\n# Source Creta terminal configuration\n\[ -f ~\/\.icarus-zsh \] && source ~\/\.icarus-zsh\n/g, '')
225
+ .replace(/\n# Source Icarus terminal configuration\n\[ -f ~\/\.icarus-zsh \] && source ~\/\.icarus-zsh\n/g, '');
226
+
227
+ fs.writeFileSync(this.zshrcPath, cleanedContent, 'utf8');
228
+ console.log('✅ Configuración eliminada de ~/.zshrc');
229
+ changesMade = true;
230
+ }
231
+ }
232
+
233
+ if (!changesMade) {
234
+ console.log('⚠️ No se encontró configuración de Creta para revertir');
235
+ return;
236
+ }
237
+
238
+ // Show available backups
239
+ this.showBackups();
240
+
241
+ console.log('\n🎉 ¡Configuración revertida exitosamente!');
242
+ console.log('💡 Reinicia tu terminal o ejecuta: source ~/.zshrc\n');
243
+
244
+ } catch (error) {
245
+ console.error('❌ Error al revertir configuración:', error.message);
246
+ throw error;
247
+ }
248
+ }
249
+
250
+ showBackups() {
251
+ try {
252
+ const backupFiles = fs.readdirSync(this.homeDir)
253
+ .filter(file => file.startsWith('.zshrc.backup.'))
254
+ .sort()
255
+ .reverse()
256
+ .slice(0, 5); // Show last 5 backups
257
+
258
+ if (backupFiles.length > 0) {
259
+ console.log('\n📦 Backups disponibles (últimos 5):');
260
+ backupFiles.forEach((file, index) => {
261
+ const filepath = path.join(this.homeDir, file);
262
+ const stats = fs.statSync(filepath);
263
+ const date = stats.mtime.toLocaleString('es-MX');
264
+ console.log(` ${index + 1}. ${file} (${date})`);
265
+ });
266
+ console.log('\n💡 Para restaurar un backup manualmente:');
267
+ console.log(' cp ~/.zshrc.backup.TIMESTAMP ~/.zshrc');
268
+ }
269
+ } catch (error) {
270
+ // Silent fail - backups are optional
271
+ }
272
+ }
273
+ }
274
+
275
+ export default TerminalCustomizer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icarusmx/creta",
3
- "version": "1.4.17",
3
+ "version": "1.4.19",
4
4
  "description": "Salgamos de este laberinto.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env bash
2
+ # Summarize a repository's architecture via codex using lightweight bash reconnaissance.
3
+ set -euo pipefail
4
+
5
+ show_help() {
6
+ cat <<'USAGE'
7
+ Usage: wea-fome-qlia.sh [path-to-repo]
8
+
9
+ Collects structural signals from the repository using basic shell commands
10
+ and streams them into `codex -p` to obtain a five-sentence architecture summary.
11
+ Set the SUMMARIZER_PROMPT environment variable to override the default prompt.
12
+ USAGE
13
+ }
14
+
15
+ if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then
16
+ show_help
17
+ exit 0
18
+ fi
19
+
20
+ if (( $# > 1 )); then
21
+ echo "Only zero or one path argument is supported." >&2
22
+ exit 1
23
+ fi
24
+
25
+ REPO_DIR=${1:-.}
26
+ if [[ ! -d "$REPO_DIR" ]]; then
27
+ echo "The path '$REPO_DIR' is not a directory." >&2
28
+ exit 1
29
+ fi
30
+
31
+ if [[ -z ${BASH_VERSION:-} ]]; then
32
+ echo "This script requires bash. Run it as './wea-fome-qlia.sh' or 'bash wea-fome-qlia.sh'." >&2
33
+ exit 1
34
+ fi
35
+
36
+ if ! command -v codex >/dev/null 2>&1; then
37
+ echo "The 'codex' CLI is required but was not found in PATH." >&2
38
+ exit 1
39
+ fi
40
+
41
+ REPO_DIR=$(cd "$REPO_DIR" && pwd)
42
+ TEMP_INPUT=$(mktemp)
43
+ trap 'rm -f "$TEMP_INPUT"' EXIT
44
+
45
+ MAX_DIRS=8
46
+ MAX_ITEMS=12
47
+ PROMPT=${SUMMARIZER_PROMPT:-"You are a senior software architect. Using the repository signals provided, write exactly five sentences that explain the current architecture, main modules, dominant technologies, notable build or tooling traits, and any potential work-in-progress areas."}
48
+
49
+ {
50
+ echo "Repository: $REPO_DIR"
51
+ echo
52
+ echo "Top-level entries (ls):"
53
+ ls -1A "$REPO_DIR" | sed 's/^/ - /'
54
+
55
+ echo
56
+ echo "Directory snapshots:"
57
+ dir_count=0
58
+ while IFS= read -r entry; do
59
+ [[ -z "$entry" ]] && continue
60
+ path="$REPO_DIR/$entry"
61
+ if [[ -d "$path" ]]; then
62
+ ((dir_count++))
63
+ echo "* $entry"
64
+ ls -1A "$path" | head -n "$MAX_ITEMS" | sed 's/^/ /'
65
+ if command -v git >/dev/null 2>&1; then
66
+ echo " (files: $(ls -1A "$path" | wc -l | tr -d ' '))"
67
+ fi
68
+ echo
69
+ fi
70
+ if (( dir_count >= MAX_DIRS )); then
71
+ break
72
+ fi
73
+ done <<EOF
74
+ $(ls -1A "$REPO_DIR")
75
+ EOF
76
+
77
+ if command -v git >/dev/null 2>&1 && git -C "$REPO_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
78
+ echo "Git status:"
79
+ git -C "$REPO_DIR" status -sb
80
+
81
+ echo
82
+ echo "Recent commits:"
83
+ git -C "$REPO_DIR" log -5 --oneline
84
+ fi
85
+ } > "$TEMP_INPUT"
86
+
87
+ {
88
+ printf '%s\n\n' "$PROMPT"
89
+ echo '--- Repository signals start ---'
90
+ cat "$TEMP_INPUT"
91
+ echo '--- Repository signals end ---'
92
+ } | codex exec -