siesa-agents 2.1.25 → 2.1.26-dev.0

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
 
@@ -52,7 +52,6 @@ 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
56
55
 
57
56
  ## Características
58
57
 
@@ -71,17 +70,22 @@ El paquete instala las siguientes carpetas en tu directorio actual:
71
70
 
72
71
  Para actualizar una instalación existente, simplemente ejecuta el comando nuevamente:
73
72
 
73
+ **Versión estable (recomendado):**
74
74
  ```bash
75
75
  npx siesa-agents
76
76
  ```
77
77
 
78
+ **Versión de desarrollo:**
79
+ ```bash
80
+ npx siesa-agents@dev
81
+ ```
82
+
78
83
  El sistema detectará automáticamente que ya existe una instalación y la actualizará.
79
84
 
80
85
  ## Requisitos
81
86
 
82
87
  - Node.js >= 14.0.0
83
88
  - npm >= 6.0.0
84
- - Python >= 3.7 (requerido para hooks de Claude Code)
85
89
 
86
90
  ## Estructura de archivos instalados
87
91
 
@@ -95,6 +99,8 @@ tu-proyecto/
95
99
  └── [workflows y configuración de GitHub]
96
100
  ```
97
101
 
102
+
103
+
98
104
  ## Soporte
99
105
 
100
106
  Si encuentras algún problema durante la instalación, por favor verifica:
@@ -109,7 +115,4 @@ MIT
109
115
 
110
116
  ## Autor
111
117
 
112
- SIESA - Sistemas de Información Empresarial
113
-
114
- ---
115
- *Versión actualizada automáticamente por CI/CD*
118
+ SIESA - Sistemas de Información Empresarial
package/bin/install.js CHANGED
@@ -4,6 +4,7 @@ const fs = require('fs-extra');
4
4
  const path = require('path');
5
5
  const readline = require('readline');
6
6
 
7
+
7
8
  class SiesaBmadInstaller {
8
9
  constructor() {
9
10
  // Definir las carpetas primero (nombres en el paquete vs nombres finales)
@@ -15,18 +16,9 @@ class SiesaBmadInstaller {
15
16
  { source: 'kiro', target: '.kiro' },
16
17
  { source: 'resources', target: '.resources' }
17
18
  ];
18
-
19
- // Lista de archivos que se preservan automáticamente (no se crean backups)
20
- this.ignoredFiles = [
21
- 'data/technical-preferences.md'
22
- ];
23
-
24
19
  this.targetDir = process.cwd();
25
20
  // Intentar múltiples ubicaciones posibles para el paquete
26
21
  this.packageDir = this.findPackageDir();
27
-
28
- // Almacenamiento temporal para contenido de archivos ignorados
29
- this.preservedContent = new Map();
30
22
  }
31
23
 
32
24
  showBanner() {
@@ -37,7 +29,8 @@ class SiesaBmadInstaller {
37
29
  console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║');
38
30
  console.log('███████║██║███████╗███████║██║ ██║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║');
39
31
  console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝');
40
- console.log('');
32
+ console.log('Version de Desarrollador Prueba Arnol');
33
+ console.log('\n');
41
34
  }
42
35
 
43
36
  findPackageDir() {
@@ -134,8 +127,7 @@ class SiesaBmadInstaller {
134
127
  modifiedFiles.push({
135
128
  folder: mapping.target,
136
129
  file: relativePath,
137
- fullPath: targetFile,
138
- is_ignored: this.ignoredFiles.includes(relativePath)
130
+ fullPath: targetFile
139
131
  });
140
132
  }
141
133
  } catch (error) {
@@ -147,8 +139,7 @@ class SiesaBmadInstaller {
147
139
  modifiedFiles.push({
148
140
  folder: mapping.target,
149
141
  file: relativePath,
150
- fullPath: targetFile,
151
- is_ignored: this.ignoredFiles.includes(relativePath)
142
+ fullPath: targetFile
152
143
  });
153
144
  }
154
145
  }
@@ -179,10 +170,6 @@ class SiesaBmadInstaller {
179
170
  }
180
171
 
181
172
  async promptUser(modifiedFiles) {
182
-
183
- const hasNonIgnoredFiles = modifiedFiles.some(file => file.is_ignored == false)
184
- if (!hasNonIgnoredFiles) return '2'
185
-
186
173
  console.log('\n⚠️ Se detectaron archivos modificados:');
187
174
 
188
175
  // Agrupar por carpeta
@@ -223,12 +210,6 @@ class SiesaBmadInstaller {
223
210
  console.log('\n🔄 Creando backup de archivos modificados...');
224
211
 
225
212
  for (const item of modifiedFiles) {
226
- // No crear backup de archivos ignorados
227
- if (item.is_ignored) {
228
- console.log(`✓ Preservando: ${item.file} (sin backup)`);
229
- continue;
230
- }
231
-
232
213
  const originalPath = item.fullPath;
233
214
  const backupPath = this.getBackupPath(originalPath);
234
215
 
@@ -292,20 +273,11 @@ class SiesaBmadInstaller {
292
273
  async copyWithBackupPreservation(sourcePath, targetPath) {
293
274
  // Obtener todos los archivos backup existentes
294
275
  const backupFiles = await this.findBackupFiles(targetPath);
295
-
296
- // Copiar la carpeta preservando technical-preferences.md
276
+
277
+ // Copiar la carpeta completa sobrescribiendo
297
278
  await fs.copy(sourcePath, targetPath, {
298
279
  overwrite: true,
299
- recursive: true,
300
- filter: (src) => {
301
- const relativePath = path.relative(sourcePath, src);
302
- // No sobrescribir archivos ignorados si ya existen
303
- if (this.ignoredFiles.includes(relativePath)) {
304
- const targetFile = path.join(targetPath, relativePath);
305
- return !fs.existsSync(targetFile);
306
- }
307
- return true;
308
- }
280
+ recursive: true
309
281
  });
310
282
 
311
283
  // Restaurar los archivos backup
@@ -360,16 +332,7 @@ class SiesaBmadInstaller {
360
332
  if (fs.existsSync(sourcePath)) {
361
333
  await fs.copy(sourcePath, targetPath, {
362
334
  overwrite: true,
363
- recursive: true,
364
- filter: (src) => {
365
- const relativePath = path.relative(sourcePath, src);
366
- // No sobrescribir archivos ignorados si ya existen
367
- if (this.ignoredFiles.includes(relativePath)) {
368
- const targetFile = path.join(targetPath, relativePath);
369
- return !fs.existsSync(targetFile);
370
- }
371
- return true;
372
- }
335
+ recursive: true
373
336
  });
374
337
  } else {
375
338
  console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
@@ -405,9 +368,6 @@ class SiesaBmadInstaller {
405
368
  await this.performUpdateWithBackups();
406
369
  } else {
407
370
  // Si no hay backups, hacer actualización normal (remover y copiar)
408
- // Pero primero preservar archivos ignorados
409
- await this.preserveIgnoredFiles();
410
-
411
371
  for (const mapping of this.folderMappings) {
412
372
  const targetPath = path.join(this.targetDir, mapping.target);
413
373
 
@@ -418,64 +378,7 @@ class SiesaBmadInstaller {
418
378
 
419
379
  // Realizar instalación nueva
420
380
  await this.performInstallation();
421
-
422
- // Restaurar archivos ignorados
423
- await this.restoreIgnoredFiles();
424
- }
425
- }
426
-
427
- async preserveIgnoredFiles() {
428
- console.log('🔒 Preservando archivos de configuración...');
429
-
430
- for (const mapping of this.folderMappings) {
431
- const targetFolderPath = path.join(this.targetDir, mapping.target);
432
-
433
- if (!fs.existsSync(targetFolderPath)) {
434
- continue;
435
- }
436
-
437
- for (const ignoredFile of this.ignoredFiles) {
438
- const filePath = path.join(targetFolderPath, ignoredFile);
439
-
440
- if (fs.existsSync(filePath)) {
441
- try {
442
- const content = await fs.readFile(filePath, 'utf8');
443
- const key = `${mapping.target}/${ignoredFile}`;
444
- this.preservedContent.set(key, content);
445
- console.log(`✓ Preservando: ${ignoredFile}`);
446
- } catch (error) {
447
- console.warn(`⚠️ Error leyendo ${ignoredFile}: ${error.message}`);
448
- }
449
- }
450
- }
451
- }
452
- }
453
-
454
- async restoreIgnoredFiles() {
455
- if (this.preservedContent.size === 0) {
456
- return;
457
- }
458
-
459
- console.log('🔄 Restaurando archivos de configuración...');
460
-
461
- for (const [key, content] of this.preservedContent) {
462
- const [targetFolder, ...filePathParts] = key.split('/');
463
- const filePath = path.join(this.targetDir, targetFolder, ...filePathParts);
464
-
465
- try {
466
- // Asegurar que el directorio existe
467
- await fs.ensureDir(path.dirname(filePath));
468
-
469
- // Restaurar el contenido
470
- await fs.writeFile(filePath, content, 'utf8');
471
- console.log(`✓ Restaurado: ${filePathParts.join('/')}`);
472
- } catch (error) {
473
- console.warn(`⚠️ Error restaurando ${filePathParts.join('/')}: ${error.message}`);
474
- }
475
381
  }
476
-
477
- // Limpiar el mapa después de restaurar
478
- this.preservedContent.clear();
479
382
  }
480
383
 
481
384
  showPostInstallMessage() {
@@ -81,8 +81,6 @@ dependencies:
81
81
  - architect-checklist.md
82
82
  data:
83
83
  - technical-preferences.md
84
- - technology-stack.md
85
- - architecture-patterns.md
86
84
  tasks:
87
85
  - create-deep-research-prompt.md
88
86
  - create-doc.md
@@ -60,7 +60,6 @@ commands:
60
60
  dependencies:
61
61
  data:
62
62
  - technical-preferences.md
63
- - technology-stack.md
64
63
  - technical-preferences-ux.md
65
64
  tasks:
66
65
  - create-doc.md
@@ -1,32 +1,43 @@
1
1
  # Backend Development Standards
2
2
 
3
- > **Note**: For architecture patterns and principles (Hexagonal Architecture, DDD, folder structure), see [architecture-patterns.md](./architecture-patterns.md)
3
+ ## Architecture Principles
4
+
5
+ ### Hexagonal Architecture Implementation
6
+ - **Application Core**: Domain entities, value objects, aggregates, and domain services
7
+ - **Primary Ports**: Use cases, commands, queries, and application services
8
+ - **Primary Adapters**: REST controllers, GraphQL resolvers, message handlers
9
+ - **Secondary Ports**: Repository interfaces, external service interfaces
10
+ - **Secondary Adapters**: Prisma repositories, HTTP clients, message publishers
11
+
12
+ ### Dependency Rules
13
+ - Application core must not depend on external frameworks
14
+ - All dependencies point inward toward the domain
15
+ - Use dependency inversion for all external concerns
16
+ - Interfaces defined in application layer, implementations in infrastructure
4
17
 
5
18
  ## Technology Stack Standards
6
19
 
7
20
  ### Core Technologies
8
21
  - **NestJS**: 10+ with TypeScript and decorators
9
22
  - **TypeScript**: Strict mode enabled, no `any` types
10
- - **Prisma**: ORM for database operations (no raw queries allowed)
11
- - **Jest + Supertest**: Unit, integration, and E2E testing
12
- - **Class-validator + Class-transformer**: DTO validation
23
+ - **Prisma**: ORM for database operations (no raw queries)
24
+ - **Jest**: Unit and integration testing
25
+ - **Class-validator**: Request validation and transformation
13
26
 
14
- ### Framework Standards
15
- - **Default Framework**: NestJS 10+ with TypeScript
16
- - **Database**: Prisma ORM only - no raw SQL queries
17
- - **Testing**: TDD approach with comprehensive test coverage
18
- - **Documentation**: Swagger/OpenAPI auto-generated from decorators
19
- - **Messaging**: NestJS Microservices (Redis, RabbitMQ, or gRPC)
27
+ ### Framework Selection Rules
28
+ - **Default**: Always use NestJS 10+ with TypeScript
29
+ - **Database**: Prisma ORM only - no raw SQL queries allowed
30
+ - **Testing**: TDD approach with Jest and Supertest
31
+ - **Documentation**: Swagger/OpenAPI for all endpoints
20
32
 
21
33
  ### Development Tools
22
- - **Nx**: MonoRepo management and build orchestration
34
+ - **Nx**: MonoRepo management and build system
23
35
  - **ESLint + Prettier**: Code quality and formatting
24
- - **Husky**: Pre-commit hooks for quality gates
25
- - **Winston**: Structured logging with log levels
26
- - **Redis**: Caching, session storage, and message transport
27
- - **Passport + JWT**: Authentication and authorization
36
+ - **Husky**: Git hooks for pre-commit validation
37
+ - **Winston**: Structured logging
38
+ - **Redis**: Caching and message transport
28
39
 
29
- ## Domain-Driven Design Implementation
40
+ ## Domain-Driven Design Standards
30
41
 
31
42
  ### Entity Structure
32
43
  ```typescript
