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:
@@ -2,7 +2,7 @@
|
||||
|
||||
## 通用规范
|
||||
|
||||
- 全程使用中文书写注释、文档和沟通
|
||||
- 全程使用中文书写注释、文档、沟通以及内部思考过程
|
||||
- 所有代码必须包含详细的中文注释,说明函数功能、参数含义、关键逻辑
|
||||
- Markdown 文件使用 `#` 标题层级,保持结构清晰
|
||||
- 变量命名采用驼峰式,类型和函数首字母大写导出
|
||||
@@ -16,6 +16,10 @@
|
||||
- 导出函数(首字母大写)供包外调用,非导出函数(首字母小写)为内部实现
|
||||
- HTTP 客户端设置超时(默认 15s),避免资源泄漏
|
||||
- JSON 序列化/反序列化使用 `encoding/json` 标准库
|
||||
- 终端颜色输出优先使用 `pkg/style` 包:
|
||||
- 8 色用 `Fg(ColorXxx)` / `Bg(ColorXxx)`
|
||||
- 真彩色用 `FgHex("#RRGGBB")` / `BgHex("#RRGGBB")`
|
||||
- 所有通配 `.Render(text)` 生成 ANSI 转义序列
|
||||
|
||||
## Agent 定义规范(.md 文件)
|
||||
|
||||
@@ -115,3 +119,11 @@ tools:
|
||||
14. **geocode 工具用 Go 代码实现比让 LLM 自己调 http-get 解析 JSON 更可靠**。LLM 在构造 URL 和解析嵌套 JSON 时容易出错(尤其是中文编码问题)。注册为 tool 后,LLM 只需提供城市名参数,Go 代码处理所有细节。
|
||||
|
||||
15. **项目正式命名为云枢·Agent(YunShu / yunshu)**,配置目录从 `~/.config/weather-cli/` 迁移到 `~/.config/yunshu/`。旧目录在首次运行时会自动迁移并删除。二进制名称改为 `yunshu`。如果迁移失败,用户可手动复制旧目录内容后重新运行。
|
||||
|
||||
### 2026-05-09
|
||||
|
||||
1. **Windows raw mode + bufio.Reader 冲突**:在禁用 `ENABLE_LINE_INPUT` 的 raw mode 下,`bufio.NewReader(os.Stdin).ReadRune()` 会因内部预读缓冲(默认 4KB)导致读取阻塞。后续尝试用 `ReadConsoleInputW` + 手动回显也因光标位置计算不一致而放弃。**最终决定放弃自实现 Tab 补全**,后续如需补全功能,引入第三方库(如 `go-prompt` / `readline`)。
|
||||
|
||||
2. **ANSI 光标移动需要启用输出 VT 处理**:`\033[A`(光标上移)/ `\033[J`(清屏)等输出序列需要输出句柄设置 `ENABLE_VIRTUAL_TERMINAL_PROCESSING`(0x0004)才能生效。只设置输入句柄的 mode 不够,输入输出句柄是两个独立的控制台句柄。
|
||||
|
||||
3. **ReadLineWithCompletion / Completer 类型已移除**。`completer.go` 清空,`main.go` 回到 `termui.ReadLine()`。`cmdCompleter`、`commonPrefix`、相关测试一并移除。`input.go` 中 `ReadConsoleInputW` 相关的 `keyEventRecord`/`inputRecord` 结构和 proc 也一并清理。
|
||||
|
||||
@@ -47,6 +47,19 @@ Tool (src/tool.go 注册) → 确定性执行(Go 代码,仅返回结果
|
||||
| 知识加载 | 预置或直接塞入 | 按需加载,仅该轮存在 |
|
||||
| 工具执行 | 依赖 LLM 构造 URL 解析 JSON | Tool 用 Go 代码,100% 可靠 |
|
||||
|
||||
## 包结构
|
||||
|
||||
```
|
||||
pkg/
|
||||
├── mdprint/ Markdown → ANSI 终端渲染(AST 架构)
|
||||
│ ├── mdprint.go Node 类型定义 + Print() 入口
|
||||
│ ├── parse.go 块级解析器(状态机)
|
||||
│ ├── inline.go 行内解析器(递归)
|
||||
│ └── render.go ANSI 渲染器(type switch)
|
||||
├── style/ 终端颜色样式库(8 色 ANSI + 24-bit 真彩色)
|
||||
└── termui/ 终端交互(行输入、模式设置)
|
||||
```
|
||||
|
||||
## 当前 tools
|
||||
|
||||
| 工具名 | 作用 | 实现 |
|
||||
|
||||
@@ -2,6 +2,34 @@
|
||||
|
||||
> 坐看云卷云舒,静听花开花落
|
||||
|
||||
## [1.1.0] - 2026-05-09
|
||||
|
||||
### 新增
|
||||
- Markdown 渲染器重构:从"一行流"改为 AST 架构(`pkg/mdprint/`)
|
||||
- 块级解析器:Heading / Paragraph / CodeBlock / Blockquote / List / Table / ThematicBreak
|
||||
- 行内解析器:Bold / Italic / Code / Link + 递归嵌套
|
||||
- ANSI 渲染器:type switch 分发,标题按级别分色
|
||||
- 标题视觉系统:1-3 级 `▪` 符号 + 加粗,4-5 级 `▫` 符号 + 加粗,6 级纯加粗
|
||||
- 所有标题前插空行,1 级标题前后各插空行
|
||||
- 真彩色支持:`style.FgHex("#RRGGBB")` / `style.BgHex("#RRGGBB")`,兼容原有 8 色 ANSI
|
||||
- 莫奈《睡莲》配色方案:H1 雾蓝灰 / H2 鼠尾草绿 / H3 薄荷青 / H4 淡紫粉 / H5 暖灰绿 / H6 浅灰
|
||||
- 排版间距优化:`---` 横线前后空行、输入与响应之间空行、输出末尾空行
|
||||
|
||||
### 修复
|
||||
- 行内解析器未闭合分隔符(`*` / `` ` ``)导致死循环
|
||||
- 代码 fence 检测不识别 ` ```go` 等带语言标识的写法
|
||||
- Windows 终端输入模式导致 `bufio.Scanner` 无法获取行输入
|
||||
|
||||
### 变更
|
||||
- 项目结构:`src/` → 根目录 + `pkg/` 子包
|
||||
- `pkg/style` 新增真彩色 API,向后兼容
|
||||
|
||||
### 技术栈
|
||||
- 语言:Go 1.25
|
||||
- 依赖:仅 `gopkg.in/yaml.v3`
|
||||
- 默认 LLM:豆包(火山引擎)`doubao-seed-2-0-pro-260215`
|
||||
- 数据源:MSN 天气非公开 API(`assets.msn.cn`)
|
||||
|
||||
## [1.0.0] - 2026-05-08
|
||||
|
||||
### 发布说明
|
||||
|
||||
100
docs/taolun.md
100
docs/taolun.md
@@ -142,3 +142,103 @@ weather/
|
||||
|
||||
### 设计理念
|
||||
"云枢"二字呼应了项目作为 AI 助理"中枢调度"的定位——云是分布式的、流转的,枢是枢纽、核心。后续主-从架构中,master 负责调度、subagent 各司其职,恰如云卷云舒。
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-09 Markdown 渲染器重构 + 终端输入修复
|
||||
|
||||
### 背景
|
||||
原本的 `pkg/mdprint/mdprint.go` 是"一行流"渲染——读取 Markdown 文本后直接正则/字符串匹配输出 ANSI。问题:heading 和后续 paragraph 无法正确分离,`#### 标题\n正文` 导致正文也被染上 heading 颜色。
|
||||
|
||||
### 方案:OOP 风格 AST 架构
|
||||
将 `pkg/mdprint/` 拆分为多文件,各司其职:
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `mdprint.go` | `Node` 接口 + 所有块级/行内类型定义 + `Print()` 入口 |
|
||||
| `parse.go` | 状态机块级解析器 `parseBlocks` |
|
||||
| `inline.go` | 递归行内解析器 `parseInline` |
|
||||
| `render.go` | `renderNode` type switch 渲染器 |
|
||||
| `mdprint_test.go` | 单元测试(待加) |
|
||||
|
||||
### AST 类型设计
|
||||
```
|
||||
Node interface
|
||||
├── Heading{Level, Content} → `#### 标题`
|
||||
├── Paragraph{Content} → 普通文本块
|
||||
├── CodeBlock{Lang, Body} → ```fenced```
|
||||
├── Blockquote{Children} → > 引用
|
||||
├── List{Ordered, Items} → - / * / 1. 列表
|
||||
├── ListItem{Checked, Content} → 含 checkbox 支持
|
||||
├── Table{Headers, Rows} → `| H1 | H2 |`
|
||||
├── ThematicBreak{} → ---
|
||||
├── Text{Text} → "纯文本"
|
||||
├── Bold{Content} → **bold**
|
||||
├── Italic{Content} → *italic*
|
||||
├── Code{Text} → `code`
|
||||
└── Link{Content, URL} → [text](url)
|
||||
```
|
||||
|
||||
### 解析器流程
|
||||
1. `Print(content)` → 按 `\n` 分割为 lines
|
||||
2. `parseBlocks(lines)` → 逐行状态机,识别 heading / code fence / quote / list / table / thematic-break / paragraph → 输出 `[]Node`
|
||||
3. 块内文本调 `parseInline()` → 递归扫描,识别 `**`/`*`/\`\`/`[]()` → 输出 `[]Node`
|
||||
4. 遍历 `[]Node` 调 `renderNode()` → type switch 分发 → `strings.Builder` 拼接
|
||||
5. `fmt.Print` 输出
|
||||
|
||||
### 关键修复
|
||||
- Heading 和 Paragraph 是独立 AST 节点,heading 后的文本永远归 Paragraph,不会再染上 heading 颜色
|
||||
- 块级解析器在 heading 行后自动切 paragraph,无需 blank line 分隔
|
||||
- 代码 fence 用状态机追踪开闭
|
||||
|
||||
### 终端输入修复(2026-05-09)
|
||||
- **Root cause**:Windows 控制台处于 character mode(`ENABLE_WINDOW_INPUT`),导致 `bufio.Scanner` 和 `ReadString` 均无法获取行输入
|
||||
- **修复**:`ensureLineMode()` 在每次读之前调 `GetConsoleMode` + `SetConsoleMode` 设置为 `ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT`
|
||||
- `ReadLine()` 改为 `bufio.NewReader(os.Stdin).ReadString('\n')`(每次新建 reader),避免 Scanner 的缓冲区冲突
|
||||
- ANSI 样式在所有提示符和状态指示器上恢复正常显示
|
||||
|
||||
### 当前进度(后续完成)
|
||||
- 2026-05-09 补充完成:`inline.go` + `render.go` + `mdprint_test.go`
|
||||
- 行内解析器支持 `**bold**` / `*italic*` / `` `code` `` / `[link](url)`,递归嵌套
|
||||
- 修复:未闭合分隔符死循环、代码 fence 不识别语言标识
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-09 标题视觉系统 + 真彩色支持
|
||||
|
||||
### 背景
|
||||
Markdown 渲染器完成 AST 解析后,需要确定标题的终端展示风格。最初方案是保留 Markdown 的 `#` 前缀,但用户反馈效果不好。
|
||||
|
||||
### 标题样式演进
|
||||
1. **最初**:`#` 前缀 + ANSI 颜色 → 用户觉得不好看
|
||||
2. **方案 A**:去掉 `#`,用 `▎` 色块 + 加粗文字 → 讨论中用户提出 `▪`/`▫` 符号更好
|
||||
3. **方案 B**:H1-H3 用 `▪` + 空格,H4-H5 用 `▫` + 空格,H6 纯加粗 → 用户确认
|
||||
4. **配色**:黄色/红色保留给重要信息,排除后从青/蓝/绿/品红/白中分配
|
||||
5. **最终使用真彩色**:用户要求莫奈(印象派)配色,现有 8 色 ANSI 无法满足
|
||||
|
||||
### 最终标题配置
|
||||
| 级别 | 符号 | 色值 | 色名 |
|
||||
|------|------|------|------|
|
||||
| H1 | `▪ ` | `#6B8E9B` | 雾蓝灰 |
|
||||
| H2 | `▪ ` | `#89A894` | 鼠尾草绿 |
|
||||
| H3 | `▪ ` | `#A6C0B5` | 薄荷青 |
|
||||
| H4 | `▫ ` | `#C3B1BD` | 淡紫粉 |
|
||||
| H5 | `▫ ` | `#7B8E8A` | 暖灰绿 |
|
||||
| H6 | 无 | Dim | 浅灰 |
|
||||
|
||||
### 排版规则
|
||||
- 所有标题前插一个空行
|
||||
- 1 级标题前后各插一个空行
|
||||
- `---` 横线前后各插一个空行
|
||||
- 输出末尾统一加空行
|
||||
- 交互模式:输入与响应之间插空行,响应与下一轮 `❯` 之间插空行
|
||||
|
||||
### 真彩色支持方案
|
||||
- `pkg/style/style.go` 新增 `FgHex()` / `BgHex()` 方法
|
||||
- 输出 `\033[38;2;R;G;Bm` 格式的 24-bit 真彩色序列
|
||||
- 底层复用 `codes []string`,`Render()` 零改动
|
||||
- 旧 `Fg(Color)` 8 色 API 完全兼容,不破坏已有代码
|
||||
|
||||
### 验证
|
||||
- 19/19 单元测试通过
|
||||
- 构建成功,二进制运行正常
|
||||
|
||||
Reference in New Issue
Block a user