@ingcrea/aumic-tailwind-killer 4.1.4 → 4.1.6
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.es.md +12 -0
- package/README.md +12 -0
- package/dist/1_atoms/constants.js +26 -0
- package/dist/1_atoms/hash.js +22 -0
- package/dist/1_atoms/types.js +6 -0
- package/dist/2_molecules/classifier.js +38 -0
- package/dist/2_molecules/concurrency.js +18 -0
- package/dist/3_cells/AiEngine.js +103 -0
- package/dist/3_cells/DuckDbCache.js +24 -0
- package/dist/3_cells/WebCloner.js +61 -0
- package/dist/4_organisms/AstParser.js +116 -0
- package/dist/5_ecosystems/RestoreEcosystem.js +85 -0
- package/dist/5_ecosystems/TransmutationEcosystem.js +552 -0
- package/dist/5_ecosystems/index.js +17 -0
- package/dist/6_galaxies/index.js +131 -0
- package/dist/index.js +5 -1629
- package/dist/worker.js +26 -14
- package/package.json +51 -50
- package/.npmrc.bak +0 -1
- package/bin/aumic-killer.js +0 -100
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runTransmutationEcosystem = runTransmutationEcosystem;
|
|
7
|
+
/**
|
|
8
|
+
* [EN] Transmutation Ecosystem: the main Tailwind → AUM-IC orchestration pipeline.
|
|
9
|
+
* Coordinates five sequential phases:
|
|
10
|
+
* Phase 1 — File scanning and class extraction via Piscina worker pool
|
|
11
|
+
* Phase 2 — JIT Validator: separates native Tailwind vs. custom CSS tokens
|
|
12
|
+
* Phase 3 — Source mutation: rewrites class attributes in all source files
|
|
13
|
+
* Phase 4 — CSS compilation: L1 DuckDB cache + L2 dynamic JIT PostCSS
|
|
14
|
+
* Phase 5 — Tailwind eradication: removes packages, config files, integrations
|
|
15
|
+
* [ES] Ecosistema de Transmutación: el pipeline principal de orquestación Tailwind → AUM-IC.
|
|
16
|
+
* Coordina cinco fases secuenciales:
|
|
17
|
+
* Fase 1 — Escaneo de archivos y extracción de clases vía pool de workers Piscina
|
|
18
|
+
* Fase 2 — JIT Validator: separa tokens nativos Tailwind vs. CSS personalizado
|
|
19
|
+
* Fase 3 — Mutación de fuentes: reescribe atributos de clase en todos los archivos fuente
|
|
20
|
+
* Fase 4 — Compilación CSS: caché L1 DuckDB + JIT dinámico PostCSS L2
|
|
21
|
+
* Fase 5 — Erradicación de Tailwind: elimina paquetes, archivos de config e integraciones
|
|
22
|
+
*/
|
|
23
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
24
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const os_1 = __importDefault(require("os"));
|
|
26
|
+
const ora_1 = __importDefault(require("ora"));
|
|
27
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
28
|
+
const cli_progress_1 = __importDefault(require("cli-progress"));
|
|
29
|
+
const glob_1 = require("glob");
|
|
30
|
+
const child_process_1 = require("child_process");
|
|
31
|
+
const postcss_1 = __importDefault(require("postcss"));
|
|
32
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
33
|
+
const piscina_1 = __importDefault(require("piscina"));
|
|
34
|
+
const hash_1 = require("../1_atoms/hash");
|
|
35
|
+
const constants_1 = require("../1_atoms/constants");
|
|
36
|
+
const classifier_1 = require("../2_molecules/classifier");
|
|
37
|
+
const concurrency_1 = require("../2_molecules/concurrency");
|
|
38
|
+
const DuckDbCache_1 = require("../3_cells/DuckDbCache");
|
|
39
|
+
const AiEngine_1 = require("../3_cells/AiEngine");
|
|
40
|
+
const WebCloner_1 = require("../3_cells/WebCloner");
|
|
41
|
+
// [EN] Hyperlink to the AUM-IC project for terminal support. [ES] Hipervínculo al proyecto AUM-IC para terminales que lo soporten.
|
|
42
|
+
const aumicLink = `\x1b]8;;https://github.com/ingcrea/aum-ic\x07AUM-IC\x1b]8;;\x07`;
|
|
43
|
+
let pkgVersion = '4.1.5';
|
|
44
|
+
try {
|
|
45
|
+
pkgVersion = JSON.parse(fs_extra_1.default.readFileSync(path_1.default.join(__dirname, '../../package.json'), 'utf-8').replace(/^\uFEFF/, '')).version;
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
// ─── Environment Detection ────────────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* [EN] Reads the target project's package.json to determine the Tailwind major version.
|
|
51
|
+
* [ES] Lee el package.json del proyecto objetivo para determinar la versión mayor de Tailwind.
|
|
52
|
+
*/
|
|
53
|
+
async function detectTailwindVersion(targetDir) {
|
|
54
|
+
try {
|
|
55
|
+
const pkg = await fs_extra_1.default.readJson(path_1.default.join(targetDir, 'package.json'));
|
|
56
|
+
const v = pkg.dependencies?.tailwindcss || pkg.devDependencies?.tailwindcss || '';
|
|
57
|
+
if (v.includes('4.'))
|
|
58
|
+
return 4;
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
return 3;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* [EN] Probes the target project's package.json and CSS entry points to build a full
|
|
65
|
+
* environment state snapshot (Tailwind version, integrations, preflight status).
|
|
66
|
+
* [ES] Sondea el package.json y los puntos de entrada CSS del proyecto objetivo para construir
|
|
67
|
+
* un snapshot completo del estado del entorno (versión Tailwind, integraciones, estado preflight).
|
|
68
|
+
*/
|
|
69
|
+
async function detectEnvironmentState(targetDir) {
|
|
70
|
+
const state = {
|
|
71
|
+
version: 3, usesAstro: false, usesVite: false, usesPostcss: false,
|
|
72
|
+
importsPreflight: false, importsUtilities: false, cssEntrypoint: null,
|
|
73
|
+
};
|
|
74
|
+
try {
|
|
75
|
+
const p = require(path_1.default.join(targetDir, 'package.json'));
|
|
76
|
+
const deps = { ...(p.dependencies || {}), ...(p.devDependencies || {}) };
|
|
77
|
+
if (deps['tailwindcss'])
|
|
78
|
+
state.version = (deps['tailwindcss'].startsWith('^4') || deps['tailwindcss'].startsWith('4')) ? 4 : 3;
|
|
79
|
+
else if (deps['@tailwindcss/vite'] || deps['@tailwindcss/postcss'])
|
|
80
|
+
state.version = 4;
|
|
81
|
+
state.usesAstro = !!deps['@astrojs/tailwind'];
|
|
82
|
+
state.usesVite = !!deps['@tailwindcss/vite'];
|
|
83
|
+
state.usesPostcss = !!deps['@tailwindcss/postcss'];
|
|
84
|
+
}
|
|
85
|
+
catch { }
|
|
86
|
+
const cssFiles = await (0, glob_1.glob)('**/*.{css,scss,sass,less,pcss}', { cwd: targetDir, absolute: true, ignore: ['node_modules/**', 'dist/**', 'public/**'] });
|
|
87
|
+
for (const f of cssFiles) {
|
|
88
|
+
const c = await fs_extra_1.default.readFile(f, 'utf-8');
|
|
89
|
+
if (c.includes('@tailwind') || c.includes('tailwindcss')) {
|
|
90
|
+
state.cssEntrypoint = f;
|
|
91
|
+
if (c.includes('@tailwind base') || c.includes('tailwindcss/preflight') || c.includes('@import "tailwindcss"'))
|
|
92
|
+
state.importsPreflight = true;
|
|
93
|
+
if (c.includes('@tailwind utilities') || c.includes('tailwindcss/utilities') || c.includes('@import "tailwindcss"'))
|
|
94
|
+
state.importsUtilities = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (state.usesAstro) {
|
|
98
|
+
state.importsPreflight = true;
|
|
99
|
+
state.importsUtilities = true;
|
|
100
|
+
}
|
|
101
|
+
return state;
|
|
102
|
+
}
|
|
103
|
+
// ─── HTML Report Generator ────────────────────────────────────────────────────
|
|
104
|
+
/**
|
|
105
|
+
* [EN] Generates the AUM-IC C4I intelligence dashboard as a self-contained HTML file.
|
|
106
|
+
* Includes animated donut chart, class mapping table with pagination, and export tools.
|
|
107
|
+
* [ES] Genera el dashboard de inteligencia AUM-IC C4I como un archivo HTML autónomo.
|
|
108
|
+
* Incluye gráfico donut animado, tabla de mapeo de clases con paginación y herramientas de exportación.
|
|
109
|
+
*/
|
|
110
|
+
function generateReport(mapping, targetDir, isSimulate) {
|
|
111
|
+
const reportPath = path_1.default.join(targetDir, 'aumic-report.html');
|
|
112
|
+
const counts = { atoms: 0, molecules: 0, organisms: 0, ecosystems: 0, galaxies: 0 };
|
|
113
|
+
const categoryMeta = {
|
|
114
|
+
atoms: { border: '#22d3ee', text: '#22d3ee', bg: 'rgba(34,211,238,0.15)', label: '⚛ Átomo' },
|
|
115
|
+
molecules: { border: '#a78bfa', text: '#a78bfa', bg: 'rgba(167,139,250,0.15)', label: '🧬 Molécula' },
|
|
116
|
+
organisms: { border: '#34d399', text: '#34d399', bg: 'rgba(52,211,153,0.15)', label: '🫀 Organismo' },
|
|
117
|
+
ecosystems: { border: '#fb923c', text: '#fb923c', bg: 'rgba(251,146,60,0.15)', label: '🌌 Ecosistema' },
|
|
118
|
+
galaxies: { border: '#facc15', text: '#facc15', bg: 'rgba(250,204,21,0.15)', label: '🪐 Galaxia' },
|
|
119
|
+
};
|
|
120
|
+
let totalOcc = 0, origBytes = 0, aumicBytes = 0;
|
|
121
|
+
const sorted = Array.from(mapping.entries()).sort((a, b) => (b[1].occurrences || 1) - (a[1].occurrences || 1));
|
|
122
|
+
const rows = [];
|
|
123
|
+
for (const [orig, map] of sorted) {
|
|
124
|
+
const cat = map.category || 'molecules';
|
|
125
|
+
const occ = map.occurrences || 1;
|
|
126
|
+
totalOcc += occ;
|
|
127
|
+
origBytes += orig.length * occ;
|
|
128
|
+
aumicBytes += map.aumicClass.length * occ;
|
|
129
|
+
if (counts[cat] !== undefined)
|
|
130
|
+
counts[cat]++;
|
|
131
|
+
const c = categoryMeta[cat] || categoryMeta.molecules;
|
|
132
|
+
rows.push(`<tr data-cat="${cat}"><td class="tw-cell copyable" onclick="copyText(this)">${orig}</td><td class="aumic-cell copyable" onclick="copyText(this)">${map.aumicClass}</td><td class="occ-cell" data-occ="${occ}"><div class="occ-bar" style="width:${Math.min(100, occ * 2)}%;background:${c.text}"></div><span>${occ}</span></td><td><span class="badge" style="border-color:${c.border};color:${c.text};background:${c.bg}">${c.label}</span></td></tr>`);
|
|
133
|
+
}
|
|
134
|
+
const saved = origBytes - aumicBytes;
|
|
135
|
+
const eff = origBytes > 0 ? ((saved / origBytes) * 100).toFixed(1) : '0';
|
|
136
|
+
let grade = 'D', gColor = '#ef4444';
|
|
137
|
+
if (Number(eff) >= 70) {
|
|
138
|
+
grade = 'S';
|
|
139
|
+
gColor = '#facc15';
|
|
140
|
+
}
|
|
141
|
+
else if (Number(eff) >= 50) {
|
|
142
|
+
grade = 'A';
|
|
143
|
+
gColor = '#34d399';
|
|
144
|
+
}
|
|
145
|
+
else if (Number(eff) >= 30) {
|
|
146
|
+
grade = 'B';
|
|
147
|
+
gColor = '#22d3ee';
|
|
148
|
+
}
|
|
149
|
+
else if (Number(eff) >= 15) {
|
|
150
|
+
grade = 'C';
|
|
151
|
+
gColor = '#a78bfa';
|
|
152
|
+
}
|
|
153
|
+
// [EN] Minimal HTML shell — full stylesheet and scripts are inlined for portability.
|
|
154
|
+
// [ES] Shell HTML mínimo — el stylesheet completo y los scripts están inlineados para portabilidad.
|
|
155
|
+
const html = `<!DOCTYPE html><html lang="es"><head><meta charset="UTF-8"><title>AUM-IC · C4I Dashboard</title>
|
|
156
|
+
<style>:root{--bg:#030712;--panel:rgba(15,23,42,.7);--text:#e2e8f0;--muted:#64748b;--border:rgba(51,65,85,.6);--accent:#00e5ff}*{box-sizing:border-box;margin:0;padding:0}body{font-family:system-ui,sans-serif;background:var(--bg);color:var(--text);padding:2rem 3rem}.panel{background:var(--panel);backdrop-filter:blur(12px);padding:1.5rem;border-radius:16px;border:1px solid var(--border);margin-bottom:1.5rem}.metric h3{font-size:1.8rem;font-weight:900;color:#34d399}.table-container{border-radius:12px;border:1px solid var(--border);overflow:hidden}.tw-cell{font-family:monospace;color:#f472b6}.aumic-cell{font-family:monospace;color:#38bdf8;font-weight:600}.badge{font-size:.65rem;padding:4px 10px;border-radius:999px;border:1px solid;font-weight:800}.toolbar{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}.fbtn{background:rgba(0,0,0,.2);border:1px solid var(--border);color:#94a3b8;font-size:.75rem;padding:8px 16px;border-radius:8px;cursor:pointer}.fbtn.active,.fbtn:hover{color:#fff;border-color:var(--accent)}.search{background:rgba(0,0,0,.2);border:1px solid var(--border);color:#fff;font-size:.8rem;padding:8px 16px;border-radius:8px;outline:none;width:200px;margin-left:auto}table{width:100%;border-collapse:collapse;font-size:.8rem}th{background:rgba(0,0,0,.3);color:var(--muted);text-align:left;padding:12px 16px;border-bottom:1px solid var(--border);text-transform:uppercase;font-size:.7rem}td{padding:12px 16px;border-bottom:1px solid rgba(255,255,255,.02)}.occ-cell{display:flex;align-items:center;gap:10px}.occ-bar{height:6px;border-radius:3px;opacity:.8}footer{text-align:center;padding:20px;font-size:.75rem;color:var(--muted);margin-top:2rem}footer a{color:var(--accent);text-decoration:none}</style>
|
|
157
|
+
</head><body>
|
|
158
|
+
<div class="panel"><h1 style="font-size:1.8rem;font-weight:900">⚔️ AUM-IC · Centro de Inteligencia</h1>
|
|
159
|
+
<p style="color:var(--muted);margin-top:.5rem">${isSimulate ? 'MODO DRY-RUN — sin mutación en disco' : 'MUTACIÓN AUM-IC COMPLETADA'} · v${pkgVersion}</p>
|
|
160
|
+
</div>
|
|
161
|
+
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-bottom:1.5rem">
|
|
162
|
+
<div class="panel metric"><h3>🔥 ${(saved / 1024).toFixed(2)} KB</h3><p>Peso estimado salvado</p></div>
|
|
163
|
+
<div class="panel metric"><h3>${eff}%</h3><p>Eficiencia de refactorización</p></div>
|
|
164
|
+
<div class="panel metric" style="font-size:2rem;text-align:center"><span style="color:${gColor};font-weight:900;font-size:3rem">${grade}</span><p style="font-size:.75rem;color:var(--muted)">Ranking AUM-IC</p></div>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="panel">
|
|
167
|
+
<nav class="toolbar">
|
|
168
|
+
<button class="fbtn active" onclick="filter('all',this)">Todos</button>
|
|
169
|
+
<button class="fbtn" onclick="filter('atoms',this)">Átomos (${counts.atoms})</button>
|
|
170
|
+
<button class="fbtn" onclick="filter('molecules',this)">Moléculas (${counts.molecules})</button>
|
|
171
|
+
<button class="fbtn" onclick="filter('organisms',this)">Organismos (${counts.organisms})</button>
|
|
172
|
+
<button class="fbtn" onclick="filter('ecosystems',this)">Ecosistemas (${counts.ecosystems})</button>
|
|
173
|
+
<button class="fbtn" onclick="filter('galaxies',this)">Galaxias (${counts.galaxies})</button>
|
|
174
|
+
<input class="search" type="text" id="q" placeholder="Buscar..." oninput="search(this.value)">
|
|
175
|
+
</nav>
|
|
176
|
+
<div class="table-container"><table><thead><tr><th>Clase Original (Tailwind)</th><th>Clase AUM-IC Transmutada</th><th>Frecuencia</th><th>Nivel</th></tr></thead>
|
|
177
|
+
<tbody id="tbody">${rows.join('')}</tbody></table></div></div>
|
|
178
|
+
<footer>Forged by <a href="https://ingcrea.com" target="_blank">INGENIERÍA CREATIVA Y DESARROLLOS TECNOLÓGICOS S.A.S.</a> | <a href="https://github.com/ingcrea/aumic-tailwind-killer" target="_blank">GitHub</a></footer>
|
|
179
|
+
<script>
|
|
180
|
+
let allRows=[],filteredRows=[],activeCat='all',q='';
|
|
181
|
+
window.onload=()=>{allRows=Array.from(document.querySelectorAll('#tbody tr'));filteredRows=[...allRows];render();};
|
|
182
|
+
function render(){const tb=document.getElementById('tbody');tb.innerHTML='';filteredRows.forEach(r=>tb.appendChild(r));}
|
|
183
|
+
function filter(c,b){document.querySelectorAll('.fbtn').forEach(x=>x.classList.remove('active'));if(b)b.classList.add('active');activeCat=c;apply();}
|
|
184
|
+
function search(v){q=v;apply();}
|
|
185
|
+
function apply(){filteredRows=allRows.filter(r=>{const catOk=activeCat==='all'||r.dataset.cat===activeCat;if(!catOk)return false;if(!q)return true;try{return new RegExp(q,'i').test(r.textContent);}catch{return r.textContent.toLowerCase().includes(q.toLowerCase());}});render();}
|
|
186
|
+
function copyText(el){navigator.clipboard.writeText(el.innerText);}
|
|
187
|
+
</script></body></html>`;
|
|
188
|
+
fs_extra_1.default.writeFileSync(reportPath, html);
|
|
189
|
+
return reportPath;
|
|
190
|
+
}
|
|
191
|
+
// ─── Main Pipeline ────────────────────────────────────────────────────────────
|
|
192
|
+
/**
|
|
193
|
+
* [EN] Main transmutation pipeline entry point. Receives fully resolved options and
|
|
194
|
+
* executes all five phases sequentially, using the worker pool for parallelism.
|
|
195
|
+
* [ES] Punto de entrada principal del pipeline de transmutación. Recibe las opciones
|
|
196
|
+
* completamente resueltas y ejecuta las cinco fases secuencialmente, usando el
|
|
197
|
+
* pool de workers para el paralelismo.
|
|
198
|
+
*/
|
|
199
|
+
async function runTransmutationEcosystem(answers, distDir) {
|
|
200
|
+
const TARGET_DIR = path_1.default.resolve(answers.targetDir);
|
|
201
|
+
const userConcurrency = (answers.concurrency && !isNaN(parseInt(answers.concurrency, 10)))
|
|
202
|
+
? parseInt(answers.concurrency, 10)
|
|
203
|
+
: (os_1.default.cpus().length * 2);
|
|
204
|
+
console.log(picocolors_1.default.gray(`[i] Motores Asíncronos Desplegados: ${userConcurrency} hilos concurrentes.`));
|
|
205
|
+
const startTime = Date.now();
|
|
206
|
+
const logPath = path_1.default.join(TARGET_DIR, 'aumic-audit.log');
|
|
207
|
+
fs_extra_1.default.writeFileSync(logPath, `=== AUM-IC AUDIT LOG ===\nDate: ${new Date().toISOString()}\nVersion: ${pkgVersion}\nMode: ${answers.mode}\nTarget: ${TARGET_DIR}\n\n`, 'utf-8');
|
|
208
|
+
const log = (msg) => fs_extra_1.default.appendFileSync(logPath, `[${new Date().toISOString()}] ${msg}\n`, 'utf-8');
|
|
209
|
+
let spinner = (0, ora_1.default)('').start();
|
|
210
|
+
// ── Clone Mode Pre-flight ──────────────────────────────────────────────────
|
|
211
|
+
let twVersion = 3;
|
|
212
|
+
if (answers.mode === 'clone') {
|
|
213
|
+
spinner.text = `Modo Forense: Infiltrando ${answers.targetUrl}...`;
|
|
214
|
+
await WebCloner_1.WebCloner.cloneWebsite(answers.targetUrl, TARGET_DIR, answers.cloneDepth);
|
|
215
|
+
spinner.succeed(`Extracción completada (${answers.cloneDepth}). Archivos en ${TARGET_DIR}.`);
|
|
216
|
+
const isTw = await WebCloner_1.WebCloner.isTailwindPowered(TARGET_DIR);
|
|
217
|
+
if (!isTw) {
|
|
218
|
+
spinner.warn('La web clonada no usa Tailwind. Abortando.');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
spinner.succeed('Firma Tailwind confirmada. Iniciando transmutación.');
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
twVersion = await detectTailwindVersion(TARGET_DIR);
|
|
225
|
+
}
|
|
226
|
+
// ── Phase 1: File Scan & Extraction ────────────────────────────────────────
|
|
227
|
+
spinner.start('Fase 1: Escaneando y extrayendo utilidades...');
|
|
228
|
+
const globPattern = (answers.mode === 'surgical' && answers.scope) ? answers.scope : '**/*.{astro,tsx,jsx,html,py,rs,php,go,erb,svelte,vue}';
|
|
229
|
+
let files = [];
|
|
230
|
+
if (!answers.scope) {
|
|
231
|
+
try {
|
|
232
|
+
// [EN] Infrared Scanner: uses `git ls-files` as a fast O(n) file enumeration path.
|
|
233
|
+
// [ES] Escáner Infrarrojo: usa `git ls-files` como ruta rápida O(n) de enumeración de archivos.
|
|
234
|
+
const r = (0, child_process_1.spawnSync)('git', ['ls-files', '*.astro', '*.tsx', '*.jsx', '*.html', '*.py', '*.rs', '*.php', '*.go', '*.erb', '*.svelte', '*.vue'], { cwd: TARGET_DIR, stdio: 'pipe' });
|
|
235
|
+
files = r.stdout.toString().split('\n').map(f => path_1.default.join(TARGET_DIR, f.trim())).filter(f => f.length > TARGET_DIR.length && fs_extra_1.default.existsSync(f));
|
|
236
|
+
}
|
|
237
|
+
catch { }
|
|
238
|
+
}
|
|
239
|
+
if (files.length === 0) {
|
|
240
|
+
files = await (0, glob_1.glob)(globPattern, { cwd: TARGET_DIR, absolute: true, ignore: ['node_modules/**', 'dist/**', '.git/**', 'target/**', '__pycache__/**', 'venv/**'] });
|
|
241
|
+
}
|
|
242
|
+
log(`Archivos escaneados: ${files.length}`);
|
|
243
|
+
// [EN] Pre-Flight Check: validate write permissions before committing to mutation.
|
|
244
|
+
// [ES] Pre-Flight Check: validar permisos de escritura antes de comprometerse con la mutación.
|
|
245
|
+
spinner.start('Pre-Flight Check de permisos NTFS/POSIX...');
|
|
246
|
+
const locked = [];
|
|
247
|
+
await (0, concurrency_1.runConcurrent)(files, 50, async (f) => { try {
|
|
248
|
+
await fs_extra_1.default.access(f, fs_extra_1.default.constants.W_OK);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
locked.push(f);
|
|
252
|
+
} });
|
|
253
|
+
if (locked.length > 0) {
|
|
254
|
+
spinner.fail(picocolors_1.default.red(`[X] Pre-Flight abortó: ${locked.length} archivo(s) sin permiso de escritura.`));
|
|
255
|
+
locked.slice(0, 5).forEach(f => console.log(picocolors_1.default.red(` - ${f}`)));
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
spinner.succeed('Pre-Flight superado. Permisos validados.');
|
|
259
|
+
const piscinaPool = new piscina_1.default({ filename: path_1.default.join(distDir, 'worker.js') });
|
|
260
|
+
const globalExtracted = new Map();
|
|
261
|
+
const vramCache = new Map();
|
|
262
|
+
spinner.succeed(`${files.length} archivos listos para escaneo.`);
|
|
263
|
+
const scanBar = new cli_progress_1.default.SingleBar({ format: picocolors_1.default.cyan('Fase 1 [Extracción] {bar}') + ' {percentage}% | ETA: {eta}s | {value}/{total}', barCompleteChar: '█', barIncompleteChar: '░', hideCursor: true });
|
|
264
|
+
scanBar.start(files.length, 0);
|
|
265
|
+
await (0, concurrency_1.runConcurrent)(files, userConcurrency, async (file) => {
|
|
266
|
+
const content = await fs_extra_1.default.readFile(file, 'utf-8');
|
|
267
|
+
vramCache.set(file, content);
|
|
268
|
+
if (!constants_1.TAILWIND_SNIPER_REGEX.test(content)) {
|
|
269
|
+
scanBar.increment();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const fileClass = (0, classifier_1.classifyComponent)(file);
|
|
273
|
+
try {
|
|
274
|
+
const entries = await piscinaPool.run({ mode: 'scan', content, filePath: file });
|
|
275
|
+
for (const [cls, count] of entries) {
|
|
276
|
+
const ex = globalExtracted.get(cls);
|
|
277
|
+
if (ex)
|
|
278
|
+
ex.occurrences += count;
|
|
279
|
+
else
|
|
280
|
+
globalExtracted.set(cls, { ...fileClass, occurrences: count });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
log(`[ERROR F1] ${e.message}`);
|
|
285
|
+
}
|
|
286
|
+
scanBar.increment();
|
|
287
|
+
});
|
|
288
|
+
scanBar.stop();
|
|
289
|
+
if (globalExtracted.size === 0) {
|
|
290
|
+
spinner.warn('No se encontraron utilidades Tailwind.');
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
spinner.succeed(`${globalExtracted.size} bloques únicos extraídos.`);
|
|
294
|
+
// ── Phase 2: JIT Validator ─────────────────────────────────────────────────
|
|
295
|
+
spinner.start('Fase 2: JIT Validator — separando clases nativas de custom...');
|
|
296
|
+
const allTokens = new Set();
|
|
297
|
+
for (const orig of globalExtracted.keys())
|
|
298
|
+
orig.split(' ').forEach(t => { if (t.trim() && !t.includes('aumic-'))
|
|
299
|
+
allTokens.add(t.trim()); });
|
|
300
|
+
const testHtml = Array.from(allTokens).map(t => `<div class="${t}"></div>`).join('\n');
|
|
301
|
+
let userConfig = {};
|
|
302
|
+
const configPath = ['tailwind.config.js', 'tailwind.config.mjs'].map(f => require('path').resolve(TARGET_DIR, f)).find(p => require('fs').existsSync(p)) || null;
|
|
303
|
+
if (configPath) {
|
|
304
|
+
try {
|
|
305
|
+
const di = new Function('mp', 'return import(mp)');
|
|
306
|
+
userConfig = (await di(require('url').pathToFileURL(configPath).href)).default || require(configPath);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
try {
|
|
310
|
+
userConfig = require(configPath);
|
|
311
|
+
}
|
|
312
|
+
catch { }
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const twPlugin = require('tailwindcss')({ content: [{ raw: testHtml, extension: 'html' }], corePlugins: { preflight: false }, theme: userConfig.theme || {} });
|
|
316
|
+
const jitTest = await (0, postcss_1.default)([twPlugin]).process('@tailwind utilities;', { from: undefined });
|
|
317
|
+
const validTwClasses = new Set();
|
|
318
|
+
postcss_1.default.parse(jitTest.css).walkRules((r) => {
|
|
319
|
+
for (const t of Array.from(allTokens)) {
|
|
320
|
+
if (r.selector.includes('.' + (0, hash_1.escapeCssSelector)(t)))
|
|
321
|
+
validTwClasses.add(t);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
spinner.succeed(`JIT Validator: ${validTwClasses.size} clases nativas reconocidas.`);
|
|
325
|
+
// ── Class Mapping Generation ───────────────────────────────────────────────
|
|
326
|
+
const classMapping = new Map();
|
|
327
|
+
if (answers.useAI && (answers.apiKey || answers.aiProvider === 'ollama')) {
|
|
328
|
+
const memPath = path_1.default.join(TARGET_DIR, '.aumic-memory.json');
|
|
329
|
+
let mem = {};
|
|
330
|
+
if (fs_extra_1.default.existsSync(memPath)) {
|
|
331
|
+
try {
|
|
332
|
+
mem = await fs_extra_1.default.readJson(memPath);
|
|
333
|
+
}
|
|
334
|
+
catch { }
|
|
335
|
+
}
|
|
336
|
+
const missing = Array.from(globalExtracted.keys()).filter(u => !mem[u]);
|
|
337
|
+
let newMap = {};
|
|
338
|
+
if (missing.length > 0) {
|
|
339
|
+
spinner.start(picocolors_1.default.magenta(`Titanium Cache Miss: conectando con ${answers.aiProvider.toUpperCase()} para ${missing.length} clases...`));
|
|
340
|
+
const ai = new AiEngine_1.AIEngine(answers.aiProvider, answers.apiKey || 'ollama-local');
|
|
341
|
+
const rc = fs_extra_1.default.existsSync(path_1.default.join(TARGET_DIR, '.aumicrc.json')) ? (await fs_extra_1.default.readJson(path_1.default.join(TARGET_DIR, '.aumicrc.json'))).rules || '' : '';
|
|
342
|
+
newMap = (await ai.generateSemanticNames({ utilities: missing, customRules: rc })).mapping;
|
|
343
|
+
spinner.succeed(picocolors_1.default.magenta('Bautizo semántico completado.'));
|
|
344
|
+
}
|
|
345
|
+
const final = { ...mem, ...newMap };
|
|
346
|
+
await fs_extra_1.default.writeJson(memPath, final, { spaces: 2 });
|
|
347
|
+
for (const [orig, { category, component, occurrences }] of globalExtracted) {
|
|
348
|
+
const aumicClass = final[orig] || `aumic-ai-${component}-${(0, hash_1.getHash)(orig)}`;
|
|
349
|
+
const fullArr = orig.split(' ');
|
|
350
|
+
const twArr = fullArr.filter(c => validTwClasses.has(c));
|
|
351
|
+
const custArr = fullArr.filter(c => !validTwClasses.has(c));
|
|
352
|
+
const rep = custArr.length > 0 ? (twArr.length > 0 ? aumicClass + ' ' + custArr.join(' ') : custArr.join(' ')) : aumicClass;
|
|
353
|
+
if (twArr.length > 0)
|
|
354
|
+
classMapping.set(orig, { original: orig, array: fullArr, tailwindOnlyArray: twArr, customArray: custArr, aumicClass, replacementString: rep, category, component, occurrences });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
spinner.start('Generando hashes deterministas AUM-IC...');
|
|
359
|
+
for (const [orig, { category, component, occurrences }] of globalExtracted) {
|
|
360
|
+
const prefix = constants_1.LEVEL_PREFIX[category] || 'molecule';
|
|
361
|
+
const fullArr = orig.split(' ');
|
|
362
|
+
const twArr = fullArr.filter(c => validTwClasses.has(c));
|
|
363
|
+
const custArr = fullArr.filter(c => !validTwClasses.has(c));
|
|
364
|
+
const aumicClass = `aumic-${prefix}-${component}-${(0, hash_1.getHash)(orig)}`;
|
|
365
|
+
const rep = custArr.length > 0 ? (twArr.length > 0 ? aumicClass + ' ' + custArr.join(' ') : custArr.join(' ')) : aumicClass;
|
|
366
|
+
if (twArr.length > 0)
|
|
367
|
+
classMapping.set(orig, { original: orig, array: fullArr, tailwindOnlyArray: twArr, customArray: custArr, aumicClass, replacementString: rep, category, component, occurrences });
|
|
368
|
+
}
|
|
369
|
+
spinner.succeed('Hashes deterministas generados.');
|
|
370
|
+
}
|
|
371
|
+
// ── Simulate Mode Early Exit ───────────────────────────────────────────────
|
|
372
|
+
if (answers.simulate) {
|
|
373
|
+
spinner.start('Simulador activo: generando reporte de impacto...');
|
|
374
|
+
const rp = generateReport(classMapping, TARGET_DIR, true);
|
|
375
|
+
spinner.succeed(`Simulación finalizada. Reporte en: ${rp}`);
|
|
376
|
+
console.log(picocolors_1.default.green(picocolors_1.default.bold('\n[✔] DRY-RUN COMPLETADO. No se mutaron archivos.\n')));
|
|
377
|
+
const { open } = await inquirer_1.default.prompt([{ type: 'confirm', name: 'open', message: '¿Abrir el reporte en el navegador?', default: true }]);
|
|
378
|
+
if (open) {
|
|
379
|
+
const pl = os_1.default.platform();
|
|
380
|
+
if (pl === 'win32')
|
|
381
|
+
(0, child_process_1.spawn)('explorer', [rp]);
|
|
382
|
+
else if (pl === 'darwin')
|
|
383
|
+
(0, child_process_1.spawn)('open', [rp]);
|
|
384
|
+
else
|
|
385
|
+
(0, child_process_1.spawn)('xdg-open', [rp]);
|
|
386
|
+
}
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
// ── Phase 3: Source Mutation ───────────────────────────────────────────────
|
|
390
|
+
const serial = {};
|
|
391
|
+
for (const [k, v] of classMapping.entries())
|
|
392
|
+
serial[k] = v;
|
|
393
|
+
spinner.succeed(`Iniciando mutación concurrente en ${files.length} archivos...`);
|
|
394
|
+
const mutBar = new cli_progress_1.default.SingleBar({ format: picocolors_1.default.red('Fase 3 [Mutación] {bar}') + ' {percentage}% | ETA: {eta}s | {value}/{total}', barCompleteChar: '█', barIncompleteChar: '░', hideCursor: true });
|
|
395
|
+
mutBar.start(files.length, 0);
|
|
396
|
+
let modifiedFiles = 0;
|
|
397
|
+
await (0, concurrency_1.runConcurrent)(files, userConcurrency, async (file) => {
|
|
398
|
+
const content = vramCache.get(file) || await fs_extra_1.default.readFile(file, 'utf-8');
|
|
399
|
+
vramCache.delete(file); // [EN] Anti-OOM GC: release after use. [ES] GC anti-OOM: liberar tras el uso.
|
|
400
|
+
if (!constants_1.TAILWIND_SNIPER_REGEX.test(content)) {
|
|
401
|
+
mutBar.increment();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
try {
|
|
405
|
+
const newCode = await piscinaPool.run({ mode: 'mutate', content, filePath: file, map: serial });
|
|
406
|
+
if (newCode !== content) {
|
|
407
|
+
await fs_extra_1.default.writeFile(file, newCode, 'utf-8');
|
|
408
|
+
modifiedFiles++;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
catch (e) {
|
|
412
|
+
log(`[ERROR F3] ${e.message}`);
|
|
413
|
+
}
|
|
414
|
+
mutBar.increment();
|
|
415
|
+
});
|
|
416
|
+
mutBar.stop();
|
|
417
|
+
log(`[F3] Mutados: ${modifiedFiles}/${files.length}`);
|
|
418
|
+
spinner.succeed(`${modifiedFiles} archivos fuente mutados estructuralmente.`);
|
|
419
|
+
// ── Phase 4: CSS Generation ────────────────────────────────────────────────
|
|
420
|
+
spinner.start(`Fase 4: L1 Cache DuckDB + JIT dinámico v${twVersion}...`);
|
|
421
|
+
const utilityToAumic = new Map();
|
|
422
|
+
for (const [, map] of classMapping) {
|
|
423
|
+
for (const util of map.tailwindOnlyArray) {
|
|
424
|
+
const esc = '.' + (0, hash_1.escapeCssSelector)(util);
|
|
425
|
+
const list = utilityToAumic.get(esc) || [];
|
|
426
|
+
list.push({ aumicClass: map.aumicClass, category: map.category });
|
|
427
|
+
utilityToAumic.set(esc, list);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const dbPath = path_1.default.join(distDir, '../aumic-lexicon.duckdb');
|
|
431
|
+
const allTwClasses = Array.from(new Set(Array.from(classMapping.values()).flatMap(m => m.tailwindOnlyArray)));
|
|
432
|
+
const { css: l1Css, unresolved } = await (0, DuckDbCache_1.queryL1Cache)(allTwClasses, twVersion, dbPath);
|
|
433
|
+
const virtualHtml = Array.from(unresolved).map(c => `<div class="${c}"></div>`).join('\n');
|
|
434
|
+
const projectTwPath = path_1.default.join(TARGET_DIR, 'node_modules', 'tailwindcss');
|
|
435
|
+
const twFn = fs_extra_1.default.existsSync(projectTwPath) ? require(projectTwPath) : require('tailwindcss');
|
|
436
|
+
await piscinaPool.destroy();
|
|
437
|
+
const jit = await (0, postcss_1.default)([twFn({ content: [{ raw: virtualHtml, extension: 'html' }], corePlugins: { preflight: false }, theme: userConfig.theme || {} })]).process('@tailwind utilities;', { from: undefined });
|
|
438
|
+
const envState = await detectEnvironmentState(TARGET_DIR);
|
|
439
|
+
const categoryRoots = { atoms: postcss_1.default.root(), molecules: postcss_1.default.root(), organisms: postcss_1.default.root(), ecosystems: postcss_1.default.root(), galaxies: postcss_1.default.root() };
|
|
440
|
+
const globalRoot = postcss_1.default.root();
|
|
441
|
+
if (envState.importsPreflight) {
|
|
442
|
+
try {
|
|
443
|
+
const pf = await (0, postcss_1.default)([twFn({ content: [{ raw: '<div class="a"></div>', extension: 'html' }], theme: userConfig.theme || {} })]).process('@tailwind base;', { from: undefined });
|
|
444
|
+
globalRoot.prepend(postcss_1.default.parse(pf.css));
|
|
445
|
+
}
|
|
446
|
+
catch { }
|
|
447
|
+
}
|
|
448
|
+
postcss_1.default.parse(l1Css + '\n' + jit.css).walkRules((rule) => {
|
|
449
|
+
for (const [esc, targets] of utilityToAumic) {
|
|
450
|
+
if (rule.selector.includes(esc)) {
|
|
451
|
+
for (const target of targets) {
|
|
452
|
+
const cloned = rule.clone();
|
|
453
|
+
cloned.selector = cloned.selector.replace(esc, `.${target.aumicClass}`);
|
|
454
|
+
const dest = answers.outputMode === 'aumic' ? categoryRoots[target.category] : globalRoot;
|
|
455
|
+
if (rule.parent?.type === 'atrule') {
|
|
456
|
+
const pa = rule.parent;
|
|
457
|
+
const ar = postcss_1.default.atRule({ name: pa.name, params: pa.params });
|
|
458
|
+
ar.append(cloned);
|
|
459
|
+
dest.append(ar);
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
dest.append(cloned);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
// [EN] Write CSS output according to selected architecture (AUM-IC modular or global).
|
|
469
|
+
// [ES] Escribir la salida CSS según la arquitectura seleccionada (modular AUM-IC o global).
|
|
470
|
+
if (answers.outputMode === 'global') {
|
|
471
|
+
const outPath = path_1.default.join(TARGET_DIR, 'src', 'styles');
|
|
472
|
+
fs_extra_1.default.ensureDirSync(outPath);
|
|
473
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outPath, 'aumic-styles.css'), globalRoot.toString(), 'utf-8');
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
for (const [cat, root] of Object.entries(categoryRoots)) {
|
|
477
|
+
if (root.nodes && root.nodes.length > 0) {
|
|
478
|
+
const dir = path_1.default.join(TARGET_DIR, 'src', 'styles', cat);
|
|
479
|
+
await fs_extra_1.default.ensureDir(dir);
|
|
480
|
+
await fs_extra_1.default.writeFile(path_1.default.join(dir, `_${cat}.scss`), root.toString(), 'utf-8');
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
spinner.succeed('CSS fusionado matemáticamente.');
|
|
485
|
+
// [EN] Write the reverse mapping lock file for future rollback operations.
|
|
486
|
+
// [ES] Escribir el archivo lock de mapeo inverso para futuras operaciones de rollback.
|
|
487
|
+
const lockData = {};
|
|
488
|
+
for (const [, m] of classMapping)
|
|
489
|
+
lockData[m.aumicClass] = m.original;
|
|
490
|
+
await fs_extra_1.default.writeJson(path_1.default.join(TARGET_DIR, 'aumic-lock.json'), lockData, { spaces: 2 });
|
|
491
|
+
console.log(picocolors_1.default.blue('\n[i] Mapa reverso generado en aumic-lock.json'));
|
|
492
|
+
// ── Phase 5: Tailwind Eradication ─────────────────────────────────────────
|
|
493
|
+
if (answers.mode === 'local' && answers.eradicate !== false) {
|
|
494
|
+
spinner.start(picocolors_1.default.red('Fase 5: Erradicando dependencias de Tailwind...'));
|
|
495
|
+
try {
|
|
496
|
+
const pkgPath = path_1.default.join(TARGET_DIR, 'package.json');
|
|
497
|
+
if (fs_extra_1.default.existsSync(pkgPath))
|
|
498
|
+
fs_extra_1.default.copyFileSync(pkgPath, `${pkgPath}.aumic-bak`);
|
|
499
|
+
for (const conf of ['tailwind.config.js', 'tailwind.config.ts', 'tailwind.config.cjs', 'tailwind.config.mjs', 'tailwind.js']) {
|
|
500
|
+
const p = path_1.default.join(TARGET_DIR, conf);
|
|
501
|
+
if (fs_extra_1.default.existsSync(p))
|
|
502
|
+
fs_extra_1.default.renameSync(p, `${p}.aumic-bak`);
|
|
503
|
+
}
|
|
504
|
+
const integrations = [
|
|
505
|
+
{ file: 'astro.config.mjs', r1: /import\s+tailwind\s+from\s+['"]@astrojs\/tailwind['"];?\n?/, r2: /tailwind\(\)\s*,?/ },
|
|
506
|
+
{ file: 'astro.config.ts', r1: /import\s+tailwind\s+from\s+['"]@astrojs\/tailwind['"];?\n?/, r2: /tailwind\(\)\s*,?/ },
|
|
507
|
+
{ file: 'vite.config.js', r1: /import\s+tailwindcss\s+from\s+['"]@tailwindcss\/vite['"];?\n?/, r2: /tailwindcss\(\)\s*,?/ },
|
|
508
|
+
{ file: 'vite.config.ts', r1: /import\s+tailwindcss\s+from\s+['"]@tailwindcss\/vite['"];?\n?/, r2: /tailwindcss\(\)\s*,?/ },
|
|
509
|
+
];
|
|
510
|
+
for (const intg of integrations) {
|
|
511
|
+
const ip = path_1.default.join(TARGET_DIR, intg.file);
|
|
512
|
+
if (fs_extra_1.default.existsSync(ip)) {
|
|
513
|
+
let c = fs_extra_1.default.readFileSync(ip, 'utf8');
|
|
514
|
+
c = c.replace(intg.r1, '').replace(intg.r2, '');
|
|
515
|
+
fs_extra_1.default.writeFileSync(ip, c, 'utf8');
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
const pkg = require(path_1.default.join(TARGET_DIR, 'package.json'));
|
|
520
|
+
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
521
|
+
const targets = ['tailwindcss', '@tailwindcss/vite', '@tailwindcss/postcss', '@tailwindcss/cli', '@astrojs/tailwind'];
|
|
522
|
+
const toRemove = targets.filter(t => allDeps[t]);
|
|
523
|
+
if (toRemove.length > 0) {
|
|
524
|
+
// [EN] Zero-Trust spawn: arguments passed as array, no shell expansion.
|
|
525
|
+
// [ES] Spawn Zero-Trust: argumentos pasados como array, sin expansión de shell.
|
|
526
|
+
require('child_process').spawnSync(os_1.default.platform() === 'win32' ? 'npm.cmd' : 'npm', ['uninstall', ...toRemove], { cwd: TARGET_DIR, stdio: 'ignore' });
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch { }
|
|
530
|
+
spinner.succeed(picocolors_1.default.green('Tailwind purgado. Configuraciones respaldadas en .aumic-bak.'));
|
|
531
|
+
}
|
|
532
|
+
catch {
|
|
533
|
+
spinner.warn('Fallo menor en la erradicación.');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
537
|
+
log(`[FIN] Completado en ${duration}s.`);
|
|
538
|
+
console.log(picocolors_1.default.green(picocolors_1.default.bold(`\n[✔] PROYECTO TRANSMUTADO AL ESTÁNDAR ${aumicLink}. (v${pkgVersion})\n`)));
|
|
539
|
+
spinner.start('Generando reporte post-transmutación...');
|
|
540
|
+
const rp = generateReport(classMapping, TARGET_DIR, false);
|
|
541
|
+
spinner.succeed(`Reporte post-mutación: ${rp}`);
|
|
542
|
+
const { open } = await inquirer_1.default.prompt([{ type: 'confirm', name: 'open', message: '¿Abrir el reporte en el navegador?', default: true }]);
|
|
543
|
+
if (open) {
|
|
544
|
+
const pl = os_1.default.platform();
|
|
545
|
+
if (pl === 'win32')
|
|
546
|
+
(0, child_process_1.spawn)('explorer', [rp]);
|
|
547
|
+
else if (pl === 'darwin')
|
|
548
|
+
(0, child_process_1.spawn)('open', [rp]);
|
|
549
|
+
else
|
|
550
|
+
(0, child_process_1.spawn)('xdg-open', [rp]);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runRestoreEcosystem = exports.runTransmutationEcosystem = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* [EN] Transmutation Ecosystem: orchestrates the main Tailwind→AUM-IC pipeline.
|
|
6
|
+
* Coordinates all phases: environment detection, file scanning (Phase 1),
|
|
7
|
+
* hash generation or AI semantic naming, source mutation (Phase 3),
|
|
8
|
+
* JIT CSS compilation (Phase 4), and optional Tailwind eradication (Phase 5).
|
|
9
|
+
* [ES] Ecosistema de Transmutación: orquesta el pipeline principal Tailwind→AUM-IC.
|
|
10
|
+
* Coordina todas las fases: detección de entorno, escaneo de archivos (Fase 1),
|
|
11
|
+
* generación de hashes o nombrado semántico IA, mutación de fuentes (Fase 3),
|
|
12
|
+
* compilación CSS JIT (Fase 4) y erradicación opcional de Tailwind (Fase 5).
|
|
13
|
+
*/
|
|
14
|
+
var TransmutationEcosystem_1 = require("./TransmutationEcosystem");
|
|
15
|
+
Object.defineProperty(exports, "runTransmutationEcosystem", { enumerable: true, get: function () { return TransmutationEcosystem_1.runTransmutationEcosystem; } });
|
|
16
|
+
var RestoreEcosystem_1 = require("./RestoreEcosystem");
|
|
17
|
+
Object.defineProperty(exports, "runRestoreEcosystem", { enumerable: true, get: function () { return RestoreEcosystem_1.runRestoreEcosystem; } });
|