@@ -35,6 +46,7 @@ export class UserEntity extends AggregateRoot {
35
46
  public readonly id: UserId,
36
47
  private _email: EmailValueObject,
37
48
  private _name: NameValueObject,
49
+ private _createdAt: Date,
38
50
  ) {
39
51
  super();
40
52
  }
@@ -44,6 +56,7 @@ export class UserEntity extends AggregateRoot {
44
56
  UserId.generate(),
45
57
  EmailValueObject.create(props.email),
46
58
  NameValueObject.create(props.name),
59
+ new Date(),
47
60
  );
48
61
  user.addDomainEvent(new UserCreatedEvent(user.id));
49
62
  return user;
@@ -78,6 +91,11 @@ export class EmailValueObject {
78
91
  }
79
92
  }
80
93
 
94
+ private isValidEmail(email: string): boolean {
95
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
96
+ return emailRegex.test(email);
97
+ }
98
+
81
99
  equals(other: EmailValueObject): boolean {
82
100
  return this.value === other.value;
83
101
  }
@@ -88,45 +106,15 @@ export class EmailValueObject {
88
106
  }
89
107
  ```
90
108
 
91
- ### Repository Pattern
109
+ ### Repository Interface Pattern
92
110
  ```typescript
93
- // Interface (in application/ports/repositories)
94
111
  export interface UserRepositoryInterface {
95
112
  save(user: UserEntity): Promise<UserEntity>;
96
113
  findById(id: UserId): Promise<UserEntity | null>;
97
114
  findByEmail(email: EmailValueObject): Promise<UserEntity | null>;
115
+ findAll(criteria: FindUsersCriteria): Promise<UserEntity[]>;
98
116
  delete(id: UserId): Promise<void>;
99
117
  }
