edit | blame | history | raw

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 添加:

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: 运行测试确认失败
cd ~/workspace/kb-cli
go test ./internal/index -run TestGetNodeLinks -v

Expected: FAIL - "store.GetNodeLinks undefined"

  • [ ] Step 3: 实现 GetNodeLinks 方法

internal/index/sqlite.goGetNodeContent 方法后添加:

// 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: 运行测试确认通过
cd ~/workspace/kb-cli
go test ./internal/index -run TestGetNodeLinks -v

Expected: PASS

  • [ ] Step 5: 提交
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 添加:

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: 运行测试确认失败
cd ~/workspace/kb-cli
go test ./internal/search -run TestSearchResultJSON_OmitEmpty -v

Expected: FAIL - "Content undefined" 或测试失败(因为字段不存在)

  • [ ] Step 3: 扩展 SearchResult 结构体

修改 internal/search/engine.go 中的 SearchResult 结构体:

// 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: 运行测试确认通过
cd ~/workspace/kb-cli
go test ./internal/search -run TestSearchResultJSON_OmitEmpty -v

Expected: PASS

  • [ ] Step 5: 提交
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 添加:

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: 运行测试确认失败
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

// 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: 运行测试确认通过
cd ~/workspace/kb-cli
go test ./internal/search -run "TestSearch_WithContent|TestSearch_WithLinks" -v

Expected: PASS

  • [ ] Step 5: 运行所有测试确认无回归
cd ~/workspace/kb-cli
go test ./... -v

Expected: 所有测试通过

  • [ ] Step 6: 提交
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 的变量声明区域添加:

var (
	withContent bool
	withLinks   bool
)
  • [ ] Step 2: 注册 flags

init() 函数中添加:

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 函数:

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 输出
cd ~/workspace/kb-cli
go build -o bin/kb .
./bin/kb search --help

Expected: 显示 --with-content--with-links flags

  • [ ] Step 5: 提交
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: 增强的 FormatTableFormatJSON 方法

  • [ ] Step 1: 编写失败测试

internal/output/formatter_test.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: 运行测试确认失败
cd ~/workspace/kb-cli
go test ./internal/output -run "TestFormatTable_With|TestFormatJSON_With" -v

Expected: FAIL - 测试失败(输出不包含新字段)

  • [ ] Step 3: 修改 FormatTable 方法

修改 internal/output/formatter.go 中的 FormatTable 函数:

// 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: 运行测试确认通过
cd ~/workspace/kb-cli
go test ./internal/output -run "TestFormatTable_With|TestFormatJSON_With" -v

Expected: PASS

  • [ ] Step 5: 运行所有测试确认无回归
cd ~/workspace/kb-cli
go test ./... -v

Expected: 所有测试通过

  • [ ] Step 6: 提交
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: 构建最新版本
cd ~/workspace/kb-cli
go build -o bin/kb .
  • [ ] Step 2: 测试基础搜索(无增强)
./bin/kb search 充装 --top 3

Expected: 显示 3 条结果,不包含内容和链接

  • [ ] Step 3: 测试带内容搜索
./bin/kb search 充装 --with-content --top 3

Expected: 显示 3 条结果,每条后跟 --- 内容 --- 和文件内容

  • [ ] Step 4: 测试带链接搜索
./bin/kb search 充装 --with-links --top 3

Expected: 显示 3 条结果,有链接的显示 --- 关联文档 ---

  • [ ] Step 5: 测试两者都有
./bin/kb search 充装 --with-content --with-links --top 3

Expected: 显示 3 条结果,同时包含内容和链接

  • [ ] Step 6: 测试 JSON 输出
./bin/kb search 充装 --with-content --with-links --json --top 3

Expected: JSON 格式输出,包含 contentlinks 字段

  • [ ] Step 7: 性能测试
time ./bin/kb search 充装 --with-content --with-links --top 10

Expected: 总耗时 < 100ms

  • [ ] Step 8: 提交(如有修复)
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: 备份现有文档
cp ~/.hermes/skills/kb-knowledge/kb-search/SKILL.md ~/.hermes/skills/kb-knowledge/kb-search/SKILL.md.bak
  • [ ] Step 2: 修改核心工具部分

## 核心工具 部分从:

## 核心工具

**kb-search.py**:知识库搜索

改为:

## 核心工具

**kb-cli**:知识库搜索(优先使用)

**完整路径**:`~/go/bin/kb`

**基本用法**:

基础搜索

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

# 方式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: 添加降级方案章节

在文档末尾添加:

## 降级方案

**仅当 kb-cli 不可用时**,使用 kb-search.py:

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: 验证文档格式
cat ~/.hermes/skills/kb-knowledge/kb-search/SKILL.md | head -50

Expected: 显示更新后的文档,核心工具为 kb-cli

  • [ ] Step 6: 提交到知识库
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## 使用方法 部分添加新功能示例:

### 高级搜索

带文件内容

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: 运行完整测试套件
cd ~/workspace/kb-cli
go test ./... -v

Expected: 所有测试通过

  • [ ] Step 3: 构建并安装
cd ~/workspace/kb-cli
go build -o bin/kb .
cp bin/kb ~/go/bin/
  • [ ] Step 4: 最终功能验证
# 测试所有功能
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: 提交所有更改
cd ~/workspace/kb-cli
git add README.md
git commit -m "docs: update README with new features"
git push
  • [ ] Step 6: 创建发布说明
cat > RELEASE_NOTES.md << 'EOF'
# kb-cli v1.1.0 发布说明

## 新功能

- `--with-content`: 搜索时返回完整文件内容
- `--with-links`: 搜索时显示关联文档链接

## 使用示例

带内容搜索

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: 提交发布说明

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?