feat: catálogo crons/ + scripts dev-scripts/cron/ + Fire() en scheduler

Implementa issue 0025: catálogo central de automatizaciones cron y scaffolder.

- crons/: directorio de automatizaciones nombradas con README explicando la
  convención. Incluye dos ejemplos listos para usar:
    · good-morning (send_message, 0 9 * * *) — saludo diario
    · daily-summary (llm_prompt, 0 18 * * *)  — resumen generado por LLM

- dev-scripts/cron/new.sh: scaffolder interactivo — pregunta nombre,
  descripción, tipo de acción y cron expression; crea schedule.yaml +
  archivo de prompt vacío; imprime el bloque YAML para copiar en config.yaml.

- dev-scripts/cron/list.sh: lista todas las automatizaciones del catálogo
  con nombre, tipo, cron y descripción en formato tabular.

- dev-scripts/cron/apply.sh: añade la automatización al config.yaml del
  agente indicado usando yq si está disponible; si no, imprime el bloque
  YAML para copiar a mano (sin dependencias obligatorias).

- shell/cron/scheduler.go: exporta Fire(ctx, sc) para disparo inmediato
  de un schedule sin esperar al timer cron — útil en tests y CLI.

- shell/cron/scheduler_test.go: cuatro tests nuevos para Fire()
  (send_message inline, llm_prompt, sin output_room, sin LLM).
  TestScheduler_SkipsInvalidSchedule y TestFire_LLMPrompt_NoLLM_Skips
  reemplazados por versiones instantáneas usando Fire en lugar de
  @every 100ms + sleep, eliminando ~700ms de tiempo de test.
This commit is contained in:
2026-03-08 20:01:02 +00:00
parent fb2c7fdaa9
commit e481cb8783
10 changed files with 474 additions and 71 deletions
+16
View File
@@ -45,6 +45,22 @@ func New(
}
}
// Fire immediately executes the action for the given schedule, bypassing the cron timer.
// Useful for tests and manual triggering from CLI.
func (s *Scheduler) Fire(ctx context.Context, sc config.ScheduleCfg) {
room := sc.OutputRoom
if room == "" {
s.logger.Warn("Fire: schedule has no output_room, skipping", "name", sc.Name)
return
}
handler := s.buildHandler(sc)
if handler == nil {
s.logger.Warn("Fire: unsupported action kind", "name", sc.Name, "kind", sc.Action.Kind)
return
}
handler(ctx, room)
}
// Start registers all schedules and starts the cron loop.
// It returns when ctx is cancelled, stopping the cron runner.
func (s *Scheduler) Start(ctx context.Context) {