Add local JSON daemon and route TUI/CLI through it.
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>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
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})
|
||||
}
|
||||
Reference in New Issue
Block a user