refactor: 项目结构重组,src/ 扁平化为根目录,提取 pkg/ 子包

- 模块名重命名 yunshu -> hub.gaomia.site/titor/YunShu
- Go 版本升级 1.21 -> 1.25
- src/ 目录删除,所有文件移至根目录
- 新增 pkg/mdprint/: Markdown AST 解析+ANSI 渲染
- 新增 pkg/style/: 终端颜色样式(8色 ANSI + 24位真彩色)
- 新增 pkg/termui/: 终端输入组件(交互式输入/密码/确认)
- 更新文档:AGENTS.md、architecture.md、changelog.md、taolun.md
- gitignore 通配符修复 yunshu.exe -> yunshu.exe*
This commit is contained in:
titor
2026-05-09 03:55:56 +08:00
parent 5f355a0d7c
commit d2b9b2c4bb
26 changed files with 1739 additions and 159 deletions

76
loader.go Normal file
View File

@@ -0,0 +1,76 @@
package main
import (
"fmt"
"os"
"strings"
"gopkg.in/yaml.v3"
)
// LoadAgent 从 .md 文件加载 agent 定义
// 搜索结果:项目目录 → 全局配置目录
func LoadAgent(name string) (*AgentDef, error) {
path := SearchFile(name)
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("读取 agent 文件失败 (搜索路径: %s): %w", name, err)
}
content := string(data)
frontmatter, body, err := parseFrontmatter(content)
if err != nil {
return nil, err
}
def := &AgentDef{SystemPrompt: strings.TrimSpace(body)}
if err := yaml.Unmarshal([]byte(frontmatter), def); err != nil {
return nil, fmt.Errorf("解析 frontmatter 失败: %w", err)
}
if def.Name == "" {
return nil, fmt.Errorf("agent 定义缺少 name 字段")
}
// 注入能力边界目录到 system prompt
def.SystemPrompt += BuildInjectPrompt(def.Tools)
return def, nil
}
func parseFrontmatter(content string) (string, string, error) {
lines := strings.Split(content, "\n")
if len(lines) < 2 || strings.TrimSpace(lines[0]) != "---" {
return "", content, nil
}
endIdx := -1
for i := 1; i < len(lines); i++ {
if strings.TrimSpace(lines[i]) == "---" {
endIdx = i
break
}
}
if endIdx == -1 {
return "", content, nil
}
frontmatter := strings.Join(lines[1:endIdx], "\n")
body := strings.Join(lines[endIdx+1:], "\n")
return frontmatter, body, nil
}
// LoadSkill 按名称加载 skill 知识内容
// 搜索结果skills/<name>/SKILL.md → ~/.config/weather-cli/skills/<name>/SKILL.md
func LoadSkill(name string) (string, error) {
relativePath := fmt.Sprintf("skills/%s/SKILL.md", name)
path := SearchFile(relativePath)
data, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("skill %q 未找到", name)
}
_, body, _ := parseFrontmatter(string(data))
return strings.TrimSpace(body), nil
}