Files
Agent-System/internal/server/project_doc_handlers.go
T
WeiCHENandCursor 68765023a2 feat(api): add workflow document list, content read, and backfill script
Expose project controlled documents from DocGov, serve authenticated
output.md content by doc_id, and add idempotent backfill for run_1789111889557885000.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 02:50:22 +00:00

69 lines
2.0 KiB
Go

package server
import (
"net/http"
"path/filepath"
"strconv"
)
func (s *Server) repoRoot() string {
if s.cfg != nil && s.cfg.DataDir != "" {
// DataDir 形如 ./data/dev;工作区路径形如 data/dev/workspaces/...,相对仓库根目录
return filepath.Clean(filepath.Join(s.cfg.DataDir, "..", ".."))
}
return "."
}
// handleListProjectWorkflowDocuments 列出项目工作流受控文档。
func (s *Server) handleListProjectWorkflowDocuments(w http.ResponseWriter, r *http.Request) {
projectID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || projectID <= 0 {
http.Error(w, "invalid project id", http.StatusBadRequest)
return
}
category := r.URL.Query().Get("category")
if category != "" && category != "workflow" {
http.Error(w, "unsupported category", http.StatusBadRequest)
return
}
if s.svc == nil || s.svc.DocGov() == nil {
http.Error(w, "docgov engine not initialized", http.StatusServiceUnavailable)
return
}
docs, err := s.svc.DocGov().ListWorkflowDocumentsByProject(r.Context(), projectID)
if err != nil {
http.Error(w, "list project documents failed: "+err.Error(), http.StatusInternalServerError)
return
}
writeJSONResponse(w, http.StatusOK, docs)
}
// handleDocGovGetDocumentContent 读取受控文档 Markdown 正文。
func (s *Server) handleDocGovGetDocumentContent(w http.ResponseWriter, r *http.Request) {
docID := r.PathValue("doc_id")
if docID == "" {
http.Error(w, "doc_id required", http.StatusBadRequest)
return
}
if s.svc == nil || s.svc.DocGov() == nil {
http.Error(w, "docgov engine not initialized", http.StatusServiceUnavailable)
return
}
content, err := s.svc.DocGov().ReadDocumentContent(r.Context(), docID, s.repoRoot())
if err != nil {
http.Error(w, "read document content failed: "+err.Error(), http.StatusNotFound)
return
}
if inm := r.Header.Get("If-None-Match"); inm != "" && inm == content.ContentSHA256 {
w.WriteHeader(http.StatusNotModified)
return
}
w.Header().Set("ETag", content.ContentSHA256)
writeJSONResponse(w, http.StatusOK, content)
}