A per-DataDir background process owns ticket JSON, history, and sync so multiple TUI instances stay consistent; MCP token APIs are ready for phase 2. Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
2.8 KiB
Go
85 lines
2.8 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"task/internal/command"
|
|
"task/internal/project"
|
|
"task/internal/ticket"
|
|
)
|
|
|
|
// Server is the daemon HTTP API.
|
|
type Server struct {
|
|
store ticket.Store
|
|
timeStore ticket.TimeStore
|
|
projects project.Store
|
|
history command.Executor
|
|
hub *hub
|
|
mux *http.ServeMux
|
|
}
|
|
|
|
// New constructs the API server.
|
|
func New(store ticket.Store, timeStore ticket.TimeStore, projects project.Store, history command.Executor) *Server {
|
|
s := &Server{
|
|
store: store,
|
|
timeStore: timeStore,
|
|
projects: projects,
|
|
history: history,
|
|
hub: newHub(),
|
|
mux: http.NewServeMux(),
|
|
}
|
|
s.routes()
|
|
return s
|
|
}
|
|
|
|
// Handler returns the root HTTP handler with auth middleware.
|
|
func (s *Server) Handler() http.Handler {
|
|
return s.withAuth(s.mux)
|
|
}
|
|
|
|
func (s *Server) routes() {
|
|
s.mux.HandleFunc("GET /v1/health", s.handleHealth)
|
|
|
|
s.mux.HandleFunc("GET /v1/projects", s.handleListProjects)
|
|
s.mux.HandleFunc("POST /v1/projects", s.handleEnsureProject)
|
|
s.mux.HandleFunc("DELETE /v1/projects/{id}", s.handleDeleteProject)
|
|
s.mux.HandleFunc("GET /v1/projects/{id}/meta", s.handleGetMeta)
|
|
s.mux.HandleFunc("PUT /v1/projects/{id}/meta", s.handleSaveMeta)
|
|
s.mux.HandleFunc("GET /v1/projects/{id}/mcp-token", s.handleMCPTokenStatus)
|
|
s.mux.HandleFunc("POST /v1/projects/{id}/mcp-token", s.handleMCPTokenCreate)
|
|
s.mux.HandleFunc("DELETE /v1/projects/{id}/mcp-token", s.handleMCPTokenRevoke)
|
|
|
|
s.mux.HandleFunc("GET /v1/tickets", s.handleListTickets)
|
|
s.mux.HandleFunc("GET /v1/tickets/{id}", s.handleGetTicket)
|
|
s.mux.HandleFunc("POST /v1/tickets", s.handleCreateTicket)
|
|
s.mux.HandleFunc("PATCH /v1/tickets/{id}", s.handleUpdateTicket)
|
|
s.mux.HandleFunc("DELETE /v1/tickets/{id}", s.handleDeleteTicket)
|
|
s.mux.HandleFunc("POST /v1/tickets/{id}/move", s.handleMoveTicket)
|
|
|
|
s.mux.HandleFunc("GET /v1/time", s.handleListTime)
|
|
s.mux.HandleFunc("GET /v1/time/by-ticket/{ticketId}", s.handleListTimeByTicket)
|
|
s.mux.HandleFunc("GET /v1/time/sum/{ticketId}", s.handleSumTime)
|
|
s.mux.HandleFunc("POST /v1/time", s.handleAddTime)
|
|
s.mux.HandleFunc("PATCH /v1/time/{id}", s.handleUpdateTime)
|
|
s.mux.HandleFunc("DELETE /v1/time/{id}", s.handleRemoveTime)
|
|
s.mux.HandleFunc("GET /v1/timer", s.handleGetTimer)
|
|
s.mux.HandleFunc("PUT /v1/timer", s.handleSetTimer)
|
|
|
|
s.mux.HandleFunc("GET /v1/history", s.handleHistoryStatus)
|
|
s.mux.HandleFunc("POST /v1/undo", s.handleUndo)
|
|
s.mux.HandleFunc("POST /v1/redo", s.handleRedo)
|
|
|
|
s.mux.HandleFunc("POST /v1/sync/pull", s.handleSyncPull)
|
|
s.mux.HandleFunc("POST /v1/sync/push", s.handleSyncPush)
|
|
|
|
s.mux.HandleFunc("GET /v1/events", s.handleEvents)
|
|
}
|
|
|
|
func (s *Server) handleHealth(w http.ResponseWriter, _ *http.Request) {
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
|
}
|
|
|
|
func (s *Server) notify(projectID string) {
|
|
s.hub.publish(Event{Type: "changed", ProjectID: projectID})
|
|
}
|