Fold task state into one server field; add ready cancel and dismiss
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
UPDATE tasks SET state = CASE
|
||||
WHEN tasks.status != 'active' THEN tasks.status
|
||||
WHEN tasks.discard_state != '' THEN 'discarding'
|
||||
WHEN EXISTS (SELECT 1 FROM inbox_items i WHERE i.task_id = tasks.id AND i.state = 'open') THEN 'asking'
|
||||
WHEN tasks.merging_by != '' OR tasks.finalizing != '' OR tasks.parent_merge_by != '' THEN 'merging'
|
||||
WHEN tasks.merge_queued_by != '' THEN 'merge_held'
|
||||
WHEN tasks.merge_after_review_by != '' THEN 'merge_after_review'
|
||||
ELSE coalesce((
|
||||
SELECT CASE
|
||||
WHEN s.state != 'idle' THEN s.state
|
||||
WHEN s.subagents > 0 THEN 'running'
|
||||
WHEN EXISTS (SELECT 1 FROM reviews r WHERE r.task_id = tasks.id AND r.state = 'running') THEN 'reviewing'
|
||||
WHEN tasks.review_requests > 0 THEN 'review_pending'
|
||||
WHEN tasks.ready = 'merge' THEN 'ready_to_merge'
|
||||
WHEN tasks.ready = 'discard' THEN 'discard_suggested'
|
||||
ELSE 'idle'
|
||||
END
|
||||
FROM agent_sessions s
|
||||
WHERE s.task_id = tasks.id AND s.role != 'reviewer' AND s.state != 'completed'
|
||||
ORDER BY s.state = 'running' DESC, s.subagents > 0 DESC, s.created_at DESC LIMIT 1
|
||||
), 'no_agent')
|
||||
END;
|
||||
+26
-12
@@ -763,17 +763,31 @@ func (s *Store) SetReadyPromptSeq(ctx context.Context, id string, seq int64) err
|
||||
}
|
||||
|
||||
func (s *Store) MarkReady(ctx context.Context, id, overview, actor string) error {
|
||||
return s.setReady(ctx, id, actor, api.TaskReadyMerge, "task.ready", map[string]any{"id": id, "overview": overview})
|
||||
return s.setReady(ctx, id, actor, "merge", "task.ready", map[string]any{"id": id, "overview": overview})
|
||||
}
|
||||
|
||||
func (s *Store) SuggestDiscard(ctx context.Context, id, reason, actor string) error {
|
||||
return s.setReady(ctx, id, actor, api.TaskReadyDiscard, "task.discard_suggested", map[string]any{"id": id, "reason": reason})
|
||||
return s.setReady(ctx, id, actor, "discard", "task.discard_suggested", map[string]any{"id": id, "reason": reason})
|
||||
}
|
||||
|
||||
func (s *Store) setReady(ctx context.Context, id, actor string, ready api.TaskReady, kind string, payload map[string]any) error {
|
||||
func (s *Store) ClearReady(ctx context.Context, id, actor string) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
projectID := ""
|
||||
err := tx.QueryRowContext(ctx, `UPDATE tasks SET ready = ? WHERE id = ? AND status = ? RETURNING project_id`, string(ready), id, string(api.TaskStatusActive)).Scan(&projectID)
|
||||
err := tx.QueryRowContext(ctx, `UPDATE tasks SET ready = '' WHERE id = ? AND status = ? AND ready != '' RETURNING project_id`, id, string(api.TaskStatusActive)).Scan(&projectID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return emit(api.Event{Kind: "task.ready_cleared", ProjectId: &projectID, TaskId: &id, Actor: actor, Payload: map[string]any{"id": id}})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) setReady(ctx context.Context, id, actor, ready, kind string, payload map[string]any) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
projectID := ""
|
||||
err := tx.QueryRowContext(ctx, `UPDATE tasks SET ready = ? WHERE id = ? AND status = ? RETURNING project_id`, ready, id, string(api.TaskStatusActive)).Scan(&projectID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ErrNotFound
|
||||
}
|
||||
@@ -1425,13 +1439,18 @@ func settleTaskState(ctx context.Context, tx *sql.Tx, emit emitFunc, taskID, act
|
||||
const taskStateExpr = `CASE
|
||||
WHEN tasks.status != 'active' THEN tasks.status
|
||||
WHEN tasks.discard_state != '' THEN 'discarding'
|
||||
WHEN tasks.merging_by != '' OR tasks.finalizing != '' THEN 'merging'
|
||||
WHEN EXISTS (SELECT 1 FROM inbox_items i WHERE i.task_id = tasks.id AND i.state = 'open') THEN 'asking'
|
||||
WHEN tasks.merging_by != '' OR tasks.finalizing != '' OR tasks.parent_merge_by != '' THEN 'merging'
|
||||
WHEN tasks.merge_queued_by != '' THEN 'merge_held'
|
||||
WHEN tasks.merge_after_review_by != '' THEN 'merge_after_review'
|
||||
ELSE coalesce((
|
||||
SELECT CASE
|
||||
WHEN s.state != 'idle' THEN s.state
|
||||
WHEN s.subagents > 0 THEN 'running'
|
||||
WHEN EXISTS (SELECT 1 FROM reviews r WHERE r.task_id = tasks.id AND r.state = 'running') THEN 'reviewing'
|
||||
WHEN tasks.review_requests > 0 THEN 'review_pending'
|
||||
WHEN tasks.ready = 'merge' THEN 'ready_to_merge'
|
||||
WHEN tasks.ready = 'discard' THEN 'discard_suggested'
|
||||
ELSE 'idle'
|
||||
END
|
||||
FROM agent_sessions s
|
||||
@@ -1493,7 +1512,7 @@ func (s *Store) ClearReviewRequests(ctx context.Context) error {
|
||||
|
||||
const projectColumns = `id, name, repo_path, default_branch, remote, created_by, created_at`
|
||||
|
||||
const taskColumns = `id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, closed_at, merge_commit, todo_item, forked_from, forked_at, merge_queued_at, workflow_name, workflow_run, workflow_stage, parent_task_id, parent_merge_by, merge_after_review_by != '', state, merging_by != '' OR finalizing != '', discard_state != '' AND status = 'active', (SELECT coalesce(max(seq), 0) FROM events WHERE events.task_id = tasks.id AND kind = 'turn.ended' AND json_extract(payload, '$.summary') = 1), ready`
|
||||
const taskColumns = `id, project_id, title, merge_title, branch, worktree_path, base_ref, port_base, color, status, created_by, created_at, closed_at, merge_commit, todo_item, forked_from, forked_at, merge_queued_at, workflow_name, workflow_run, workflow_stage, parent_task_id, parent_merge_by, merge_after_review_by != '', state, merging_by != '' OR finalizing != '', discard_state != '' AND status = 'active', (SELECT coalesce(max(seq), 0) FROM events WHERE events.task_id = tasks.id AND kind = 'turn.ended' AND json_extract(payload, '$.summary') = 1)`
|
||||
|
||||
const sessionColumns = `id, coalesce(task_id, ''), owner, vendor, model, vendor_session_id, state, role, member, created_by, created_at, forked_from, forked_at, subagents`
|
||||
|
||||
@@ -1528,16 +1547,11 @@ func scanTask(row scanner) (api.Task, error) {
|
||||
parentTaskID := ""
|
||||
parentMergeBy := ""
|
||||
taskState := ""
|
||||
ready := ""
|
||||
err := row.Scan(&t.Id, &t.ProjectId, &t.Title, &t.MergeTitle, &t.Branch, &t.WorktreePath, &t.BaseRef, &t.PortBase, &t.Color, &status, &t.CreatedBy, &createdAt, &closedAt, &mergeCommit, &todoItem, &forkedFrom, &forkedAt, &mergeQueuedAt, &workflowName, &workflowRun, &workflowStage, &parentTaskID, &parentMergeBy, &t.MergeAfterReview, &taskState, &t.Merging, &t.Discarding, &t.SummarySeq, &ready)
|
||||
err := row.Scan(&t.Id, &t.ProjectId, &t.Title, &t.MergeTitle, &t.Branch, &t.WorktreePath, &t.BaseRef, &t.PortBase, &t.Color, &status, &t.CreatedBy, &createdAt, &closedAt, &mergeCommit, &todoItem, &forkedFrom, &forkedAt, &mergeQueuedAt, &workflowName, &workflowRun, &workflowStage, &parentTaskID, &parentMergeBy, &t.MergeAfterReview, &taskState, &t.Merging, &t.Discarding, &t.SummarySeq)
|
||||
if err != nil {
|
||||
return t, err
|
||||
}
|
||||
t.State = api.TaskState(taskState)
|
||||
if ready != "" {
|
||||
r := api.TaskReady(ready)
|
||||
t.Ready = &r
|
||||
}
|
||||
if parentTaskID != "" {
|
||||
t.ParentTaskId = &parentTaskID
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user