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.



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

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.



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

def file_path
  @file_path
end

#project_dirObject (readonly)

Returns the value of attribute project_dir.



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

def project_dir
  @project_dir
end

Instance Method Details

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

Query tasks with optional filters



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

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



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

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



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

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



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

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

#in_progressObject

Query in-progress tasks



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

def in_progress
  all(status: :in_progress)
end

#pendingObject

Query pending tasks (common operation)



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

def pending
  all(status: :pending)
end

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

Update task status

Raises:



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

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