feat(agentic): add task priority and category support
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
f07ea569ba
commit
e18dc12e1e
5 changed files with 65 additions and 7 deletions
|
|
@ -11,7 +11,7 @@ func (s *PrepSubsystem) registerTaskCommands() {
|
|||
c.Command("task", core.Command{Description: "Manage plan tasks", Action: s.cmdTask})
|
||||
c.Command("agentic:task", core.Command{Description: "Manage plan tasks", Action: s.cmdTask})
|
||||
c.Command("task/create", core.Command{Description: "Create a task in a plan phase", Action: s.cmdTaskCreate})
|
||||
c.Command("task/update", core.Command{Description: "Update a plan task status or notes", Action: s.cmdTaskUpdate})
|
||||
c.Command("task/update", core.Command{Description: "Update a plan task status, notes, priority, or category", Action: s.cmdTaskUpdate})
|
||||
c.Command("task/toggle", core.Command{Description: "Toggle a plan task between pending and completed", Action: s.cmdTaskToggle})
|
||||
}
|
||||
|
||||
|
|
@ -25,13 +25,13 @@ func (s *PrepSubsystem) cmdTask(options core.Options) core.Result {
|
|||
case "update":
|
||||
return s.cmdTaskUpdate(options)
|
||||
case "":
|
||||
core.Print(nil, "usage: core-agent task update <plan> --phase=1 --task=1 [--status=completed] [--notes=\"Done\"] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, " core-agent task create <plan> --phase=1 --title=\"Review RFC\" [--description=\"...\"] [--status=pending] [--notes=\"...\"] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, "usage: core-agent task update <plan> --phase=1 --task=1 [--status=completed] [--notes=\"Done\"] [--priority=high] [--category=security] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, " core-agent task create <plan> --phase=1 --title=\"Review RFC\" [--description=\"...\"] [--status=pending] [--notes=\"...\"] [--priority=high] [--category=security] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, " core-agent task toggle <plan> --phase=1 --task=1")
|
||||
return core.Result{OK: true}
|
||||
default:
|
||||
core.Print(nil, "usage: core-agent task update <plan> --phase=1 --task=1 [--status=completed] [--notes=\"Done\"] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, " core-agent task create <plan> --phase=1 --title=\"Review RFC\" [--description=\"...\"] [--status=pending] [--notes=\"...\"] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, "usage: core-agent task update <plan> --phase=1 --task=1 [--status=completed] [--notes=\"Done\"] [--priority=high] [--category=security] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, " core-agent task create <plan> --phase=1 --title=\"Review RFC\" [--description=\"...\"] [--status=pending] [--notes=\"...\"] [--priority=high] [--category=security] [--file=pkg/agentic/task.go|--file-ref=pkg/agentic/task.go] [--line=42|--line-ref=42]")
|
||||
core.Print(nil, " core-agent task toggle <plan> --phase=1 --task=1")
|
||||
return core.Result{Value: core.E("agentic.cmdTask", core.Concat("unknown task command: ", action), nil), OK: false}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ func (s *PrepSubsystem) cmdTaskCreate(options core.Options) core.Result {
|
|||
title := optionStringValue(options, "title", "task")
|
||||
|
||||
if planSlug == "" || phaseOrder == 0 || title == "" {
|
||||
core.Print(nil, "usage: core-agent task create <plan> --phase=1 --title=\"Review RFC\" [--description=\"...\"] [--status=pending] [--notes=\"...\"] [--file=pkg/agentic/task.go] [--line=42]")
|
||||
core.Print(nil, "usage: core-agent task create <plan> --phase=1 --title=\"Review RFC\" [--description=\"...\"] [--status=pending] [--notes=\"...\"] [--priority=high] [--category=security] [--file=pkg/agentic/task.go] [--line=42]")
|
||||
return core.Result{Value: core.E("agentic.cmdTaskCreate", "plan_slug, phase_order, and title are required", nil), OK: false}
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +54,8 @@ func (s *PrepSubsystem) cmdTaskCreate(options core.Options) core.Result {
|
|||
core.Option{Key: "description", Value: optionStringValue(options, "description")},
|
||||
core.Option{Key: "status", Value: optionStringValue(options, "status")},
|
||||
core.Option{Key: "notes", Value: optionStringValue(options, "notes")},
|
||||
core.Option{Key: "priority", Value: optionStringValue(options, "priority")},
|
||||
core.Option{Key: "category", Value: optionStringValue(options, "category")},
|
||||
core.Option{Key: "file", Value: optionStringValue(options, "file")},
|
||||
core.Option{Key: "line", Value: optionIntValue(options, "line")},
|
||||
core.Option{Key: "file_ref", Value: optionStringValue(options, "file_ref", "file-ref")},
|
||||
|
|
@ -74,6 +76,12 @@ func (s *PrepSubsystem) cmdTaskCreate(options core.Options) core.Result {
|
|||
|
||||
core.Print(nil, "task: %s", output.Task.Title)
|
||||
core.Print(nil, "status: %s", output.Task.Status)
|
||||
if output.Task.Priority != "" {
|
||||
core.Print(nil, "priority: %s", output.Task.Priority)
|
||||
}
|
||||
if output.Task.Category != "" {
|
||||
core.Print(nil, "category: %s", output.Task.Category)
|
||||
}
|
||||
if output.Task.File != "" {
|
||||
core.Print(nil, "file: %s", output.Task.File)
|
||||
}
|
||||
|
|
@ -89,7 +97,7 @@ func (s *PrepSubsystem) cmdTaskUpdate(options core.Options) core.Result {
|
|||
taskIdentifier := optionAnyValue(options, "task_identifier", "task")
|
||||
|
||||
if planSlug == "" || phaseOrder == 0 || taskIdentifierValue(taskIdentifier) == "" {
|
||||
core.Print(nil, "usage: core-agent task update <plan> --phase=1 --task=1 [--status=completed] [--notes=\"Done\"] [--file=pkg/agentic/task.go] [--line=42]")
|
||||
core.Print(nil, "usage: core-agent task update <plan> --phase=1 --task=1 [--status=completed] [--notes=\"Done\"] [--priority=high] [--category=security] [--file=pkg/agentic/task.go] [--line=42]")
|
||||
return core.Result{Value: core.E("agentic.cmdTaskUpdate", "plan_slug, phase_order, and task_identifier are required", nil), OK: false}
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +107,8 @@ func (s *PrepSubsystem) cmdTaskUpdate(options core.Options) core.Result {
|
|||
core.Option{Key: "task_identifier", Value: taskIdentifier},
|
||||
core.Option{Key: "status", Value: optionStringValue(options, "status")},
|
||||
core.Option{Key: "notes", Value: optionStringValue(options, "notes")},
|
||||
core.Option{Key: "priority", Value: optionStringValue(options, "priority")},
|
||||
core.Option{Key: "category", Value: optionStringValue(options, "category")},
|
||||
core.Option{Key: "file", Value: optionStringValue(options, "file")},
|
||||
core.Option{Key: "line", Value: optionIntValue(options, "line")},
|
||||
core.Option{Key: "file_ref", Value: optionStringValue(options, "file_ref", "file-ref")},
|
||||
|
|
@ -122,6 +132,12 @@ func (s *PrepSubsystem) cmdTaskUpdate(options core.Options) core.Result {
|
|||
if output.Task.Notes != "" {
|
||||
core.Print(nil, "notes: %s", output.Task.Notes)
|
||||
}
|
||||
if output.Task.Priority != "" {
|
||||
core.Print(nil, "priority: %s", output.Task.Priority)
|
||||
}
|
||||
if output.Task.Category != "" {
|
||||
core.Print(nil, "category: %s", output.Task.Category)
|
||||
}
|
||||
if output.Task.File != "" {
|
||||
core.Print(nil, "file: %s", output.Task.File)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ func TestCommands_TaskCommand_Good_Update(t *testing.T) {
|
|||
core.Option{Key: "task_identifier", Value: "1"},
|
||||
core.Option{Key: "status", Value: "completed"},
|
||||
core.Option{Key: "notes", Value: "Done"},
|
||||
core.Option{Key: "priority", Value: "high"},
|
||||
core.Option{Key: "category", Value: "security"},
|
||||
core.Option{Key: "file", Value: "pkg/agentic/task.go"},
|
||||
core.Option{Key: "line", Value: 128},
|
||||
))
|
||||
|
|
@ -43,6 +45,8 @@ func TestCommands_TaskCommand_Good_Update(t *testing.T) {
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, "completed", output.Task.Status)
|
||||
assert.Equal(t, "Done", output.Task.Notes)
|
||||
assert.Equal(t, "high", output.Task.Priority)
|
||||
assert.Equal(t, "security", output.Task.Category)
|
||||
assert.Equal(t, "pkg/agentic/task.go", output.Task.File)
|
||||
assert.Equal(t, 128, output.Task.Line)
|
||||
}
|
||||
|
|
@ -80,6 +84,8 @@ func TestCommands_TaskCommand_Good_Create(t *testing.T) {
|
|||
core.Option{Key: "description", Value: "Update the implementation"},
|
||||
core.Option{Key: "status", Value: "pending"},
|
||||
core.Option{Key: "notes", Value: "Do this first"},
|
||||
core.Option{Key: "priority", Value: "high"},
|
||||
core.Option{Key: "category", Value: "implementation"},
|
||||
core.Option{Key: "file", Value: "pkg/agentic/task.go"},
|
||||
core.Option{Key: "line", Value: 153},
|
||||
))
|
||||
|
|
@ -90,6 +96,8 @@ func TestCommands_TaskCommand_Good_Create(t *testing.T) {
|
|||
assert.Equal(t, "Patch code", output.Task.Title)
|
||||
assert.Equal(t, "pending", output.Task.Status)
|
||||
assert.Equal(t, "Do this first", output.Task.Notes)
|
||||
assert.Equal(t, "high", output.Task.Priority)
|
||||
assert.Equal(t, "implementation", output.Task.Category)
|
||||
assert.Equal(t, "pkg/agentic/task.go", output.Task.File)
|
||||
assert.Equal(t, 153, output.Task.Line)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ type PlanTask struct {
|
|||
ID string `json:"id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
|
|
@ -720,6 +722,8 @@ func planTaskValue(value any) (PlanTask, bool) {
|
|||
ID: stringValue(typed["id"]),
|
||||
Title: title,
|
||||
Description: stringValue(typed["description"]),
|
||||
Priority: stringValue(typed["priority"]),
|
||||
Category: stringValue(typed["category"]),
|
||||
Status: stringValue(typed["status"]),
|
||||
Notes: stringValue(typed["notes"]),
|
||||
File: file,
|
||||
|
|
@ -948,6 +952,8 @@ func normalisePlanTask(task PlanTask, index int) PlanTask {
|
|||
if task.Title == "" {
|
||||
task.Title = task.Description
|
||||
}
|
||||
task.Priority = core.Trim(task.Priority)
|
||||
task.Category = core.Trim(task.Category)
|
||||
if task.File == "" {
|
||||
task.File = task.FileRef
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ type TaskUpdateInput struct {
|
|||
TaskIdentifier any `json:"task_identifier"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Line int `json:"line,omitempty"`
|
||||
FileRef string `json:"file_ref,omitempty"`
|
||||
|
|
@ -38,6 +40,8 @@ type TaskCreateInput struct {
|
|||
Description string `json:"description,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Line int `json:"line,omitempty"`
|
||||
FileRef string `json:"file_ref,omitempty"`
|
||||
|
|
@ -71,6 +75,8 @@ func (s *PrepSubsystem) handleTaskCreate(ctx context.Context, options core.Optio
|
|||
Description: optionStringValue(options, "description"),
|
||||
Status: optionStringValue(options, "status"),
|
||||
Notes: optionStringValue(options, "notes"),
|
||||
Priority: optionStringValue(options, "priority"),
|
||||
Category: optionStringValue(options, "category"),
|
||||
File: optionStringValue(options, "file"),
|
||||
Line: optionIntValue(options, "line"),
|
||||
FileRef: optionStringValue(options, "file_ref", "file-ref"),
|
||||
|
|
@ -90,6 +96,8 @@ func (s *PrepSubsystem) handleTaskUpdate(ctx context.Context, options core.Optio
|
|||
TaskIdentifier: optionAnyValue(options, "task_identifier", "task"),
|
||||
Status: optionStringValue(options, "status"),
|
||||
Notes: optionStringValue(options, "notes"),
|
||||
Priority: optionStringValue(options, "priority"),
|
||||
Category: optionStringValue(options, "category"),
|
||||
File: optionStringValue(options, "file"),
|
||||
Line: optionIntValue(options, "line"),
|
||||
FileRef: optionStringValue(options, "file_ref", "file-ref"),
|
||||
|
|
@ -150,6 +158,12 @@ func (s *PrepSubsystem) taskUpdate(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
if notes := core.Trim(input.Notes); notes != "" {
|
||||
plan.Phases[phaseIndex].Tasks[taskIndex].Notes = notes
|
||||
}
|
||||
if priority := core.Trim(input.Priority); priority != "" {
|
||||
plan.Phases[phaseIndex].Tasks[taskIndex].Priority = priority
|
||||
}
|
||||
if category := core.Trim(input.Category); category != "" {
|
||||
plan.Phases[phaseIndex].Tasks[taskIndex].Category = category
|
||||
}
|
||||
if file := core.Trim(input.File); file != "" {
|
||||
plan.Phases[phaseIndex].Tasks[taskIndex].File = file
|
||||
plan.Phases[phaseIndex].Tasks[taskIndex].FileRef = file
|
||||
|
|
@ -203,6 +217,8 @@ func (s *PrepSubsystem) taskCreate(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
ID: core.Sprint(nextIndex),
|
||||
Title: core.Trim(input.Title),
|
||||
Description: core.Trim(input.Description),
|
||||
Priority: core.Trim(input.Priority),
|
||||
Category: core.Trim(input.Category),
|
||||
Status: input.Status,
|
||||
Notes: core.Trim(input.Notes),
|
||||
File: core.Trim(input.File),
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ func TestTask_TaskUpdate_Good(t *testing.T) {
|
|||
TaskIdentifier: "1",
|
||||
Status: "completed",
|
||||
Notes: "Done",
|
||||
Priority: "high",
|
||||
Category: "security",
|
||||
File: "pkg/agentic/task.go",
|
||||
Line: 128,
|
||||
})
|
||||
|
|
@ -40,6 +42,8 @@ func TestTask_TaskUpdate_Good(t *testing.T) {
|
|||
assert.True(t, output.Success)
|
||||
assert.Equal(t, "completed", output.Task.Status)
|
||||
assert.Equal(t, "Done", output.Task.Notes)
|
||||
assert.Equal(t, "high", output.Task.Priority)
|
||||
assert.Equal(t, "security", output.Task.Category)
|
||||
assert.Equal(t, "pkg/agentic/task.go", output.Task.File)
|
||||
assert.Equal(t, 128, output.Task.Line)
|
||||
}
|
||||
|
|
@ -68,6 +72,8 @@ func TestTask_TaskCreate_Good(t *testing.T) {
|
|||
Description: "Update the implementation",
|
||||
Status: "pending",
|
||||
Notes: "Do this first",
|
||||
Priority: "high",
|
||||
Category: "implementation",
|
||||
File: "pkg/agentic/task.go",
|
||||
Line: 153,
|
||||
})
|
||||
|
|
@ -76,6 +82,8 @@ func TestTask_TaskCreate_Good(t *testing.T) {
|
|||
assert.Equal(t, "Patch code", output.Task.Title)
|
||||
assert.Equal(t, "pending", output.Task.Status)
|
||||
assert.Equal(t, "Do this first", output.Task.Notes)
|
||||
assert.Equal(t, "high", output.Task.Priority)
|
||||
assert.Equal(t, "implementation", output.Task.Category)
|
||||
assert.Equal(t, "pkg/agentic/task.go", output.Task.File)
|
||||
assert.Equal(t, 153, output.Task.Line)
|
||||
}
|
||||
|
|
@ -150,10 +158,14 @@ func TestTask_TaskCreate_Ugly_CriteriaFallback(t *testing.T) {
|
|||
PlanSlug: plan.Slug,
|
||||
PhaseOrder: 1,
|
||||
Title: "Patch code",
|
||||
Priority: "medium",
|
||||
Category: "research",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, output.Success)
|
||||
assert.Equal(t, "Patch code", output.Task.Title)
|
||||
assert.Equal(t, "medium", output.Task.Priority)
|
||||
assert.Equal(t, "research", output.Task.Category)
|
||||
|
||||
updated, err := readPlan(PlansRoot(), plan.ID)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue