package template import ( "fmt" "os" "path/filepath" "strings" "chat-agent-system/templates" ) func findProjectRoot() string { wd, _ := os.Getwd() candidates := []string{wd} dir := wd for i := 0; i < 10; i++ { candidates = append(candidates, dir) parent := filepath.Dir(dir) if parent == dir { break } dir = parent } if env := strings.TrimSpace(os.Getenv("APP_ROOT")); env != "" { candidates = append(candidates, env) } // Image WORKDIR is /app; Dockerfile copies templates/configs here. candidates = append(candidates, "/app") for _, root := range candidates { if root == "" { continue } if _, err := os.Stat(filepath.Join(root, "templates", "docs")); err == nil { return root } } return wd } func GetDocTemplate(name string) (string, error) { name = strings.TrimSuffix(name, ".md") if name == "" || strings.Contains(name, "..") || strings.ContainsAny(name, `/\`) { return "", fmt.Errorf("read doc template: invalid name %q", name) } if b, err := templates.DocTemplates.ReadFile("docs/" + name + ".md"); err == nil && len(strings.TrimSpace(string(b))) > 0 { return string(b), nil } root := findProjectRoot() path := filepath.Join(root, "templates", "docs", name+".md") b, err := os.ReadFile(path) if err != nil { return "", fmt.Errorf("read doc template %s: %w", name, err) } return string(b), nil } func GetAgentInstruction(role string) (string, error) { role = strings.TrimSuffix(role, ".md") root := findProjectRoot() path := filepath.Join(root, "configs", "agents", role+".md") b, err := os.ReadFile(path) if err != nil { return "", fmt.Errorf("read agent instruction %s: %w", role, err) } inst := string(b) writingPath := filepath.Join(root, "configs", "shared", "writing.md") if wb, err := os.ReadFile(writingPath); err == nil { inst += "\n\n" + string(wb) } return inst, nil }