project_init.go
1 package daemon 2 3 import ( 4 "net/http" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "github.com/Kocoro-lab/ShanClaw/internal/agents" 10 ) 11 12 func (s *Server) handleProjectInit(w http.ResponseWriter, r *http.Request) { 13 if s.deps == nil { 14 writeError(w, http.StatusInternalServerError, "daemon deps not configured") 15 return 16 } 17 var req struct { 18 CWD string `json:"cwd"` 19 Instructions string `json:"instructions,omitempty"` 20 } 21 if !decodeBody(w, r, &req) { 22 return 23 } 24 25 if !filepath.IsAbs(req.CWD) { 26 writeError(w, http.StatusBadRequest, "cwd must be an absolute path") 27 return 28 } 29 info, err := os.Stat(req.CWD) 30 if err != nil { 31 writeError(w, http.StatusBadRequest, "cwd does not exist: "+req.CWD) 32 return 33 } 34 if !info.IsDir() { 35 writeError(w, http.StatusBadRequest, "cwd is not a directory: "+req.CWD) 36 return 37 } 38 39 shannonClean := filepath.Clean(s.deps.ShannonDir) 40 if resolved, err := filepath.EvalSymlinks(s.deps.ShannonDir); err == nil { 41 shannonClean = resolved 42 } 43 cwdClean := filepath.Clean(req.CWD) 44 if resolved, err := filepath.EvalSymlinks(req.CWD); err == nil { 45 cwdClean = resolved 46 } 47 if cwdClean == shannonClean || strings.HasPrefix(cwdClean, shannonClean+string(filepath.Separator)) { 48 writeError(w, http.StatusBadRequest, "cannot initialize project inside the global shannon directory") 49 return 50 } 51 52 dotShannon := filepath.Join(req.CWD, ".shannon") 53 var created, existed []string 54 55 if _, err := os.Stat(dotShannon); os.IsNotExist(err) { 56 if err := os.MkdirAll(dotShannon, 0700); err != nil { 57 writeError(w, http.StatusInternalServerError, err.Error()) 58 return 59 } 60 created = append(created, ".shannon/") 61 } else { 62 existed = append(existed, ".shannon/") 63 } 64 65 if req.Instructions != "" { 66 instPath := filepath.Join(dotShannon, "instructions.md") 67 if _, err := os.Stat(instPath); os.IsNotExist(err) { 68 if err := agents.AtomicWrite(instPath, []byte(req.Instructions)); err != nil { 69 writeError(w, http.StatusInternalServerError, err.Error()) 70 return 71 } 72 created = append(created, ".shannon/instructions.md") 73 } else { 74 existed = append(existed, ".shannon/instructions.md") 75 } 76 } 77 78 if created == nil { 79 created = []string{} 80 } 81 if existed == nil { 82 existed = []string{} 83 } 84 85 s.auditHTTPOp("POST", "/project/init", "initialized project at "+req.CWD) 86 writeJSON(w, http.StatusOK, map[string]interface{}{ 87 "created": created, 88 "existed": existed, 89 }) 90 }