fix: harden auth, sse, search, and docs
This commit is contained in:
107
tao_core.go
107
tao_core.go
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -13,8 +14,10 @@ import (
|
||||
|
||||
// --- 道 (Config & State) ---
|
||||
type Config struct {
|
||||
MemoryRoot string
|
||||
Port string
|
||||
MemoryRoot string
|
||||
Port string
|
||||
SearchRoot string
|
||||
MaxSearchFiles int
|
||||
}
|
||||
|
||||
type TaoServer struct {
|
||||
@@ -415,14 +418,14 @@ func (s *TaoServer) HousekeepMemory(targetMonth string) (string, error) {
|
||||
if entry.IsDir() && strings.HasPrefix(entry.Name(), "W") {
|
||||
src := filepath.Join(monthDir, entry.Name())
|
||||
dst := filepath.Join(archiveRoot, entry.Name())
|
||||
if err := os.Rename(src, dst); err != nil {
|
||||
if err := movePath(src, dst); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if !entry.IsDir() && entry.Name() != "Month_Summary.md" {
|
||||
src := filepath.Join(monthDir, entry.Name())
|
||||
dst := filepath.Join(archiveRoot, entry.Name())
|
||||
if err := os.Rename(src, dst); err != nil {
|
||||
if err := movePath(src, dst); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@@ -434,6 +437,72 @@ func (s *TaoServer) HousekeepMemory(targetMonth string) (string, error) {
|
||||
return fmt.Sprintf("归档完成: %s", archiveRoot), nil
|
||||
}
|
||||
|
||||
func movePath(src string, dst string) error {
|
||||
if err := os.Rename(src, dst); err == nil {
|
||||
return nil
|
||||
}
|
||||
info, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return copyDir(src, dst)
|
||||
}
|
||||
if err := copyFile(src, dst); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.RemoveAll(src)
|
||||
}
|
||||
|
||||
func copyDir(src string, dst string) error {
|
||||
if err := os.MkdirAll(dst, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
sPath := filepath.Join(src, entry.Name())
|
||||
dPath := filepath.Join(dst, entry.Name())
|
||||
if entry.IsDir() {
|
||||
if err := copyDir(sPath, dPath); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := copyFile(sPath, dPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src string, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
if _, err := io.Copy(out, in); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := out.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mustAtoi(s string) int {
|
||||
n, _ := strconv.Atoi(s)
|
||||
return n
|
||||
@@ -447,8 +516,23 @@ func (s *TaoServer) InspectAndPropose(repoPath string) (string, error) {
|
||||
repoPath = "/root/.openclaw/workspace/tao_mcp_go"
|
||||
}
|
||||
|
||||
// 1) 拉取最新代码(若失败则继续)
|
||||
_ = exec.Command("git", "-C", repoPath, "pull").Run()
|
||||
allowed := getEnv("TAO_ALLOWED_REPOS", repoPath)
|
||||
allowList := strings.Split(allowed, ",")
|
||||
permitted := false
|
||||
for _, item := range allowList {
|
||||
item = strings.TrimSpace(item)
|
||||
if item != "" && repoPath == item {
|
||||
permitted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !permitted {
|
||||
return "repo_path not allowed", fmt.Errorf("repo_path not allowed: %s", repoPath)
|
||||
}
|
||||
|
||||
if getEnvBool("TAO_ALLOW_GIT_PULL", false) {
|
||||
_ = exec.Command("git", "-C", repoPath, "pull").Run()
|
||||
}
|
||||
|
||||
// 2) 收集灵感(包含 #Todo/#Fix)
|
||||
inspDir := filepath.Join(s.config.MemoryRoot, "Inspirations")
|
||||
@@ -568,7 +652,7 @@ func (s *TaoServer) RecordSummary(content string, weekOffset int) (string, error
|
||||
return summaryPath, nil
|
||||
}
|
||||
|
||||
// SearchMemory 遍历所有 Markdown 文件,寻找包含关键词的内容
|
||||
// SearchMemoryAdvanced 遍历所有 Markdown 文件,寻找包含关键词的内容
|
||||
func (s *TaoServer) SearchMemoryAdvanced(keyword string, related []string, causal bool, includeArchive bool) ([]string, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@@ -589,14 +673,19 @@ func (s *TaoServer) SearchMemoryAdvanced(keyword string, related []string, causa
|
||||
}
|
||||
}
|
||||
|
||||
err := filepath.Walk(s.config.MemoryRoot, func(path string, info os.FileInfo, err error) error {
|
||||
scanned := 0
|
||||
err := filepath.Walk(s.config.SearchRoot, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.config.MaxSearchFiles > 0 && scanned >= s.config.MaxSearchFiles {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !includeArchive && info.IsDir() && strings.Contains(path, string(filepath.Separator)+"_Archive"+string(filepath.Separator)) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !info.IsDir() && filepath.Ext(path) == ".md" {
|
||||
scanned++
|
||||
if !includeArchive && strings.Contains(path, string(filepath.Separator)+"_Archive"+string(filepath.Separator)) {
|
||||
return nil
|
||||
}
|
||||
@@ -607,7 +696,7 @@ func (s *TaoServer) SearchMemoryAdvanced(keyword string, related []string, causa
|
||||
text := string(content)
|
||||
for _, term := range terms {
|
||||
if term != "" && strings.Contains(text, term) {
|
||||
rel, _ := filepath.Rel(s.config.MemoryRoot, path)
|
||||
rel, _ := filepath.Rel(s.config.SearchRoot, path)
|
||||
label := "命中"
|
||||
isCausal := term != keyword
|
||||
if isCausal {
|
||||
|
||||
Reference in New Issue
Block a user