siesa-agents 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/install.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const fs = require('fs-extra');
4
4
  const path = require('path');
5
+ const readline = require('readline');
5
6
 
6
7
  class SiesaBmadInstaller {
7
8
  constructor() {
@@ -16,6 +17,17 @@ class SiesaBmadInstaller {
16
17
  this.packageDir = this.findPackageDir();
17
18
  }
18
19
 
20
+ showBanner() {
21
+ console.log('\n');
22
+ console.log('███████╗██╗███████╗███████╗ █████╗ █████╗ ██████╗ ███████╗███╗ ██╗████████╗███████╗');
23
+ console.log('██╔════╝██║██╔════╝██╔════╝██╔══██╗ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔════╝');
24
+ console.log('███████╗██║█████╗ ███████╗███████║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ███████╗');
25
+ console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║');
26
+ console.log('███████║██║███████╗███████║██║ ██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║');
27
+ console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝');
28
+ console.log('');
29
+ }
30
+
19
31
  findPackageDir() {
20
32
  // Opción 1: directorio padre del bin (instalación normal)
21
33
  let packageDir = path.dirname(__dirname);
@@ -32,18 +44,14 @@ class SiesaBmadInstaller {
32
44
  process.cwd(), // directorio actual como último recurso
33
45
  ];
34
46
 
35
- console.log('🔍 Buscando paquete en ubicaciones alternativas...');
36
47
  for (const possiblePath of possiblePaths) {
37
- console.log(` Probando: ${possiblePath}`);
38
48
  if (this.hasRequiredFolders(possiblePath)) {
39
- console.log(` ✅ Encontrado en: ${possiblePath}`);
40
49
  packageDir = possiblePath;
41
50
  break;
42
51
  }
43
52
  }
44
53
  }
45
54
 
46
- console.log(`🎯 Directorio del paquete seleccionado: ${packageDir}`);
47
55
  return packageDir;
48
56
  }
49
57
 
@@ -55,9 +63,8 @@ class SiesaBmadInstaller {
55
63
  }
56
64
 
57
65
  async install() {
58
- console.log('🔍 Directorio del paquete:', this.packageDir);
59
- console.log('🚀 Instalando SIESA BMAD Agents...');
60
- console.log(`📁 Directorio de destino: ${this.targetDir}`);
66
+ this.showBanner();
67
+ console.log(' Instalando SIESA Agents...');
61
68
 
62
69
  try {
63
70
  // Verificar si ya existe una instalación
@@ -71,7 +78,7 @@ class SiesaBmadInstaller {
71
78
  await this.performInstallation();
72
79
  }
73
80
 
74
- console.log('✅ SIESA BMAD Agents instalado correctamente!');
81
+ console.log('✅ SIESA Agents instalado correctamente!');
75
82
  this.showPostInstallMessage();
76
83
 
77
84
  } catch (error) {
@@ -87,28 +94,241 @@ class SiesaBmadInstaller {
87
94
  });
88
95
  }
89
96
 
90
- async performInstallation() {
91
- // Debug: listar contenido del directorio del paquete
92
- console.log('🔍 Contenido del directorio del paquete:');
93
- try {
94
- const packageContents = await fs.readdir(this.packageDir);
95
- console.log('📋 Archivos/carpetas encontrados:', packageContents);
96
- } catch (error) {
97
- console.log('❌ Error leyendo directorio del paquete:', error.message);
97
+ async checkModifiedFiles() {
98
+ const modifiedFiles = [];
99
+
100
+ for (const mapping of this.folderMappings) {
101
+ const sourcePath = path.join(this.packageDir, mapping.source);
102
+ const targetPath = path.join(this.targetDir, mapping.target);
103
+
104
+ if (!fs.existsSync(sourcePath) || !fs.existsSync(targetPath)) {
105
+ continue;
106
+ }
107
+
108
+ // Obtener todos los archivos recursivamente
109
+ const sourceFiles = await this.getAllFiles(sourcePath);
110
+
111
+ for (const sourceFile of sourceFiles) {
112
+ const relativePath = path.relative(sourcePath, sourceFile);
113
+ const targetFile = path.join(targetPath, relativePath);
114
+
115
+ if (fs.existsSync(targetFile)) {
116
+ try {
117
+ // Comparar contenido de archivos
118
+ const sourceContent = await fs.readFile(sourceFile, 'utf8');
119
+ const targetContent = await fs.readFile(targetFile, 'utf8');
120
+
121
+ if (sourceContent !== targetContent) {
122
+ modifiedFiles.push({
123
+ folder: mapping.target,
124
+ file: relativePath,
125
+ fullPath: targetFile
126
+ });
127
+ }
128
+ } catch (error) {
129
+ // Si no se puede leer como texto, comparar como buffer (archivos binarios)
130
+ const sourceBuffer = await fs.readFile(sourceFile);
131
+ const targetBuffer = await fs.readFile(targetFile);
132
+
133
+ if (!sourceBuffer.equals(targetBuffer)) {
134
+ modifiedFiles.push({
135
+ folder: mapping.target,
136
+ file: relativePath,
137
+ fullPath: targetFile
138
+ });
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ return modifiedFiles;
146
+ }
147
+
148
+ async getAllFiles(dir) {
149
+ const files = [];
150
+ const items = await fs.readdir(dir);
151
+
152
+ for (const item of items) {
153
+ const fullPath = path.join(dir, item);
154
+ const stat = await fs.stat(fullPath);
155
+
156
+ if (stat.isDirectory()) {
157
+ const subFiles = await this.getAllFiles(fullPath);
158
+ files.push(...subFiles);
159
+ } else {
160
+ files.push(fullPath);
161
+ }
162
+ }
163
+
164
+ return files;
165
+ }
166
+
167
+ async promptUser(modifiedFiles) {
168
+ console.log('\n⚠️ Se detectaron archivos modificados:');
169
+
170
+ // Agrupar por carpeta
171
+ const filesByFolder = {};
172
+ modifiedFiles.forEach(item => {
173
+ if (!filesByFolder[item.folder]) {
174
+ filesByFolder[item.folder] = [];
175
+ }
176
+ filesByFolder[item.folder].push(item.file);
177
+ });
178
+
179
+ // Mostrar archivos modificados por carpeta
180
+ Object.keys(filesByFolder).forEach(folder => {
181
+ console.log(`\n📁 ${folder}:`);
182
+ filesByFolder[folder].forEach(file => {
183
+ console.log(` - ${file}`);
184
+ });
185
+ });
186
+
187
+ console.log('\n¿Qué deseas hacer?');
188
+ console.log('1. Reemplazar todos los archivos (se perderán las modificaciones)');
189
+ console.log('2. Hacer backup de archivos modificados (se agregarán con sufijo _bk)');
190
+
191
+ const rl = readline.createInterface({
192
+ input: process.stdin,
193
+ output: process.stdout
194
+ });
195
+
196
+ return new Promise((resolve) => {
197
+ rl.question('\nElige una opción (1 o 2): ', (answer) => {
198
+ rl.close();
199
+ resolve(answer.trim());
200
+ });
201
+ });
202
+ }
203
+
204
+ async backupModifiedFiles(modifiedFiles) {
205
+ console.log('\n🔄 Creando backup de archivos modificados...');
206
+
207
+ for (const item of modifiedFiles) {
208
+ const originalPath = item.fullPath;
209
+ const backupPath = this.getBackupPath(originalPath);
210
+
211
+ try {
212
+ await fs.copy(originalPath, backupPath);
213
+
214
+ // Determinar tipo de backup para mostrar mensaje apropiado
215
+ const backupName = path.basename(backupPath);
216
+ const isVersionedBackup = backupName.includes('_bk_');
217
+
218
+ if (isVersionedBackup) {
219
+ console.log(`✓ Backup versionado: ${path.relative(this.targetDir, backupPath)}`);
220
+ } else {
221
+ console.log(`✓ Backup creado: ${path.relative(this.targetDir, backupPath)}`);
222
+ }
223
+ } catch (error) {
224
+ console.warn(`⚠️ Error creando backup de ${item.file}: ${error.message}`);
225
+ }
226
+ }
227
+ }
228
+
229
+ getBackupPath(filePath) {
230
+ const dir = path.dirname(filePath);
231
+ const ext = path.extname(filePath);
232
+ const name = path.basename(filePath, ext);
233
+
234
+ // Primer intento: archivo_bk.ext
235
+ const basicBackupPath = path.join(dir, `${name}_bk${ext}`);
236
+
237
+ // Si no existe, usar el nombre básico
238
+ if (!fs.existsSync(basicBackupPath)) {
239
+ return basicBackupPath;
98
240
  }
99
241
 
242
+ // Si ya existe _bk, crear versión con timestamp
243
+ const now = new Date();
244
+ const timestamp = now.getFullYear().toString() +
245
+ (now.getMonth() + 1).toString().padStart(2, '0') +
246
+ now.getDate().toString().padStart(2, '0') + '_' +
247
+ now.getHours().toString().padStart(2, '0') +
248
+ now.getMinutes().toString().padStart(2, '0') +
249
+ now.getSeconds().toString().padStart(2, '0');
250
+
251
+ return path.join(dir, `${name}_bk_${timestamp}${ext}`);
252
+ }
253
+
254
+ async performUpdateWithBackups() {
255
+ for (const mapping of this.folderMappings) {
256
+ const sourcePath = path.join(this.packageDir, mapping.source);
257
+ const targetPath = path.join(this.targetDir, mapping.target);
258
+
259
+ if (fs.existsSync(sourcePath)) {
260
+ // Copiar archivos selectivamente, preservando los _bk
261
+ await this.copyWithBackupPreservation(sourcePath, targetPath);
262
+ } else {
263
+ console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
264
+ }
265
+ }
266
+ }
267
+
268
+ async copyWithBackupPreservation(sourcePath, targetPath) {
269
+ // Obtener todos los archivos backup existentes
270
+ const backupFiles = await this.findBackupFiles(targetPath);
271
+
272
+ // Copiar la carpeta completa sobrescribiendo
273
+ await fs.copy(sourcePath, targetPath, {
274
+ overwrite: true,
275
+ recursive: true
276
+ });
277
+
278
+ // Restaurar los archivos backup
279
+ for (const backupFile of backupFiles) {
280
+ const backupSourcePath = backupFile.tempPath;
281
+ const backupTargetPath = backupFile.originalPath;
282
+
283
+ try {
284
+ await fs.copy(backupSourcePath, backupTargetPath);
285
+ // Limpiar archivo temporal
286
+ await fs.remove(backupSourcePath);
287
+ } catch (error) {
288
+ console.warn(`⚠️ Error restaurando backup ${backupFile.relativePath}: ${error.message}`);
289
+ }
290
+ }
291
+ }
292
+
293
+ async findBackupFiles(targetPath) {
294
+ if (!fs.existsSync(targetPath)) {
295
+ return [];
296
+ }
297
+
298
+ const backupFiles = [];
299
+ const allFiles = await this.getAllFiles(targetPath);
300
+
301
+ for (const filePath of allFiles) {
302
+ const fileName = path.basename(filePath);
303
+ // Detectar archivos _bk y _bk_timestamp
304
+ if (fileName.includes('_bk')) {
305
+ const tempPath = path.join(require('os').tmpdir(), `backup_${Date.now()}_${fileName}`);
306
+ const relativePath = path.relative(targetPath, filePath);
307
+
308
+ // Crear copia temporal del backup
309
+ await fs.copy(filePath, tempPath);
310
+
311
+ backupFiles.push({
312
+ originalPath: filePath,
313
+ tempPath: tempPath,
314
+ relativePath: relativePath
315
+ });
316
+ }
317
+ }
318
+
319
+ return backupFiles;
320
+ }
321
+
322
+ async performInstallation() {
100
323
  for (const mapping of this.folderMappings) {
101
324
  const sourcePath = path.join(this.packageDir, mapping.source);
102
325
  const targetPath = path.join(this.targetDir, mapping.target);
103
326
 
104
- console.log(`🔍 Buscando: ${sourcePath}`);
105
327
  if (fs.existsSync(sourcePath)) {
106
- console.log(`📋 Copiando ${mapping.source} -> ${mapping.target}...`);
107
328
  await fs.copy(sourcePath, targetPath, {
108
329
  overwrite: true,
109
330
  recursive: true
110
331
  });
111
- console.log(`✓ ${mapping.target} copiado exitosamente`);
112
332
  } else {
113
333
  console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
114
334
  }
@@ -116,19 +336,44 @@ class SiesaBmadInstaller {
116
336
  }
117
337
 
118
338
  async update() {
119
- // Crear backup de archivos existentes si es necesario
120
- for (const mapping of this.folderMappings) {
121
- const targetPath = path.join(this.targetDir, mapping.target);
339
+ // Verificar archivos modificados
340
+ console.log('🔍 Verificando archivos modificados...');
341
+ const modifiedFiles = await this.checkModifiedFiles();
122
342
 
123
- if (fs.existsSync(targetPath)) {
124
- console.log(`🔄 Actualizando ${mapping.target}...`);
125
- // Remover carpeta existente
126
- await fs.remove(targetPath);
343
+ let hasBackups = false;
344
+ if (modifiedFiles.length > 0) {
345
+ const userChoice = await this.promptUser(modifiedFiles);
346
+
347
+ if (userChoice === '2') {
348
+ // Crear backup de archivos modificados
349
+ await this.backupModifiedFiles(modifiedFiles);
350
+ hasBackups = true;
351
+ } else if (userChoice !== '1') {
352
+ console.log('❌ Opción no válida. Cancelando actualización.');
353
+ return;
127
354
  }
355
+
356
+ console.log('\n🔄 Procediendo con la actualización...');
357
+ } else {
358
+ console.log('✓ No se detectaron archivos modificados.');
128
359
  }
129
360
 
130
- // Realizar instalación nueva
131
- await this.performInstallation();
361
+ // Si hay backups, hacer actualización preservando backups
362
+ if (hasBackups) {
363
+ await this.performUpdateWithBackups();
364
+ } else {
365
+ // Si no hay backups, hacer actualización normal (remover y copiar)
366
+ for (const mapping of this.folderMappings) {
367
+ const targetPath = path.join(this.targetDir, mapping.target);
368
+
369
+ if (fs.existsSync(targetPath)) {
370
+ await fs.remove(targetPath);
371
+ }
372
+ }
373
+
374
+ // Realizar instalación nueva
375
+ await this.performInstallation();
376
+ }
132
377
  }
133
378
 
134
379
  showPostInstallMessage() {
@@ -1,7 +1,7 @@
1
1
  <!-- Powered by BMAD™ Core -->
2
2
 
3
3
  # dev
4
-
4
+ hola papu
5
5
  ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
6
6
 
7
7
  CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your operating params, start and follow exactly your activation-instructions to alter your state of being, stay in this being until told to exit this mode:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "siesa-agents",
3
- "version": "2.0.0",
4
- "description": "Paquete para instalar y configurar agentes SIESA BMAD en tu proyecto",
3
+ "version": "2.1.0",
4
+ "description": "Paquete para instalar y configurar agentes SIESA en tu proyecto",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "siesa-agents": "./bin/install.js"