100
-
101
- // Implementation (in infrastructure/repositories)
102
- @Injectable()
103
- export class PrismaUserRepository implements UserRepositoryInterface {
104
- constructor(private readonly prisma: PrismaService) {}
105
-
106
- async save(user: UserEntity): Promise<UserEntity> {
107
- const data = {
108
- id: user.id.toString(),
109
- email: user.email.toString(),
110
- name: user.name.toString(),
111
- };
112
-
113
- const savedUser = await this.prisma.user.upsert({
114
- where: { id: data.id },
115
- update: data,
116
- create: data,
117
- });
118
-
119
- return this.toDomain(savedUser);
120
- }
121
-
122
- private toDomain(prismaUser: User): UserEntity {
123
- return UserEntity.reconstitute({
124
- id: UserId.create(prismaUser.id),
125
- email: EmailValueObject.create(prismaUser.email),
126
- name: NameValueObject.create(prismaUser.name),
127
- });
128
- }
129
- }
130
118
  ```
131
119
 
132
120
  ## Use Case Standards
@@ -145,19 +133,20 @@ export class CreateUserUseCase {
145
133
  async execute(command: CreateUserCommand): Promise<UserResponseDto> {
146
134
  // 1. Validate business rules
147
135
  await this.validateUserDoesNotExist(command.email);
148
-
136
+
149
137
  // 2. Create domain entity
150
138
  const user = UserEntity.create({
151
139
  email: command.email,
152
140
  name: command.name,
153
141
  });
154
-
142
+
155
143
  // 3. Persist entity
156
144
  const savedUser = await this.userRepository.save(user);
157
-
145
+
158
146
  // 4. Publish domain events
159
147
  await this.eventBus.publishAll(savedUser.getUncommittedEvents());
160
-
148
+ savedUser.markEventsAsCommitted();
149
+
161
150
  // 5. Return response DTO
162
151
  return UserResponseDto.fromEntity(savedUser);
163
152
  }
@@ -183,16 +172,20 @@ export class CreateUserCommand {
183
172
  @IsNotEmpty()
184
173
  @Length(2, 50)
185
174
  readonly name: string;
175
+
176
+ @IsOptional()
177
+ @IsString()
178
+ readonly organizationId?: string;
186
179
  }
187
180
  ```
