package api import ( "context" "net/http" "task/internal/project" "task/internal/tmsync" "task/internal/ytsync" ) func (s *Server) handleSyncPull(w http.ResponseWriter, r *http.Request) { s.runSync(w, r, false) } func (s *Server) handleSyncPush(w http.ResponseWriter, r *http.Request) { s.runSync(w, r, true) } func (s *Server) runSync(w http.ResponseWriter, r *http.Request, push bool) { var body struct { ProjectID string `json:"projectId"` } if err := readJSON(r, &body); err != nil { writeErr(w, http.StatusBadRequest, err.Error()) return } if body.ProjectID == "" { writeErr(w, http.StatusBadRequest, "projectId required") return } if !requireMCPProject(r, body.ProjectID) { writeErr(w, http.StatusForbidden, "mcp token project mismatch") return } meta, err := s.projects.LoadMeta(body.ProjectID) if err != nil { writeErr(w, http.StatusInternalServerError, err.Error()) return } var res ytsync.Result ctx := context.Background() switch meta.EffectiveBackend() { case project.BackendTaskMaster: if meta.TaskMaster == nil || !meta.TaskMaster.Configured() { writeErr(w, http.StatusBadRequest, "taskmaster not configured") return } syncer := &tmsync.Syncer{Store: s.store, TimeStore: s.timeStore} if push { res, err = syncer.Push(ctx, body.ProjectID, *meta.TaskMaster) } else { res, err = syncer.Pull(ctx, body.ProjectID, *meta.TaskMaster) } default: if push { res, err = ytsync.PushProject(ctx, s.projects, s.store, s.timeStore, body.ProjectID) } else { res, err = ytsync.PullProject(ctx, s.projects, s.store, s.timeStore, body.ProjectID) } } if err != nil { writeErr(w, http.StatusBadRequest, err.Error()) return } s.notify(body.ProjectID) writeJSON(w, http.StatusOK, res) }