Skip to content

Commit b0e3d96

Browse files
committed
feat: extend spark task command with init, create, delete, impl subcommands
Add new task management subcommands: New Commands: - spark task init # Initialize task directory structure - spark task list # List all tasks and features - spark task create <name> # Create new feature file - spark task delete <name> # Delete feature file - spark task impl <name> # Implement feature using kimi CLI Features: - Task directory structure: tasks/features/, config/, analysis/, etc. - Feature template generation with example-feature.md - Cross-platform support (Mac, Linux, Windows) - TUI and CLI modes - Skill for external directory initialization New files: - internal/task/task_feature.go # Feature management - internal/task/task_impl.go # Feature implementation - internal/task/task_feature_test.go # Unit tests - spark-task-init-skill/SKILL.md # Skill definition Updated: - cmd/task.go # Add new subcommands - internal/tui/ui.go # Add Confirm method - README.md # Add usage examples - AGENTS.md # Add complete documentation Tests: All passing Refs: #4
1 parent 9a69862 commit b0e3d96

8 files changed

Lines changed: 1011 additions & 22 deletions

File tree

AGENTS.md

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,12 +298,51 @@ spark agent current # 查看当前项目使用的模板
298298
### 任务管理
299299

300300
#### `spark task`
301-
任务分发和同步管理(仅处理 `.md` Markdown 文件)
301+
任务管理和特性实现命令
302302

303303
```bash
304-
spark task list --task-dir ./tasks
305-
spark task dispatch my-task --task-dir ./tasks --owner myuser
306-
spark task sync my-task --task-dir ./tasks --work-path ./workspace
304+
# 初始化任务目录结构
305+
spark task init # 创建 tasks/ 目录结构
306+
307+
# 列出所有任务和特性
308+
spark task list # 列出任务目录和特性文件
309+
310+
# 创建新特性
311+
spark task create my-feature # 创建 tasks/features/my-feature.md
312+
spark task create my-feature --content "Custom description"
313+
314+
# 删除特性
315+
spark task delete my-feature # 删除特性文件
316+
spark task delete my-feature --force # 强制删除不提示
317+
318+
# 实现特性(使用 kimi CLI)
319+
spark task impl my-feature # 执行特性实现
320+
321+
# 分发和同步任务
322+
spark task dispatch my-task --dest ./workspace
323+
spark task sync my-task --work-path ./workspace
324+
```
325+
326+
| 子命令 | 说明 |
327+
|--------|------|
328+
| `init` | 初始化任务目录结构 |
329+
| `list` | 列出所有任务和特性 |
330+
| `create` | 创建新特性文件 |
331+
| `delete` | 删除特性文件 |
332+
| `impl` | 实现特性(使用 kimi CLI)|
333+
| `dispatch` | 分发任务到新目录 |
334+
| `sync` | 同步任务回任务目录 |
335+
336+
**任务目录结构**:
337+
```
338+
tasks/
339+
├── example-feature.md # 示例特性模板
340+
├── features/ # 特性文件目录
341+
├── config/ # 配置任务目录
342+
├── analysis/ # 分析任务目录
343+
├── mindstorm/ # 头脑风暴目录
344+
├── planning/ # 规划任务目录
345+
└── prd/ # PRD 文档目录
307346
```
308347
309348
支持 `--tui` 标志启用交互式终端 UI。

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,37 @@ spark script run list-dirs
7171
# 执行脚本并传递参数
7272
spark script run copy-template my-new-feature
7373
```
74+
75+
### 任务管理
76+
77+
```bash
78+
# 初始化任务目录结构
79+
spark task init
80+
81+
# 列出所有任务和特性
82+
spark task list
83+
84+
# 创建新特性文件
85+
spark task create my-feature
86+
87+
# 创建带内容的特性文件
88+
spark task create my-feature --content "Custom description"
89+
90+
# 删除特性文件
91+
spark task delete my-feature
92+
93+
# 强制删除(不提示)
94+
spark task delete my-feature --force
95+
96+
# 实现特性(使用 kimi CLI)
97+
spark task impl my-feature
98+
99+
# 分发任务到新目录
100+
spark task dispatch my-feature --dest ./workspace
101+
102+
# 同步任务回任务目录
103+
spark task sync my-feature --work-path ./workspace
104+
```
74105
```
75106
76107
---

