#!/bin/bash # next-task — print the ID of the next PENDING task to run, or nothing if none. # # Selection logic: # 1. Find the most recently updated COMPLETED or READY task. # 2. If READY, run its first PENDING child (subtask) to begin the series. # 3. If COMPLETED, run its next PENDING sibling to continue the series. # 4. If neither yields a task, fall back to highest-priority oldest PENDING # task across the whole queue. # # Usage: next_id=$(scripts/next-task) # Example: scripts/start-next-task DB_PATH="${DB_PATH:-/site/doot.terst.org/data/claudomator.db}" # 1. Fetch the most recently updated COMPLETED or READY task target=$(sqlite3 "$DB_PATH" "SELECT id, state, parent_task_id FROM tasks WHERE state IN ('COMPLETED', 'READY') ORDER BY updated_at DESC LIMIT 1;") if [ -z "$target" ]; then exit 0 fi IFS='|' read -r id state parent_id <<< "$target" if [ "$state" == "READY" ]; then # 2. READY = parent task; run its first PENDING child to begin the series next_task=$(sqlite3 "$DB_PATH" "SELECT id FROM tasks WHERE parent_task_id = '$id' AND state = 'PENDING' ORDER BY created_at ASC LIMIT 1;") elif [ "$state" == "COMPLETED" ]; then # 3. Find next PENDING sibling to continue the series next_task=$(sqlite3 "$DB_PATH" "SELECT id FROM tasks WHERE parent_task_id = '$parent_id' AND state = 'PENDING' ORDER BY created_at ASC LIMIT 1;") fi if [ -z "$next_task" ]; then # 4. No child/sibling found: fall back to highest-priority oldest PENDING task # Exclude tasks that have a rejection comment or have already been executed # to avoid auto-approving rejected tasks. FALLBACK_SQL="SELECT id FROM tasks WHERE (state = 'PENDING' AND (rejection_comment IS NULL OR rejection_comment = '') AND id NOT IN (SELECT task_id FROM executions)) OR state = 'QUEUED' ORDER BY CASE priority WHEN 'critical' THEN 4 WHEN 'high' THEN 3 WHEN 'normal' THEN 2 WHEN 'low' THEN 1 ELSE 0 END DESC, created_at ASC LIMIT 1;" next_task=$(sqlite3 "$DB_PATH" "$FALLBACK_SQL") fi echo "$next_task"