Files
joakim 32cc05a546 feat: add task history via log command and info integration
Add engine/history.go with GetTaskHistory and diff-style FormatTaskHistory
that compares consecutive change_log entries to show only what changed.
Add cmd/log.go command for full task history. Integrate last 5 history
entries into FormatTaskDetail (info view) as a "Recent Changes" section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:56:55 +01:00

76 lines
1.6 KiB
Go

package cmd
import (
"fmt"
"os"
"git.jnss.me/joakim/opal/internal/engine"
"github.com/spf13/cobra"
)
var logCmd = &cobra.Command{
Use: "log [filter]",
Short: "Show change history for a task",
Long: `Show the change history for a single task, pulled from the change log.
Examples:
opal 2 log
opal log +bug`,
Run: func(cmd *cobra.Command, args []string) {
parsed := getParsedArgs(cmd)
if err := showTaskLog(parsed.Filters); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
},
}
func showTaskLog(args []string) error {
if len(args) == 0 {
return fmt.Errorf("no task specified for log command")
}
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 task *engine.Task
if len(filter.IDs) > 0 {
if len(filter.IDs) != 1 {
return fmt.Errorf("log requires exactly one task")
}
task, err = ws.GetTaskByDisplayID(filter.IDs[0])
if err != nil {
return err
}
} 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")
}
if len(tasks) > 1 {
return fmt.Errorf("log requires exactly one task (filter matched %d)", len(tasks))
}
task = tasks[0]
}
entries, err := engine.GetTaskHistory(task.UUID)
if err != nil {
return err
}
fmt.Printf("History for: %s\n\n", task.Description)
fmt.Print(engine.FormatTaskHistory(entries))
return nil
}