# 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?**