ai_xiaopei
9 days ago 3d32162df6f0af1b89004140fd3191ba8753fb1d
docs: add kb-cli enhancement implementation plan
1 files added
1047 ■■■■■ changed files
docs/superpowers/plans/2026-07-26-kb-cli-enhancement.md 1047 ●●●●● patch | view | raw | blame | history
docs/superpowers/plans/2026-07-26-kb-cli-enhancement.md
New file
@@ -0,0 +1,1047 @@
# kb-cli 增强功能实现计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 为 kb-cli 添加 `--with-content` 和 `--with-links` 功能,并调整 kb-search 技能优先使用 kb-cli
**Architecture:** 在现有 SearchResult 结构体上添加可选字段 Content 和 Links,通过 SearchOptions 控制是否填充这些字段。修改输出格式化器支持新字段的展示。
**Tech Stack:** Go 1.22, SQLite FTS5, Cobra CLI
## Global Constraints
- 所有新功能必须有单元测试
- JSON 输出使用 `omitempty` 标签
- 保持向后兼容(不破坏现有命令)
- 性能目标:< 100ms(包含内容和链接获取)
---
## Task 1: 添加 GetNodeLinks 数据库方法
**Files:**
- Modify: `internal/index/sqlite.go:120-140`
- Test: `internal/index/sqlite_test.go`
**Interfaces:**
- Consumes: `Store.db` (SQLite 连接)
- Produces: `GetNodeLinks(nodeID int64) ([]string, error)` 方法
- [ ] **Step 1: 编写失败测试**
在 `internal/index/sqlite_test.go` 添加:
```go
func TestGetNodeLinks(t *testing.T) {
    store := setupTestStore(t)
    defer store.Close()
    // 插入测试节点
    node1 := &graph.Node{
        Path:    "FAQ/001-测试.md",
        Title:   "测试文档",
        Section: "FAQ",
        Content: "# 测试\n\n内容",
    }
    node2 := &graph.Node{
        Path:    "FAQ/002-相关.md",
        Title:   "相关文档",
        Section: "FAQ",
        Content: "# 相关\n\n内容",
    }
    id1, err := store.InsertNode(node1)
    require.NoError(t, err)
    id2, err := store.InsertNode(node2)
    require.NoError(t, err)
    // 插入 wikilink 边
    edge := &graph.Edge{
        FromNode: id1,
        ToNode:   id2,
        Relation: "wikilink",
        Label:    "相关文档",
    }
    err = store.InsertEdge(edge)
    require.NoError(t, err)
    // 测试获取链接
    links, err := store.GetNodeLinks(id1)
    require.NoError(t, err)
    assert.Len(t, links, 1)
    assert.Equal(t, "FAQ/002-相关.md", links[0])
    // 测试无链接的节点
    links, err = store.GetNodeLinks(id2)
    require.NoError(t, err)
    assert.Len(t, links, 0)
}
```
- [ ] **Step 2: 运行测试确认失败**
```bash
cd ~/workspace/kb-cli
go test ./internal/index -run TestGetNodeLinks -v
```
Expected: FAIL - "store.GetNodeLinks undefined"
- [ ] **Step 3: 实现 GetNodeLinks 方法**
在 `internal/index/sqlite.go` 的 `GetNodeContent` 方法后添加:
```go
// GetNodeLinks 获取节点的关联链接(wikilink 目标)
func (s *Store) GetNodeLinks(nodeID int64) ([]string, error) {
    query := `
        SELECT n.path
        FROM edges e
        JOIN nodes n ON n.id = e.to_node
        WHERE e.from_node = ? AND e.relation = 'wikilink'
    `
    rows, err := s.db.Query(query, nodeID)
    if err != nil {
        return nil, fmt.Errorf("查询链接失败: %w", err)
    }
    defer rows.Close()
    var links []string
    for rows.Next() {
        var path string
        if err := rows.Scan(&path); err != nil {
            return nil, fmt.Errorf("扫描链接失败: %w", err)
        }
        links = append(links, path)
    }
    if err := rows.Err(); err != nil {
        return nil, fmt.Errorf("遍历链接失败: %w", err)
    }
    return links, nil
}
```
- [ ] **Step 4: 运行测试确认通过**
```bash
cd ~/workspace/kb-cli
go test ./internal/index -run TestGetNodeLinks -v
```
Expected: PASS
- [ ] **Step 5: 提交**
```bash
cd ~/workspace/kb-cli
git add internal/index/sqlite.go internal/index/sqlite_test.go
git commit -m "feat: add GetNodeLinks method for wikilink retrieval"
```
---
## Task 2: 扩展 SearchResult 结构体
**Files:**
- Modify: `internal/search/engine.go:15-25`
- Test: `internal/search/engine_test.go`
**Interfaces:**
- Consumes: 无
- Produces: 扩展的 `SearchResult` 结构体(Content, Links 字段)
- [ ] **Step 1: 编写失败测试**
在 `internal/search/engine_test.go` 添加:
```go
func TestSearchResultJSON_OmitEmpty(t *testing.T) {
    // 测试无内容和链接时,JSON 不包含这些字段
    result := SearchResult{
        ID:      1,
        Path:    "test.md",
        Title:   "测试",
        Section: "FAQ",
        Score:   10,
    }
    jsonBytes, err := json.Marshal(result)
    require.NoError(t, err)
    jsonStr := string(jsonBytes)
    assert.NotContains(t, jsonStr, "content")
    assert.NotContains(t, jsonStr, "links")
    // 测试有内容时,JSON 包含 content 字段
    result.Content = "# 测试内容"
    jsonBytes, err = json.Marshal(result)
    require.NoError(t, err)
    jsonStr = string(jsonBytes)
    assert.Contains(t, jsonStr, `"content":"# 测试内容"`)
    // 测试有链接时,JSON 包含 links 字段
    result.Links = []string{"related.md"}
    jsonBytes, err = json.Marshal(result)
    require.NoError(t, err)
    jsonStr = string(jsonBytes)
    assert.Contains(t, jsonStr, `"links":["related.md"]`)
}
```
- [ ] **Step 2: 运行测试确认失败**
```bash
cd ~/workspace/kb-cli
go test ./internal/search -run TestSearchResultJSON_OmitEmpty -v
```
Expected: FAIL - "Content undefined" 或测试失败(因为字段不存在)
- [ ] **Step 3: 扩展 SearchResult 结构体**
修改 `internal/search/engine.go` 中的 `SearchResult` 结构体:
```go
// SearchResult 搜索结果
type SearchResult struct {
    ID      int64    `json:"id"`
    Path    string   `json:"path"`
    Title   string   `json:"title"`
    Section string   `json:"section"`
    Score   int      `json:"score"`
    // 可选字段(omitempty)
    Content string   `json:"content,omitempty"` // --with-content 时填充
    Links   []string `json:"links,omitempty"`   // --with-links 时填充
}
```
- [ ] **Step 4: 运行测试确认通过**
```bash
cd ~/workspace/kb-cli
go test ./internal/search -run TestSearchResultJSON_OmitEmpty -v
```
Expected: PASS
- [ ] **Step 5: 提交**
```bash
cd ~/workspace/kb-cli
git add internal/search/engine.go internal/search/engine_test.go
git commit -m "feat: extend SearchResult with Content and Links fields"
```
---
## Task 3: 扩展 SearchOptions 并修改 Search 函数
**Files:**
- Modify: `internal/search/engine.go:30-40, 80-120`
- Test: `internal/search/engine_test.go`
**Interfaces:**
- Consumes: `Store.GetNodeContent`, `Store.GetNodeLinks` (Task 1)
- Produces: 扩展的 `SearchOptions` 和增强的 `Search` 函数
- [ ] **Step 1: 编写失败测试**
在 `internal/search/engine_test.go` 添加:
```go
func TestSearch_WithContent(t *testing.T) {
    store := setupTestStore(t)
    defer store.Close()
    // 插入测试节点
    node := &graph.Node{
        Path:    "FAQ/001-测试.md",
        Title:   "测试文档",
        Section: "FAQ",
        Content: "# 测试\n\n这是测试内容",
    }
    id, err := store.InsertNode(node)
    require.NoError(t, err)
    err = store.CreateFTS()
    require.NoError(t, err)
    err = store.PopulateFTS()
    require.NoError(t, err)
    // 测试带内容的搜索
    opts := SearchOptions{
        TopN:        5,
        WithContent: true,
    }
    results, err := Search(store, []string{"测试"}, opts)
    require.NoError(t, err)
    require.Len(t, results, 1)
    assert.Equal(t, id, results[0].ID)
    assert.Equal(t, "# 测试\n\n这是测试内容", results[0].Content)
    // 测试不带内容的搜索
    opts.WithContent = false
    results, err = Search(store, []string{"测试"}, opts)
    require.NoError(t, err)
    require.Len(t, results, 1)
    assert.Empty(t, results[0].Content)
}
func TestSearch_WithLinks(t *testing.T) {
    store := setupTestStore(t)
    defer store.Close()
    // 插入两个节点
    node1 := &graph.Node{
        Path:    "FAQ/001-测试.md",
        Title:   "测试文档",
        Section: "FAQ",
        Content: "# 测试",
    }
    node2 := &graph.Node{
        Path:    "FAQ/002-相关.md",
        Title:   "相关文档",
        Section: "FAQ",
        Content: "# 相关",
    }
    id1, err := store.InsertNode(node1)
    require.NoError(t, err)
    id2, err := store.InsertNode(node2)
    require.NoError(t, err)
    // 插入 wikilink 边
    edge := &graph.Edge{
        FromNode: id1,
        ToNode:   id2,
        Relation: "wikilink",
        Label:    "相关文档",
    }
    err = store.InsertEdge(edge)
    require.NoError(t, err)
    err = store.CreateFTS()
    require.NoError(t, err)
    err = store.PopulateFTS()
    require.NoError(t, err)
    // 测试带链接的搜索
    opts := SearchOptions{
        TopN:      5,
        WithLinks: true,
    }
    results, err := Search(store, []string{"测试"}, opts)
    require.NoError(t, err)
    require.Len(t, results, 1)
    assert.Equal(t, id1, results[0].ID)
    assert.Len(t, results[0].Links, 1)
    assert.Equal(t, "FAQ/002-相关.md", results[0].Links[0])
    // 测试不带链接的搜索
    opts.WithLinks = false
    results, err = Search(store, []string{"测试"}, opts)
    require.NoError(t, err)
    require.Len(t, results, 1)
    assert.Empty(t, results[0].Links)
}
```
- [ ] **Step 2: 运行测试确认失败**
```bash
cd ~/workspace/kb-cli
go test ./internal/search -run "TestSearch_WithContent|TestSearch_WithLinks" -v
```
Expected: FAIL - "WithContent undefined" 或测试失败
- [ ] **Step 3: 扩展 SearchOptions 并修改 Search 函数**
修改 `internal/search/engine.go`:
```go
// SearchOptions 搜索选项
type SearchOptions struct {
    Expanded    []string
    Symptom     []string
    TopN        int
    WithContent bool // 新增:是否返回内容
    WithLinks   bool // 新增:是否返回链接
}
// Search 执行搜索
func Search(store *index.Store, keywords []string, opts SearchOptions) ([]SearchResult, error) {
    // 合并所有关键词
    allKeywords := append(keywords, opts.Expanded...)
    allKeywords = append(allKeywords, opts.Symptom...)
    // FTS5 搜索
    ftsResults, err := store.FTSSearch(allKeywords, 100)
    if err != nil {
        return nil, err
    }
    // 评分
    scoreMap := make(map[int64]int)
    for _, r := range ftsResults {
        score := 0
        for _, kw := range keywords {
            score += scoreResult(r, kw, ScoreNormal)
        }
        for _, kw := range opts.Expanded {
            score += scoreResult(r, kw, ScoreExpanded)
        }
        for _, kw := range opts.Symptom {
            score += scoreResult(r, kw, ScoreSymptom)
        }
        scoreMap[r.ID] = score
    }
    // 转换为结果列表
    var results []SearchResult
    for _, r := range ftsResults {
        results = append(results, SearchResult{
            ID:      r.ID,
            Path:    r.Path,
            Title:   r.Title,
            Section: r.Section,
            Score:   scoreMap[r.ID],
        })
    }
    // 按分数排序
    sort.Slice(results, func(i, j int) bool {
        return results[i].Score > results[j].Score
    })
    // 限制返回数量
    if opts.TopN > 0 && len(results) > opts.TopN {
        results = results[:opts.TopN]
    }
    // 增强结果(新增)
    for i := range results {
        if opts.WithContent {
            content, _, _, err := store.GetNodeContent(results[i].ID)
            if err == nil {
                results[i].Content = content
            }
        }
        if opts.WithLinks {
            links, err := store.GetNodeLinks(results[i].ID)
            if err == nil {
                results[i].Links = links
            }
        }
    }
    return results, nil
}
```
- [ ] **Step 4: 运行测试确认通过**
```bash
cd ~/workspace/kb-cli
go test ./internal/search -run "TestSearch_WithContent|TestSearch_WithLinks" -v
```
Expected: PASS
- [ ] **Step 5: 运行所有测试确认无回归**
```bash
cd ~/workspace/kb-cli
go test ./... -v
```
Expected: 所有测试通过
- [ ] **Step 6: 提交**
```bash
cd ~/workspace/kb-cli
git add internal/search/engine.go internal/search/engine_test.go
git commit -m "feat: add WithContent and WithLinks options to Search"
```
---
## Task 4: 添加 CLI flags 并传递给 SearchOptions
**Files:**
- Modify: `cmd/search.go:20-50`
**Interfaces:**
- Consumes: `SearchOptions.WithContent`, `SearchOptions.WithLinks` (Task 3)
- Produces: 新增 `--with-content` 和 `--with-links` flags
- [ ] **Step 1: 添加 flag 变量**
在 `cmd/search.go` 的变量声明区域添加:
```go
var (
    withContent bool
    withLinks   bool
)
```
- [ ] **Step 2: 注册 flags**
在 `init()` 函数中添加:
```go
func init() {
    searchCmd.Flags().StringSliceVar(&expanded, "expanded", nil, "扩展词(提升相关实体权重)")
    searchCmd.Flags().StringSliceVar(&symptom, "symptom", nil, "症状词(针对具体症状)")
    searchCmd.Flags().IntVar(&topN, "top", 10, "返回前 N 条结果")
    searchCmd.Flags().BoolVar(&jsonOut, "json", false, "JSON 格式输出")
    // 新增 flags
    searchCmd.Flags().BoolVar(&withContent, "with-content", false, "返回完整文件内容")
    searchCmd.Flags().BoolVar(&withLinks, "with-links", false, "显示关联文档链接")
}
```
- [ ] **Step 3: 传递 flags 到 SearchOptions**
修改 `runSearch` 函数:
```go
func runSearch(cmd *cobra.Command, args []string) error {
    // ... 现有代码 ...
    opts := search.SearchOptions{
        Expanded:    expanded,
        Symptom:     symptom,
        TopN:        topN,
        WithContent: withContent,
        WithLinks:   withLinks,
    }
    results, err := search.Search(store, args, opts)
    // ... 现有代码 ...
}
```
- [ ] **Step 4: 构建并测试 help 输出**
```bash
cd ~/workspace/kb-cli
go build -o bin/kb .
./bin/kb search --help
```
Expected: 显示 `--with-content` 和 `--with-links` flags
- [ ] **Step 5: 提交**
```bash
cd ~/workspace/kb-cli
git add cmd/search.go
git commit -m "feat: add --with-content and --with-links CLI flags"
```
---
## Task 5: 修改输出格式化器支持新字段
**Files:**
- Modify: `internal/output/formatter.go`
- Test: `internal/output/formatter_test.go`
**Interfaces:**
- Consumes: `SearchResult.Content`, `SearchResult.Links` (Task 2)
- Produces: 增强的 `FormatTable` 和 `FormatJSON` 方法
- [ ] **Step 1: 编写失败测试**
在 `internal/output/formatter_test.go` 添加:
```go
func TestFormatTable_WithContent(t *testing.T) {
    results := []search.SearchResult{
        {
            ID:      1,
            Path:    "FAQ/001-测试.md",
            Title:   "测试文档",
            Section: "FAQ",
            Score:   10,
            Content: "# 测试\n\n这是内容",
        },
    }
    output := FormatTable(results)
    assert.Contains(t, output, "FAQ/001-测试.md")
    assert.Contains(t, output, "--- 内容 ---")
    assert.Contains(t, output, "# 测试")
}
func TestFormatTable_WithLinks(t *testing.T) {
    results := []search.SearchResult{
        {
            ID:      1,
            Path:    "FAQ/001-测试.md",
            Title:   "测试文档",
            Section: "FAQ",
            Score:   10,
            Links:   []string{"FAQ/002-相关.md"},
        },
    }
    output := FormatTable(results)
    assert.Contains(t, output, "--- 关联文档 ---")
    assert.Contains(t, output, "FAQ/002-相关.md")
}
func TestFormatTable_WithBoth(t *testing.T) {
    results := []search.SearchResult{
        {
            ID:      1,
            Path:    "FAQ/001-测试.md",
            Title:   "测试文档",
            Section: "FAQ",
            Score:   10,
            Content: "# 测试",
            Links:   []string{"FAQ/002-相关.md"},
        },
    }
    output := FormatTable(results)
    assert.Contains(t, output, "--- 内容 ---")
    assert.Contains(t, output, "--- 关联文档 ---")
}
func TestFormatJSON_WithContentAndLinks(t *testing.T) {
    results := []search.SearchResult{
        {
            ID:      1,
            Path:    "FAQ/001-测试.md",
            Title:   "测试文档",
            Section: "FAQ",
            Score:   10,
            Content: "# 测试",
            Links:   []string{"FAQ/002-相关.md"},
        },
    }
    output, err := FormatJSON(results)
    require.NoError(t, err)
    assert.Contains(t, output, `"content":"# 测试"`)
    assert.Contains(t, output, `"links":["FAQ/002-相关.md"]`)
}
```
- [ ] **Step 2: 运行测试确认失败**
```bash
cd ~/workspace/kb-cli
go test ./internal/output -run "TestFormatTable_With|TestFormatJSON_With" -v
```
Expected: FAIL - 测试失败(输出不包含新字段)
- [ ] **Step 3: 修改 FormatTable 方法**
修改 `internal/output/formatter.go` 中的 `FormatTable` 函数:
```go
// FormatTable 格式化表格输出
func FormatTable(results []search.SearchResult) string {
    if len(results) == 0 {
        return "未找到匹配结果\n"
    }
    var buf bytes.Buffer
    // 表头
    buf.WriteString(fmt.Sprintf("%-50s %-30s %-10s %s\n", "路径", "标题", "板块", "得分"))
    buf.WriteString(strings.Repeat("-", 100) + "\n")
    // 每行结果
    for _, r := range results {
        title := r.Title
        if len(title) > 28 {
            title = title[:28] + ".."
        }
        buf.WriteString(fmt.Sprintf("%-50s %-30s %-10s %d\n", r.Path, title, r.Section, r.Score))
        // 输出内容(如果有)
        if r.Content != "" {
            buf.WriteString("\n--- 内容 ---\n")
            buf.WriteString(r.Content)
            buf.WriteString("\n")
        }
        // 输出关联文档(如果有)
        if len(r.Links) > 0 {
            buf.WriteString("\n--- 关联文档 ---\n")
            for _, link := range r.Links {
                buf.WriteString(fmt.Sprintf("- %s\n", link))
            }
        }
    }
    buf.WriteString(fmt.Sprintf("\n共 %d 条结果\n", len(results)))
    return buf.String()
}
```
- [ ] **Step 4: 运行测试确认通过**
```bash
cd ~/workspace/kb-cli
go test ./internal/output -run "TestFormatTable_With|TestFormatJSON_With" -v
```
Expected: PASS
- [ ] **Step 5: 运行所有测试确认无回归**
```bash
cd ~/workspace/kb-cli
go test ./... -v
```
Expected: 所有测试通过
- [ ] **Step 6: 提交**
```bash
cd ~/workspace/kb-cli
git add internal/output/formatter.go internal/output/formatter_test.go
git commit -m "feat: enhance output formatter with content and links support"
```
---
## Task 6: 集成测试与性能验证
**Files:**
- 无新文件(使用现有测试数据)
**Interfaces:**
- Consumes: 所有之前的任务
- Produces: 验证完整功能链
- [ ] **Step 1: 构建最新版本**
```bash
cd ~/workspace/kb-cli
go build -o bin/kb .
```
- [ ] **Step 2: 测试基础搜索(无增强)**
```bash
./bin/kb search 充装 --top 3
```
Expected: 显示 3 条结果,不包含内容和链接
- [ ] **Step 3: 测试带内容搜索**
```bash
./bin/kb search 充装 --with-content --top 3
```
Expected: 显示 3 条结果,每条后跟 `--- 内容 ---` 和文件内容
- [ ] **Step 4: 测试带链接搜索**
```bash
./bin/kb search 充装 --with-links --top 3
```
Expected: 显示 3 条结果,有链接的显示 `--- 关联文档 ---`
- [ ] **Step 5: 测试两者都有**
```bash
./bin/kb search 充装 --with-content --with-links --top 3
```
Expected: 显示 3 条结果,同时包含内容和链接
- [ ] **Step 6: 测试 JSON 输出**
```bash
./bin/kb search 充装 --with-content --with-links --json --top 3
```
Expected: JSON 格式输出,包含 `content` 和 `links` 字段
- [ ] **Step 7: 性能测试**
```bash
time ./bin/kb search 充装 --with-content --with-links --top 10
```
Expected: 总耗时 < 100ms
- [ ] **Step 8: 提交(如有修复)**
```bash
cd ~/workspace/kb-cli
git add -A
git commit -m "test: integration tests for enhanced search"
```
---
## Task 7: 更新 kb-search 技能文档
**Files:**
- Modify: `~/.hermes/skills/kb-knowledge/kb-search/SKILL.md`
**Interfaces:**
- Consumes: kb-cli 新功能
- Produces: 更新的技能文档
- [ ] **Step 1: 备份现有文档**
```bash
cp ~/.hermes/skills/kb-knowledge/kb-search/SKILL.md ~/.hermes/skills/kb-knowledge/kb-search/SKILL.md.bak
```
- [ ] **Step 2: 修改核心工具部分**
将 `## 核心工具` 部分从:
```markdown
## 核心工具
**kb-search.py**:知识库搜索
```
改为:
```markdown
## 核心工具
**kb-cli**:知识库搜索(优先使用)
**完整路径**:`~/go/bin/kb`
**基本用法**:
```bash
# 基础搜索
kb search "关键词" --top 5
# 带内容
kb search "关键词" --with-content --top 3
# 带链接
kb search "关键词" --with-links --top 3
# 带扩展词和症状词
kb search "充装" --expanded "重量 规格" --symptom "报错" --with-content --top 3
# JSON 输出
kb search "关键词" --json --top 5
```
**kb-search.py**:知识库搜索(降级方案,仅当 kb-cli 不可用时)
```
- [ ] **Step 3: 修改执行流程部分**
将 `## 执行流程` 部分的命令示例从 `python3 kb-search.py` 改为 `kb`:
```bash
# 方式1: 基础搜索
kb search "用户问题关键词" --top 3
# 方式2: 带内容(推荐)
kb search "用户问题关键词" --with-content --top 3
# 方式3: 带内容和链接
kb search "用户问题关键词" --with-content --with-links --top 3
# 方式4: 带扩展词和症状词
kb search "关键词" --expanded "扩展词" --symptom "症状词" --with-content --top 3
```
- [ ] **Step 4: 添加降级方案章节**
在文档末尾添加:
```markdown
## 降级方案
**仅当 kb-cli 不可用时**,使用 kb-search.py:
```bash
export KB_VAULT=/home/aisim-p/aisim/note/001/笔记001
python3 ~/.hermes/skills/kb-knowledge/kb-search/scripts/kb-search.py search "关键词" --with-content --top 3
```
**注意**:kb-search.py 当前有索引问题,可能返回空结果。优先使用 kb-cli。
```
- [ ] **Step 5: 验证文档格式**
```bash
cat ~/.hermes/skills/kb-knowledge/kb-search/SKILL.md | head -50
```
Expected: 显示更新后的文档,核心工具为 kb-cli
- [ ] **Step 6: 提交到知识库**
```bash
cd ~/aisim/note/001/笔记001
git add .
git commit -m "docs: update kb-search skill to prioritize kb-cli"
git push
```
---
## Task 8: 最终验证与文档更新
**Files:**
- Modify: `~/workspace/kb-cli/README.md`
**Interfaces:**
- Consumes: 所有功能
- Produces: 完整的文档和验证
- [ ] **Step 1: 更新 README**
在 `~/workspace/kb-cli/README.md` 的 `## 使用方法` 部分添加新功能示例:
```markdown
### 高级搜索
```bash
# 带文件内容
kb search 充装规格 --with-content --top 3
# 带关联文档
kb search 充装规格 --with-links --top 3
# 带内容和关联
kb search 充装规格 --with-content --with-links --top 3
# 带扩展词和症状词
kb search 充装 --expanded "重量 规格" --symptom "报错" --with-content --top 3
```
```
- [ ] **Step 2: 运行完整测试套件**
```bash
cd ~/workspace/kb-cli
go test ./... -v
```
Expected: 所有测试通过
- [ ] **Step 3: 构建并安装**
```bash
cd ~/workspace/kb-cli
go build -o bin/kb .
cp bin/kb ~/go/bin/
```
- [ ] **Step 4: 最终功能验证**
```bash
# 测试所有功能
kb search 充装 --top 3
kb search 充装 --with-content --top 3
kb search 充装 --with-links --top 3
kb search 充装 --with-content --with-links --top 3
kb search 充装 --with-content --json --top 3
```
Expected: 所有命令正常工作
- [ ] **Step 5: 提交所有更改**
```bash
cd ~/workspace/kb-cli
git add README.md
git commit -m "docs: update README with new features"
git push
```
- [ ] **Step 6: 创建发布说明**
```bash
cat > RELEASE_NOTES.md << 'EOF'
# kb-cli v1.1.0 发布说明
## 新功能
- `--with-content`: 搜索时返回完整文件内容
- `--with-links`: 搜索时显示关联文档链接
## 使用示例
```bash
# 带内容搜索
kb search 充装规格 --with-content --top 3
# 带关联文档
kb search 充装规格 --with-links --top 3
# 两者都有
kb search 充装规格 --with-content --with-links --top 3
```
## 性能
- 搜索 + 内容 + 链接:< 100ms
- 向后兼容:现有命令不受影响
## 技能调整
- kb-search 技能现在优先使用 kb-cli
- kb-search.py 降级为备选方案
EOF
```
- [ ] **Step 7: 提交发布说明**
```bash
cd ~/workspace/kb-cli
git add RELEASE_NOTES.md
git commit -m "docs: add release notes for v1.1.0"
git push
```
---
## 完成标准
所有任务完成后,必须满足:
1. ✅ 所有单元测试通过
2. ✅ 集成测试通过
3. ✅ 性能 < 100ms
4. ✅ kb-search 技能文档已更新
5. ✅ README 已更新
6. ✅ 发布说明已创建
7. ✅ 代码已推送到远程仓库
---
## 执行选项
**Plan complete and saved to `docs/superpowers/plans/2026-07-26-kb-cli-enhancement.md`. Two execution options:**
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
**Which approach?**