diff --git a/pkg/agentic/plan.go b/pkg/agentic/plan.go index 93ab5e7..1455102 100644 --- a/pkg/agentic/plan.go +++ b/pkg/agentic/plan.go @@ -438,26 +438,11 @@ func (s *PrepSubsystem) planUpdate(_ context.Context, _ *mcp.CallToolRequest, in } func (s *PrepSubsystem) planDelete(_ context.Context, _ *mcp.CallToolRequest, input PlanDeleteInput) (*mcp.CallToolResult, PlanDeleteOutput, error) { - ref := planReference(input.ID, input.Slug) - if ref == "" { - return nil, PlanDeleteOutput{}, core.E("planDelete", "id is required", nil) - } - - plan, err := readPlan(PlansRoot(), ref) + plan, err := archivePlanResult(input, "id is required", "planDelete") if err != nil { return nil, PlanDeleteOutput{}, err } - path := planPath(PlansRoot(), plan.ID) - if !fs.Exists(path) { - return nil, PlanDeleteOutput{}, core.E("planDelete", core.Concat("plan not found: ", ref), nil) - } - - if r := fs.Delete(path); !r.OK { - err, _ := r.Value.(error) - return nil, PlanDeleteOutput{}, core.E("planDelete", "failed to delete plan", err) - } - return nil, PlanDeleteOutput{ Success: true, Deleted: plan.ID, diff --git a/pkg/agentic/plan_compat.go b/pkg/agentic/plan_compat.go index 0886ff3..36d9fe5 100644 --- a/pkg/agentic/plan_compat.go +++ b/pkg/agentic/plan_compat.go @@ -176,31 +176,11 @@ func (s *PrepSubsystem) planUpdateStatusCompat(ctx context.Context, _ *mcp.CallT } func (s *PrepSubsystem) planArchiveCompat(ctx context.Context, _ *mcp.CallToolRequest, input PlanDeleteInput) (*mcp.CallToolResult, PlanArchiveOutput, error) { - ref := planReference(input.ID, input.Slug) - if ref == "" { - return nil, PlanArchiveOutput{}, core.E("planArchiveCompat", "slug is required", nil) - } - - plan, err := readPlan(PlansRoot(), ref) + plan, err := archivePlanResult(input, "slug is required", "planArchiveCompat") if err != nil { return nil, PlanArchiveOutput{}, err } - now := time.Now() - plan.Status = "archived" - plan.ArchivedAt = now - plan.UpdatedAt = now - if notes := archiveReasonValue(input.Reason); notes != "" { - plan.Notes = appendPlanNote(plan.Notes, notes) - } - if result := writePlanResult(PlansRoot(), plan); !result.OK { - err, _ := result.Value.(error) - if err == nil { - err = core.E("planArchiveCompat", "failed to write plan", nil) - } - return nil, PlanArchiveOutput{}, err - } - return nil, PlanArchiveOutput{ Success: true, Archived: plan.Slug, @@ -312,3 +292,32 @@ func planCompatibilityOutputStatus(status string) string { return status } } + +func archivePlanResult(input PlanDeleteInput, missingMessage, op string) (*Plan, error) { + ref := planReference(input.ID, input.Slug) + if ref == "" { + return nil, core.E(op, missingMessage, nil) + } + + plan, err := readPlan(PlansRoot(), ref) + if err != nil { + return nil, err + } + + now := time.Now() + plan.Status = "archived" + plan.ArchivedAt = now + plan.UpdatedAt = now + if notes := archiveReasonValue(input.Reason); notes != "" { + plan.Notes = appendPlanNote(plan.Notes, notes) + } + if result := writePlanResult(PlansRoot(), plan); !result.OK { + err, _ := result.Value.(error) + if err == nil { + err = core.E(op, "failed to write plan", nil) + } + return nil, err + } + + return plan, nil +} diff --git a/pkg/agentic/plan_crud_test.go b/pkg/agentic/plan_crud_test.go index ce02a61..695aaef 100644 --- a/pkg/agentic/plan_crud_test.go +++ b/pkg/agentic/plan_crud_test.go @@ -268,7 +268,12 @@ func TestPlan_PlanDelete_Good(t *testing.T) { assert.True(t, delOut.Success) assert.Equal(t, createOut.ID, delOut.Deleted) - assert.False(t, fs.Exists(createOut.Path)) + assert.True(t, fs.Exists(createOut.Path)) + + plan, readErr := readPlan(PlansRoot(), createOut.ID) + require.NoError(t, readErr) + assert.Equal(t, "archived", plan.Status) + assert.False(t, plan.ArchivedAt.IsZero()) } func TestPlan_PlanDelete_Bad_MissingID(t *testing.T) { diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index 660c733..1cd2073 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -185,7 +185,7 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result { c.Action("plan.update", s.handlePlanUpdate).Description = "Update plan status, phases, notes, or agent assignment" c.Action("plan.update_status", s.handlePlanUpdateStatus).Description = "Update an implementation plan lifecycle status by slug" c.Action("plan.archive", s.handlePlanArchive).Description = "Archive an implementation plan by slug" - c.Action("plan.delete", s.handlePlanDelete).Description = "Delete an implementation plan by ID" + c.Action("plan.delete", s.handlePlanDelete).Description = "Archive an implementation plan by ID" c.Action("plan.list", s.handlePlanList).Description = "List implementation plans with optional filters" c.Action("phase.get", s.handlePhaseGet).Description = "Read a plan phase by slug and order" c.Action("phase.update_status", s.handlePhaseUpdateStatus).Description = "Update plan phase status by slug and order"