Class: Aidp::Execute::PersistentTasklist

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/execute/persistent_tasklist.rb

Overview

Persistent tasklist for tracking tasks across sessions Uses append-only JSONL format for git-friendly storage

Defined Under Namespace

Classes: InvalidTaskError, TaskNotFoundError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_dir) ⇒ PersistentTasklist

Returns a new instance of PersistentTasklist.



40
41
42
43
44
# File 'lib/aidp/execute/persistent_tasklist.rb', line 40

def initialize(project_dir)
  @project_dir = project_dir
  @file_path = File.join(project_dir, ".aidp", "tasklist.jsonl")
  ensure_file_exists
end

Instance Attribute Details

#file_pathObject (readonly)

Returns the value of attribute file_path.



35
36
37
# File 'lib/aidp/execute/persistent_tasklist.rb', line 35

def file_path
  @file_path
end

#project_dirObject (readonly)

Returns the value of attribute project_dir.



35
36
37
# File 'lib/aidp/execute/persistent_tasklist.rb', line 35

def project_dir
  @project_dir
end

Instance Method Details

#all(status: nil, priority: nil, since: nil, tags: nil) ⇒ Object

Query tasks with optional filters



93
94
95
96
97
98
99
100
101
102
# File 'lib/aidp/execute/persistent_tasklist.rb', line 93

def all(status: nil, priority: nil, since: nil, tags: nil)
  tasks = load_latest_tasks

  tasks = tasks.select { |t| t.status == status } if status
  tasks = tasks.select { |t| t.priority == priority } if priority
  tasks = tasks.select { |t| t.created_at >= since } if since
  tasks = tasks.select { |t| (Array(t.tags) & Array(tags)).any? } if tags && !tags.empty?

  tasks.sort_by(&:created_at).reverse
end

#countsObject

Count tasks by status



120
121
122
123
124
125
126
127
128
129
# File 'lib/aidp/execute/persistent_tasklist.rb', line 120

def counts
  tasks = load_latest_tasks
  {
    total: tasks.size,
    pending: tasks.count { |t| t.status == :pending },
    in_progress: tasks.count { |t| t.status == :in_progress },
    done: tasks.count { |t| t.status == :done },
    abandoned: tasks.count { |t| t.status == :abandoned }
  }
end

#create(description, priority: :medium, session: nil, discovered_during: nil, tags: []) ⇒ Object

Create a new task



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/aidp/execute/persistent_tasklist.rb', line 47

def create(description, priority: :medium, session: nil, discovered_during: nil, tags: [])
  validate_description!(description)
  validate_priority!(priority)

  task = Task.new(
    id: generate_id,
    description: description.strip,
    status: :pending,
    priority: priority,
    created_at: Time.now,
    updated_at: Time.now,
    session: session,
    discovered_during: discovered_during,
    tags: Array(tags)
  )

  append_task(task)
  Aidp.log_debug("tasklist", "Created task", task_id: task.id, description: task.description)
  task
end

#find(task_id) ⇒ Object

Find single task by ID



105
106
107
# File 'lib/aidp/execute/persistent_tasklist.rb', line 105

def find(task_id)
  all.find { |t| t.id == task_id }
end

#in_progressObject

Query in-progress tasks



115
116
117
# File 'lib/aidp/execute/persistent_tasklist.rb', line 115

def in_progress
  all(status: :in_progress)
end

#pendingObject

Query pending tasks (common operation)



110
111
112
# File 'lib/aidp/execute/persistent_tasklist.rb', line 110

def pending
  all(status: :pending)
end

#update_status(task_id, new_status, reason: nil) ⇒ Object

Update task status

Raises:



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/aidp/execute/persistent_tasklist.rb', line 69

def update_status(task_id, new_status, reason: nil)
  validate_status!(new_status)
  task = find(task_id)
  raise TaskNotFoundError, "Task not found: #{task_id}" unless task

  task.status = new_status
  task.updated_at = Time.now

  case new_status
  when :in_progress
    task.started_at ||= Time.now
  when :done
    task.completed_at = Time.now
  when :abandoned
    task.abandoned_at = Time.now
    task.abandoned_reason = reason
  end

  append_task(task)
  Aidp.log_debug("tasklist", "Updated task status", task_id: task.id, status: new_status)
  task
end