pub struct TaskManager<'a> { /* private fields */ }Implementations§
Source§impl<'a> TaskManager<'a>
impl<'a> TaskManager<'a>
pub fn new(pool: &'a SqlitePool) -> Self
Sourcepub fn with_project_path(pool: &'a SqlitePool, project_path: String) -> Self
pub fn with_project_path(pool: &'a SqlitePool, project_path: String) -> Self
Create a TaskManager with project path for CLI notifications
Sourcepub fn with_websocket(
pool: &'a SqlitePool,
ws_state: Arc<WebSocketState>,
project_path: String,
) -> Self
pub fn with_websocket( pool: &'a SqlitePool, ws_state: Arc<WebSocketState>, project_path: String, ) -> Self
Create a TaskManager with WebSocket notification support
Sourcepub async fn add_task(
&self,
name: &str,
spec: Option<&str>,
parent_id: Option<i64>,
owner: Option<&str>,
) -> Result<Task>
pub async fn add_task( &self, name: &str, spec: Option<&str>, parent_id: Option<i64>, owner: Option<&str>, ) -> Result<Task>
Add a new task owner: ‘human’ (created via CLI/Dashboard) or ‘ai’ (created via MCP)
Sourcepub async fn create_task_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
name: &str,
spec: Option<&str>,
priority: Option<i32>,
status: Option<&str>,
active_form: Option<&str>,
owner: &str,
) -> Result<i64>
pub async fn create_task_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, name: &str, spec: Option<&str>, priority: Option<i32>, status: Option<&str>, active_form: Option<&str>, owner: &str, ) -> Result<i64>
Create a task within a transaction (no notification)
This is used by PlanExecutor for batch operations where:
- Multiple tasks need atomic creation
- Notification should happen after all tasks are committed
§Arguments
tx- The active transactionname- Task namespec- Optional task specificationpriority- Optional priority (1=critical, 2=high, 3=medium, 4=low)status- Optional status string (“todo”, “doing”, “done”)active_form- Optional active form descriptionowner- Task owner (“human” or “ai”)
§Returns
The ID of the created task
Sourcepub async fn update_task_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
spec: Option<&str>,
priority: Option<i32>,
status: Option<&str>,
active_form: Option<&str>,
) -> Result<()>
pub async fn update_task_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, spec: Option<&str>, priority: Option<i32>, status: Option<&str>, active_form: Option<&str>, ) -> Result<()>
Update a task within a transaction (no notification)
Only updates fields that are Some - supports partial updates. Does NOT update name (used for identity) or timestamps.
§Arguments
tx- The active transactiontask_id- ID of the task to updatespec- New spec (if Some)priority- New priority (if Some)status- New status (if Some)active_form- New active form (if Some)
Sourcepub async fn set_parent_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
parent_id: i64,
) -> Result<()>
pub async fn set_parent_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, parent_id: i64, ) -> Result<()>
Set parent_id for a task within a transaction (no notification)
Used to establish parent-child relationships after tasks are created.
Sourcepub async fn clear_parent_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
) -> Result<()>
pub async fn clear_parent_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, ) -> Result<()>
Clear parent_id for a task in a transaction (make it a root task)
Used when explicitly setting parent_id to null in JSON.
Sourcepub async fn delete_task_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
) -> Result<DeleteTaskResult>
pub async fn delete_task_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, ) -> Result<DeleteTaskResult>
Delete a task within a transaction (no notification)
Used by PlanExecutor for batch delete operations. WebSocket notification is sent after transaction commit via notify_batch_changed().
Warning: Due to ON DELETE CASCADE on parent_id, deleting a parent task
will also delete all descendant tasks. The returned DeleteTaskResult includes
the count of descendants that will be cascade-deleted.
Returns DeleteTaskResult with:
found: whether the task existeddescendant_count: number of descendants that will be cascade-deleted
Note: Focus protection is handled by the caller (PlanExecutor) BEFORE
calling this function, using find_focused_in_subtree_in_tx.
Sourcepub async fn find_focused_in_subtree_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
) -> Result<Option<(i64, String)>>
pub async fn find_focused_in_subtree_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, ) -> Result<Option<(i64, String)>>
Find if a task or any of its descendants is ANY session’s focus
This is critical for delete protection: deleting a parent task cascades to all descendants, so we must check the entire subtree for focus.
Focus protection is GLOBAL - a task focused by any session cannot be deleted. This prevents one session from accidentally breaking another session’s work.
Returns Some((task_id, session_id)) if any task in the subtree is focused,
None if no focus found in the subtree.
Sourcepub async fn count_incomplete_children_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
) -> Result<i64>
pub async fn count_incomplete_children_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, ) -> Result<i64>
Count incomplete children of a task within a transaction
Returns the number of child tasks that are not in ‘done’ status. Used to validate that all children are complete before marking parent as done.
Sourcepub async fn complete_task_in_tx(
&self,
tx: &mut Transaction<'_, Sqlite>,
task_id: i64,
) -> Result<()>
pub async fn complete_task_in_tx( &self, tx: &mut Transaction<'_, Sqlite>, task_id: i64, ) -> Result<()>
Complete a task within a transaction (core business logic)
This is the single source of truth for task completion logic:
- Validates all children are complete
- Updates status to ‘done’
- Sets first_done_at timestamp
Called by both done_task() and PlanExecutor.
Sourcepub async fn notify_batch_changed(&self)
pub async fn notify_batch_changed(&self)
Notify Dashboard about a batch operation
Call this after committing a transaction that created/updated multiple tasks. Sends a single “batch_update” notification instead of per-task notifications.
Sourcepub async fn get_task_with_events(&self, id: i64) -> Result<TaskWithEvents>
pub async fn get_task_with_events(&self, id: i64) -> Result<TaskWithEvents>
Get a task with events summary
Sourcepub async fn get_task_ancestry(&self, task_id: i64) -> Result<Vec<Task>>
pub async fn get_task_ancestry(&self, task_id: i64) -> Result<Vec<Task>>
Get full ancestry chain for a task
Returns a vector of tasks from the given task up to the root: [task itself, parent, grandparent, …, root]
Example:
- Task 42 (parent_id: 55) → [Task 42, Task 55, …]
- Task 100 (parent_id: null) → [Task 100]
Sourcepub async fn get_task_context(&self, id: i64) -> Result<TaskContext>
pub async fn get_task_context(&self, id: i64) -> Result<TaskContext>
Get task context - the complete family tree of a task
Returns:
- task: The requested task
- ancestors: Parent chain up to root (ordered from immediate parent to root)
- siblings: Other tasks at the same level (same parent_id)
- children: Direct subtasks of this task
Sourcepub async fn get_descendants(&self, task_id: i64) -> Result<Vec<Task>>
pub async fn get_descendants(&self, task_id: i64) -> Result<Vec<Task>>
Get all descendants of a task recursively (children, grandchildren, etc.) Uses recursive CTE for efficient querying
Sourcepub async fn get_status(
&self,
task_id: i64,
with_events: bool,
) -> Result<StatusResponse>
pub async fn get_status( &self, task_id: i64, with_events: bool, ) -> Result<StatusResponse>
Get status response for a task (the “spotlight” view)
This is the main method for ie status command
Sourcepub async fn get_root_tasks(&self) -> Result<Vec<Task>>
pub async fn get_root_tasks(&self) -> Result<Vec<Task>>
Get root tasks (tasks with no parent) for NoFocusResponse
Sourcepub async fn update_task(
&self,
id: i64,
name: Option<&str>,
spec: Option<&str>,
parent_id: Option<Option<i64>>,
status: Option<&str>,
complexity: Option<i32>,
priority: Option<i32>,
) -> Result<Task>
pub async fn update_task( &self, id: i64, name: Option<&str>, spec: Option<&str>, parent_id: Option<Option<i64>>, status: Option<&str>, complexity: Option<i32>, priority: Option<i32>, ) -> Result<Task>
Update a task
Sourcepub async fn delete_task(&self, id: i64) -> Result<()>
pub async fn delete_task(&self, id: i64) -> Result<()>
Delete a task
Sourcepub async fn find_tasks(
&self,
status: Option<&str>,
parent_id: Option<Option<i64>>,
sort_by: Option<TaskSortBy>,
limit: Option<i64>,
offset: Option<i64>,
) -> Result<PaginatedTasks>
pub async fn find_tasks( &self, status: Option<&str>, parent_id: Option<Option<i64>>, sort_by: Option<TaskSortBy>, limit: Option<i64>, offset: Option<i64>, ) -> Result<PaginatedTasks>
Find tasks with optional filters, sorting, and pagination
Sourcepub async fn get_stats(&self) -> Result<WorkspaceStats>
pub async fn get_stats(&self) -> Result<WorkspaceStats>
Get workspace statistics using SQL aggregation (no data loading)
This is much more efficient than loading all tasks just to count them. Used by session restore when there’s no focused task.
Sourcepub async fn start_task(
&self,
id: i64,
with_events: bool,
) -> Result<TaskWithEvents>
pub async fn start_task( &self, id: i64, with_events: bool, ) -> Result<TaskWithEvents>
Start a task (atomic: update status + set current)
Sourcepub async fn done_task(&self, is_ai_caller: bool) -> Result<DoneTaskResponse>
pub async fn done_task(&self, is_ai_caller: bool) -> Result<DoneTaskResponse>
Complete the current focused task (atomic: check children + update status + clear current) This command only operates on the current_task_id. Prerequisites: A task must be set as current
§Arguments
is_ai_caller- Whether this is called from AI (MCP) or human (CLI/Dashboard). When true and task is human-owned, the operation will fail. Human tasks can only be completed via CLI or Dashboard.
Sourcepub async fn spawn_subtask(
&self,
name: &str,
spec: Option<&str>,
) -> Result<SpawnSubtaskResponse>
pub async fn spawn_subtask( &self, name: &str, spec: Option<&str>, ) -> Result<SpawnSubtaskResponse>
Create a subtask under the current task and switch to it (atomic operation) Returns error if there is no current task Returns response with subtask info and parent task info
Sourcepub async fn pick_next_tasks(
&self,
max_count: usize,
capacity_limit: usize,
) -> Result<Vec<Task>>
pub async fn pick_next_tasks( &self, max_count: usize, capacity_limit: usize, ) -> Result<Vec<Task>>
Intelligently pick tasks from ‘todo’ and transition them to ‘doing’ Returns tasks that were successfully transitioned
§Arguments
max_count- Maximum number of tasks to pickcapacity_limit- Maximum total number of tasks allowed in ‘doing’ status
§Logic
- Check current ‘doing’ task count
- Calculate available capacity
- Select tasks from ‘todo’ (prioritized by: priority DESC, complexity ASC)
- Transition selected tasks to ‘doing’
Sourcepub async fn pick_next(&self) -> Result<PickNextResponse>
pub async fn pick_next(&self) -> Result<PickNextResponse>
Intelligently recommend the next task to work on based on context-aware priority model.
Priority logic:
- First priority: Subtasks of the current focused task (depth-first)
- Second priority: Top-level tasks (breadth-first)
- No recommendation: Return appropriate empty state
This command does NOT modify task status.
Auto Trait Implementations§
impl<'a> Freeze for TaskManager<'a>
impl<'a> !RefUnwindSafe for TaskManager<'a>
impl<'a> Send for TaskManager<'a>
impl<'a> Sync for TaskManager<'a>
impl<'a> Unpin for TaskManager<'a>
impl<'a> !UnwindSafe for TaskManager<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more