siesa-agents 2.1.9 → 2.1.10-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 +3 -8
- package/bin/install.js +6 -105
- package/claude/hooks/file-restriction-hook.py +51 -0
- package/claude/hooks/track-agent.py +67 -0
- package/claude/settings.local.json +37 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# SIESA Agents
|
|
1
|
+
# SIESA BMAD Agents
|
|
2
2
|
|
|
3
|
-
Paquete para instalar y configurar agentes SIESA en tu proyecto.
|
|
3
|
+
Paquete para instalar y configurar agentes SIESA en tu proyecto. Test post 2.1.10 - debería generar 2.1.10-dev.1 (porque .0 ya existe).
|
|
4
4
|
|
|
5
5
|
## Instalación
|
|
6
6
|
|
|
@@ -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
|
|
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
|
}
|