siesa-agents 2.1.14-dev.0 → 2.1.14

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.md CHANGED
@@ -1,4 +1,4 @@
1
- # SIESA BMAD Agents
1
+ # SIESA Agents
2
2
 
3
3
  Paquete para instalar y configurar agentes SIESA en tu proyecto.
4
4
 
@@ -52,6 +52,7 @@ El paquete instala las siguientes carpetas en tu directorio actual:
52
52
  - **`.bmad-core/`** - Archivos principales del sistema BMAD
53
53
  - **`.vscode/`** - Configuración de Visual Studio Code
54
54
  - **`.github/`** - Configuración de GitHub Actions y workflows
55
+ - **`.claude/`** - Configuración de Claude Code Commands y workflows
55
56
 
56
57
  ## Características
57
58
 
@@ -80,6 +81,7 @@ El sistema detectará automáticamente que ya existe una instalación y la actua
80
81
 
81
82
  - Node.js >= 14.0.0
82
83
  - npm >= 6.0.0
84
+ - Python >= 3.7 (requerido para hooks de Claude Code)
83
85
 
84
86
  ## Estructura de archivos instalados
85
87
 
@@ -93,8 +95,6 @@ tu-proyecto/
93
95
  └── [workflows y configuración de GitHub]
94
96
  ```
95
97
 
96
-
97
-
98
98
  ## Soporte
99
99
 
100
100
  Si encuentras algún problema durante la instalación, por favor verifica:
@@ -109,4 +109,7 @@ MIT
109
109
 
110
110
  ## Autor
111
111
 
112
- SIESA - Sistemas de Información Empresarial
112
+ SIESA - Sistemas de Información Empresarial
113
+
114
+ ---
115
+ *Versión actualizada automáticamente por CI/CD*
package/bin/install.js CHANGED
@@ -13,9 +13,18 @@ class SiesaBmadInstaller {
13
13
  { source: 'github', target: '.github' },
14
14
  { source: 'claude', target: '.claude' }
15
15
  ];
16
+
17
+ // Lista de archivos que se preservan automáticamente (no se crean backups)
18
+ this.ignoredFiles = [
19
+ 'data/technical-preferences.md'
20
+ ];
21
+
16
22
  this.targetDir = process.cwd();
17
23
  // Intentar múltiples ubicaciones posibles para el paquete
18
24
  this.packageDir = this.findPackageDir();
25
+
26
+ // Almacenamiento temporal para contenido de archivos ignorados
27
+ this.preservedContent = new Map();
19
28
  }
20
29
 
21
30
  showBanner() {
@@ -26,7 +35,7 @@ class SiesaBmadInstaller {
26
35
  console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║');
27
36
  console.log('███████║██║███████╗███████║██║ ██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║');
28
37
  console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝');
29
- console.log('Esto es una pruebita');
38
+ console.log('');
30
39
  }
31
40
 
32
41
  findPackageDir() {
@@ -123,7 +132,8 @@ class SiesaBmadInstaller {
123
132
  modifiedFiles.push({
124
133
  folder: mapping.target,
125
134
  file: relativePath,
126
- fullPath: targetFile
135
+ fullPath: targetFile,
136
+ is_ignored: this.ignoredFiles.includes(relativePath)
127
137
  });
128
138
  }
129
139
  } catch (error) {
@@ -135,7 +145,8 @@ class SiesaBmadInstaller {
135
145
  modifiedFiles.push({
136
146
  folder: mapping.target,
137
147
  file: relativePath,
138
- fullPath: targetFile
148
+ fullPath: targetFile,
149
+ is_ignored: this.ignoredFiles.includes(relativePath)
139
150
  });
140
151
  }
141
152
  }
@@ -166,6 +177,10 @@ class SiesaBmadInstaller {
166
177
  }
167
178
 
168
179
  async promptUser(modifiedFiles) {
180
+
181
+ const hasNonIgnoredFiles = modifiedFiles.some(file => file.is_ignored == false)
182
+ if (!hasNonIgnoredFiles) return '2'
183
+
169
184
  console.log('\n⚠️ Se detectaron archivos modificados:');
170
185
 
171
186
  // Agrupar por carpeta
@@ -206,6 +221,12 @@ class SiesaBmadInstaller {
206
221
  console.log('\n🔄 Creando backup de archivos modificados...');
207
222
 
208
223
  for (const item of modifiedFiles) {
224
+ // No crear backup de archivos ignorados
225
+ if (item.is_ignored) {
226
+ console.log(`✓ Preservando: ${item.file} (sin backup)`);
227
+ continue;
228
+ }
229
+
209
230
  const originalPath = item.fullPath;
210
231
  const backupPath = this.getBackupPath(originalPath);
211
232
 
@@ -270,10 +291,19 @@ class SiesaBmadInstaller {
270
291
  // Obtener todos los archivos backup existentes
271
292
  const backupFiles = await this.findBackupFiles(targetPath);
272
293
 
273
- // Copiar la carpeta completa sobrescribiendo
294
+ // Copiar la carpeta preservando technical-preferences.md
274
295
  await fs.copy(sourcePath, targetPath, {
275
296
  overwrite: true,
276
- recursive: true
297
+ recursive: true,
298
+ filter: (src) => {
299
+ const relativePath = path.relative(sourcePath, src);
300
+ // No sobrescribir archivos ignorados si ya existen
301
+ if (this.ignoredFiles.includes(relativePath)) {
302
+ const targetFile = path.join(targetPath, relativePath);
303
+ return !fs.existsSync(targetFile);
304
+ }
305
+ return true;
306
+ }
277
307
  });
278
308
 
279
309
  // Restaurar los archivos backup
@@ -328,7 +358,16 @@ class SiesaBmadInstaller {
328
358
  if (fs.existsSync(sourcePath)) {
329
359
  await fs.copy(sourcePath, targetPath, {
330
360
  overwrite: true,
331
- recursive: true
361
+ recursive: true,
362
+ filter: (src) => {
363
+ const relativePath = path.relative(sourcePath, src);
364
+ // No sobrescribir archivos ignorados si ya existen
365
+ if (this.ignoredFiles.includes(relativePath)) {
366
+ const targetFile = path.join(targetPath, relativePath);
367
+ return !fs.existsSync(targetFile);
368
+ }
369
+ return true;
370
+ }
332
371
  });
333
372
  } else {
334
373
  console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
@@ -364,6 +403,9 @@ class SiesaBmadInstaller {
364
403
  await this.performUpdateWithBackups();
365
404
  } else {
366
405
  // Si no hay backups, hacer actualización normal (remover y copiar)
406
+ // Pero primero preservar archivos ignorados
407
+ await this.preserveIgnoredFiles();
408
+
367
409
  for (const mapping of this.folderMappings) {
368
410
  const targetPath = path.join(this.targetDir, mapping.target);
369
411
 
@@ -374,9 +416,66 @@ class SiesaBmadInstaller {
374
416
 
375
417
  // Realizar instalación nueva
376
418
  await this.performInstallation();
419
+
420
+ // Restaurar archivos ignorados
421
+ await this.restoreIgnoredFiles();
422
+ }
423
+ }
424
+
425
+ async preserveIgnoredFiles() {
426
+ console.log('🔒 Preservando archivos de configuración...');
427
+
428
+ for (const mapping of this.folderMappings) {
429
+ const targetFolderPath = path.join(this.targetDir, mapping.target);
430
+
431
+ if (!fs.existsSync(targetFolderPath)) {
432
+ continue;
433
+ }
434
+
435
+ for (const ignoredFile of this.ignoredFiles) {
436
+ const filePath = path.join(targetFolderPath, ignoredFile);
437
+
438
+ if (fs.existsSync(filePath)) {
439
+ try {
440
+ const content = await fs.readFile(filePath, 'utf8');
441
+ const key = `${mapping.target}/${ignoredFile}`;
442
+ this.preservedContent.set(key, content);
443
+ console.log(`✓ Preservando: ${ignoredFile}`);
444
+ } catch (error) {
445
+ console.warn(`⚠️ Error leyendo ${ignoredFile}: ${error.message}`);
446
+ }
447
+ }
448
+ }
377
449
  }
378
450
  }
379
451
 
452
+ async restoreIgnoredFiles() {
453
+ if (this.preservedContent.size === 0) {
454
+ return;
455
+ }
456
+
457
+ console.log('🔄 Restaurando archivos de configuración...');
458
+
459
+ for (const [key, content] of this.preservedContent) {
460
+ const [targetFolder, ...filePathParts] = key.split('/');
461
+ const filePath = path.join(this.targetDir, targetFolder, ...filePathParts);
462
+
463
+ try {
464
+ // Asegurar que el directorio existe
465
+ await fs.ensureDir(path.dirname(filePath));
466
+
467
+ // Restaurar el contenido
468
+ await fs.writeFile(filePath, content, 'utf8');
469
+ console.log(`✓ Restaurado: ${filePathParts.join('/')}`);
470
+ } catch (error) {
471
+ console.warn(`⚠️ Error restaurando ${filePathParts.join('/')}: ${error.message}`);
472
+ }
473
+ }
474
+
475
+ // Limpiar el mapa después de restaurar
476
+ this.preservedContent.clear();
477
+ }
478
+
380
479
  showPostInstallMessage() {
381
480
  console.log('\n📚 Carpetas instaladas:');
382
481
  this.folderMappings.forEach(mapping => {
@@ -16,41 +16,5 @@
16
16
  ],
17
17
  "deny": [],
18
18
  "ask": []
19
- },
20
- "hooks": {
21
- "UserPromptSubmit": [
22
- {
23
- "matcher": ".*",
24
- "hooks": [
25
- {
26
- "type": "command",
27
- "command": "python .claude/hooks/track-agent.py"
28
- }
29
- ]
30
- }
31
- ],
32
- "PreToolUse": [
33
- {
34
- "matcher": "Write|Edit",
35
- "hooks": [
36
- {
37
- "type": "command",
38
- "command": "python .claude/hooks/file-restriction-hook.py"
39
- }
40
- ]
41
- }
42
- ],
43
- "SessionEnd": [
44
- {
45
- "matcher": ".*",
46
- "hooks": [
47
- {
48
- "type": "command",
49
- "command": "python .claude/hooks/cleanup-agent.py"
50
- }
51
- ]
52
- }
53
- ]
54
- },
55
- "disableAllHooks": false
19
+ }
56
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siesa-agents",
3
- "version": "2.1.14-dev.0",
3
+ "version": "2.1.14",
4
4
  "description": "Paquete para instalar y configurar agentes SIESA en tu proyecto",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1,51 +0,0 @@
1
- import sys
2
- import json
3
- import os
4
-
5
- try:
6
- # Leer JSON desde stdin
7
- data = json.load(sys.stdin)
8
-
9
- # Obtener información del archivo y sesión
10
- file_path = data.get('tool_input', {}).get('file_path', '')
11
- extension = os.path.splitext(file_path)[1].lower() if file_path else ''
12
- session_id = data.get('session_id', '')
13
- cwd = data.get('cwd', '')
14
-
15
- # Construir ruta relativa al log desde el cwd
16
- log_file = os.path.join(cwd, '.claude', 'logs', 'active_agents.json')
17
-
18
- # Agentes que solo pueden escribir markdown
19
- MARKDOWN_ONLY_AGENTS = ['PO', 'SM', 'PM', 'ANALYST', 'ARCHITECT', 'UX-EXPERT']
20
-
21
- # Verificar si la sesión actual tiene un agente activo
22
- if session_id and os.path.exists(log_file):
23
- try:
24
- with open(log_file, 'r', encoding='utf-8') as f:
25
- active_agents = json.load(f)
26
-
27
- # Si la sesión actual tiene un agente activo
28
- if session_id in active_agents:
29
- agent_type = active_agents[session_id]['agent']
30
-
31
- # Si el agente está en la lista de solo markdown
32
- if agent_type in MARKDOWN_ONLY_AGENTS:
33
- # Solo permitir archivos markdown
34
- if extension != '.md':
35
- result = {
36
- "hookSpecificOutput": {
37
- "hookEventName": "PreToolUse",
38
- "permissionDecision": "deny",
39
- "permissionDecisionReason": f"⛔ El agente de tipo {agent_type} solo puede redactar archivos markdown"
40
- }
41
- }
42
- print(json.dumps(result))
43
- sys.exit(0)
44
- except:
45
- # Si hay error leyendo el log, permitir la operación
46
- pass
47
-
48
- # Si no está bloqueado, permitir la operación (no imprimir nada)
49
- except Exception as e:
50
- # En caso de error, permitir la operación
51
- pass
@@ -1,67 +0,0 @@
1
- import sys
2
- import json
3
- import os
4
- from datetime import datetime
5
-
6
- try:
7
- # Leer JSON desde stdin
8
- data = json.load(sys.stdin)
9
-
10
- session_id = data.get('session_id', '')
11
- prompt = data.get('prompt', '').lower()
12
- cwd = data.get('cwd', '')
13
-
14
- # Construir ruta relativa al log desde el cwd
15
- log_file = os.path.join(cwd, '.claude', 'logs', 'active_agents.json')
16
-
17
- # Crear directorio si no existe
18
- log_dir = os.path.dirname(log_file)
19
- os.makedirs(log_dir, exist_ok=True)
20
-
21
- # Lista completa de agentes disponibles
22
- agent_identifiers = {
23
- 'agents:po': 'PO',
24
- 'agents:sm': 'SM',
25
- 'agents:pm': 'PM',
26
- 'agents:analyst': 'ANALYST',
27
- 'agents:architect': 'ARCHITECT',
28
- 'agents:dev': 'DEV',
29
- 'agents:backend': 'BACKEND',
30
- 'agents:frontend': 'FRONTEND',
31
- 'agents:qa': 'QA',
32
- 'agents:ux-expert': 'UX-EXPERT',
33
- 'agents:bmad-master': 'BMAD-MASTER',
34
- 'agents:bmad-orchestrator': 'BMAD-ORCHESTRATOR'
35
- }
36
-
37
- # Detectar si se está invocando un agente
38
- agent_type = None
39
- for identifier, agent_name in agent_identifiers.items():
40
- if identifier in prompt or f'/bmad:{identifier}' in prompt:
41
- agent_type = agent_name
42
- break
43
-
44
- if agent_type and session_id:
45
- # Leer log existente
46
- active_agents = {}
47
- if os.path.exists(log_file):
48
- try:
49
- with open(log_file, 'r', encoding='utf-8') as f:
50
- active_agents = json.load(f)
51
- except:
52
- active_agents = {}
53
-
54
- # Actualizar o agregar la sesión con el agente actual
55
- active_agents[session_id] = {
56
- 'agent': agent_type,
57
- 'timestamp': datetime.now().isoformat(),
58
- 'last_prompt': prompt[:100] # Guardar inicio del prompt para debug
59
- }
60
-
61
- # Guardar log actualizado
62
- with open(log_file, 'w', encoding='utf-8') as f:
63
- json.dump(active_agents, f, indent=2, ensure_ascii=False)
64
-
65
- except Exception as e:
66
- # En caso de error, no bloquear la operación
67
- pass