cmd/task.go

Lines changed: 148 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,40 +90,48 @@ Example:
9090

9191
var taskListCmd = &cobra.Command{
9292
Use: "list",
93-
Short: "List all tasks in the task directory",
94-
Long: `List all tasks (directories) in the configured task directory.`,
93+
Short: "List all tasks and features",
94+
Long: `List all tasks (directories) in the task directory and features in tasks/features.`,
9595
RunE: func(cmd *cobra.Command, args []string) error {
9696
if taskDir == "" {
97-
return fmt.Errorf("task directory is required, use --task-dir or set in config")
97+
taskDir = "."
9898
}
9999

100100
mgr := task.NewManager(taskDir, githubOwner, workDir, false)
101+
102+
// List task directories
101103
tasks, err := mgr.ListTasks()
102104
if err != nil {
103105
return err
104106
}
105107

106-
if len(tasks) == 0 {
107-
pterm.Info.Println("No tasks found.")
108-
return nil
109-
}
110-
111-
if useTUI {
112-
pterm.DefaultHeader.WithFullWidth().Println("Task List")
113-
pterm.Println()
114-
var listItems []pterm.BulletListItem
115-
for _, t := range tasks {
116-
listItems = append(listItems, pterm.BulletListItem{Level: 0, Text: t})
117-
}
118-
pterm.DefaultBulletList.WithItems(listItems).Render()
119-
} else {
120-
pterm.DefaultSection.Printf("Tasks in %s", taskDir)
108+
if len(tasks) > 0 {
109+
pterm.DefaultSection.Println("Task Directories")
121110
tableData := pterm.TableData{}
122111
for i, t := range tasks {
123112
tableData = append(tableData, []string{fmt.Sprintf("%d", i+1), t})
124113
}
125114
pterm.DefaultTable.WithHasHeader().WithData(pterm.TableData{{"#", "Task Name"}}).WithData(tableData).Render()
115+
pterm.Println()
126116
}
117+
118+
// List features
119+
features, err := mgr.ListFeatures()
120+
if err == nil && len(features) > 0 {
121+
pterm.DefaultSection.Println("Feature Files")
122+
tableData := pterm.TableData{}
123+
for i, f := range features {
124+
tableData = append(tableData, []string{fmt.Sprintf("%d", i+1), f})
125+
}
126+
pterm.DefaultTable.WithHasHeader().WithData(pterm.TableData{{"#", "Feature Name"}}).WithData(tableData).Render()
127+
}
128+
129+
if len(tasks) == 0 && (err != nil || len(features) == 0) {
130+
pterm.Info.Println("No tasks or features found.")
131+
pterm.Println()
132+
pterm.Println("Run 'spark task init' to initialize task structure.")
133+
}
134+
127135
return nil
128136
},
129137
}
@@ -212,6 +220,120 @@ func runSyncTUI(taskName string) error {
212220
return mgr.SyncBack(taskName, workPath)
213221
}
214222

223+
// Task Feature Commands
224+
225+
var taskInitCmd = &cobra.Command{
226+
Use: "init",
227+
Short: "Initialize task directory structure",
228+
Long: `Create the default task directory structure with example feature file.
229+
230+
Creates the following directories:
231+
- tasks/features/
232+
- tasks/config/
233+
- tasks/analysis/
234+
- tasks/mindstorm/
235+
- tasks/planning/
236+
- tasks/prd/
237+
- tasks/example-feature.md
238+
239+
If directories already exist, they will be preserved.`,
240+
RunE: func(cmd *cobra.Command, args []string) error {
241+
if taskDir == "" {
242+
taskDir = "."
243+
}
244+
245+
mgr := task.NewManager(taskDir, githubOwner, workDir, useTUI)
246+
return mgr.InitTaskStructure()
247+
},
248+
}
249+
250+
var taskCreateCmd = &cobra.Command{
251+
Use: "create <feature-name>",
252+
Short: "Create a new feature file",
253+
Long: `Create a new feature file in tasks/features/ directory.
254+
255+
The feature name will have .md extension added automatically if not provided.
256+
Uses example-feature.md as template.
257+
258+
Example:
259+
spark task create my-new-feature
260+
spark task create my-new-feature --content "Custom description"`,
261+
Args: cobra.ExactArgs(1),
262+
RunE: func(cmd *cobra.Command, args []string) error {
263+
if taskDir == "" {
264+
taskDir = "."
265+
}
266+
267+
featureName := args[0]
268+
content, _ := cmd.Flags().GetString("content")
269+
270+
mgr := task.NewManager(taskDir, githubOwner, workDir, useTUI)
271+
return mgr.CreateFeature(featureName, content)
272+
},
273+
}
274+
275+
var taskDeleteCmd = &cobra.Command{
276+
Use: "delete <feature-name>",
277+
Short: "Delete a feature file",
278+
Long: `Delete a feature file from tasks/features/ directory.
279+
280+
Example:
281+
spark task delete my-feature
282+
spark task delete my-feature --force`,
283+
Args: cobra.ExactArgs(1),
284+
RunE: func(cmd *cobra.Command, args []string) error {
285+
if taskDir == "" {
286+
taskDir = "."
287+
}
288+
289+
featureName := args[0]
290+
force, _ := cmd.Flags().GetBool("force")
291+
292+
mgr := task.NewManager(taskDir, githubOwner, workDir, useTUI)
293+
294+
if !force && useTUI {
295+
confirmed, err := tui.Confirm(fmt.Sprintf("Delete feature '%s'?", featureName))
296+
if err != nil || !confirmed {
297+
pterm.Info.Println("Delete cancelled.")
298+
return nil
299+
}
300+
}
301+
302+
return mgr.DeleteFeature(featureName, force)
303+
},
304+
}
305+
306+
var taskImplCmd = &cobra.Command{
307+
Use: "impl <feature-name>",
308+
Short: "Implement a feature",
309+
Long: `Execute a feature implementation using kimi CLI and github-task-workflow.
310+
311+
This command will:
312+
1. Read the feature file
313+
2. Create a GitHub issue
314+
3. Execute the task using kimi CLI
315+
4. Update the issue and commit changes
316+
317+
Requirements:
318+
- kim CLI must be installed
319+
- github-task-workflow must be configured
320+
321+
Example:
322+
spark task impl my-feature
323+
spark task impl my-feature --tui`,
324+
Args: cobra.ExactArgs(1),
325+
RunE: func(cmd *cobra.Command, args []string) error {
326+
if taskDir == "" {
327+
taskDir = "."
328+
}
329+
330+
featureName := args[0]
331+
mgr := task.NewManager(taskDir, githubOwner, workDir, useTUI)
332+
333+
return mgr.RunFeature(featureName, useTUI)
334+
},
335+
}
336+
215337
func init() {
216338
taskCmd.PersistentFlags().StringVar(&taskDir, "task-dir", "", "Task directory containing all tasks")
217339
taskCmd.PersistentFlags().StringVar(&githubOwner, "owner", "", "GitHub owner for creating repositories")
@@ -225,9 +347,17 @@ func init() {
225347
taskDispatchCmd.Flags().String("dest", "", "Destination path for the dispatched task (default: <work-dir>/<task-name>)")
226348
taskSyncCmd.Flags().String("work-path", "", "Working path of the task to sync (default: <work-dir>/<task-name>)")
227349

350+
// Feature command flags
351+
taskCreateCmd.Flags().String("content", "", "Custom content for the feature file")
352+
taskDeleteCmd.Flags().Bool("force", false, "Force deletion without confirmation")
353+
228354
taskCmd.AddCommand(taskDispatchCmd)
229355
taskCmd.AddCommand(taskSyncCmd)
230356
taskCmd.AddCommand(taskListCmd)
357+
taskCmd.AddCommand(taskInitCmd)
358+
taskCmd.AddCommand(taskCreateCmd)
359+
taskCmd.AddCommand(taskDeleteCmd)
360+
taskCmd.AddCommand(taskImplCmd)
231361

232362
rootCmd.AddCommand(taskCmd)
233363
}

0 commit comments

Comments
 (0)