@icarusmx/creta 1.5.12 → 1.5.13
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/bin/creta.js +30 -1
- package/lib/data/command-help/aws-ec2.js +34 -0
- package/lib/data/command-help/grep.js +72 -0
- package/lib/data/command-help/index.js +9 -1
- package/lib/executors/CommandHelpExecutor.js +6 -1
- package/lib/exercises/.claude/settings.local.json +12 -0
- package/lib/exercises/01-developing-muscle-for-nvim.md +528 -0
- package/lib/exercises/{iterm2-pane-navigation.md → 02-iterm2-pane-navigation.md} +1 -1
- package/lib/exercises/05-svelte-first-steps.md +1340 -0
- package/lib/exercises/{curl-and-pipes.md → 06-curl-and-pipes.md} +187 -72
- package/lib/exercises/07-claude-api-first-steps.md +855 -0
- package/lib/exercises/08-playwright-svelte-guide.md +1384 -0
- package/lib/exercises/09-docker-first-steps.md +1475 -0
- package/lib/exercises/{railway-deployment.md → 10-railway-deployment.md} +1 -0
- package/lib/exercises/{aws-billing-detective.md → 11-aws-billing-detective.md} +215 -35
- package/lib/exercises/12-install-skills.md +755 -0
- package/lib/exercises/README.md +180 -0
- package/lib/exercises/utils/booklet-2up.js +133 -0
- package/lib/exercises/utils/booklet-manual-duplex.js +159 -0
- package/lib/exercises/utils/booklet-simple.js +136 -0
- package/lib/exercises/utils/create-booklet.js +116 -0
- package/lib/scripts/aws-ec2-all.sh +58 -0
- package/package.json +3 -2
- /package/lib/exercises/{git-stash-workflow.md → 03-git-stash-workflow.md} +0 -0
- /package/lib/exercises/{array-object-manipulation.md → 04-array-object-manipulation.md} +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { shortEdge } from 'pdf-book';
|
|
4
|
+
import { PDFDocument } from 'pdf-lib';
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
|
|
9
|
+
const rl = readline.createInterface({
|
|
10
|
+
input: process.stdin,
|
|
11
|
+
output: process.stdout
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function ask(question) {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
rl.question(question, resolve);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function createBooklet(inputPath) {
|
|
21
|
+
try {
|
|
22
|
+
const filename = path.basename(inputPath, '.pdf');
|
|
23
|
+
console.log(`\n📚 Creando booklet para: ${filename}`);
|
|
24
|
+
|
|
25
|
+
// Leer PDF original
|
|
26
|
+
const srcFile = await fs.readFile(inputPath);
|
|
27
|
+
|
|
28
|
+
// Crear booklet (ordena páginas para doblar por la mitad)
|
|
29
|
+
console.log('⚙️ Reorganizando páginas para booklet...');
|
|
30
|
+
|
|
31
|
+
// Suprimir console.log temporalmente
|
|
32
|
+
const originalLog = console.log;
|
|
33
|
+
console.log = () => {};
|
|
34
|
+
|
|
35
|
+
const { saved } = await shortEdge(srcFile);
|
|
36
|
+
|
|
37
|
+
// Restaurar console.log
|
|
38
|
+
console.log = originalLog;
|
|
39
|
+
|
|
40
|
+
// Cargar el booklet para separar páginas
|
|
41
|
+
const bookletDoc = await PDFDocument.load(saved);
|
|
42
|
+
const totalPages = bookletDoc.getPageCount();
|
|
43
|
+
|
|
44
|
+
console.log(`📄 Total de páginas en booklet: ${totalPages}`);
|
|
45
|
+
|
|
46
|
+
// Crear PDF para FRENTE (páginas impares: 1, 3, 5, 7...)
|
|
47
|
+
const frontDoc = await PDFDocument.create();
|
|
48
|
+
// Crear PDF para REVERSO (páginas pares: 2, 4, 6, 8...)
|
|
49
|
+
const backDoc = await PDFDocument.create();
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < totalPages; i++) {
|
|
52
|
+
const [page] = await (i % 2 === 0 ? frontDoc : backDoc).copyPages(bookletDoc, [i]);
|
|
53
|
+
(i % 2 === 0 ? frontDoc : backDoc).addPage(page);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Guardar PDFs separados
|
|
57
|
+
const frontPath = path.join(path.dirname(inputPath), `${filename}-FRENTE.pdf`);
|
|
58
|
+
const backPath = path.join(path.dirname(inputPath), `${filename}-REVERSO.pdf`);
|
|
59
|
+
|
|
60
|
+
await fs.writeFile(frontPath, await frontDoc.save());
|
|
61
|
+
await fs.writeFile(backPath, await backDoc.save());
|
|
62
|
+
|
|
63
|
+
console.log('\n✅ Booklets creados:\n');
|
|
64
|
+
console.log(` 📄 FRENTE: ${path.basename(frontPath)}`);
|
|
65
|
+
console.log(` 📄 REVERSO: ${path.basename(backPath)}`);
|
|
66
|
+
|
|
67
|
+
console.log('\n📖 INSTRUCCIONES DE IMPRESIÓN:\n');
|
|
68
|
+
console.log('1. Imprime PRIMERO el archivo FRENTE');
|
|
69
|
+
console.log(' → Imprime todas las páginas');
|
|
70
|
+
console.log(' → Deja las hojas EN EL ORDEN que salieron\n');
|
|
71
|
+
console.log('2. Toma la pila de hojas impresas');
|
|
72
|
+
console.log(' → VOLTÉALAS (como voltear una página de libro)');
|
|
73
|
+
console.log(' → Mételas de nuevo en la bandeja\n');
|
|
74
|
+
console.log('3. Imprime el archivo REVERSO');
|
|
75
|
+
console.log(' → Se imprimirá en el reverso de las hojas\n');
|
|
76
|
+
console.log('4. Dobla las hojas por la mitad');
|
|
77
|
+
console.log('5. Encuaderna por el lado IZQUIERDO\n');
|
|
78
|
+
|
|
79
|
+
return { frontPath, backPath };
|
|
80
|
+
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error('❌ Error:', error.message);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function main() {
|
|
88
|
+
const args = process.argv.slice(2);
|
|
89
|
+
|
|
90
|
+
if (args.length === 0) {
|
|
91
|
+
console.log('Uso: node create-booklet.js <archivo.pdf>');
|
|
92
|
+
console.log('Ejemplo: node create-booklet.js aws-billing-detective.pdf');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const inputPath = path.resolve(args[0]);
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
await fs.access(inputPath);
|
|
100
|
+
} catch {
|
|
101
|
+
console.error(`❌ Archivo no encontrado: ${inputPath}`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const { frontPath, backPath } = await createBooklet(inputPath);
|
|
106
|
+
|
|
107
|
+
console.log('\n🖨️ Los PDFs están listos para imprimir.');
|
|
108
|
+
console.log('\n✅ Para abrirlos, ejecuta:');
|
|
109
|
+
console.log(` open "${path.basename(frontPath)}"`);
|
|
110
|
+
console.log(` open "${path.basename(backPath)}"`);
|
|
111
|
+
|
|
112
|
+
rl.close();
|
|
113
|
+
console.log('\n¡Listo! 🎉\n');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# AWS EC2 All Regions Audit
|
|
4
|
+
# Scans every AWS region for EC2 instances and EBS volumes
|
|
5
|
+
# Usage: ./aws-ec2-all.sh
|
|
6
|
+
|
|
7
|
+
echo "🔍 AWS EC2 & EBS Volumes Audit"
|
|
8
|
+
echo "Scanning all regions for instances and volumes..."
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
|
|
12
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
13
|
+
echo "📍 Region: $region"
|
|
14
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
# Check EC2 Instances
|
|
18
|
+
echo "💻 EC2 Instances:"
|
|
19
|
+
instances=$(aws ec2 describe-instances --region $region --output table 2>/dev/null | grep -v "^$")
|
|
20
|
+
if [ -z "$instances" ]; then
|
|
21
|
+
echo " No instances found"
|
|
22
|
+
else
|
|
23
|
+
echo "$instances"
|
|
24
|
+
fi
|
|
25
|
+
echo ""
|
|
26
|
+
|
|
27
|
+
# Check ALL EBS Volumes
|
|
28
|
+
echo "💾 All EBS Volumes (VolumeId | State | Size | Type):"
|
|
29
|
+
volumes=$(aws ec2 describe-volumes --region $region \
|
|
30
|
+
--query 'Volumes[].[VolumeId,State,Size,VolumeType]' \
|
|
31
|
+
--output table 2>/dev/null | grep -v "^$")
|
|
32
|
+
if [ -z "$volumes" ]; then
|
|
33
|
+
echo " No volumes found"
|
|
34
|
+
else
|
|
35
|
+
echo "$volumes"
|
|
36
|
+
fi
|
|
37
|
+
echo ""
|
|
38
|
+
|
|
39
|
+
# Check AVAILABLE Volumes (💰 MONEY WASTERS!)
|
|
40
|
+
echo "⚠️ AVAILABLE Volumes (NOT ATTACHED - WASTING MONEY!):"
|
|
41
|
+
available=$(aws ec2 describe-volumes --region $region \
|
|
42
|
+
--filters "Name=status,Values=available" \
|
|
43
|
+
--query 'Volumes[].[VolumeId,Size,VolumeType,CreateTime]' \
|
|
44
|
+
--output table 2>/dev/null | grep -v "^$")
|
|
45
|
+
if [ -z "$available" ]; then
|
|
46
|
+
echo " ✅ No unattached volumes (good!)"
|
|
47
|
+
else
|
|
48
|
+
echo "$available"
|
|
49
|
+
echo " 💡 Delete these volumes if you don't need them!"
|
|
50
|
+
fi
|
|
51
|
+
echo ""
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
55
|
+
echo "✅ Scan complete"
|
|
56
|
+
echo ""
|
|
57
|
+
echo "💡 Pro tip: AVAILABLE volumes are costing you money every month!"
|
|
58
|
+
echo " Use 'aws ec2 delete-volume --volume-id vol-xxxxx' to remove them"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icarusmx/creta",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.13",
|
|
4
4
|
"description": "Salgamos de este laberinto.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"chalk": "^5.3.0",
|
|
27
27
|
"chokidar": "^3.5.3",
|
|
28
|
-
"node-fetch": "^3.3.2"
|
|
28
|
+
"node-fetch": "^3.3.2",
|
|
29
|
+
"pdf-book": "^0.0.10"
|
|
29
30
|
}
|
|
30
31
|
}
|
|
File without changes
|
|
File without changes
|