siesa-agents 2.1.7 → 2.1.8-dev.1

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 Agents
1
+ # SIESA BMAD Agents
2
2
 
3
3
  Paquete para instalar y configurar agentes SIESA en tu proyecto.
4
4
 
@@ -26,7 +26,6 @@ El paquete instala las siguientes carpetas en tu directorio actual:
26
26
  - **`.bmad-core/`** - Archivos principales del sistema BMAD
27
27
  - **`.vscode/`** - Configuración de Visual Studio Code
28
28
  - **`.github/`** - Configuración de GitHub Actions y workflows
29
- - **`.claude/`** - Configuración de Claude Code Commands y workflows
30
29
 
31
30
  ## Características
32
31
 
@@ -55,7 +54,6 @@ El sistema detectará automáticamente que ya existe una instalación y la actua
55
54
 
56
55
  - Node.js >= 14.0.0
57
56
  - npm >= 6.0.0
58
- - Python >= 3.7 (requerido para hooks de Claude Code)
59
57
 
60
58
  ## Estructura de archivos instalados
61
59
 
@@ -83,7 +81,4 @@ MIT
83
81
 
84
82
  ## Autor
85
83
 
86
- SIESA - Sistemas de Información Empresarial
87
-
88
- ---
89
- *Versión actualizada automáticamente por CI/CD*
84
+ SIESA - Sistemas de Información Empresarial
package/bin/install.js CHANGED
@@ -13,18 +13,9 @@ 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
-
22
16
  this.targetDir = process.cwd();
23
17
  // Intentar múltiples ubicaciones posibles para el paquete
24
18
  this.packageDir = this.findPackageDir();
25
-
26
- // Almacenamiento temporal para contenido de archivos ignorados
27
- this.preservedContent = new Map();
28
19
  }
29
20
 
30
21
  showBanner() {
@@ -35,7 +26,7 @@ class SiesaBmadInstaller {
35
26
  console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║');
36
27
  console.log('███████║██║███████╗███████║██║ ██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║');
37
28
  console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝');
38
- console.log('');
29
+ console.log('Esto es una pruebita');
39
30
  }
40
31
 
41
32
  findPackageDir() {
@@ -132,8 +123,7 @@ class SiesaBmadInstaller {
132
123
  modifiedFiles.push({
133
124
  folder: mapping.target,
134
125
  file: relativePath,
135
- fullPath: targetFile,
136
- is_ignored: this.ignoredFiles.includes(relativePath)
126
+ fullPath: targetFile
137
127
  });
138
128
  }
139
129
  } catch (error) {
@@ -145,8 +135,7 @@ class SiesaBmadInstaller {
145
135
  modifiedFiles.push({
146
136
  folder: mapping.target,
147
137
  file: relativePath,
148
- fullPath: targetFile,
149
- is_ignored: this.ignoredFiles.includes(relativePath)
138
+ fullPath: targetFile
150
139
  });
151
140
  }
152
141
  }
@@ -177,10 +166,6 @@ class SiesaBmadInstaller {
177
166
  }
178
167
 
179
168
  async promptUser(modifiedFiles) {
180
-
181
- const hasNonIgnoredFiles = modifiedFiles.some(file => file.is_ignored == false)
182
- if (!hasNonIgnoredFiles) return '2'
183
-
184
169
  console.log('\n⚠️ Se detectaron archivos modificados:');
185
170
 
186
171
  // Agrupar por carpeta
@@ -221,12 +206,6 @@ class SiesaBmadInstaller {
221
206
  console.log('\n🔄 Creando backup de archivos modificados...');
222
207
 
223
208
  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
-
230
209
  const originalPath = item.fullPath;
231
210
  const backupPath = this.getBackupPath(originalPath);
232
211
 
@@ -291,19 +270,10 @@ class SiesaBmadInstaller {
291
270
  // Obtener todos los archivos backup existentes
292
271
  const backupFiles = await this.findBackupFiles(targetPath);
293
272
 
294
- // Copiar la carpeta preservando technical-preferences.md
273
+ // Copiar la carpeta completa sobrescribiendo
295
274
  await fs.copy(sourcePath, targetPath, {
296
275
  overwrite: 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
- }
276
+ recursive: true
307
277
  });
308
278
 
309
279
  // Restaurar los archivos backup
@@ -358,16 +328,7 @@ class SiesaBmadInstaller {
358
328
  if (fs.existsSync(sourcePath)) {
359
329
  await fs.copy(sourcePath, targetPath, {
360
330
  overwrite: 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
- }
331
+ recursive: true
371
332
  });
372
333
  } else {
373
334
  console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
@@ -403,9 +364,6 @@ class SiesaBmadInstaller {
403
364
  await this.performUpdateWithBackups();
404
365
  } else {
405
366
  // Si no hay backups, hacer actualización normal (remover y copiar)
406
- // Pero primero preservar archivos ignorados
407
- await this.preserveIgnoredFiles();
408
-
409
367
  for (const mapping of this.folderMappings) {
410
368
  const targetPath = path.join(this.targetDir, mapping.target);
411
369
 
@@ -416,66 +374,9 @@ class SiesaBmadInstaller {
416
374
 
417
375
  // Realizar instalación nueva
418
376
  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
- }
449
377
  }
450
378
  }
451
379
 
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
-
479
380
  showPostInstallMessage() {
480
381
  console.log('\n📚 Carpetas instaladas:');
481
382
  this.folderMappings.forEach(mapping => {
@@ -0,0 +1,51 @@
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
@@ -0,0 +1,67 @@
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
@@ -16,5 +16,41 @@
16
16
  ],
17
17
  "deny": [],
18
18
  "ask": []
19
- }
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
20
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siesa-agents",
3
- "version": "2.1.7",
3
+ "version": "2.1.8-dev.1",
4
4
  "description": "Paquete para instalar y configurar agentes SIESA en tu proyecto",
5
5
  "main": "index.js",
6
6
  "bin": {