/** * Router de comandos (Etapa 3) * Maneja 'configurar' y 'web', y delega el resto al código actual (null → fallback). * Nota: No importar CommandService aquí para evitar ciclos de import. */ import type { Database } from 'bun:sqlite'; import { ACTION_ALIASES } from './shared'; import { handleConfigurar } from './handlers/configurar'; import { handleWeb } from './handlers/web'; import { handleVer } from './handlers/ver'; import { handleCompletar } from './handlers/completar'; import { handleTomar } from './handlers/tomar'; import { handleSoltar } from './handlers/soltar'; import { handleNueva } from './handlers/nueva'; type NuevaCtx = Parameters[0]; type VerCtx = Parameters[0]; type CompletarCtx = Parameters[0]; type TomarCtx = Parameters[0]; type SoltarCtx = Parameters[0]; type ConfigurarCtx = Parameters[0]; type WebCtx = Parameters[0]; import { ResponseQueue } from '../response-queue'; import { isGroupId } from '../../utils/whatsapp'; import { Metrics } from '../metrics'; function getQuickHelp(): string { return [ 'Guía rápida:', '- Ver tus tareas: `/t mias`', '- Ver todas: `/t todas`', '- Crear: `/t n Descripción 2028-11-26 @Ana`', '- Completar: `/t x 123`', '- Tomar: `/t tomar 12`', '- Configurar recordatorios: `/t configurar diario|l-v|semanal|off [HH:MM]`', '- Web: `/t web`' ].join('\n'); } function getFullHelp(): string { return [ 'Ayuda avanzada:', 'Comandos y alias:', ' · Crear: `n`, `nueva`, `crear`, `+`', ' · Ver: `ver`, `listar`, `mostrar`, `ls` (scopes: `mis` | `todas`)', ' · Completar: `x`, `hecho`, `completar`, `done`', ' · Tomar: `tomar`, `claim`', ' · Soltar: `soltar`, `unassign`', 'Preferencias:', ' · `/t configurar diario|l-v|semanal|off [HH:MM]`', 'Fechas:', ' · `YYYY-MM-DD` o `YY-MM-DD` → `20YY-MM-DD` (ej.: 27-09-04)', ' · Palabras: `hoy`, `mañana`', 'Acceso web:', ' · `/t web`', 'Atajos:', ' · `/t mias`', ' · `/t todas`' ].join('\n'); } function buildUnknownHelp(): string { const header = '❓ COMANDO NO RECONOCIDO'; const cta = 'Prueba `/t ayuda`'; return [header, cta, '', getQuickHelp()].join('\n'); } export type RoutedMessage = { recipient: string; message: string; mentions?: string[]; }; export type RouteContext = { sender: string; groupId: string; message: string; mentions: string[]; messageId?: string; participant?: string; fromMe?: boolean; }; export async function route(context: RouteContext, deps?: { db: Database }): Promise { const trimmed = (context.message || '').trim(); const tokens = trimmed.split(/\s+/); const rawAction = (tokens[1] || '').toLowerCase(); const action = ACTION_ALIASES[rawAction] || rawAction; // Ayuda (no requiere DB) if (action === 'ayuda') { // Métrica de alias "info" (compatibilidad con legacy) try { if (rawAction === 'info' || rawAction === '?') { Metrics.inc('commands_alias_used_total', 1, { action: 'info' }); } } catch {} try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} const isAdvanced = (tokens[2] || '').toLowerCase() === 'avanzada'; const message = isAdvanced ? getFullHelp() : [getQuickHelp(), '', 'Ayuda avanzada: `/t ayuda avanzada`'].join('\n'); return [{ recipient: context.sender, message }]; } // Requiere db inyectada para poder operar (CommandService la inyecta) const database = deps?.db; if (!database) return null; if (action === 'nueva') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} return await handleNueva(context as unknown as NuevaCtx, { db: database }); } if (action === 'ver') { // Métricas de alias (mias/todas) como en el código actual try { if (rawAction === 'mias' || rawAction === 'mías') { Metrics.inc('commands_alias_used_total', 1, { action: 'mias' }); } else if (rawAction === 'todas' || rawAction === 'todos') { Metrics.inc('commands_alias_used_total', 1, { action: 'todas' }); } } catch {} try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} // En grupo: transición a DM if (isGroupId(context.groupId)) { try { Metrics.inc('ver_dm_transition_total'); } catch {} return [{ recipient: context.sender, message: 'No respondo en grupos. Tus tareas: /t mias · Todas: /t todas · Info: /t info · Web: /t web' }]; } return await handleVer(context as unknown as VerCtx); } if (action === 'completar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} return await handleCompletar(context as unknown as CompletarCtx); } if (action === 'tomar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} return await handleTomar(context as unknown as TomarCtx); } if (action === 'soltar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} return await handleSoltar(context as unknown as SoltarCtx); } if (action === 'configurar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} return handleConfigurar(context as unknown as ConfigurarCtx, { db: database }); } if (action === 'web') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} return await handleWeb(context as unknown as WebCtx, { db: database }); } // Desconocido → ayuda rápida try { Metrics.inc('commands_unknown_total'); } catch {} return [{ recipient: context.sender, message: buildUnknownHelp() }]; }