|  |  |  | @ -14,12 +14,13 @@ type CommandContext = { | 
		
	
		
			
				|  |  |  |  | export type CommandResponse = { | 
		
	
		
			
				|  |  |  |  |   recipient: string; | 
		
	
		
			
				|  |  |  |  |   message: string; | 
		
	
		
			
				|  |  |  |  |   mentions?: string[]; // full JIDs to mention in the outgoing message
 | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | export class CommandService { | 
		
	
		
			
				|  |  |  |  |   static dbInstance: Database = db; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   private static parseNueva(message: string): { | 
		
	
		
			
				|  |  |  |  |   private static parseNueva(message: string, mentionsNormalized: string[]): { | 
		
	
		
			
				|  |  |  |  |     action: string; | 
		
	
		
			
				|  |  |  |  |     description: string; | 
		
	
		
			
				|  |  |  |  |     dueDate: string | null; | 
		
	
	
		
			
				
					|  |  |  | @ -44,15 +45,23 @@ export class CommandService { | 
		
	
		
			
				|  |  |  |  |     let dueDate: string | null = null; | 
		
	
		
			
				|  |  |  |  |     let descriptionTokens: string[] = []; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     const isMentionToken = (token: string) => token.startsWith('@'); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (dateIndices.length > 0) { | 
		
	
		
			
				|  |  |  |  |       const last = dateIndices[dateIndices.length - 1]; | 
		
	
		
			
				|  |  |  |  |       dueDate = last.text; | 
		
	
		
			
				|  |  |  |  |       for (let i = 2; i < parts.length; i++) { | 
		
	
		
			
				|  |  |  |  |         if (i === last.index) continue; | 
		
	
		
			
				|  |  |  |  |         descriptionTokens.push(parts[i]); | 
		
	
		
			
				|  |  |  |  |         const token = parts[i]; | 
		
	
		
			
				|  |  |  |  |         if (isMentionToken(token)) continue; // quitar @menciones del texto
 | 
		
	
		
			
				|  |  |  |  |         descriptionTokens.push(token); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       descriptionTokens = parts.slice(2); | 
		
	
		
			
				|  |  |  |  |       for (let i = 2; i < parts.length; i++) { | 
		
	
		
			
				|  |  |  |  |         const token = parts[i]; | 
		
	
		
			
				|  |  |  |  |         if (isMentionToken(token)) continue; | 
		
	
		
			
				|  |  |  |  |         descriptionTokens.push(token); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     const description = descriptionTokens.join(' ').trim(); | 
		
	
	
		
			
				
					|  |  |  | @ -79,7 +88,14 @@ export class CommandService { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Parseo específico de "nueva"
 | 
		
	
		
			
				|  |  |  |  |     const { description, dueDate } = this.parseNueva(trimmed); | 
		
	
		
			
				|  |  |  |  |     // Normalizar menciones del contexto para parseo y asignaciones
 | 
		
	
		
			
				|  |  |  |  |     const mentionsNormalizedFromContext = Array.from(new Set( | 
		
	
		
			
				|  |  |  |  |       (context.mentions || []) | 
		
	
		
			
				|  |  |  |  |         .map(j => normalizeWhatsAppId(j)) | 
		
	
		
			
				|  |  |  |  |         .filter((id): id is string => !!id) | 
		
	
		
			
				|  |  |  |  |     )); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     const { description, dueDate } = this.parseNueva(trimmed, mentionsNormalizedFromContext); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Asegurar creador
 | 
		
	
		
			
				|  |  |  |  |     const createdBy = ensureUserExists(context.sender, this.dbInstance); | 
		
	
	
		
			
				
					|  |  |  | @ -90,9 +106,7 @@ export class CommandService { | 
		
	
		
			
				|  |  |  |  |     // Normalizar menciones y excluir duplicados y el número del bot
 | 
		
	
		
			
				|  |  |  |  |     const botNumber = process.env.CHATBOT_PHONE_NUMBER || ''; | 
		
	
		
			
				|  |  |  |  |     const assigneesNormalized = Array.from(new Set( | 
		
	
		
			
				|  |  |  |  |       (context.mentions || []) | 
		
	
		
			
				|  |  |  |  |         .map(j => normalizeWhatsAppId(j)) | 
		
	
		
			
				|  |  |  |  |         .filter((id): id is string => !!id) | 
		
	
		
			
				|  |  |  |  |       mentionsNormalizedFromContext | 
		
	
		
			
				|  |  |  |  |         .filter(id => !botNumber || id !== botNumber) | 
		
	
		
			
				|  |  |  |  |     )); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -123,7 +137,11 @@ export class CommandService { | 
		
	
		
			
				|  |  |  |  |       })) | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     const assignedList = assignmentUserIds.join(', '); | 
		
	
		
			
				|  |  |  |  |     const mentionsForSending = ensuredAssignees.length > 0 | 
		
	
		
			
				|  |  |  |  |       ? ensuredAssignees.map(uid => `${uid}@s.whatsapp.net`) | 
		
	
		
			
				|  |  |  |  |       : []; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     const assignedList = assignmentUserIds.map(uid => `@${uid}`).join(' '); | 
		
	
		
			
				|  |  |  |  |     const resp = | 
		
	
		
			
				|  |  |  |  |       `✅ Tarea ${taskId} creada: "${description || '(sin descripción)'}"` + | 
		
	
		
			
				|  |  |  |  |       (dueDate ? ` (vence ${dueDate})` : '') + | 
		
	
	
		
			
				
					|  |  |  | @ -131,7 +149,8 @@ export class CommandService { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return [{ | 
		
	
		
			
				|  |  |  |  |       recipient: createdBy, | 
		
	
		
			
				|  |  |  |  |       message: resp | 
		
	
		
			
				|  |  |  |  |       message: resp, | 
		
	
		
			
				|  |  |  |  |       mentions: mentionsForSending.length > 0 ? mentionsForSending : undefined | 
		
	
		
			
				|  |  |  |  |     }]; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | 
 |