package hook import ( "io" "os" "github.com/longbin/agent-notify/internal/config" "github.com/longbin/agent-notify/internal/context" "github.com/longbin/agent-notify/internal/logx" "github.com/longbin/agent-notify/internal/notify" "github.com/longbin/agent-notify/internal/tmux" ) type cursorPayload struct { WorkspaceRoots []string `json:"workspace_roots"` HookEventName string `json:"hook_event_name"` Status string `json:"status"` ConversationID string `json:"conversation_id"` TranscriptPath string `json:"transcript_path"` } var ( sendForHook = notify.SendForHookWithResult sendAuto = notify.SendAutoWithResult ) func RunCursor(r io.Reader, cfg config.Config, event string, _ io.Writer) error { var payload cursorPayload fromHook := !isInteractiveStdin(r) decodeJSON(r, &payload) hookName := payload.HookEventName if hookName == "" { hookName = event } clientTTY, _ := tmux.ClientTTY() logx.Append("hook cursor event=%s hook_event_name=%s status=%s enabled=%v from_hook=%v stdout_tty=%v client_tty=%q", event, hookName, payload.Status, cfg.EventEnabled(event), fromHook, stdoutIsTerminal(), clientTTY) if !cfg.EventEnabled(event) { logx.Append("hook cursor event=%s skipped (disabled in config)", event) return nil } meta := context.MetaFromEnv("Cursor", event) if len(payload.WorkspaceRoots) > 0 { meta.CWD = payload.WorkspaceRoots[0] } title := context.Render(cfg.Notify.TitleTemplate, meta) body := cfg.BodyForEvent(event) if shouldDebounce(title) { logx.Append("hook cursor event=%s skipped (debounced duplicate)", event) return nil } var result notify.SendResult var err error if fromHook { result, err = sendForHook(cfg.Notify.Protocol, title, body) } else { result, err = sendAuto(cfg.Notify.Protocol, title, body) } if err != nil { logx.Append("hook cursor event=%s send FAILED: %v", event, err) return err } logx.Append("hook cursor event=%s send OK via %s title=%q", event, result.Method, title) if cfg.Remote.Enabled { reportRemoteHook(cfg, "Cursor", event, meta.CWD, payload.TranscriptPath, payload.ConversationID) } else if cfg.Inbox.Enabled { recordInbox(cfg, "Cursor", event, meta.CWD, title, body) } return nil } func stdoutIsTerminal() bool { fi, err := os.Stdout.Stat() if err != nil { return false } return fi.Mode()&os.ModeCharDevice != 0 }