// 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 "" }