188
181
 
189
182
  ## Testing Standards
190
183
 
191
184
  ### Testing Strategy
192
- - **Unit Tests**: Domain entities, value objects, use cases (isolated logic)
193
- - **Integration Tests**: Repository implementations, database operations
194
- - **E2E Tests**: Complete API workflows with Supertest
195
- - **TDD Approach**: Write tests before implementation
185
+ - **Unit Tests**: Domain entities, value objects, use cases
186
+ - **Integration Tests**: Repository implementations, external services
187
+ - **E2E Tests**: Complete API workflows
188
+ - **Contract Tests**: External service integrations
196
189
 
197
190
  ### Test Structure
198
191
  ```typescript
@@ -205,8 +198,19 @@ describe('CreateUserUseCase', () => {
205
198
  const module = await Test.createTestingModule({
206
199
  providers: [
207
200
  CreateUserUseCase,
208
- { provide: USER_REPOSITORY, useValue: { save: jest.fn(), findByEmail: jest.fn() } },
209
- { provide: EVENT_BUS, useValue: { publishAll: jest.fn() } },
201
+ {
202
+ provide: USER_REPOSITORY,
203
+ useValue: {
204
+ save: jest.fn(),
205
+ findByEmail: jest.fn(),
206
+ },
207
+ },
208
+ {
209
+ provide: EVENT_BUS,
210
+ useValue: {
211
+ publishAll: jest.fn(),
212
+ },
213
+ },
210
214
  ],
211
215
  }).compile();
212
216
 
@@ -215,33 +219,46 @@ describe('CreateUserUseCase', () => {
215
219
  eventBus = module.get(EVENT_BUS);
216
220
  });
217
221
 
218
- it('should create user successfully', async () => {
219
- // Arrange
220
- const command = new CreateUserCommand();
221
- command.email = 'test@example.com';
222
- command.name = 'Test User';
222
+ describe('execute', () => {
223
+ it('should create user successfully', async () => {
224
+ // Arrange
225
+ const command = new CreateUserCommand();
226
+ command.email = 'test@example.com';
227
+ command.name = 'Test User';
223
228
 
224
- userRepository.findByEmail.mockResolvedValue(null);
225
- userRepository.save.mockResolvedValue(UserEntity.create(command));
229
+ const expectedUser = UserEntity.create({
230
+ email: command.email,
231
+ name: command.name,
232
+ });
226
233
 
227
- // Act
228
- const result = await useCase.execute(command);
234
+ userRepository.findByEmail.mockResolvedValue(null);
235
+ userRepository.save.mockResolvedValue(expectedUser);
229
236
 
230
- // Assert
231
- expect(result.email).toBe(command.email);
232
- expect(userRepository.save).toHaveBeenCalledWith(expect.any(UserEntity));
233
- expect(eventBus.publishAll).toHaveBeenCalled();
234
- });
237
+ // Act
238
+ const result = await useCase.execute(command);
235
239
 
236
- it('should throw error when user already exists', async () => {
237
- // Arrange
238
- const command = new CreateUserCommand();
239
- command.email = 'existing@example.com';
240
+ // Assert
241
+ expect(result.email).toBe(command.email);
242
+ expect(userRepository.save).toHaveBeenCalledWith(expect.any(UserEntity));
243
+ expect(eventBus.publishAll).toHaveBeenCalled();
244
+ });
240
245
 
241
- userRepository.findByEmail.mockResolvedValue(UserEntity.create(command));
246
+ it('should throw error when user already exists', async () => {
247
+ // Arrange
248
+ const command = new CreateUserCommand();
249
+ command.email = 'existing@example.com';
250
+ command.name = 'Test User';
242
251
 
243
- // Act & Assert
244
- await expect(useCase.execute(command)).rejects.toThrow(UserAlreadyExistsException);
252
+ const existingUser = UserEntity.create({
253
+ email: command.email,
254
+ name: 'Existing User',
255
+ });
256
+
257
+ userRepository.findByEmail.mockResolvedValue(existingUser);
258
+
259
+ // Act & Assert
260
+ await expect(useCase.execute(command)).rejects.toThrow(UserAlreadyExistsException);
261
+ });
245
262
  });
246
263
  });
247
264
  ```
