siesa-agents 2.1.2 → 2.1.3
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 +83 -83
- package/bin/install.js +400 -400
- package/bin/prepare-publish.js +26 -26
- package/bin/restore-folders.js +26 -26
- package/bmad-core/agent-teams/team-all.yaml +15 -15
- package/bmad-core/agent-teams/team-fullstack.yaml +19 -19
- package/bmad-core/agent-teams/team-ide-minimal.yaml +11 -11
- package/bmad-core/agent-teams/team-no-ui.yaml +14 -14
- package/bmad-core/agents/analyst.md +84 -84
- package/bmad-core/agents/architect.md +94 -94
- package/bmad-core/agents/backend-agent.md +189 -189
- package/bmad-core/agents/bmad-master.md +110 -110
- package/bmad-core/agents/bmad-orchestrator.md +147 -147
- package/bmad-core/agents/dev.md +81 -81
- package/bmad-core/agents/frontend-agent.md +168 -168
- package/bmad-core/agents/pm.md +84 -84
- package/bmad-core/agents/po.md +79 -79
- package/bmad-core/agents/qa.md +91 -91
- package/bmad-core/agents/sm.md +65 -65
- package/bmad-core/agents/ux-expert.md +69 -69
- package/bmad-core/checklists/architect-checklist.md +440 -440
- package/bmad-core/checklists/backend-checklist.md +142 -142
- package/bmad-core/checklists/change-checklist.md +184 -184
- package/bmad-core/checklists/frontend-checklist.md +105 -105
- package/bmad-core/checklists/pm-checklist.md +372 -372
- package/bmad-core/checklists/po-master-checklist.md +434 -434
- package/bmad-core/checklists/story-dod-checklist.md +96 -96
- package/bmad-core/checklists/story-draft-checklist.md +155 -155
- package/bmad-core/core-config.yaml +22 -22
- package/bmad-core/data/backend-standards.md +439 -439
- package/bmad-core/data/bmad-kb.md +809 -809
- package/bmad-core/data/brainstorming-techniques.md +38 -38
- package/bmad-core/data/elicitation-methods.md +156 -156
- package/bmad-core/data/frontend-standards.md +323 -323
- package/bmad-core/data/technical-preferences.md +5 -5
- package/bmad-core/data/test-levels-framework.md +148 -148
- package/bmad-core/data/test-priorities-matrix.md +174 -174
- package/bmad-core/enhanced-ide-development-workflow.md +248 -248
- package/bmad-core/install-manifest.yaml +230 -230
- package/bmad-core/tasks/advanced-elicitation.md +119 -119
- package/bmad-core/tasks/apply-qa-fixes.md +150 -150
- package/bmad-core/tasks/brownfield-create-epic.md +162 -162
- package/bmad-core/tasks/brownfield-create-story.md +149 -149
- package/bmad-core/tasks/correct-course.md +72 -72
- package/bmad-core/tasks/create-brownfield-story.md +314 -314
- package/bmad-core/tasks/create-component.md +102 -102
- package/bmad-core/tasks/create-deep-research-prompt.md +280 -280
- package/bmad-core/tasks/create-doc.md +103 -103
- package/bmad-core/tasks/create-entity.md +132 -132
- package/bmad-core/tasks/create-feature.md +90 -90
- package/bmad-core/tasks/create-next-story.md +114 -114
- package/bmad-core/tasks/create-service.md +117 -117
- package/bmad-core/tasks/create-use-case.md +140 -140
- package/bmad-core/tasks/document-project.md +345 -345
- package/bmad-core/tasks/execute-checklist.md +88 -88
- package/bmad-core/tasks/facilitate-brainstorming-session.md +138 -138
- package/bmad-core/tasks/generate-ai-frontend-prompt.md +53 -53
- package/bmad-core/tasks/index-docs.md +175 -175
- package/bmad-core/tasks/kb-mode-interaction.md +77 -77
- package/bmad-core/tasks/nfr-assess.md +345 -345
- package/bmad-core/tasks/qa-gate.md +163 -163
- package/bmad-core/tasks/review-story.md +316 -316
- package/bmad-core/tasks/risk-profile.md +355 -355
- package/bmad-core/tasks/scaffold-backend.md +110 -110
- package/bmad-core/tasks/scaffold-frontend.md +78 -78
- package/bmad-core/tasks/shard-doc.md +187 -187
- package/bmad-core/tasks/test-design.md +176 -176
- package/bmad-core/tasks/trace-requirements.md +266 -266
- package/bmad-core/tasks/validate-next-story.md +136 -136
- package/bmad-core/templates/architecture-tmpl.yaml +662 -662
- package/bmad-core/templates/brainstorming-output-tmpl.yaml +156 -156
- package/bmad-core/templates/brownfield-architecture-tmpl.yaml +477 -477
- package/bmad-core/templates/brownfield-prd-tmpl.yaml +281 -281
- package/bmad-core/templates/competitor-analysis-tmpl.yaml +307 -307
- package/bmad-core/templates/front-end-architecture-tmpl.yaml +258 -258
- package/bmad-core/templates/front-end-spec-tmpl.yaml +350 -350
- package/bmad-core/templates/fullstack-architecture-tmpl.yaml +824 -824
- package/bmad-core/templates/market-research-tmpl.yaml +253 -253
- package/bmad-core/templates/prd-tmpl.yaml +203 -203
- package/bmad-core/templates/project-brief-tmpl.yaml +222 -222
- package/bmad-core/templates/qa-gate-tmpl.yaml +103 -103
- package/bmad-core/templates/story-tmpl.yaml +138 -138
- package/bmad-core/user-guide.md +530 -530
- package/bmad-core/utils/bmad-doc-template.md +327 -327
- package/bmad-core/utils/workflow-management.md +71 -71
- package/bmad-core/workflows/brownfield-fullstack.yaml +298 -298
- package/bmad-core/workflows/brownfield-service.yaml +188 -188
- package/bmad-core/workflows/brownfield-ui.yaml +198 -198
- package/bmad-core/workflows/greenfield-fullstack.yaml +241 -241
- package/bmad-core/workflows/greenfield-service.yaml +207 -207
- package/bmad-core/workflows/greenfield-ui.yaml +236 -236
- package/bmad-core/working-in-the-brownfield.md +606 -606
- package/claude/commands/BMad/agents/backend.md +187 -187
- package/claude/commands/BMad/agents/frontend.md +150 -150
- package/github/b-mad-expert.md +742 -742
- package/github/chatmodes/analyst.chatmode.md +89 -89
- package/github/chatmodes/architect.chatmode.md +97 -97
- package/github/chatmodes/backend.chatmode.md +194 -194
- package/github/chatmodes/bmad-master.chatmode.md +115 -115
- package/github/chatmodes/bmad-orchestrator.chatmode.md +152 -152
- package/github/chatmodes/dev.chatmode.md +86 -86
- package/github/chatmodes/frontend.chatmode.md +157 -157
- package/github/chatmodes/pm.chatmode.md +89 -89
- package/github/chatmodes/po.chatmode.md +84 -84
- package/github/chatmodes/qa.chatmode.md +96 -96
- package/github/chatmodes/sm.chatmode.md +70 -70
- package/github/chatmodes/ux-expert.chatmode.md +74 -74
- package/index.js +9 -9
- package/package.json +37 -37
- package/vscode/mcp.json +11 -11
- package/vscode/settings.json +12 -12
package/bin/install.js
CHANGED
|
@@ -1,401 +1,401 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs-extra');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const readline = require('readline');
|
|
6
|
-
|
|
7
|
-
class SiesaBmadInstaller {
|
|
8
|
-
constructor() {
|
|
9
|
-
// Definir las carpetas primero (nombres en el paquete vs nombres finales)
|
|
10
|
-
this.folderMappings = [
|
|
11
|
-
{ source: 'bmad-core', target: '.bmad-core' },
|
|
12
|
-
{ source: 'vscode', target: '.vscode' },
|
|
13
|
-
{ source: 'github', target: '.github' },
|
|
14
|
-
{ source: 'claude', target: '.claude' }
|
|
15
|
-
];
|
|
16
|
-
this.targetDir = process.cwd();
|
|
17
|
-
// Intentar múltiples ubicaciones posibles para el paquete
|
|
18
|
-
this.packageDir = this.findPackageDir();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
showBanner() {
|
|
22
|
-
console.log('\n');
|
|
23
|
-
console.log('███████╗██╗███████╗███████╗ █████╗ █████╗ ██████╗ ███████╗███╗ ██╗████████╗███████╗');
|
|
24
|
-
console.log('██╔════╝██║██╔════╝██╔════╝██╔══██╗ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔════╝');
|
|
25
|
-
console.log('███████╗██║█████╗ ███████╗███████║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ███████╗');
|
|
26
|
-
console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║');
|
|
27
|
-
console.log('███████║██║███████╗███████║██║ ██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║');
|
|
28
|
-
console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝');
|
|
29
|
-
console.log('');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
findPackageDir() {
|
|
33
|
-
// Opción 1: directorio padre del bin (instalación normal)
|
|
34
|
-
let packageDir = path.dirname(__dirname);
|
|
35
|
-
|
|
36
|
-
// Opción 2: si estamos en npx, buscar en node_modules
|
|
37
|
-
if (!this.hasRequiredFolders(packageDir)) {
|
|
38
|
-
// Para npm 6.14+ y npx, intentar ubicaciones alternativas
|
|
39
|
-
const possiblePaths = [
|
|
40
|
-
path.join(__dirname, '..'), // bin -> paquete
|
|
41
|
-
path.resolve(__dirname, '..'), // alternativa con resolve
|
|
42
|
-
path.resolve(__dirname, '..', '..', 'siesa-bmad-agents'), // desde node_modules
|
|
43
|
-
// Intentar buscar basado en __dirname específicamente para npx
|
|
44
|
-
path.resolve(__dirname.replace(/\\bin$|\/bin$/, '')),
|
|
45
|
-
process.cwd(), // directorio actual como último recurso
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
for (const possiblePath of possiblePaths) {
|
|
49
|
-
if (this.hasRequiredFolders(possiblePath)) {
|
|
50
|
-
packageDir = possiblePath;
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return packageDir;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
hasRequiredFolders(dir) {
|
|
60
|
-
return this.folderMappings.some(mapping => {
|
|
61
|
-
const folderPath = path.join(dir, mapping.source);
|
|
62
|
-
return fs.existsSync(folderPath);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async install() {
|
|
67
|
-
this.showBanner();
|
|
68
|
-
console.log(' Instalando SIESA Agents...');
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
// Verificar si ya existe una instalación
|
|
72
|
-
const hasExistingInstallation = this.checkExistingInstallation();
|
|
73
|
-
|
|
74
|
-
if (hasExistingInstallation) {
|
|
75
|
-
console.log('🔄 Instalación existente detectada. Actualizando...');
|
|
76
|
-
await this.update();
|
|
77
|
-
} else {
|
|
78
|
-
console.log('✨ Nueva instalación...');
|
|
79
|
-
await this.performInstallation();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
console.log('✅ SIESA Agents instalado correctamente!');
|
|
83
|
-
this.showPostInstallMessage();
|
|
84
|
-
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.error('❌ Error durante la instalación:', error.message);
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
checkExistingInstallation() {
|
|
92
|
-
return this.folderMappings.some(mapping => {
|
|
93
|
-
const targetPath = path.join(this.targetDir, mapping.target);
|
|
94
|
-
return fs.existsSync(targetPath);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async checkModifiedFiles() {
|
|
99
|
-
const modifiedFiles = [];
|
|
100
|
-
|
|
101
|
-
for (const mapping of this.folderMappings) {
|
|
102
|
-
const sourcePath = path.join(this.packageDir, mapping.source);
|
|
103
|
-
const targetPath = path.join(this.targetDir, mapping.target);
|
|
104
|
-
|
|
105
|
-
if (!fs.existsSync(sourcePath) || !fs.existsSync(targetPath)) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Obtener todos los archivos recursivamente
|
|
110
|
-
const sourceFiles = await this.getAllFiles(sourcePath);
|
|
111
|
-
|
|
112
|
-
for (const sourceFile of sourceFiles) {
|
|
113
|
-
const relativePath = path.relative(sourcePath, sourceFile);
|
|
114
|
-
const targetFile = path.join(targetPath, relativePath);
|
|
115
|
-
|
|
116
|
-
if (fs.existsSync(targetFile)) {
|
|
117
|
-
try {
|
|
118
|
-
// Comparar contenido de archivos
|
|
119
|
-
const sourceContent = await fs.readFile(sourceFile, 'utf8');
|
|
120
|
-
const targetContent = await fs.readFile(targetFile, 'utf8');
|
|
121
|
-
|
|
122
|
-
if (sourceContent !== targetContent) {
|
|
123
|
-
modifiedFiles.push({
|
|
124
|
-
folder: mapping.target,
|
|
125
|
-
file: relativePath,
|
|
126
|
-
fullPath: targetFile
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
} catch (error) {
|
|
130
|
-
// Si no se puede leer como texto, comparar como buffer (archivos binarios)
|
|
131
|
-
const sourceBuffer = await fs.readFile(sourceFile);
|
|
132
|
-
const targetBuffer = await fs.readFile(targetFile);
|
|
133
|
-
|
|
134
|
-
if (!sourceBuffer.equals(targetBuffer)) {
|
|
135
|
-
modifiedFiles.push({
|
|
136
|
-
folder: mapping.target,
|
|
137
|
-
file: relativePath,
|
|
138
|
-
fullPath: targetFile
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return modifiedFiles;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async getAllFiles(dir) {
|
|
150
|
-
const files = [];
|
|
151
|
-
const items = await fs.readdir(dir);
|
|
152
|
-
|
|
153
|
-
for (const item of items) {
|
|
154
|
-
const fullPath = path.join(dir, item);
|
|
155
|
-
const stat = await fs.stat(fullPath);
|
|
156
|
-
|
|
157
|
-
if (stat.isDirectory()) {
|
|
158
|
-
const subFiles = await this.getAllFiles(fullPath);
|
|
159
|
-
files.push(...subFiles);
|
|
160
|
-
} else {
|
|
161
|
-
files.push(fullPath);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return files;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async promptUser(modifiedFiles) {
|
|
169
|
-
console.log('\n⚠️ Se detectaron archivos modificados:');
|
|
170
|
-
|
|
171
|
-
// Agrupar por carpeta
|
|
172
|
-
const filesByFolder = {};
|
|
173
|
-
modifiedFiles.forEach(item => {
|
|
174
|
-
if (!filesByFolder[item.folder]) {
|
|
175
|
-
filesByFolder[item.folder] = [];
|
|
176
|
-
}
|
|
177
|
-
filesByFolder[item.folder].push(item.file);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Mostrar archivos modificados por carpeta
|
|
181
|
-
Object.keys(filesByFolder).forEach(folder => {
|
|
182
|
-
console.log(`\n📁 ${folder}:`);
|
|
183
|
-
filesByFolder[folder].forEach(file => {
|
|
184
|
-
console.log(` - ${file}`);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
console.log('\n¿Qué deseas hacer?');
|
|
189
|
-
console.log('1. Reemplazar todos los archivos (se perderán las modificaciones)');
|
|
190
|
-
console.log('2. Hacer backup de archivos modificados (se agregarán con sufijo _bk)');
|
|
191
|
-
|
|
192
|
-
const rl = readline.createInterface({
|
|
193
|
-
input: process.stdin,
|
|
194
|
-
output: process.stdout
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return new Promise((resolve) => {
|
|
198
|
-
rl.question('\nElige una opción (1 o 2): ', (answer) => {
|
|
199
|
-
rl.close();
|
|
200
|
-
resolve(answer.trim());
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async backupModifiedFiles(modifiedFiles) {
|
|
206
|
-
console.log('\n🔄 Creando backup de archivos modificados...');
|
|
207
|
-
|
|
208
|
-
for (const item of modifiedFiles) {
|
|
209
|
-
const originalPath = item.fullPath;
|
|
210
|
-
const backupPath = this.getBackupPath(originalPath);
|
|
211
|
-
|
|
212
|
-
try {
|
|
213
|
-
await fs.copy(originalPath, backupPath);
|
|
214
|
-
|
|
215
|
-
// Determinar tipo de backup para mostrar mensaje apropiado
|
|
216
|
-
const backupName = path.basename(backupPath);
|
|
217
|
-
const isVersionedBackup = backupName.includes('_bk_');
|
|
218
|
-
|
|
219
|
-
if (isVersionedBackup) {
|
|
220
|
-
console.log(`✓ Backup versionado: ${path.relative(this.targetDir, backupPath)}`);
|
|
221
|
-
} else {
|
|
222
|
-
console.log(`✓ Backup creado: ${path.relative(this.targetDir, backupPath)}`);
|
|
223
|
-
}
|
|
224
|
-
} catch (error) {
|
|
225
|
-
console.warn(`⚠️ Error creando backup de ${item.file}: ${error.message}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
getBackupPath(filePath) {
|
|
231
|
-
const dir = path.dirname(filePath);
|
|
232
|
-
const ext = path.extname(filePath);
|
|
233
|
-
const name = path.basename(filePath, ext);
|
|
234
|
-
|
|
235
|
-
// Primer intento: archivo_bk.ext
|
|
236
|
-
const basicBackupPath = path.join(dir, `${name}_bk${ext}`);
|
|
237
|
-
|
|
238
|
-
// Si no existe, usar el nombre básico
|
|
239
|
-
if (!fs.existsSync(basicBackupPath)) {
|
|
240
|
-
return basicBackupPath;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Si ya existe _bk, crear versión con timestamp
|
|
244
|
-
const now = new Date();
|
|
245
|
-
const timestamp = now.getFullYear().toString() +
|
|
246
|
-
(now.getMonth() + 1).toString().padStart(2, '0') +
|
|
247
|
-
now.getDate().toString().padStart(2, '0') + '_' +
|
|
248
|
-
now.getHours().toString().padStart(2, '0') +
|
|
249
|
-
now.getMinutes().toString().padStart(2, '0') +
|
|
250
|
-
now.getSeconds().toString().padStart(2, '0');
|
|
251
|
-
|
|
252
|
-
return path.join(dir, `${name}_bk_${timestamp}${ext}`);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
async performUpdateWithBackups() {
|
|
256
|
-
for (const mapping of this.folderMappings) {
|
|
257
|
-
const sourcePath = path.join(this.packageDir, mapping.source);
|
|
258
|
-
const targetPath = path.join(this.targetDir, mapping.target);
|
|
259
|
-
|
|
260
|
-
if (fs.existsSync(sourcePath)) {
|
|
261
|
-
// Copiar archivos selectivamente, preservando los _bk
|
|
262
|
-
await this.copyWithBackupPreservation(sourcePath, targetPath);
|
|
263
|
-
} else {
|
|
264
|
-
console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
async copyWithBackupPreservation(sourcePath, targetPath) {
|
|
270
|
-
// Obtener todos los archivos backup existentes
|
|
271
|
-
const backupFiles = await this.findBackupFiles(targetPath);
|
|
272
|
-
|
|
273
|
-
// Copiar la carpeta completa sobrescribiendo
|
|
274
|
-
await fs.copy(sourcePath, targetPath, {
|
|
275
|
-
overwrite: true,
|
|
276
|
-
recursive: true
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
// Restaurar los archivos backup
|
|
280
|
-
for (const backupFile of backupFiles) {
|
|
281
|
-
const backupSourcePath = backupFile.tempPath;
|
|
282
|
-
const backupTargetPath = backupFile.originalPath;
|
|
283
|
-
|
|
284
|
-
try {
|
|
285
|
-
await fs.copy(backupSourcePath, backupTargetPath);
|
|
286
|
-
// Limpiar archivo temporal
|
|
287
|
-
await fs.remove(backupSourcePath);
|
|
288
|
-
} catch (error) {
|
|
289
|
-
console.warn(`⚠️ Error restaurando backup ${backupFile.relativePath}: ${error.message}`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async findBackupFiles(targetPath) {
|
|
295
|
-
if (!fs.existsSync(targetPath)) {
|
|
296
|
-
return [];
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const backupFiles = [];
|
|
300
|
-
const allFiles = await this.getAllFiles(targetPath);
|
|
301
|
-
|
|
302
|
-
for (const filePath of allFiles) {
|
|
303
|
-
const fileName = path.basename(filePath);
|
|
304
|
-
// Detectar archivos _bk y _bk_timestamp
|
|
305
|
-
if (fileName.includes('_bk')) {
|
|
306
|
-
const tempPath = path.join(require('os').tmpdir(), `backup_${Date.now()}_${fileName}`);
|
|
307
|
-
const relativePath = path.relative(targetPath, filePath);
|
|
308
|
-
|
|
309
|
-
// Crear copia temporal del backup
|
|
310
|
-
await fs.copy(filePath, tempPath);
|
|
311
|
-
|
|
312
|
-
backupFiles.push({
|
|
313
|
-
originalPath: filePath,
|
|
314
|
-
tempPath: tempPath,
|
|
315
|
-
relativePath: relativePath
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return backupFiles;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
async performInstallation() {
|
|
324
|
-
for (const mapping of this.folderMappings) {
|
|
325
|
-
const sourcePath = path.join(this.packageDir, mapping.source);
|
|
326
|
-
const targetPath = path.join(this.targetDir, mapping.target);
|
|
327
|
-
|
|
328
|
-
if (fs.existsSync(sourcePath)) {
|
|
329
|
-
await fs.copy(sourcePath, targetPath, {
|
|
330
|
-
overwrite: true,
|
|
331
|
-
recursive: true
|
|
332
|
-
});
|
|
333
|
-
} else {
|
|
334
|
-
console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
async update() {
|
|
340
|
-
// Verificar archivos modificados
|
|
341
|
-
console.log('🔍 Verificando archivos modificados...');
|
|
342
|
-
const modifiedFiles = await this.checkModifiedFiles();
|
|
343
|
-
|
|
344
|
-
let hasBackups = false;
|
|
345
|
-
if (modifiedFiles.length > 0) {
|
|
346
|
-
const userChoice = await this.promptUser(modifiedFiles);
|
|
347
|
-
|
|
348
|
-
if (userChoice === '2') {
|
|
349
|
-
// Crear backup de archivos modificados
|
|
350
|
-
await this.backupModifiedFiles(modifiedFiles);
|
|
351
|
-
hasBackups = true;
|
|
352
|
-
} else if (userChoice !== '1') {
|
|
353
|
-
console.log('❌ Opción no válida. Cancelando actualización.');
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
console.log('\n🔄 Procediendo con la actualización...');
|
|
358
|
-
} else {
|
|
359
|
-
console.log('✓ No se detectaron archivos modificados.');
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Si hay backups, hacer actualización preservando backups
|
|
363
|
-
if (hasBackups) {
|
|
364
|
-
await this.performUpdateWithBackups();
|
|
365
|
-
} else {
|
|
366
|
-
// Si no hay backups, hacer actualización normal (remover y copiar)
|
|
367
|
-
for (const mapping of this.folderMappings) {
|
|
368
|
-
const targetPath = path.join(this.targetDir, mapping.target);
|
|
369
|
-
|
|
370
|
-
if (fs.existsSync(targetPath)) {
|
|
371
|
-
await fs.remove(targetPath);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Realizar instalación nueva
|
|
376
|
-
await this.performInstallation();
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
showPostInstallMessage() {
|
|
381
|
-
console.log('\n📚 Carpetas instaladas:');
|
|
382
|
-
this.folderMappings.forEach(mapping => {
|
|
383
|
-
const targetPath = path.join(this.targetDir, mapping.target);
|
|
384
|
-
if (fs.existsSync(targetPath)) {
|
|
385
|
-
console.log(` ✓ ${mapping.target}`);
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
console.log('\n🎉 ¡Instalación completada!');
|
|
390
|
-
console.log('💡 Las carpetas han sido instaladas en tu directorio actual.');
|
|
391
|
-
console.log('🔧 Puedes ejecutar "npx siesa-agents" nuevamente para actualizar.');
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Ejecutar instalación si el script es llamado directamente
|
|
396
|
-
if (require.main === module) {
|
|
397
|
-
const installer = new SiesaBmadInstaller();
|
|
398
|
-
installer.install();
|
|
399
|
-
}
|
|
400
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
|
|
7
|
+
class SiesaBmadInstaller {
|
|
8
|
+
constructor() {
|
|
9
|
+
// Definir las carpetas primero (nombres en el paquete vs nombres finales)
|
|
10
|
+
this.folderMappings = [
|
|
11
|
+
{ source: 'bmad-core', target: '.bmad-core' },
|
|
12
|
+
{ source: 'vscode', target: '.vscode' },
|
|
13
|
+
{ source: 'github', target: '.github' },
|
|
14
|
+
{ source: 'claude', target: '.claude' }
|
|
15
|
+
];
|
|
16
|
+
this.targetDir = process.cwd();
|
|
17
|
+
// Intentar múltiples ubicaciones posibles para el paquete
|
|
18
|
+
this.packageDir = this.findPackageDir();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
showBanner() {
|
|
22
|
+
console.log('\n');
|
|
23
|
+
console.log('███████╗██╗███████╗███████╗ █████╗ █████╗ ██████╗ ███████╗███╗ ██╗████████╗███████╗');
|
|
24
|
+
console.log('██╔════╝██║██╔════╝██╔════╝██╔══██╗ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔════╝');
|
|
25
|
+
console.log('███████╗██║█████╗ ███████╗███████║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ███████╗');
|
|
26
|
+
console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║');
|
|
27
|
+
console.log('███████║██║███████╗███████║██║ ██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║');
|
|
28
|
+
console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝');
|
|
29
|
+
console.log('');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
findPackageDir() {
|
|
33
|
+
// Opción 1: directorio padre del bin (instalación normal)
|
|
34
|
+
let packageDir = path.dirname(__dirname);
|
|
35
|
+
|
|
36
|
+
// Opción 2: si estamos en npx, buscar en node_modules
|
|
37
|
+
if (!this.hasRequiredFolders(packageDir)) {
|
|
38
|
+
// Para npm 6.14+ y npx, intentar ubicaciones alternativas
|
|
39
|
+
const possiblePaths = [
|
|
40
|
+
path.join(__dirname, '..'), // bin -> paquete
|
|
41
|
+
path.resolve(__dirname, '..'), // alternativa con resolve
|
|
42
|
+
path.resolve(__dirname, '..', '..', 'siesa-bmad-agents'), // desde node_modules
|
|
43
|
+
// Intentar buscar basado en __dirname específicamente para npx
|
|
44
|
+
path.resolve(__dirname.replace(/\\bin$|\/bin$/, '')),
|
|
45
|
+
process.cwd(), // directorio actual como último recurso
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
for (const possiblePath of possiblePaths) {
|
|
49
|
+
if (this.hasRequiredFolders(possiblePath)) {
|
|
50
|
+
packageDir = possiblePath;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return packageDir;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
hasRequiredFolders(dir) {
|
|
60
|
+
return this.folderMappings.some(mapping => {
|
|
61
|
+
const folderPath = path.join(dir, mapping.source);
|
|
62
|
+
return fs.existsSync(folderPath);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async install() {
|
|
67
|
+
this.showBanner();
|
|
68
|
+
console.log(' Instalando SIESA Agents...');
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Verificar si ya existe una instalación
|
|
72
|
+
const hasExistingInstallation = this.checkExistingInstallation();
|
|
73
|
+
|
|
74
|
+
if (hasExistingInstallation) {
|
|
75
|
+
console.log('🔄 Instalación existente detectada. Actualizando...');
|
|
76
|
+
await this.update();
|
|
77
|
+
} else {
|
|
78
|
+
console.log('✨ Nueva instalación...');
|
|
79
|
+
await this.performInstallation();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log('✅ SIESA Agents instalado correctamente!');
|
|
83
|
+
this.showPostInstallMessage();
|
|
84
|
+
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('❌ Error durante la instalación:', error.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
checkExistingInstallation() {
|
|
92
|
+
return this.folderMappings.some(mapping => {
|
|
93
|
+
const targetPath = path.join(this.targetDir, mapping.target);
|
|
94
|
+
return fs.existsSync(targetPath);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async checkModifiedFiles() {
|
|
99
|
+
const modifiedFiles = [];
|
|
100
|
+
|
|
101
|
+
for (const mapping of this.folderMappings) {
|
|
102
|
+
const sourcePath = path.join(this.packageDir, mapping.source);
|
|
103
|
+
const targetPath = path.join(this.targetDir, mapping.target);
|
|
104
|
+
|
|
105
|
+
if (!fs.existsSync(sourcePath) || !fs.existsSync(targetPath)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Obtener todos los archivos recursivamente
|
|
110
|
+
const sourceFiles = await this.getAllFiles(sourcePath);
|
|
111
|
+
|
|
112
|
+
for (const sourceFile of sourceFiles) {
|
|
113
|
+
const relativePath = path.relative(sourcePath, sourceFile);
|
|
114
|
+
const targetFile = path.join(targetPath, relativePath);
|
|
115
|
+
|
|
116
|
+
if (fs.existsSync(targetFile)) {
|
|
117
|
+
try {
|
|
118
|
+
// Comparar contenido de archivos
|
|
119
|
+
const sourceContent = await fs.readFile(sourceFile, 'utf8');
|
|
120
|
+
const targetContent = await fs.readFile(targetFile, 'utf8');
|
|
121
|
+
|
|
122
|
+
if (sourceContent !== targetContent) {
|
|
123
|
+
modifiedFiles.push({
|
|
124
|
+
folder: mapping.target,
|
|
125
|
+
file: relativePath,
|
|
126
|
+
fullPath: targetFile
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
// Si no se puede leer como texto, comparar como buffer (archivos binarios)
|
|
131
|
+
const sourceBuffer = await fs.readFile(sourceFile);
|
|
132
|
+
const targetBuffer = await fs.readFile(targetFile);
|
|
133
|
+
|
|
134
|
+
if (!sourceBuffer.equals(targetBuffer)) {
|
|
135
|
+
modifiedFiles.push({
|
|
136
|
+
folder: mapping.target,
|
|
137
|
+
file: relativePath,
|
|
138
|
+
fullPath: targetFile
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return modifiedFiles;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async getAllFiles(dir) {
|
|
150
|
+
const files = [];
|
|
151
|
+
const items = await fs.readdir(dir);
|
|
152
|
+
|
|
153
|
+
for (const item of items) {
|
|
154
|
+
const fullPath = path.join(dir, item);
|
|
155
|
+
const stat = await fs.stat(fullPath);
|
|
156
|
+
|
|
157
|
+
if (stat.isDirectory()) {
|
|
158
|
+
const subFiles = await this.getAllFiles(fullPath);
|
|
159
|
+
files.push(...subFiles);
|
|
160
|
+
} else {
|
|
161
|
+
files.push(fullPath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return files;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async promptUser(modifiedFiles) {
|
|
169
|
+
console.log('\n⚠️ Se detectaron archivos modificados:');
|
|
170
|
+
|
|
171
|
+
// Agrupar por carpeta
|
|
172
|
+
const filesByFolder = {};
|
|
173
|
+
modifiedFiles.forEach(item => {
|
|
174
|
+
if (!filesByFolder[item.folder]) {
|
|
175
|
+
filesByFolder[item.folder] = [];
|
|
176
|
+
}
|
|
177
|
+
filesByFolder[item.folder].push(item.file);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Mostrar archivos modificados por carpeta
|
|
181
|
+
Object.keys(filesByFolder).forEach(folder => {
|
|
182
|
+
console.log(`\n📁 ${folder}:`);
|
|
183
|
+
filesByFolder[folder].forEach(file => {
|
|
184
|
+
console.log(` - ${file}`);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
console.log('\n¿Qué deseas hacer?');
|
|
189
|
+
console.log('1. Reemplazar todos los archivos (se perderán las modificaciones)');
|
|
190
|
+
console.log('2. Hacer backup de archivos modificados (se agregarán con sufijo _bk)');
|
|
191
|
+
|
|
192
|
+
const rl = readline.createInterface({
|
|
193
|
+
input: process.stdin,
|
|
194
|
+
output: process.stdout
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return new Promise((resolve) => {
|
|
198
|
+
rl.question('\nElige una opción (1 o 2): ', (answer) => {
|
|
199
|
+
rl.close();
|
|
200
|
+
resolve(answer.trim());
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async backupModifiedFiles(modifiedFiles) {
|
|
206
|
+
console.log('\n🔄 Creando backup de archivos modificados...');
|
|
207
|
+
|
|
208
|
+
for (const item of modifiedFiles) {
|
|
209
|
+
const originalPath = item.fullPath;
|
|
210
|
+
const backupPath = this.getBackupPath(originalPath);
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
await fs.copy(originalPath, backupPath);
|
|
214
|
+
|
|
215
|
+
// Determinar tipo de backup para mostrar mensaje apropiado
|
|
216
|
+
const backupName = path.basename(backupPath);
|
|
217
|
+
const isVersionedBackup = backupName.includes('_bk_');
|
|
218
|
+
|
|
219
|
+
if (isVersionedBackup) {
|
|
220
|
+
console.log(`✓ Backup versionado: ${path.relative(this.targetDir, backupPath)}`);
|
|
221
|
+
} else {
|
|
222
|
+
console.log(`✓ Backup creado: ${path.relative(this.targetDir, backupPath)}`);
|
|
223
|
+
}
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.warn(`⚠️ Error creando backup de ${item.file}: ${error.message}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
getBackupPath(filePath) {
|
|
231
|
+
const dir = path.dirname(filePath);
|
|
232
|
+
const ext = path.extname(filePath);
|
|
233
|
+
const name = path.basename(filePath, ext);
|
|
234
|
+
|
|
235
|
+
// Primer intento: archivo_bk.ext
|
|
236
|
+
const basicBackupPath = path.join(dir, `${name}_bk${ext}`);
|
|
237
|
+
|
|
238
|
+
// Si no existe, usar el nombre básico
|
|
239
|
+
if (!fs.existsSync(basicBackupPath)) {
|
|
240
|
+
return basicBackupPath;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Si ya existe _bk, crear versión con timestamp
|
|
244
|
+
const now = new Date();
|
|
245
|
+
const timestamp = now.getFullYear().toString() +
|
|
246
|
+
(now.getMonth() + 1).toString().padStart(2, '0') +
|
|
247
|
+
now.getDate().toString().padStart(2, '0') + '_' +
|
|
248
|
+
now.getHours().toString().padStart(2, '0') +
|
|
249
|
+
now.getMinutes().toString().padStart(2, '0') +
|
|
250
|
+
now.getSeconds().toString().padStart(2, '0');
|
|
251
|
+
|
|
252
|
+
return path.join(dir, `${name}_bk_${timestamp}${ext}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async performUpdateWithBackups() {
|
|
256
|
+
for (const mapping of this.folderMappings) {
|
|
257
|
+
const sourcePath = path.join(this.packageDir, mapping.source);
|
|
258
|
+
const targetPath = path.join(this.targetDir, mapping.target);
|
|
259
|
+
|
|
260
|
+
if (fs.existsSync(sourcePath)) {
|
|
261
|
+
// Copiar archivos selectivamente, preservando los _bk
|
|
262
|
+
await this.copyWithBackupPreservation(sourcePath, targetPath);
|
|
263
|
+
} else {
|
|
264
|
+
console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async copyWithBackupPreservation(sourcePath, targetPath) {
|
|
270
|
+
// Obtener todos los archivos backup existentes
|
|
271
|
+
const backupFiles = await this.findBackupFiles(targetPath);
|
|
272
|
+
|
|
273
|
+
// Copiar la carpeta completa sobrescribiendo
|
|
274
|
+
await fs.copy(sourcePath, targetPath, {
|
|
275
|
+
overwrite: true,
|
|
276
|
+
recursive: true
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Restaurar los archivos backup
|
|
280
|
+
for (const backupFile of backupFiles) {
|
|
281
|
+
const backupSourcePath = backupFile.tempPath;
|
|
282
|
+
const backupTargetPath = backupFile.originalPath;
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
await fs.copy(backupSourcePath, backupTargetPath);
|
|
286
|
+
// Limpiar archivo temporal
|
|
287
|
+
await fs.remove(backupSourcePath);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.warn(`⚠️ Error restaurando backup ${backupFile.relativePath}: ${error.message}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async findBackupFiles(targetPath) {
|
|
295
|
+
if (!fs.existsSync(targetPath)) {
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const backupFiles = [];
|
|
300
|
+
const allFiles = await this.getAllFiles(targetPath);
|
|
301
|
+
|
|
302
|
+
for (const filePath of allFiles) {
|
|
303
|
+
const fileName = path.basename(filePath);
|
|
304
|
+
// Detectar archivos _bk y _bk_timestamp
|
|
305
|
+
if (fileName.includes('_bk')) {
|
|
306
|
+
const tempPath = path.join(require('os').tmpdir(), `backup_${Date.now()}_${fileName}`);
|
|
307
|
+
const relativePath = path.relative(targetPath, filePath);
|
|
308
|
+
|
|
309
|
+
// Crear copia temporal del backup
|
|
310
|
+
await fs.copy(filePath, tempPath);
|
|
311
|
+
|
|
312
|
+
backupFiles.push({
|
|
313
|
+
originalPath: filePath,
|
|
314
|
+
tempPath: tempPath,
|
|
315
|
+
relativePath: relativePath
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return backupFiles;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async performInstallation() {
|
|
324
|
+
for (const mapping of this.folderMappings) {
|
|
325
|
+
const sourcePath = path.join(this.packageDir, mapping.source);
|
|
326
|
+
const targetPath = path.join(this.targetDir, mapping.target);
|
|
327
|
+
|
|
328
|
+
if (fs.existsSync(sourcePath)) {
|
|
329
|
+
await fs.copy(sourcePath, targetPath, {
|
|
330
|
+
overwrite: true,
|
|
331
|
+
recursive: true
|
|
332
|
+
});
|
|
333
|
+
} else {
|
|
334
|
+
console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async update() {
|
|
340
|
+
// Verificar archivos modificados
|
|
341
|
+
console.log('🔍 Verificando archivos modificados...');
|
|
342
|
+
const modifiedFiles = await this.checkModifiedFiles();
|
|
343
|
+
|
|
344
|
+
let hasBackups = false;
|
|
345
|
+
if (modifiedFiles.length > 0) {
|
|
346
|
+
const userChoice = await this.promptUser(modifiedFiles);
|
|
347
|
+
|
|
348
|
+
if (userChoice === '2') {
|
|
349
|
+
// Crear backup de archivos modificados
|
|
350
|
+
await this.backupModifiedFiles(modifiedFiles);
|
|
351
|
+
hasBackups = true;
|
|
352
|
+
} else if (userChoice !== '1') {
|
|
353
|
+
console.log('❌ Opción no válida. Cancelando actualización.');
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
console.log('\n🔄 Procediendo con la actualización...');
|
|
358
|
+
} else {
|
|
359
|
+
console.log('✓ No se detectaron archivos modificados.');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Si hay backups, hacer actualización preservando backups
|
|
363
|
+
if (hasBackups) {
|
|
364
|
+
await this.performUpdateWithBackups();
|
|
365
|
+
} else {
|
|
366
|
+
// Si no hay backups, hacer actualización normal (remover y copiar)
|
|
367
|
+
for (const mapping of this.folderMappings) {
|
|
368
|
+
const targetPath = path.join(this.targetDir, mapping.target);
|
|
369
|
+
|
|
370
|
+
if (fs.existsSync(targetPath)) {
|
|
371
|
+
await fs.remove(targetPath);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Realizar instalación nueva
|
|
376
|
+
await this.performInstallation();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
showPostInstallMessage() {
|
|
381
|
+
console.log('\n📚 Carpetas instaladas:');
|
|
382
|
+
this.folderMappings.forEach(mapping => {
|
|
383
|
+
const targetPath = path.join(this.targetDir, mapping.target);
|
|
384
|
+
if (fs.existsSync(targetPath)) {
|
|
385
|
+
console.log(` ✓ ${mapping.target}`);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
console.log('\n🎉 ¡Instalación completada!');
|
|
390
|
+
console.log('💡 Las carpetas han sido instaladas en tu directorio actual.');
|
|
391
|
+
console.log('🔧 Puedes ejecutar "npx siesa-agents" nuevamente para actualizar.');
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Ejecutar instalación si el script es llamado directamente
|
|
396
|
+
if (require.main === module) {
|
|
397
|
+
const installer = new SiesaBmadInstaller();
|
|
398
|
+
installer.install();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
401
|
module.exports = SiesaBmadInstaller;
|