types.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package planning
  6
  7import (
  8	"crypto/sha256"
  9	"fmt"
 10	"strings"
 11	"time"
 12)
 13
 14// TaskStatus represents the status of a task
 15type TaskStatus int
 16
 17const (
 18	StatusPending TaskStatus = iota
 19	StatusInProgress
 20	StatusCompleted
 21	StatusFailed
 22	StatusCancelled
 23)
 24
 25// String returns the emoji representation of the task status
 26func (s TaskStatus) String() string {
 27	switch s {
 28	case StatusPending:
 29		return "☐"
 30	case StatusInProgress:
 31		return "⟳"
 32	case StatusCompleted:
 33		return "☑"
 34	case StatusFailed:
 35		return "☒"
 36	case StatusCancelled:
 37		return "⊗"
 38	default:
 39		return "☐"
 40	}
 41}
 42
 43// ParseStatus converts a string status to TaskStatus enum
 44func ParseStatus(status string) TaskStatus {
 45	switch strings.ToLower(status) {
 46	case "pending":
 47		return StatusPending
 48	case "in_progress":
 49		return StatusInProgress
 50	case "completed":
 51		return StatusCompleted
 52	case "failed":
 53		return StatusFailed
 54	case "cancelled":
 55		return StatusCancelled
 56	default:
 57		return StatusPending
 58	}
 59}
 60
 61// Goal represents the overarching goal
 62type Goal struct {
 63	Text      string    `json:"text"`
 64	UpdatedAt time.Time `json:"updated_at"`
 65}
 66
 67// Task represents a single task
 68type Task struct {
 69	ID          string     `json:"id"`
 70	Title       string     `json:"title"`
 71	Description string     `json:"description"`
 72	Status      TaskStatus `json:"status"`
 73	CreatedAt   time.Time  `json:"created_at"`
 74	UpdatedAt   time.Time  `json:"updated_at"`
 75}
 76
 77// NewTask creates a new task with a deterministic ID
 78func NewTask(title, description string) *Task {
 79	// Generate deterministic ID based on title and description
 80	id := generateTaskID(title, description)
 81
 82	return &Task{
 83		ID:          id,
 84		Title:       title,
 85		Description: description,
 86		Status:      StatusPending,
 87		CreatedAt:   time.Now(),
 88		UpdatedAt:   time.Now(),
 89	}
 90}
 91
 92// UpdateStatus updates the task status and timestamp
 93func (t *Task) UpdateStatus(status TaskStatus) {
 94	t.Status = status
 95	t.UpdatedAt = time.Now()
 96}
 97
 98// UpdateContent updates the task title and/or description and regenerates ID
 99func (t *Task) UpdateContent(title, description string) {
100	if title != "" {
101		t.Title = title
102	}
103	if description != "" {
104		t.Description = description
105	}
106	// Regenerate ID based on new content
107	t.ID = generateTaskID(t.Title, t.Description)
108	t.UpdatedAt = time.Now()
109}
110
111// generateTaskID creates a deterministic 8-character ID based on task content
112func generateTaskID(title, description string) string {
113	content := fmt.Sprintf("%s:%s", title, description)
114	hash := sha256.Sum256([]byte(content))
115	return fmt.Sprintf("%x", hash[:4]) // 8 hex characters
116}