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

146
main.go Normal file
View File

@@ -0,0 +1,146 @@
package main
import (
"fmt"
"os"
"strings"
"syscall"
"hub.gaomia.site/titor/YunShu/pkg/style"
"hub.gaomia.site/titor/YunShu/pkg/termui"
)
const version = "1.0.0"
func init() {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
setConsoleCP := kernel32.NewProc("SetConsoleOutputCP")
setConsoleCP.Call(65001)
}
func printHelp() {
fmt.Println()
fmt.Println(style.Cyan.Render("☁ 云枢·Agent"), style.Dim.Render("v"+version))
fmt.Println()
fmt.Println(style.Bold.Render("用法:"))
fmt.Println(" yunshu [命令] [查询内容]")
fmt.Println()
fmt.Println(style.Bold.Render("命令:"))
fmt.Println(" onboard 交互式初始化配置")
fmt.Println(" help, -h 显示帮助信息")
fmt.Println(" version, -v 显示版本号")
fmt.Println()
fmt.Println(style.Bold.Render("示例:"))
fmt.Println(" yunshu \"北京今天天气\" ", style.Dim.Render("单次天气查询"))
fmt.Println(" yunshu ", style.Dim.Render("启动交互模式"))
fmt.Println(" yunshu onboard ", style.Dim.Render("重新初始化配置"))
fmt.Println()
fmt.Println(style.Bold.Render("环境变量:"))
fmt.Println(" LLM_API_KEY API Key优先级高于配置文件")
fmt.Println(" LLM_ENDPOINT API 端点")
fmt.Println(" LLM_MODEL 模型名")
fmt.Println()
fmt.Println(style.Bold.Render("配置文件:"), "~/.config/yunshu/config.yaml")
fmt.Println()
}
func printVersion() {
fmt.Println("yunshu", version)
}
func main() {
args := os.Args[1:]
if len(args) > 0 {
switch args[0] {
case "onboard":
runOnboard()
return
case "help", "--help", "-h":
printHelp()
return
case "version", "--version", "-v":
printVersion()
return
default:
if strings.HasPrefix(args[0], "-") {
fmt.Fprintln(os.Stderr, style.Red.Render("未知选项: "+args[0]))
fmt.Fprintln(os.Stderr, "可用命令: onboard, help, version")
os.Exit(1)
}
}
}
cfg, err := LoadConfig()
if err != nil {
fmt.Fprintln(os.Stderr, style.Red.Render("未找到配置文件。请先运行:"))
fmt.Fprintln(os.Stderr, " yunshu onboard")
os.Exit(1)
}
_ = cfg
GenerateToolsYAML()
agentPath := SearchFile("agents/weather-agent.md")
def, err := LoadAgent(agentPath)
if err != nil {
fmt.Fprintln(os.Stderr, style.Red.Render("加载 agent 失败: "+err.Error()))
os.Exit(1)
}
if len(args) > 0 {
ClearSession()
query := strings.Join(args, " ")
if err := RunAgent(def, query); err != nil {
fmt.Fprintln(os.Stderr, style.Red.Render("错误: "+err.Error()))
os.Exit(1)
}
return
}
fmt.Println()
fmt.Println(style.Cyan.Render("☁ 云枢·Agent"), style.Dim.Render("· 天气情报官"))
fmt.Println(style.Dim.Render(" /exit 退出,// 开头的行不发给 LLM"))
fmt.Println()
ClearSession()
for {
fmt.Print(style.Cyan.Render(" "))
input := termui.ReadLine()
input = strings.TrimSpace(input)
if input == "" {
continue
}
if strings.HasPrefix(input, "//") {
continue
}
switch input {
case "/exit", "exit", "quit":
fmt.Println("再见!")
fmt.Println()
return
case "/clear":
ClearSession()
fmt.Print("\033[2J\033[H")
fmt.Println(style.Dim.Render("会话已清空"))
fmt.Println()
continue
case "/help":
fmt.Println("可用命令:")
fmt.Println(" /exit 退出")
fmt.Println(" /clear 清空会话")
fmt.Println(" /help 显示帮助")
fmt.Println(" // 不发给 LLM 的注释行")
fmt.Println()
continue
}
if err := RunAgent(def, input); err != nil {
fmt.Fprintln(os.Stderr, style.Red.Render("错误: "+err.Error()))
}
fmt.Println()
}
}