210 lines
5.4 KiB
Go
210 lines
5.4 KiB
Go
// task/agent.go – Task-Agent: add/list/done/delete
|
||
package task
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"my-brain-importer/internal/agents"
|
||
)
|
||
|
||
// Agent verwaltet Aufgaben über tasks.json.
|
||
type Agent struct {
|
||
store *Store
|
||
}
|
||
|
||
// New erstellt einen neuen Task-Agenten.
|
||
func New() *Agent {
|
||
return &Agent{store: NewStore()}
|
||
}
|
||
|
||
// Handle unterstützt: add, list, done, delete
|
||
func (a *Agent) Handle(req agents.Request) agents.Response {
|
||
switch req.Action {
|
||
case agents.ActionAdd:
|
||
return a.add(req)
|
||
case agents.ActionList:
|
||
return a.list()
|
||
case agents.ActionDone:
|
||
return a.done(req)
|
||
case agents.ActionDelete:
|
||
return a.del(req)
|
||
default:
|
||
return agents.Response{Text: "❌ Unbekannte Task-Aktion. Verfügbar: add, list, done, delete"}
|
||
}
|
||
}
|
||
|
||
// parseAddArgs parst Text, --due YYYY-MM-DD und --priority WERT aus den Args.
|
||
func parseAddArgs(args []string) (text, priority string, dueDate *time.Time) {
|
||
var textParts []string
|
||
for i := 0; i < len(args); i++ {
|
||
switch args[i] {
|
||
case "--due", "-d":
|
||
i++
|
||
if i < len(args) {
|
||
t, err := time.Parse("2006-01-02", args[i])
|
||
if err == nil {
|
||
dueDate = &t
|
||
}
|
||
}
|
||
case "--priority", "-p":
|
||
i++
|
||
if i < len(args) {
|
||
priority = strings.ToLower(args[i])
|
||
}
|
||
default:
|
||
textParts = append(textParts, args[i])
|
||
}
|
||
}
|
||
text = strings.Join(textParts, " ")
|
||
return
|
||
}
|
||
|
||
func (a *Agent) add(req agents.Request) agents.Response {
|
||
if len(req.Args) == 0 {
|
||
return agents.Response{Text: "❌ Kein Task-Text angegeben."}
|
||
}
|
||
text, priority, dueDate := parseAddArgs(req.Args)
|
||
if text == "" {
|
||
return agents.Response{Text: "❌ Kein Task-Text angegeben."}
|
||
}
|
||
t, err := a.store.Add(text, priority, dueDate)
|
||
if err != nil {
|
||
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
|
||
}
|
||
shortID := t.ID
|
||
if len(shortID) > 6 {
|
||
shortID = shortID[len(shortID)-6:]
|
||
}
|
||
var extras []string
|
||
if t.Priority != "" {
|
||
extras = append(extras, "Priorität: "+t.Priority)
|
||
}
|
||
if t.DueDate != nil {
|
||
extras = append(extras, "Fällig: "+t.DueDate.Format("02.01.2006"))
|
||
}
|
||
info := ""
|
||
if len(extras) > 0 {
|
||
info = " (" + strings.Join(extras, ", ") + ")"
|
||
}
|
||
return agents.Response{Text: fmt.Sprintf("✅ Task hinzugefügt: `%s`%s (ID: `%s`)", t.Text, info, shortID)}
|
||
}
|
||
|
||
func (a *Agent) list() agents.Response {
|
||
tasks, err := a.store.Load()
|
||
if err != nil {
|
||
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
|
||
}
|
||
if len(tasks) == 0 {
|
||
return agents.Response{Text: "📋 Keine Tasks vorhanden."}
|
||
}
|
||
|
||
today := time.Now().Truncate(24 * time.Hour)
|
||
tomorrow := today.Add(24 * time.Hour)
|
||
|
||
var sb strings.Builder
|
||
sb.WriteString("📋 **Task-Liste:**\n\n")
|
||
openCount := 0
|
||
for _, t := range tasks {
|
||
status := "⬜"
|
||
if t.Done {
|
||
status = "✅"
|
||
} else {
|
||
openCount++
|
||
}
|
||
shortID := t.ID
|
||
if len(shortID) > 6 {
|
||
shortID = shortID[len(shortID)-6:]
|
||
}
|
||
|
||
var meta []string
|
||
if t.Priority != "" {
|
||
switch t.Priority {
|
||
case "hoch":
|
||
meta = append(meta, "🔴 hoch")
|
||
case "mittel":
|
||
meta = append(meta, "🟡 mittel")
|
||
case "niedrig":
|
||
meta = append(meta, "🟢 niedrig")
|
||
default:
|
||
meta = append(meta, t.Priority)
|
||
}
|
||
}
|
||
if t.DueDate != nil && !t.Done {
|
||
due := t.DueDate.Truncate(24 * time.Hour)
|
||
switch {
|
||
case due.Before(today):
|
||
meta = append(meta, "⏰ **ÜBERFÄLLIG** "+t.DueDate.Format("02.01."))
|
||
case due.Equal(today):
|
||
meta = append(meta, "⏰ heute fällig")
|
||
case due.Equal(tomorrow):
|
||
meta = append(meta, "📅 morgen fällig")
|
||
default:
|
||
meta = append(meta, "📅 "+t.DueDate.Format("02.01.2006"))
|
||
}
|
||
}
|
||
|
||
line := fmt.Sprintf("%s `%s` – %s", status, shortID, t.Text)
|
||
if len(meta) > 0 {
|
||
line += " · " + strings.Join(meta, " · ")
|
||
}
|
||
sb.WriteString(line + "\n")
|
||
}
|
||
fmt.Fprintf(&sb, "\n*%d offen, %d gesamt*", openCount, len(tasks))
|
||
return agents.Response{Text: sb.String()}
|
||
}
|
||
|
||
func (a *Agent) done(req agents.Request) agents.Response {
|
||
if len(req.Args) == 0 {
|
||
return agents.Response{Text: "❌ Keine Task-ID angegeben."}
|
||
}
|
||
id := req.Args[0]
|
||
tasks, err := a.store.Load()
|
||
if err != nil {
|
||
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
|
||
}
|
||
fullID := resolveID(tasks, id)
|
||
if fullID == "" {
|
||
return agents.Response{Text: fmt.Sprintf("❌ Task `%s` nicht gefunden.", id)}
|
||
}
|
||
if err := a.store.MarkDone(fullID); err != nil {
|
||
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
|
||
}
|
||
return agents.Response{Text: fmt.Sprintf("✅ Task `%s` als erledigt markiert.", id)}
|
||
}
|
||
|
||
func (a *Agent) del(req agents.Request) agents.Response {
|
||
if len(req.Args) == 0 {
|
||
return agents.Response{Text: "❌ Keine Task-ID angegeben."}
|
||
}
|
||
id := req.Args[0]
|
||
tasks, err := a.store.Load()
|
||
if err != nil {
|
||
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
|
||
}
|
||
fullID := resolveID(tasks, id)
|
||
if fullID == "" {
|
||
return agents.Response{Text: fmt.Sprintf("❌ Task `%s` nicht gefunden.", id)}
|
||
}
|
||
if err := a.store.Delete(fullID); err != nil {
|
||
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
|
||
}
|
||
return agents.Response{Text: fmt.Sprintf("🗑️ Task `%s` gelöscht.", id)}
|
||
}
|
||
|
||
// resolveID findet eine vollständige ID aus einer vollständigen oder kurzen (letzte 6 Zeichen).
|
||
func resolveID(tasks []Task, id string) string {
|
||
for _, t := range tasks {
|
||
if t.ID == id {
|
||
return t.ID
|
||
}
|
||
}
|
||
for _, t := range tasks {
|
||
if len(t.ID) >= 6 && t.ID[len(t.ID)-6:] == id {
|
||
return t.ID
|
||
}
|
||
}
|
||
return ""
|
||
}
|