siesa-agents 2.1.10-dev.0 → 2.1.10
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 +8 -3
- package/bin/install.js +105 -6
- package/claude/settings.local.json +1 -37
- package/package.json +1 -1
- package/claude/hooks/file-restriction-hook.py +0 -51
- package/claude/hooks/track-agent.py +0 -67
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# SIESA
|
|
1
|
+
# SIESA 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. Release 2.1.10 test.
|
|
4
4
|
|
|
5
5
|
## Instalación
|
|
6
6
|
|
|
@@ -26,6 +26,7 @@ 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
|
|
29
30
|
|
|
30
31
|
## Características
|
|
31
32
|
|
|
@@ -54,6 +55,7 @@ El sistema detectará automáticamente que ya existe una instalación y la actua
|
|
|
54
55
|
|
|
55
56
|
- Node.js >= 14.0.0
|
|
56
57
|
- npm >= 6.0.0
|
|
58
|
+
- Python >= 3.7 (requerido para hooks de Claude Code)
|
|
57
59
|
|
|
58
60
|
## Estructura de archivos instalados
|
|
59
61
|
|
|
@@ -81,4 +83,7 @@ MIT
|
|
|
81
83
|
|
|
82
84
|
## Autor
|
|
83
85
|
|
|
84
|
-
SIESA - Sistemas de Información Empresarial
|
|
86
|
+
SIESA - Sistemas de Información Empresarial
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
*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('
|
|
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
|
|
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,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
|