Files
gems/opal-task/cmd/uncomplete.go
T
joakim 07d1a78dfc feat: add uncomplete command to restore completed tasks to pending
Dedicated command that sets status back to pending and clears End time.
Unlike undo, works on any completed task regardless of when it was
completed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:22:51 +01:00

89 lines
2.0 KiB
Go

package cmd
import (
"fmt"
"os"
"git.jnss.me/joakim/opal/internal/engine"
"github.com/spf13/cobra"
)
var uncompleteCmd = &cobra.Command{
Use: "uncomplete [filter...]",
Short: "Restore a completed task to pending",
Long: `Restore a completed task back to pending status.
Unlike undo, this is a targeted action that works on any completed task
regardless of when it was completed.
Examples:
opal 2 uncomplete
opal uncomplete +errand`,
Run: func(cmd *cobra.Command, args []string) {
parsed := getParsedArgs(cmd)
if err := uncompleteTasks(parsed.Filters); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
},
}
func uncompleteTasks(args []string) error {
if len(args) == 0 {
return fmt.Errorf("no task specified")
}
filter, err := engine.ParseFilter(args)
if err != nil {
return fmt.Errorf("failed to parse filter: %w", err)
}
ws, err := engine.LoadWorkingSet()
if err != nil {
return fmt.Errorf("failed to load working set: %w", err)
}
var tasks []*engine.Task
if len(filter.IDs) > 0 {
for _, id := range filter.IDs {
task, err := ws.GetTaskByDisplayID(id)
if err != nil {
return err
}
tasks = append(tasks, task)
}
} else {
tasks, err = engine.GetTasks(filter)
if err != nil {
return fmt.Errorf("failed to get tasks: %w", err)
}
}
if len(tasks) == 0 {
return fmt.Errorf("no tasks matched filter")
}
uncompleted := 0
for _, task := range tasks {
if task.Status != engine.StatusCompleted {
fmt.Fprintf(os.Stderr, "Warning: task %s is not completed, skipping\n", task.UUID)
continue
}
task.Status = engine.StatusPending
task.End = nil
if err := task.Save(); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to uncomplete task %s: %v\n", task.UUID, err)
} else {
uncompleted++
}
}
if uncompleted == 1 {
fmt.Printf("Restored task %s to pending\n", engine.FormatTaskSummary(tasks[0], ws))
} else {
fmt.Printf("Restored %d task(s) to pending.\n", uncompleted)
}
return nil
}