@@ -260,20 +277,23 @@ export class UserController {
260
277
 
261
278
  @Post()
262
279
  @ApiOperation({ summary: 'Create a new user' })
263
- @ApiResponse({ status: 201, type: UserResponseDto })
280
+ @ApiResponse({ status: 201, description: 'User created successfully', type: UserResponseDto })
264
281
  @ApiResponse({ status: 400, description: 'Bad request' })
265
- async createUser(@Body() dto: CreateUserDto): Promise<UserResponseDto> {
282
+ @ApiResponse({ status: 409, description: 'User already exists' })
283
+ async createUser(@Body() createUserDto: CreateUserDto): Promise<UserResponseDto> {
266
284
  const command = new CreateUserCommand();
267
- Object.assign(command, dto);
285
+ Object.assign(command, createUserDto);
268
286
  return this.createUserUseCase.execute(command);
269
287
  }
270
288
 
271
289
  @Get(':id')
272
290
  @ApiOperation({ summary: 'Get user by ID' })
273
- @ApiResponse({ status: 200, type: UserResponseDto })
291
+ @ApiParam({ name: 'id', description: 'User ID' })
292
+ @ApiResponse({ status: 200, description: 'User found', type: UserResponseDto })
274
293
  @ApiResponse({ status: 404, description: 'User not found' })
275
294
  async getUser(@Param('id', ParseUUIDPipe) id: string): Promise<UserResponseDto> {
276
- return this.getUserUseCase.execute(new GetUserQuery(id));
295
+ const query = new GetUserQuery(id);
296
+ return this.getUserUseCase.execute(query);
277
297
  }
278
298
  }
279
299
  ```
@@ -288,7 +308,9 @@ model User {
288
308
  name String
289
309
  createdAt DateTime @default(now())
290
310
  updatedAt DateTime @updatedAt
291
- orders Order[]
311
+
312
+ // Relationships
313
+ orders Order[]
292
314
 
293
315
  @@map("users")
294
316
  }
@@ -298,6 +320,8 @@ model Order {
298
320
  total Decimal @db.Decimal(10, 2)
299
321
  status OrderStatus
300
322
  userId String
323
+
324
+ // Relationships
301
325
  user User @relation(fields: [userId], references: [id])
302
326
  items OrderItem[]
303
327
 
@@ -313,60 +337,104 @@ enum OrderStatus {
313
337
  }
314
338
  ```
315
339
 
316
- ### Prisma Best Practices
317
- - Use enums for fixed value sets
318
- - Always add indexes on foreign keys
319
- - Use `@@map` for table naming (plural snake_case)
320
- - Include `createdAt` and `updatedAt` timestamps
321
- - Use `cuid()` for primary keys
322
- - No raw SQL queries - use Prisma Client only
340
+ ### Repository Implementation
341
+ ```typescript
342
+ @Injectable()
343
+ export class PrismaUserRepository implements UserRepositoryInterface {
344
+ constructor(private readonly prisma: PrismaService) {}
345
+
346
+ async save(user: UserEntity): Promise<UserEntity> {
347
+ const data = {
348
+ id: user.id.toString(),
349
+ email: user.email.toString(),
350
+ name: user.name.toString(),
351
+ };
352
+
353
+ const savedUser = await this.prisma.user.upsert({
354
+ where: { id: data.id },
355
+ update: data,
356
+ create: data,
357
+ });
358
+
359
+ return this.toDomain(savedUser);
360
+ }
361
+
362
+ async findById(id: UserId): Promise<UserEntity | null> {
363
+ const user = await this.prisma.user.findUnique({
364
+ where: { id: id.toString() },
365
+ });
366
+
367
+ return user ? this.toDomain(user) : null;
368
+ }
369
+
370
+ private toDomain(prismaUser: User): UserEntity {
371
+ return UserEntity.reconstitute({
372
+ id: UserId.create(prismaUser.id),
373
+ email: EmailValueObject.create(prismaUser.email),
374
+ name: NameValueObject.create(prismaUser.name),
375
+ createdAt: prismaUser.createdAt,
376
+ });
377
+ }
378
+ }
379
+ ```
323
380
 
324
381
  ## Security Standards
325
382
 
326
383
  ### Authentication & Authorization
327
- - **JWT Tokens**: Proper expiration and refresh token handling
328
- - **RBAC**: Role-based access control with Guards
329
- - **Validation**: Input validation on all endpoints (class-validator)
330
- - **Rate Limiting**: Throttle public endpoints to prevent abuse
331
- - **Environment**: HTTPS only in production, secrets in env variables
384
+ - JWT tokens with proper expiration
385
+ - Role-based access control (RBAC)
386
+ - Input validation on all endpoints
387
+ - Rate limiting for public endpoints
388
+ - HTTPS only in production
332
389
 
333
390
  ### Data Protection
334
- - Encrypt sensitive data at rest and in transit
335
- - Never commit secrets to repository
336
- - Implement audit logging for critical operations
337
- - OWASP Top 10 compliance
338
- - Regular dependency security audits
391
+ - Encrypt sensitive data at rest
392
+ - Use environment variables for secrets
393
+ - Implement audit logging
394
+ - Regular security updates
395
+ - OWASP compliance
339
396
 
340
397
  ## Performance Standards
341
398
 
342
399
  ### Database Optimization
343
- - Proper indexing on frequently queried fields
344
- - Connection pooling via Prisma
345
- - Pagination for large datasets (cursor-based preferred)
346
- - Avoid N+1 queries with Prisma `include`
347
- - Query monitoring and slow query logging
400
+ - Proper indexing strategies
401
+ - Connection pooling
402
+ - Query optimization
403
+ - Pagination for large datasets
404
+ - Database monitoring
348
405
 
349
406
  ### Caching Strategy
350
- - **Redis**: Session data, rate limiting, and frequently accessed data
351
- - **Application Cache**: In-memory caching for configuration
352
- - **TTL Strategy**: Appropriate time-to-live for different data types
353
- - **Invalidation**: Event-driven cache invalidation
407
+ - Redis for session data
408
+ - Application-level caching
409
+ - HTTP caching headers
410
+ - CDN for static assets
411
+ - Cache invalidation patterns
354
412
 
355
- ## Error Handling
413
+ ## MonoRepo Organization
356
414
 
357
- ### Exception Hierarchy
358
- - Domain exceptions for business rule violations
359
- - Application exceptions for use case errors
360
- - Infrastructure exceptions for external service failures
361
- - HTTP exception filters for API responses
415
+ ### Shared Libraries Structure
416
+ ```
417
+ libs/
418
+ ├── common/
419
+ │ ├── decorators/
420
+ │ ├── filters/
421
+ │ ├── guards/
422
+ │ ├── interceptors/
423
+ │ ├── pipes/
424
+ │ └── utils/
425
+ ├── domain-core/
426
+ │ ├── base/
427
+ │ ├── interfaces/
428
+ │ └── exceptions/
429
+ └── database/
430
+ ├── base-repository.ts
431
+ ├── transaction.decorator.ts
432
+ └── prisma.service.ts
433
+ ```
362
434
 
363
- ### Error Response Format
364
- ```typescript
365
- {
366
- "statusCode": 400,
367
- "message": "User with email already exists",
368
- "error": "UserAlreadyExistsException",
369
- "timestamp": "2024-01-15T10:30:00Z",
370
- "path": "/api/users"
371
- }
372
- ```
435
+ ### Service Independence
436
+ - Each microservice has its own database
437
+ - Shared code through libraries only
438
+ - Independent deployment pipelines
439
+ - Service-to-service communication via events
440
+ - No direct database access between services
@@ -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.25",
3
+ "version": "2.1.26-dev.0",
4
4
  "description": "Paquete para instalar y configurar agentes SIESA en tu proyecto",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1,261 +0,0 @@
1
- # Architecture Patterns & Design Decisions
2
-
3
- ## Frontend Architecture
4
-
5
- ### Architecture Style
6
- - **Clean Architecture** + **Domain-Driven Design (DDD)**
7
-
8
- ### Folder Structure
9
-
10
- Next.js 15 App Router Structure with Clean Architecture + DDD:
11
-
12
- ```
13
- ├── app/ # Next.js App Router directory
14
- │ ├── (dashboard)/ # Route groups for dashboard
15
- │ ├── sales/ # Routes for sales module
16
- │ │ ├── quotes/ # Quote management pages
17
- │ │ └── invoices/ # Invoice pages
18
- │ ├── inventory/ # Inventory routes
19
- │ ├── globals.css # Global styles
20
- │ ├── layout.tsx # Root layout component
21
- │ ├── page.tsx # Home page
22
- │ ├── loading.tsx # Global loading UI
23
- │ └── not-found.tsx # 404 page
24
-
25
- ├── src/
26
- │ ├── modules/ # Business modules following DDD
27
- │ │ ├── sales/ # Sales module
28
- │ │ │ ├── quotes/ # Quote domain
29
- │ │ │ │ ├── cart/ # Shopping cart feature
30
- │ │ │ │ │ ├── domain/
31
- │ │ │ │ │ │ ├── entities/
32
- │ │ │ │ │ │ ├── repositories/
33
- │ │ │ │ │ │ ├── services/
34
- │ │ │ │ │ │ └── types/
35
- │ │ │ │ │ ├── application/
36
- │ │ │ │ │ │ ├── use-cases/
37
- │ │ │ │ │ │ ├── hooks/
38
- │ │ │ │ │ │ └── store/
39
- │ │ │ │ │ ├── infrastructure/
40
- │ │ │ │ │ │ ├── repositories/
41
- │ │ │ │ │ │ ├── api/
42
- │ │ │ │ │ │ └── adapters/
43
- │ │ │ │ │ └── presentation/
44
- │ │ │ │ │ └── components/ # Only components, pages in app/
45
- │ │ │ │ └── products/ # Products feature
46
- │ │ │ └── billing/ # Billing domain
47
- │ │ ├── inventory/ # Inventory module
48
- │ │ └── users/ # User module
49
- │ │
50
- │ ├── shared/
51
- │ │ ├── components/ # Reusable UI components
52
- │ │ ├── hooks/ # Shared hooks
53
- │ │ ├── utils/ # Utility functions
54
- │ │ ├── types/ # Common TypeScript types
55
- │ │ └── constants/ # App constants
56
- │ │
57
- │ ├── providers/ # React context providers
58
- │ ├── store/ # Global Zustand stores
59
- │ └── middleware.ts # Next.js middleware
60
-
61
- ├── lib/ # Next.js utilities and configurations
62
- ├── components/ # Global UI components (alternative to src/shared)
63
- ├── public/ # Static assets and PWA manifest
64
- └── styles/ # Additional stylesheets
65
- ```
66
-
67
- ### Core Principles
68
-
69
- #### Clean Architecture First
70
- Strict separation of:
71
- - **Domain layer** - Business entities, repositories interfaces, domain services, and types
72
- - **Application layer** - Use cases, hooks, and state management (Zustand stores)
73
- - **Infrastructure layer** - Repository implementations, API clients, and adapters
74
- - **Presentation layer** - UI components (pages go in `app/`, components in `presentation/`)
75
-
76
- #### Domain-Driven Design
77
- Business logic drives architecture decisions. Organize by business modules and domains, not technical layers.
78
-
79
- #### Component Composition
80
- Build complex UIs from simple, reusable components.
81
-
82
- #### Type Safety
83
- Leverage TypeScript for compile-time safety and developer experience.
84
-
85
- #### Performance by Design
86
- - Lazy loading
87
- - Memoization
88
- - Bundle optimization
89
-
90
- #### Accessibility as Standard
91
- WCAG 2.1 AA compliance in all components.
92
-
93
- #### Test-Driven Development
94
- Unit tests for all use cases and components.
95
-
96
- #### Progressive Web App
97
- Offline-first approach with service workers.
98
-
99
- #### Minimal and Functional
100
- Only build what's explicitly requested, nothing more.
101
-
102
- #### User-Centered Design
103
- Start with user needs and work backward to implementation.
104
-
105
- #### MCP Shadcn Available
106
- Use MCP to install Shadcn components instead of creating manually.
107
-
108
- ### Framework Selection Rules
109
-
110
- **Default**: Always use Next.js 15 with App Router unless explicitly told otherwise.
111
-
112
- **Exceptions**: Only use pure React + Vite when user specifically mentions offline-first functionality or requests non-Next.js setup.
113
-
114
- **Reasoning**: Next.js provides better developer experience, built-in optimization, and easier deployment while maintaining PWA capabilities.
115
-
116
- ## Backend Architecture
117
-
118
- ### Architecture Style
119
- - **Hexagonal Architecture** (Ports & Adapters) + **Domain-Driven Design (DDD)**
120
-
121
- ### Folder Structure
122
-
123
- MonoRepo Structure with Hexagonal Architecture + DDD:
124
-
125
- ```
126
- ├── apps/ # Microservices applications
127
- │ ├── sales-service/ # Sales domain microservice
128
- │ │ ├── src/
129
- │ │ │ ├── modules/
130
- │ │ │ │ ├── quotes/ # Quote bounded context
131
- │ │ │ │ │ ├── application/
132
- │ │ │ │ │ │ ├── ports/ # Interfaces (secondary ports)
133
- │ │ │ │ │ │ │ ├── repositories/
134
- │ │ │ │ │ │ │ └── services/
135
- │ │ │ │ │ │ ├── use-cases/ # Primary ports
136
- │ │ │ │ │ │ ├── commands/
137
- │ │ │ │ │ │ ├── queries/
138
- │ │ │ │ │ │ └── dto/
139
- │ │ │ │ │ ├── domain/
140
- │ │ │ │ │ │ ├── entities/
141
- │ │ │ │ │ │ ├── value-objects/
142
- │ │ │ │ │ │ ├── aggregates/
143
- │ │ │ │ │ │ ├── events/
144
- │ │ │ │ │ │ └── services/ # Domain services
145
- │ │ │ │ │ └── infrastructure/ # Adapters (secondary adapters)
146
- │ │ │ │ │ ├── repositories/ # Prisma implementations
147
- │ │ │ │ │ ├── services/ # External service adapters
148
- │ │ │ │ │ └── events/
149
- │ │ │ │ └── products/ # Product bounded context
150
- │ │ │ ├── api/ # Primary adapters
151
- │ │ │ │ ├── controllers/
152
- │ │ │ │ ├── guards/
153
- │ │ │ │ ├── middlewares/
154
- │ │ │ │ └── filters/
155
- │ │ │ ├── config/
156
- │ │ │ ├── main.ts
157
- │ │ │ └── app.module.ts
158
- │ │ ├── test/
159
- │ │ ├── prisma/
160
- │ │ │ ├── schema.prisma
161
- │ │ │ └── migrations/
162
- │ │ └── package.json
163
- │ │
164
- │ ├── inventory-service/ # Inventory domain microservice
165
- │ └── user-service/ # User domain microservice
166
-
167
- ├── libs/ # Shared libraries
168
- │ ├── common/ # Common utilities
169
- │ │ ├── src/
170
- │ │ │ ├── decorators/
171
- │ │ │ ├── filters/
172
- │ │ │ ├── guards/
173
- │ │ │ ├── interceptors/
174
- │ │ │ ├── pipes/
175
- │ │ │ ├── types/
176
- │ │ │ └── utils/
177
- │ │ └── package.json
178
- │ │
179
- │ ├── domain-core/ # Shared domain concepts
180
- │ │ ├── src/
181
- │ │ │ ├── base/
182
- │ │ │ │ ├── aggregate-root.ts
183
- │ │ │ │ ├── entity.ts
184
- │ │ │ │ ├── value-object.ts
185
- │ │ │ │ └── domain-event.ts
186
- │ │ │ ├── interfaces/
187
- │ │ │ └── exceptions/
188
- │ │ └── package.json
189
- │ │
190
- │ └── database/ # Shared database utilities
191
- │ ├── src/
192
- │ │ ├── base-repository.ts
193
- │ │ ├── transaction.decorator.ts
194
- │ │ └── prisma.service.ts
195
- │ └── package.json
196
-
197
- ├── tools/ # Development tools
198
- ├── nx.json # Nx workspace configuration
199
- ├── package.json # Root package.json
200
- └── tsconfig.base.json # Base TypeScript config
201
- ```
202
-
203
- ### Core Principles
204
-
205
- #### Hexagonal Architecture First
206
- Strict separation of concerns following ports & adapters pattern:
207
- - **Domain Layer**: Pure business logic with entities, value objects, aggregates, and domain services
208
- - **Application Layer**: Use cases orchestrating domain logic, defining ports (interfaces)
209
- - **Infrastructure Layer**: Adapters implementing ports (Prisma repos, HTTP clients, message publishers)
210
- - **API Layer**: Primary adapters exposing application via REST/GraphQL (controllers, resolvers)
211
-
212
- #### Domain-Driven Design
213
- Business logic drives all architectural decisions:
214
- - **Bounded Contexts**: Each module represents a bounded context (quotes, products, billing)
215
- - **Ubiquitous Language**: Code reflects business terminology
216
- - **Aggregates**: Consistency boundaries for domain entities
217
- - **Domain Events**: Communicate changes across bounded contexts
218
- - **Repository Pattern**: Abstract data access behind interfaces
219
-
220
- #### Dependency Rules
221
- - Domain layer has zero dependencies on frameworks or external libraries
222
- - All dependencies point inward toward the domain core
223
- - Use dependency inversion for all external concerns (databases, APIs, messaging)
224
- - Interfaces defined in application layer, implementations in infrastructure layer
225
-
226
- #### Microservices Independence
227
- - Each microservice has its own database (no shared databases)
228
- - Shared code through libraries only (common, domain-core, database)
229
- - Independent deployment pipelines per service
230
- - Service-to-service communication via events (async messaging)
231
- - No direct database access between services
232
-
233
- #### Test-Driven Development
234
- - Unit tests for domain entities, value objects, and use cases
235
- - Integration tests for repository implementations
236
- - E2E tests for complete API workflows
237
- - TDD approach: write tests before implementation
238
-
239
- #### Type Safety & Validation
240
- - Leverage TypeScript strict mode for compile-time safety
241
- - Domain validation in value objects and entities
242
- - DTO validation at API boundaries with class-validator
243
- - No `any` types allowed
244
-
245
- #### Security by Design
246
- - Authentication and authorization at every layer
247
- - Input validation on all endpoints
248
- - OWASP Top 10 compliance
249
- - Audit logging for critical operations
250
-
251
- ### Framework Selection Rules
252
-
253
- **Default**: Always use NestJS 10+ with TypeScript for backend services.
254
-
255
- **Database**: Prisma ORM only - no raw SQL queries allowed.
256
-
257
- **Testing**: Jest + Supertest with TDD approach.
258
-
259
- **Documentation**: Swagger/OpenAPI auto-generated from decorators.
260
-
261
- **Reasoning**: NestJS provides excellent DI container, decorator-based development, and native support for microservices patterns while enforcing SOLID principles.
@@ -1,81 +0,0 @@
1
- # Technology Stack
2
-
3
- ## Frontend Stack
4
-
5
- ### Framework
6
- - **Next.js 15** with TypeScript (App Router)
7
- - Default framework unless explicitly told otherwise
8
- - Built-in Turbopack/Webpack for building
9
- - File-based routing with App Router
10
- - Exception: Use pure React + Vite only when user specifically mentions offline-first functionality or requests non-Next.js setup
11
-
12
- ### State Management
13
- - **Zustand**
14
-
15
- ### UI Framework & Styling
16
- - **Shadcn/ui** (component library)
17
- - **Radix UI** (primitives)
18
- - **TailwindCSS v4** (styling)
19
-
20
- ### Architecture
21
- - **Clean Architecture** + **Domain-Driven Design (DDD)**
22
-
23
- ### Testing
24
- - **Vitest** (test runner)
25
- - **React Testing Library** (component testing)
26
- - **MSW** (Mock Service Worker - API mocking)
27
-
28
- ### Forms & Validation
29
- - **React Hook Form** (form management)
30
- - **Zod** (schema validation)
31
-
32
- ### HTTP Client
33
- - **Axios** with interceptors
34
-
35
- ### Progressive Web App (PWA)
36
- - **Next.js PWA plugin**
37
- - **Workbox** (service worker library)
38
-
39
- ### Routing
40
- - **Next.js App Router** (file-based routing)
41
-
42
- ## Core Principles
43
-
44
- ### Clean Architecture First
45
- Strict separation of:
46
- - Domain layer
47
- - Application layer
48
- - Infrastructure layer
49
- - Presentation layer
50
-
51
- ### Domain-Driven Design
52
- Business logic drives architecture decisions
53
-
54
- ### Component Composition
55
- Build complex UIs from simple, reusable components
56
-
57
- ### Type Safety
58
- Leverage TypeScript for compile-time safety and developer experience
59
-
60
- ### Performance by Design
61
- - Lazy loading
62
- - Memoization
63
- - Bundle optimization
64
-
65
- ### Accessibility as Standard
66
- WCAG 2.1 AA compliance in all components
67
-
68
- ### Test-Driven Development
69
- Unit tests for all use cases and components
70
-
71
- ### Progressive Web App
72
- Offline-first approach with service workers
73
-
74
- ### Minimal and Functional
75
- Only build what's explicitly requested, nothing more
76
-
77
- ### User-Centered Design
78
- Start with user needs and work backward to implementation
79
-
80
- ### MCP Shadcn Available
81
- Use MCP to install Shadcn components instead of creating manually