@@ -473,6 +473,9 @@ func (d *Daemon) writeNotification(task *Task, status, detail string) {
473473 }); err != nil {
474474 d .logger .Printf ("notification: desktop notify error: %v" , err )
475475 }
476+
477+ // Send webhook notifications (if configured)
478+ d .sendWebhookNotifications (status , task )
476479}
477480
478481// truncate shortens a string to maxLen, adding "..." if truncated.
@@ -483,3 +486,45 @@ func truncate(s string, maxLen int) string {
483486 }
484487 return s [:maxLen - 3 ] + "..."
485488}
489+
490+ // sendWebhookNotifications sends notifications to all configured webhooks.
491+ func (d * Daemon ) sendWebhookNotifications (status string , task * Task ) {
492+ webhooks , err := config .ListWebhooks ()
493+ if err != nil || len (webhooks ) == 0 {
494+ return
495+ }
496+
497+ // Determine event type
498+ eventType := "task_completed"
499+ if status == "failed" {
500+ eventType = "task_failed"
501+ }
502+
503+ notification := notify.Notification {
504+ Title : fmt .Sprintf ("codes: Task %s" , status ),
505+ Message : fmt .Sprintf ("[%s] #%d %s" , d .TeamName , task .ID , task .Subject ),
506+ Sound : false , // webhooks don't use sound
507+ }
508+
509+ for _ , webhook := range webhooks {
510+ // Check event filter
511+ if len (webhook .Events ) > 0 {
512+ allowed := false
513+ for _ , event := range webhook .Events {
514+ if event == eventType {
515+ allowed = true
516+ break
517+ }
518+ }
519+ if ! allowed {
520+ continue
521+ }
522+ }
523+
524+ // Send notification
525+ notifier := notify .NewWebhookNotifier (webhook .URL , webhook .Format )
526+ if err := notifier .Send (notification ); err != nil {
527+ d .logger .Printf ("webhook notification error (%s): %v" , webhook .URL , err )
528+ }
529+ }
530+ }
0 commit comments