11package main
22
33import (
4+ "fmt"
5+ "strconv"
46 "strings"
57
68 "github.com/spf13/cobra"
@@ -37,7 +39,7 @@ time tracking. Tasks can be filtered by status, priority, project, or context.`,
3739 )
3840
3941 for _ , init := range []func (* handlers.TaskHandler ) * cobra.Command {
40- addTaskCmd , listTaskCmd , viewTaskCmd , updateTaskCmd , editTaskCmd , deleteTaskCmd ,
42+ addTaskCmd , listTaskCmd , viewTaskCmd , updateTaskCmd , editTaskCmd , deleteTaskCmd , taskAnnotateCmd , taskBulkEditCmd ,
4143 } {
4244 cmd := init (c .handler )
4345 cmd .GroupID = "task-ops"
@@ -53,7 +55,7 @@ time tracking. Tasks can be filtered by status, priority, project, or context.`,
5355 }
5456
5557 for _ , init := range []func (* handlers.TaskHandler ) * cobra.Command {
56- timesheetViewCmd , taskStartCmd , taskStopCmd , taskCompleteCmd , taskRecurCmd , taskDependCmd ,
58+ timesheetViewCmd , taskStartCmd , taskStopCmd , taskCompleteCmd , taskRecurCmd , taskDependCmd , taskUndoCmd , taskHistoryCmd ,
5759 } {
5860 cmd := init (c .handler )
5961 cmd .GroupID = "task-tracking"
@@ -609,3 +611,146 @@ UUIDs to specify dependencies.`,
609611 root .AddCommand (addCmd , removeCmd , listCmd , blockedByCmd )
610612 return root
611613}
614+
615+ func taskAnnotateCmd (h * handlers.TaskHandler ) * cobra.Command {
616+ root := & cobra.Command {
617+ Use : "annotate" ,
618+ Aliases : []string {"note" },
619+ Short : "Manage task annotations" ,
620+ Long : `Add, list, or remove annotations on tasks.
621+
622+ Annotations are timestamped notes that provide context and updates
623+ about a task's progress or relevant information.` ,
624+ }
625+
626+ addCmd := & cobra.Command {
627+ Use : "add <task-id> <annotation>" ,
628+ Short : "Add an annotation to a task" ,
629+ Aliases : []string {"create" },
630+ Args : cobra .MinimumNArgs (2 ),
631+ RunE : func (c * cobra.Command , args []string ) error {
632+ taskID := args [0 ]
633+ annotation := strings .Join (args [1 :], " " )
634+ defer h .Close ()
635+ return h .Annotate (c .Context (), taskID , annotation )
636+ },
637+ }
638+
639+ listCmd := & cobra.Command {
640+ Use : "list <task-id>" ,
641+ Short : "List all annotations for a task" ,
642+ Aliases : []string {"ls" , "show" },
643+ Args : cobra .ExactArgs (1 ),
644+ RunE : func (c * cobra.Command , args []string ) error {
645+ defer h .Close ()
646+ return h .ListAnnotations (c .Context (), args [0 ])
647+ },
648+ }
649+
650+ removeCmd := & cobra.Command {
651+ Use : "remove <task-id> <index>" ,
652+ Short : "Remove an annotation by index" ,
653+ Aliases : []string {"rm" , "delete" },
654+ Args : cobra .ExactArgs (2 ),
655+ RunE : func (c * cobra.Command , args []string ) error {
656+ taskID := args [0 ]
657+ index , err := strconv .Atoi (args [1 ])
658+ if err != nil {
659+ return fmt .Errorf ("invalid annotation index: %w" , err )
660+ }
661+ defer h .Close ()
662+ return h .RemoveAnnotation (c .Context (), taskID , index )
663+ },
664+ }
665+
666+ root .AddCommand (addCmd , listCmd , removeCmd )
667+ return root
668+ }
669+
670+ func taskBulkEditCmd (h * handlers.TaskHandler ) * cobra.Command {
671+ cmd := & cobra.Command {
672+ Use : "bulk-edit <task-id>..." ,
673+ Aliases : []string {"bulk" },
674+ Short : "Update multiple tasks at once" ,
675+ Long : `Update multiple tasks with the same changes.
676+
677+ Allows batch updates to status, priority, project, context, and tags.
678+ Use --add-tags to add tags without replacing existing ones.
679+ Use --remove-tags to remove specific tags from tasks.
680+
681+ Examples:
682+ noteleaf todo bulk-edit 1 2 3 --status done
683+ noteleaf todo bulk-edit 1 2 --project web --priority high
684+ noteleaf todo bulk-edit 1 2 3 --add-tags urgent,review` ,
685+ Args : cobra .MinimumNArgs (1 ),
686+ RunE : func (c * cobra.Command , args []string ) error {
687+ status , _ := c .Flags ().GetString ("status" )
688+ priority , _ := c .Flags ().GetString ("priority" )
689+ project , _ := c .Flags ().GetString ("project" )
690+ context , _ := c .Flags ().GetString ("context" )
691+ tags , _ := c .Flags ().GetStringSlice ("tags" )
692+ addTags , _ := c .Flags ().GetBool ("add-tags" )
693+ removeTags , _ := c .Flags ().GetBool ("remove-tags" )
694+
695+ defer h .Close ()
696+ return h .BulkEdit (c .Context (), args , status , priority , project , context , tags , addTags , removeTags )
697+ },
698+ }
699+
700+ cmd .Flags ().String ("status" , "" , "Set status for all tasks" )
701+ cmd .Flags ().String ("priority" , "" , "Set priority for all tasks" )
702+ cmd .Flags ().String ("project" , "" , "Set project for all tasks" )
703+ cmd .Flags ().String ("context" , "" , "Set context for all tasks" )
704+ cmd .Flags ().StringSlice ("tags" , []string {}, "Set tags for all tasks" )
705+ cmd .Flags ().Bool ("add-tags" , false , "Add tags instead of replacing" )
706+ cmd .Flags ().Bool ("remove-tags" , false , "Remove specified tags" )
707+
708+ return cmd
709+ }
710+
711+ func taskUndoCmd (h * handlers.TaskHandler ) * cobra.Command {
712+ cmd := & cobra.Command {
713+ Use : "undo <task-id>" ,
714+ Short : "Undo the last change to a task" ,
715+ Long : `Revert a task to its previous state before the last update.
716+
717+ This command uses the task history to restore the task to how it was
718+ before the most recent modification.
719+
720+ Examples:
721+ noteleaf todo undo 1
722+ noteleaf todo undo abc-123-uuid` ,
723+ Args : cobra .ExactArgs (1 ),
724+ RunE : func (c * cobra.Command , args []string ) error {
725+ defer h .Close ()
726+ return h .UndoTask (c .Context (), args [0 ])
727+ },
728+ }
729+
730+ return cmd
731+ }
732+
733+ func taskHistoryCmd (h * handlers.TaskHandler ) * cobra.Command {
734+ cmd := & cobra.Command {
735+ Use : "history <task-id>" ,
736+ Aliases : []string {"log" },
737+ Short : "Show change history for a task" ,
738+ Long : `Display the history of changes made to a task.
739+
740+ Shows a chronological list of modifications with timestamps.
741+
742+ Examples:
743+ noteleaf todo history 1
744+ noteleaf todo history 1 --limit 5` ,
745+ Args : cobra .ExactArgs (1 ),
746+ RunE : func (c * cobra.Command , args []string ) error {
747+ limit , _ := c .Flags ().GetInt ("limit" )
748+ defer h .Close ()
749+ return h .ShowHistory (c .Context (), args [0 ], limit )
750+ },
751+ }
752+
753+ cmd .Flags ().IntP ("limit" , "n" , 10 , "Limit number of history entries" )
754+
755+ return cmd
756+ }
0 commit comments