@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
package/README.es.md
CHANGED
|
@@ -380,3 +380,15 @@ Para organizaciones con monorepos de gran escala, **INGENIERÍA CREATIVA Y DESAR
|
|
|
380
380
|
---
|
|
381
381
|
|
|
382
382
|
> Desarrollado bajo la estándar tecnológica de **INGENIERÍA CREATIVA Y DESARROLLOS TECNOLÓGICOS S.A.S.** Excelencia, Determinismo y Zero-Trust.
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
### 🛡️ Seguridad Zero-Trust y Arquitectura AUM-IC (v4.1.6)
|
|
386
|
+
A partir de la versión 4.1.5, el compilador AUM-IC Tailwind Killer ha sido reescrito desde cero utilizando nuestra propia **Arquitectura Cósmica AUM-IC (Átomos a Galaxias)**.
|
|
387
|
+
- **Desintegración del Monolito:** El núcleo ha sido purificado en 6 capas de abstracción (Átomos, Moléculas, Células, Organismos, Ecosistemas y Galaxias), promoviendo mantenibilidad y separación de responsabilidades a niveles fractales.
|
|
388
|
+
- **Modelo de Ejecución Zero-Trust:** Hemos erradicado TODAS las instancias de child_process.exec y execSync. Ahora, toda ejecución nativa opera estrictamente bajo spawn/spawnSync puro, pasando los argumentos como arreglos inmutables y deshabilitando intérpretes de shell. Esto cierra definitivamente cualquier vector de Command Injection (OWASP A03:2021) en la herramienta. AUM-IC es intrínsecamente seguro por diseño.
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
### 🛡️ Seguridad Zero-Trust y Arquitectura AUM-IC (v4.1.6)
|
|
392
|
+
A partir de la versión 4.1.5, el compilador AUM-IC Tailwind Killer ha sido reescrito desde cero utilizando nuestra propia **Arquitectura Cósmica AUM-IC (Átomos a Galaxias)**.
|
|
393
|
+
- **Desintegración del Monolito:** El núcleo ha sido purificado en 6 capas de abstracción (Átomos, Moléculas, Células, Organismos, Ecosistemas y Galaxias), promoviendo mantenibilidad y separación de responsabilidades a niveles fractales.
|
|
394
|
+
- **Modelo de Ejecución Zero-Trust:** Hemos erradicado TODAS las instancias de child_process.exec y execSync. Ahora, toda ejecución nativa opera estrictamente bajo spawn/spawnSync puro, pasando los argumentos como arreglos inmutables y deshabilitando intérpretes de shell. Esto cierra definitivamente cualquier vector de Command Injection (OWASP A03:2021) en la herramienta. AUM-IC es intrínsecamente seguro por diseño.
|
package/README.md
CHANGED
|
@@ -422,3 +422,15 @@ For organizations with large-scale monorepos, **INGENIERÍA CREATIVA Y DESARROLL
|
|
|
422
422
|
---
|
|
423
423
|
|
|
424
424
|
> Developed under the technological standard of **INGENIERÍA CREATIVA Y DESARROLLOS TECNOLÓGICOS S.A.S.** Excellence, Determinism and Zero-Trust.
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
### 🛡️ Seguridad Zero-Trust y Arquitectura AUM-IC (v4.1.6)
|
|
428
|
+
A partir de la versión 4.1.5, el compilador AUM-IC Tailwind Killer ha sido reescrito desde cero utilizando nuestra propia **Arquitectura Cósmica AUM-IC (Átomos a Galaxias)**.
|
|
429
|
+
- **Desintegración del Monolito:** El núcleo ha sido purificado en 6 capas de abstracción (Átomos, Moléculas, Células, Organismos, Ecosistemas y Galaxias), promoviendo mantenibilidad y separación de responsabilidades a niveles fractales.
|
|
430
|
+
- **Modelo de Ejecución Zero-Trust:** Hemos erradicado TODAS las instancias de child_process.exec y execSync. Ahora, toda ejecución nativa opera estrictamente bajo spawn/spawnSync puro, pasando los argumentos como arreglos inmutables y deshabilitando intérpretes de shell. Esto cierra definitivamente cualquier vector de Command Injection (OWASP A03:2021) en la herramienta. AUM-IC es intrínsecamente seguro por diseño.
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
### 🛡️ Seguridad Zero-Trust y Arquitectura AUM-IC (v4.1.6)
|
|
434
|
+
A partir de la versión 4.1.5, el compilador AUM-IC Tailwind Killer ha sido reescrito desde cero utilizando nuestra propia **Arquitectura Cósmica AUM-IC (Átomos a Galaxias)**.
|
|
435
|
+
- **Desintegración del Monolito:** El núcleo ha sido purificado en 6 capas de abstracción (Átomos, Moléculas, Células, Organismos, Ecosistemas y Galaxias), promoviendo mantenibilidad y separación de responsabilidades a niveles fractales.
|
|
436
|
+
- **Modelo de Ejecución Zero-Trust:** Hemos erradicado TODAS las instancias de child_process.exec y execSync. Ahora, toda ejecución nativa opera estrictamente bajo spawn/spawnSync puro, pasando los argumentos como arreglos inmutables y deshabilitando intérpretes de shell. Esto cierra definitivamente cualquier vector de Command Injection (OWASP A03:2021) en la herramienta. AUM-IC es intrínsecamente seguro por diseño.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* [EN] Immutable constants that form the AUM-IC transmutation vocabulary.
|
|
4
|
+
* [ES] Constantes inmutables que forman el vocabulario de transmutación AUM-IC.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.LEVEL_PREFIX = exports.COMPONENT_ALIASES = exports.TAILWIND_SNIPER_REGEX = void 0;
|
|
8
|
+
/** [EN] O(n) pre-filter: quickly confirms Tailwind presence before invoking the Babel AST pipeline. [ES] Pre-filtro O(n): confirma rápidamente la presencia de Tailwind antes de invocar el pipeline AST Babel. */
|
|
9
|
+
exports.TAILWIND_SNIPER_REGEX = /(class(Name)?=|className:|\b(sm:|md:|lg:|xl:|2xl:|hover:|focus:|active:|disabled:|dark:|flex\b|grid\b|block\b|hidden\b|absolute\b|relative\b|bg-[a-z]+-\d{1,3}|text-[a-z]+-\d{1,3}|p[xytrbl]?-\d|m[xytrbl]?-\d|w-\d|h-\d|gap-\d|border|rounded|shadow|z-\d0|opacity-\d{2}|leading-|tracking-)|@apply|@tailwind)/;
|
|
10
|
+
/** [EN] Maps component file names to AUM-IC abbreviated identifiers for class generation. [ES] Mapea nombres de archivo de componentes a identificadores abreviados AUM-IC para la generación de clases. */
|
|
11
|
+
exports.COMPONENT_ALIASES = {
|
|
12
|
+
button: 'btn', icon: 'icon', input: 'input', badge: 'badge',
|
|
13
|
+
link: 'link', label: 'lbl', card: 'card', form: 'form',
|
|
14
|
+
dropdown: 'drop', menu: 'menu', list: 'list', modal: 'modal',
|
|
15
|
+
header: 'header', footer: 'footer', sidebar: 'sidebar', hero: 'hero',
|
|
16
|
+
table: 'table', nav: 'nav', main: 'main', section: 'section',
|
|
17
|
+
article: 'article', page: 'page', layout: 'layout', index: 'page',
|
|
18
|
+
pricing: 'pricing', trust: 'trust', features: 'features', ecosystem: 'eco',
|
|
19
|
+
teaser: 'teaser', banner: 'banner', toast: 'toast', chip: 'chip',
|
|
20
|
+
avatar: 'avatar', tag: 'tag',
|
|
21
|
+
};
|
|
22
|
+
/** [EN] Maps AUM-IC structural categories to their class name prefixes. [ES] Mapea categorías estructurales AUM-IC a sus prefijos de nombre de clase. */
|
|
23
|
+
exports.LEVEL_PREFIX = {
|
|
24
|
+
atoms: 'atom', molecules: 'molecule', organisms: 'organism',
|
|
25
|
+
ecosystems: 'ecosystem', galaxies: 'galaxy',
|
|
26
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
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.getHash = getHash;
|
|
7
|
+
exports.escapeCssSelector = escapeCssSelector;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
/**
|
|
10
|
+
* [EN] Deterministic 6-char hex hash for reproducible AUM-IC class identifiers.
|
|
11
|
+
* [ES] Hash hex determinista de 6 chars para identificadores de clase AUM-IC reproducibles.
|
|
12
|
+
*/
|
|
13
|
+
function getHash(str) {
|
|
14
|
+
return crypto_1.default.createHash('shake256', { outputLength: 3 }).update(str).digest('hex');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* [EN] Escapes a string for safe use as a CSS class selector.
|
|
18
|
+
* [ES] Escapa un string para uso seguro como selector de clase CSS.
|
|
19
|
+
*/
|
|
20
|
+
function escapeCssSelector(className) {
|
|
21
|
+
return className.replace(/[^a-zA-Z0-9_-]/g, '\\$&');
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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.classifyComponent = classifyComponent;
|
|
7
|
+
/**
|
|
8
|
+
* [EN] Component classifier: maps a file name to its AUM-IC structural tier.
|
|
9
|
+
* [ES] Clasificador de componentes: mapea un nombre de archivo a su nivel estructural AUM-IC.
|
|
10
|
+
*/
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const constants_1 = require("../1_atoms/constants");
|
|
13
|
+
/** [EN] Classifies a file into its AUM-IC tier using alias lookup then regex patterns. [ES] Clasifica un archivo en su nivel AUM-IC usando búsqueda de alias y luego patrones regex. */
|
|
14
|
+
function classifyComponent(fileName) {
|
|
15
|
+
const name = path_1.default.basename(fileName, path_1.default.extname(fileName)).toLowerCase();
|
|
16
|
+
if (constants_1.COMPONENT_ALIASES[name]) {
|
|
17
|
+
const comp = constants_1.COMPONENT_ALIASES[name];
|
|
18
|
+
if (/(button|icon|input|badge|link|label)/.test(name))
|
|
19
|
+
return { category: 'atoms', component: comp };
|
|
20
|
+
if (/(card|form|dropdown|menu|list|modal)/.test(name))
|
|
21
|
+
return { category: 'molecules', component: comp };
|
|
22
|
+
if (/(header|footer|sidebar|hero|table|nav)/.test(name))
|
|
23
|
+
return { category: 'organisms', component: comp };
|
|
24
|
+
return { category: 'ecosystems', component: comp };
|
|
25
|
+
}
|
|
26
|
+
const comp = name.replace(/[^a-z0-9]/g, '').slice(0, 8) || 'comp';
|
|
27
|
+
if (/(button|btn|icon|input|badge|link|label|chip|tag|avatar)/.test(name))
|
|
28
|
+
return { category: 'atoms', component: comp };
|
|
29
|
+
if (/(card|form|dropdown|drop|menu|list|modal|toast|banner)/.test(name))
|
|
30
|
+
return { category: 'molecules', component: comp };
|
|
31
|
+
if (/(header|footer|sidebar|hero|table|nav|pricing|trust|features|teaser|rmm|cta)/.test(name))
|
|
32
|
+
return { category: 'organisms', component: comp };
|
|
33
|
+
if (/(main|section|article|page|layout|index)/.test(name))
|
|
34
|
+
return { category: 'ecosystems', component: comp };
|
|
35
|
+
if (/(app|root|core|galaxy|global|provider)/.test(name))
|
|
36
|
+
return { category: 'galaxies', component: comp };
|
|
37
|
+
return { category: 'molecules', component: comp };
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runConcurrent = runConcurrent;
|
|
4
|
+
/**
|
|
5
|
+
* [EN] Bounded concurrent task runner. Processes items in parallel up to the configured worker limit.
|
|
6
|
+
* [ES] Ejecutor de tareas concurrentes acotado. Procesa ítems en paralelo hasta el límite configurado.
|
|
7
|
+
*/
|
|
8
|
+
async function runConcurrent(items, concurrency, task) {
|
|
9
|
+
const results = [];
|
|
10
|
+
const iterator = items.entries();
|
|
11
|
+
const workers = Array(concurrency).fill(iterator).map(async (iter) => {
|
|
12
|
+
for (const [index, item] of iter) {
|
|
13
|
+
results[index] = await task(item);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
await Promise.all(workers);
|
|
17
|
+
return results;
|
|
18
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AIEngine = void 0;
|
|
4
|
+
class AIEngine {
|
|
5
|
+
provider;
|
|
6
|
+
apiKey;
|
|
7
|
+
model;
|
|
8
|
+
constructor(provider, apiKey, model) {
|
|
9
|
+
this.provider = provider;
|
|
10
|
+
this.apiKey = apiKey;
|
|
11
|
+
this.model = model || this.getDefaultModel(provider);
|
|
12
|
+
}
|
|
13
|
+
/** [EN] Canonical default model for each provider. [ES] Modelo predeterminado canónico por proveedor. */
|
|
14
|
+
getDefaultModel(provider) {
|
|
15
|
+
const map = {
|
|
16
|
+
openai: 'gpt-4o-mini', deepseek: 'deepseek-chat', xai: 'grok-beta',
|
|
17
|
+
alibaba: 'qwen-turbo', claude: 'claude-3-haiku-20240307',
|
|
18
|
+
gemini: 'gemini-1.5-flash', ollama: 'llama3',
|
|
19
|
+
};
|
|
20
|
+
return map[provider] || 'gpt-4o-mini';
|
|
21
|
+
}
|
|
22
|
+
/** [EN] Base endpoint URL per provider. [ES] URL de endpoint base por proveedor. */
|
|
23
|
+
getProviderBaseUrl(provider) {
|
|
24
|
+
const map = {
|
|
25
|
+
openai: 'https://api.openai.com/v1/chat/completions',
|
|
26
|
+
deepseek: 'https://api.deepseek.com/chat/completions',
|
|
27
|
+
xai: 'https://api.x.ai/v1/chat/completions',
|
|
28
|
+
alibaba: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
|
|
29
|
+
ollama: 'http://127.0.0.1:11434/api/generate',
|
|
30
|
+
};
|
|
31
|
+
return map[provider] || '';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* [EN] Dispatches the naming request to the correct provider and returns a normalized mapping.
|
|
35
|
+
* [ES] Despacha la solicitud de nombrado al proveedor correcto y devuelve un mapeo normalizado.
|
|
36
|
+
*/
|
|
37
|
+
async generateSemanticNames(request) {
|
|
38
|
+
let sys = "Eres un Arquitecto CSS AUM-IC. Te daré un array JSON de cadenas de utilidades de Tailwind. Devuelve un objeto JSON donde la clave es la cadena exacta de Tailwind, y el valor es un nombre de clase semántico BEM corto que empiece con 'aumic-'. Responde ÚNICAMENTE con el objeto JSON válido.";
|
|
39
|
+
if (request.customRules)
|
|
40
|
+
sys += `\n\nREGLAS PERSONALIZADAS:\n${request.customRules}\nDEBES DAR PRIORIDAD ABSOLUTA A ESTAS REGLAS.`;
|
|
41
|
+
const user = JSON.stringify(request.utilities);
|
|
42
|
+
let raw = '';
|
|
43
|
+
if (['openai', 'deepseek', 'xai', 'alibaba'].includes(this.provider))
|
|
44
|
+
raw = await this.callOpenAICompatible(sys, user);
|
|
45
|
+
else if (this.provider === 'gemini')
|
|
46
|
+
raw = await this.callGemini(sys, user);
|
|
47
|
+
else if (this.provider === 'claude')
|
|
48
|
+
raw = await this.callClaude(sys, user);
|
|
49
|
+
else if (this.provider === 'ollama')
|
|
50
|
+
raw = await this.callOllama(sys, user);
|
|
51
|
+
else
|
|
52
|
+
throw new Error(`Proveedor ${this.provider} no implementado.`);
|
|
53
|
+
try {
|
|
54
|
+
// [EN] Strip markdown fences — some LLMs ignore the plain-JSON instruction.
|
|
55
|
+
// [ES] Eliminar bloques markdown — algunos LLMs ignoran la instrucción de JSON plano.
|
|
56
|
+
return { mapping: JSON.parse(raw.replace(/```json/g, '').replace(/```/g, '').trim()) };
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { mapping: {} };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** [EN] Adapter for OpenAI-compatible REST APIs. [ES] Adaptador para APIs REST compatibles con OpenAI. */
|
|
63
|
+
async callOpenAICompatible(sys, user) {
|
|
64
|
+
const res = await fetch(this.getProviderBaseUrl(this.provider), {
|
|
65
|
+
method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` },
|
|
66
|
+
body: JSON.stringify({ model: this.model, messages: [{ role: 'system', content: sys }, { role: 'user', content: user }], temperature: 0.1 })
|
|
67
|
+
});
|
|
68
|
+
if (!res.ok)
|
|
69
|
+
throw new Error(`[IA] HTTP ${res.status}: ${await res.text()}`);
|
|
70
|
+
return (await res.json()).choices[0].message.content;
|
|
71
|
+
}
|
|
72
|
+
/** [EN] Adapter for Google Gemini. [ES] Adaptador para Google Gemini. */
|
|
73
|
+
async callGemini(sys, user) {
|
|
74
|
+
const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${this.model}:generateContent?key=${this.apiKey}`, {
|
|
75
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
76
|
+
body: JSON.stringify({ system_instruction: { parts: { text: sys } }, contents: [{ parts: [{ text: user }] }], generationConfig: { temperature: 0.1 } })
|
|
77
|
+
});
|
|
78
|
+
if (!res.ok)
|
|
79
|
+
throw new Error(`[IA] HTTP ${res.status}: ${await res.text()}`);
|
|
80
|
+
return (await res.json()).candidates[0].content.parts[0].text;
|
|
81
|
+
}
|
|
82
|
+
/** [EN] Adapter for Anthropic Claude. [ES] Adaptador para Anthropic Claude. */
|
|
83
|
+
async callClaude(sys, user) {
|
|
84
|
+
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
85
|
+
method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': this.apiKey, 'anthropic-version': '2023-06-01' },
|
|
86
|
+
body: JSON.stringify({ model: this.model, system: sys, messages: [{ role: 'user', content: user }], temperature: 0.1, max_tokens: 4096 })
|
|
87
|
+
});
|
|
88
|
+
if (!res.ok)
|
|
89
|
+
throw new Error(`[IA] HTTP ${res.status}: ${await res.text()}`);
|
|
90
|
+
return (await res.json()).content[0].text;
|
|
91
|
+
}
|
|
92
|
+
/** [EN] Adapter for self-hosted Ollama. [ES] Adaptador para Ollama auto-hospedado. */
|
|
93
|
+
async callOllama(sys, user) {
|
|
94
|
+
const res = await fetch(this.getProviderBaseUrl(this.provider), {
|
|
95
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
96
|
+
body: JSON.stringify({ model: this.model, system: sys, prompt: user, stream: false, options: { temperature: 0.1 } })
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok)
|
|
99
|
+
throw new Error(`[IA] Ollama HTTP ${res.status}: ¿Está corriendo Ollama?`);
|
|
100
|
+
return (await res.json()).response;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.AIEngine = AIEngine;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queryL1Cache = queryL1Cache;
|
|
4
|
+
/**
|
|
5
|
+
* [EN] Queries the bundled DuckDB lexicon. Unresolved classes are forwarded to the L2 JIT compiler.
|
|
6
|
+
* [ES] Consulta el léxico DuckDB incluido. Las clases no resueltas se reenvían al compilador JIT L2.
|
|
7
|
+
*/
|
|
8
|
+
async function queryL1Cache(classes, version, dbPath) {
|
|
9
|
+
const duckdb = require('duckdb');
|
|
10
|
+
const db = new duckdb.Database(dbPath);
|
|
11
|
+
let css = '';
|
|
12
|
+
const unresolved = new Set();
|
|
13
|
+
await Promise.all(classes.map(cls => new Promise(resolve => {
|
|
14
|
+
db.all('SELECT css FROM tw_lexicon WHERE version = ? AND class = ?', [version, cls], (err, rows) => {
|
|
15
|
+
if (err || rows.length === 0)
|
|
16
|
+
unresolved.add(cls);
|
|
17
|
+
else
|
|
18
|
+
css += `\n/* tw: ${cls} (L1) */\n.${cls} { ${rows[0].css} }\n`;
|
|
19
|
+
resolve();
|
|
20
|
+
});
|
|
21
|
+
})));
|
|
22
|
+
db.close();
|
|
23
|
+
return { css, unresolved };
|
|
24
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
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.WebCloner = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* [EN] Web Cloner cell: network I/O handler for Forensic Mode.
|
|
9
|
+
* [ES] Célula Clonador Web: manejador I/O de red para el Modo Forense.
|
|
10
|
+
*/
|
|
11
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
const website_scraper_1 = __importDefault(require("website-scraper"));
|
|
15
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
16
|
+
class WebCloner {
|
|
17
|
+
/**
|
|
18
|
+
* [EN] Downloads and mirrors a URL. Rewrites all asset paths for offline use.
|
|
19
|
+
* [ES] Descarga y espeja una URL. Reescribe rutas de assets para uso offline.
|
|
20
|
+
*/
|
|
21
|
+
static async cloneWebsite(url, outputDir, cloneDepth) {
|
|
22
|
+
if (await fs_extra_1.default.pathExists(outputDir))
|
|
23
|
+
await fs_extra_1.default.emptyDir(outputDir);
|
|
24
|
+
const options = {
|
|
25
|
+
urls: [url], directory: outputDir,
|
|
26
|
+
sources: [
|
|
27
|
+
{ selector: 'img', attr: 'src' }, { selector: 'link[rel="stylesheet"]', attr: 'href' },
|
|
28
|
+
{ selector: 'script', attr: 'src' }, { selector: 'source', attr: 'src' },
|
|
29
|
+
{ selector: 'source', attr: 'srcset' }, { selector: 'img', attr: 'srcset' }
|
|
30
|
+
],
|
|
31
|
+
recursive: cloneDepth === 'site', maxDepth: cloneDepth === 'site' ? 5 : 1, ignoreErrors: true
|
|
32
|
+
};
|
|
33
|
+
try {
|
|
34
|
+
await (0, website_scraper_1.default)(options);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(picocolors_1.default.red(`\n[!] Error durante la clonación: ${error}`));
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* [EN] Scans HTML files for Tailwind atomic signatures. Returns true on confirmation.
|
|
43
|
+
* [ES] Escanea archivos HTML en busca de firmas atómicas Tailwind. Devuelve true al confirmar.
|
|
44
|
+
*/
|
|
45
|
+
static async isTailwindPowered(outputDir) {
|
|
46
|
+
const files = (await fs_extra_1.default.readdir(outputDir)).filter(f => f.endsWith('.html'));
|
|
47
|
+
const sigs = ['flex', 'grid', 'w-full', 'h-full', 'absolute', 'relative', 'bg-', 'text-', 'p-4', 'm-'];
|
|
48
|
+
let score = 0;
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
const c = await fs_extra_1.default.readFile(path_1.default.join(outputDir, file), 'utf-8');
|
|
51
|
+
for (const sig of sigs) {
|
|
52
|
+
if (c.includes(`"${sig}`))
|
|
53
|
+
score++;
|
|
54
|
+
if (c.includes(` ${sig}`))
|
|
55
|
+
score++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return score >= 5;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.WebCloner = WebCloner;
|
|
@@ -0,0 +1,116 @@
|
|
|
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.AstInterceptor = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* [EN] AST Interception Organism — the core transmutation engine.
|
|
9
|
+
* Routes files through Babel AST (JSX/TSX) or Universal Regex (HTML/templates).
|
|
10
|
+
* Supports forward (Tailwind→AUM-IC) and reverse (rollback) passes.
|
|
11
|
+
* [ES] Organismo de Intercepción AST — el motor principal de transmutación.
|
|
12
|
+
* Enruta archivos por Babel AST (JSX/TSX) o Regex Universal (HTML/plantillas).
|
|
13
|
+
* Soporta pases directo (Tailwind→AUM-IC) e inverso (rollback).
|
|
14
|
+
*/
|
|
15
|
+
const parser_1 = require("@babel/parser");
|
|
16
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
17
|
+
const generator_1 = __importDefault(require("@babel/generator"));
|
|
18
|
+
class AstInterceptor {
|
|
19
|
+
/**
|
|
20
|
+
* [EN] Public router: delegates to Babel or Regex based on file extension.
|
|
21
|
+
* `replacerFn` receives a class string and returns the replacement.
|
|
22
|
+
* Set `isRestore = true` to enable reverse (rollback) mode.
|
|
23
|
+
* [ES] Enrutador público: delega a Babel o Regex según la extensión del archivo.
|
|
24
|
+
* `replacerFn` recibe un string de clase y devuelve el reemplazo.
|
|
25
|
+
* Establece `isRestore = true` para el modo inverso (rollback).
|
|
26
|
+
*/
|
|
27
|
+
processFrameworkFile(code, fileName, replacerFn, isRestore = false) {
|
|
28
|
+
const ext = fileName.split('.').pop()?.toLowerCase();
|
|
29
|
+
return ['jsx', 'tsx', 'js', 'ts'].includes(ext || '')
|
|
30
|
+
? this.processWithBabel(code, replacerFn, isRestore)
|
|
31
|
+
: this.processWithUniversalRegex(code, replacerFn, isRestore);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* [EN] Universal Regex engine for non-JS templates.
|
|
35
|
+
* Phase 1 extracts class strings; Phase 2 mutates via replacerFn callback.
|
|
36
|
+
* [ES] Motor Regex Universal para plantillas no-JS.
|
|
37
|
+
* La Fase 1 extrae strings de clase; la Fase 2 muta mediante el callback replacerFn.
|
|
38
|
+
*/
|
|
39
|
+
processWithUniversalRegex(code, replacerFn, isRestore) {
|
|
40
|
+
const extracted = new Set();
|
|
41
|
+
const classRegex = /(class|className|class:list)\s*(=|:)\s*(["'`])(.*?)\3/gs;
|
|
42
|
+
let match;
|
|
43
|
+
while ((match = classRegex.exec(code)) !== null) {
|
|
44
|
+
const clean = match[4].replace(/\s+/g, ' ').trim();
|
|
45
|
+
if (clean && (isRestore || !clean.includes('aumic-')))
|
|
46
|
+
extracted.add(clean);
|
|
47
|
+
}
|
|
48
|
+
const newCode = code.replace(classRegex, (full, attr, sep, q, cls) => {
|
|
49
|
+
const clean = cls.replace(/\s+/g, ' ').trim();
|
|
50
|
+
if (!clean || (!isRestore && clean.includes('aumic-')))
|
|
51
|
+
return full;
|
|
52
|
+
return `${attr}${sep}${q}${replacerFn(clean)}${q}`;
|
|
53
|
+
});
|
|
54
|
+
return { newCode, extractedClasses: Array.from(extracted) };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* [EN] Babel AST engine for JSX/TSX. Visits JSXAttribute nodes (className/class)
|
|
58
|
+
* and CallExpression nodes (clsx, cva, cn, twMerge). Preserves original line numbers.
|
|
59
|
+
* [ES] Motor AST Babel para JSX/TSX. Visita nodos JSXAttribute (className/class)
|
|
60
|
+
* y CallExpression (clsx, cva, cn, twMerge). Preserva números de línea originales.
|
|
61
|
+
*/
|
|
62
|
+
processWithBabel(code, replacerFn, isRestore) {
|
|
63
|
+
const ast = (0, parser_1.parse)(code, { sourceType: 'module', plugins: ['jsx', 'typescript'] });
|
|
64
|
+
const extracted = new Set();
|
|
65
|
+
const traverseAst = traverse_1.default.default || traverse_1.default;
|
|
66
|
+
const fn = replacerFn; // Capture outside Babel visitors to avoid closure loss
|
|
67
|
+
traverseAst(ast, {
|
|
68
|
+
CallExpression(path) {
|
|
69
|
+
if (['clsx', 'cva', 'cn', 'twMerge', 'classNames'].includes(path.node.callee.name)) {
|
|
70
|
+
path.traverse({
|
|
71
|
+
StringLiteral(p) {
|
|
72
|
+
const c = p.node.value.replace(/\s+/g, ' ').trim();
|
|
73
|
+
if (c && (isRestore || !c.includes('aumic-'))) {
|
|
74
|
+
extracted.add(c);
|
|
75
|
+
p.node.value = fn(c);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
TemplateElement(p) {
|
|
79
|
+
const c = p.node.value.raw.replace(/\s+/g, ' ').trim();
|
|
80
|
+
if (c && (isRestore || !c.includes('aumic-'))) {
|
|
81
|
+
extracted.add(c);
|
|
82
|
+
p.node.value.raw = fn(c);
|
|
83
|
+
p.node.value.cooked = p.node.value.raw;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
JSXAttribute(path) {
|
|
90
|
+
if (['className', 'class'].includes(path.node.name.name)) {
|
|
91
|
+
path.traverse({
|
|
92
|
+
StringLiteral(p) {
|
|
93
|
+
const c = p.node.value.replace(/\s+/g, ' ').trim();
|
|
94
|
+
if (c && (isRestore || !c.includes('aumic-'))) {
|
|
95
|
+
extracted.add(c);
|
|
96
|
+
p.node.value = fn(c);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
TemplateElement(p) {
|
|
100
|
+
const c = p.node.value.raw.replace(/\s+/g, ' ').trim();
|
|
101
|
+
if (c && (isRestore || !c.includes('aumic-'))) {
|
|
102
|
+
extracted.add(c);
|
|
103
|
+
p.node.value.raw = fn(c);
|
|
104
|
+
p.node.value.cooked = p.node.value.raw;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
const genCode = generator_1.default.default || generator_1.default;
|
|
112
|
+
const out = genCode(ast, { retainLines: true }, code);
|
|
113
|
+
return { newCode: out.code, extractedClasses: Array.from(extracted) };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.AstInterceptor = AstInterceptor;
|
|
@@ -0,0 +1,85 @@
|
|
|
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.runRestoreEcosystem = runRestoreEcosystem;
|
|
7
|
+
/**
|
|
8
|
+
* [EN] Restore Ecosystem: orchestrates a full rollback of an AUM-IC transmutation.
|
|
9
|
+
* Reads the aumic-lock.json manifest, restores original class strings via AST,
|
|
10
|
+
* reinstates original package.json and Tailwind config files, and re-runs npm install.
|
|
11
|
+
* [ES] Ecosistema de Restauración: orquesta el rollback completo de una transmutación AUM-IC.
|
|
12
|
+
* Lee el manifiesto aumic-lock.json, restaura los strings de clase originales vía AST,
|
|
13
|
+
* restablece el package.json y los archivos de config de Tailwind originales, y re-ejecuta npm install.
|
|
14
|
+
*/
|
|
15
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const os_1 = __importDefault(require("os"));
|
|
18
|
+
const ora_1 = __importDefault(require("ora"));
|
|
19
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
20
|
+
const glob_1 = require("glob");
|
|
21
|
+
const child_process_1 = require("child_process");
|
|
22
|
+
const AstParser_1 = require("../4_organisms/AstParser");
|
|
23
|
+
const astEngine = new AstParser_1.AstInterceptor();
|
|
24
|
+
/**
|
|
25
|
+
* [EN] Entry point for the restore pipeline. Validates lock file existence,
|
|
26
|
+
* runs the AST reverse pass on all source files, and restores project dependencies.
|
|
27
|
+
* [ES] Punto de entrada del pipeline de restauración. Valida la existencia del lock file,
|
|
28
|
+
* ejecuta el pase inverso AST en todos los archivos fuente, y restaura las dependencias del proyecto.
|
|
29
|
+
*/
|
|
30
|
+
async function runRestoreEcosystem(targetDir) {
|
|
31
|
+
const lockPath = path_1.default.join(targetDir, 'aumic-lock.json');
|
|
32
|
+
if (!fs_extra_1.default.existsSync(lockPath)) {
|
|
33
|
+
console.log(picocolors_1.default.red('\n[X] Error: No se encontró aumic-lock.json. Imposible restaurar.\n'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const spinner = (0, ora_1.default)('Modo Restauración: Leyendo aumic-lock.json...').start();
|
|
37
|
+
const lockData = await fs_extra_1.default.readJson(lockPath);
|
|
38
|
+
spinner.start('Restaurando clases en archivos fuente...');
|
|
39
|
+
const files = await (0, glob_1.glob)('**/*.{astro,tsx,jsx,html,py,rs,php,go,erb,svelte,vue}', {
|
|
40
|
+
cwd: targetDir, absolute: true,
|
|
41
|
+
ignore: ['node_modules/**', 'dist/**', '.git/**', 'target/**', '__pycache__/**', 'venv/**'],
|
|
42
|
+
});
|
|
43
|
+
let restoredCount = 0;
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
const content = await fs_extra_1.default.readFile(file, 'utf-8');
|
|
46
|
+
try {
|
|
47
|
+
// [EN] Split multi-hash strings before lookup to handle concatenated hashes.
|
|
48
|
+
// [ES] Dividir strings con múltiples hashes antes de la búsqueda para manejar hashes concatenados.
|
|
49
|
+
const { newCode } = astEngine.processFrameworkFile(content, file, (twClass) => {
|
|
50
|
+
return twClass.split(' ').map(c => lockData[c] || c).join(' ');
|
|
51
|
+
}, true);
|
|
52
|
+
if (newCode !== content) {
|
|
53
|
+
await fs_extra_1.default.writeFile(file, newCode, 'utf-8');
|
|
54
|
+
restoredCount++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch { /* [EN] Skip unreadable or binary files silently. [ES] Ignorar silenciosamente archivos ilegibles o binarios. */ }
|
|
58
|
+
}
|
|
59
|
+
spinner.succeed(`Clases originales restauradas en ${restoredCount} archivos.`);
|
|
60
|
+
spinner.start('Restaurando dependencias y configuraciones...');
|
|
61
|
+
try {
|
|
62
|
+
// [EN] Restore package.json backup if it exists.
|
|
63
|
+
// [ES] Restaurar el respaldo de package.json si existe.
|
|
64
|
+
const pkgBak = path_1.default.join(targetDir, 'package.json.aumic-bak');
|
|
65
|
+
if (fs_extra_1.default.existsSync(pkgBak)) {
|
|
66
|
+
fs_extra_1.default.copyFileSync(pkgBak, path_1.default.join(targetDir, 'package.json'));
|
|
67
|
+
fs_extra_1.default.removeSync(pkgBak);
|
|
68
|
+
}
|
|
69
|
+
// [EN] Restore Tailwind config file backups.
|
|
70
|
+
// [ES] Restaurar los respaldos de archivos de configuración de Tailwind.
|
|
71
|
+
for (const conf of ['tailwind.config.js', 'tailwind.config.ts', 'tailwind.config.cjs', 'tailwind.config.mjs']) {
|
|
72
|
+
const bak = path_1.default.join(targetDir, `${conf}.aumic-bak`);
|
|
73
|
+
if (fs_extra_1.default.existsSync(bak))
|
|
74
|
+
fs_extra_1.default.renameSync(bak, path_1.default.join(targetDir, conf));
|
|
75
|
+
}
|
|
76
|
+
// [EN] Spawn npm install as a direct binary — no shell interpolation (Zero-Trust execution).
|
|
77
|
+
// [ES] Levantar npm install como binario directo — sin interpolación de shell (ejecución Zero-Trust).
|
|
78
|
+
(0, child_process_1.spawnSync)(os_1.default.platform() === 'win32' ? 'npm.cmd' : 'npm', ['install'], { cwd: targetDir, stdio: 'ignore' });
|
|
79
|
+
spinner.succeed('Tailwind rehidratado. Dependencias y configuraciones restauradas.');
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
spinner.warn('Problema reinstalando dependencias desde el package.json restaurado.');
|
|
83
|
+
}
|
|
84
|
+
console.log(picocolors_1.default.green(picocolors_1.default.bold('\n[✔] PROYECTO RESTAURADO CON ÉXITO A SU ESTADO ORIGINAL.\n')));
|
|
85
|
+
}
|