Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .agents/scripts/supervisor-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -477,11 +477,17 @@ GitHub Issue Auto-Creation (t149):
(dedup by title search). Requires: gh CLI authenticated.
Enable: --with-issue flag on add, or SUPERVISOR_AUTO_ISSUE=true globally.

Cron Integration & Auto-Pickup (t128.5, t296):
Cron Integration & Auto-Pickup (t128.5, t296, t1085.4):
Auto-pickup scans TODO.md for tasks to automatically queue:
1. Tasks tagged with #auto-dispatch anywhere in the line
2. Tasks listed under a "## Dispatch Queue" section header
Both strategies skip tasks already tracked by the supervisor.
3. Tasks tagged with #plan that have PLANS.md references (decomposition)
4. Subtasks (tXXX.N) of #auto-dispatch parents — inherits dispatch eligibility
and propagates parent model tier when subtask has no explicit model: field
All strategies skip tasks already tracked by the supervisor.
All strategies respect blocked-by: dependencies — tasks with unresolved
blockers are skipped until their dependencies are completed ([x] in TODO.md
or terminal state in supervisor DB).

Auto-batching (t296, t321): When new tasks are picked up, they are automatically
assigned to a batch. If an active batch exists, tasks are added to it.
Expand Down
123 changes: 123 additions & 0 deletions .agents/scripts/supervisor/cron.sh
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,27 @@ cmd_watch() {
return 0
}

#######################################
# Check if a task is blocked by unresolved dependencies.
# Returns 0 (should skip) if blocked, 1 (should not skip) otherwise.
# Usage: _check_and_skip_if_blocked <line> <task_id> <todo_file>
#######################################
_check_and_skip_if_blocked() {
local line
line="$1"
local task_id
task_id="$2"
local todo_file
todo_file="$3"
local unresolved_blockers

if unresolved_blockers=$(is_task_blocked "$line" "$todo_file"); then
log_info " $task_id: blocked by unresolved dependencies ($unresolved_blockers) — skipping"
return 0
fi
return 1
}

#######################################
# Scan TODO.md for tasks tagged #auto-dispatch or in a
# "Dispatch Queue" section. Auto-adds them to supervisor
Expand Down Expand Up @@ -275,6 +296,11 @@ cmd_auto_pickup() {
continue
fi

# Skip tasks with unresolved blocked-by dependencies (t1085.4)
if _check_and_skip_if_blocked "$line" "$task_id" "$todo_file"; then
continue
fi

# Check if already in supervisor
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)
Expand Down Expand Up @@ -341,6 +367,11 @@ cmd_auto_pickup() {
continue
fi

# Skip tasks with unresolved blocked-by dependencies (t1085.4)
if _check_and_skip_if_blocked "$line" "$task_id" "$todo_file"; then
continue
fi

local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)
if [[ -n "$existing" ]]; then
Expand Down Expand Up @@ -424,6 +455,98 @@ cmd_auto_pickup() {
done <<<"$plan_tasks"
fi

# Strategy 4: Subtask inheritance from #auto-dispatch parents (t1085.4)
# Find open subtasks (tXXX.N) whose parent task (tXXX) has #auto-dispatch,
# even if the subtask itself doesn't have the tag. Also propagates model tier
# from parent when the subtask has no explicit model: field.
# This unblocks subtask trees like t1081.1-t1081.4 and t1082.1-t1082.4.

# Step 1: Collect parent task IDs that have #auto-dispatch
local parent_ids
parent_ids=$(grep -E '^[[:space:]]*- \[[ xX-]\] (t[0-9]+) .*#auto-dispatch' "$todo_file" 2>/dev/null |
grep -oE 't[0-9]+' | head -50 | sort -u || true)

if [[ -n "$parent_ids" ]]; then
while IFS= read -r parent_id; do
[[ -z "$parent_id" ]] && continue

# Extract parent's model tier for propagation
local parent_line
parent_line=$(grep -E "^[[:space:]]*- \[[ xX-]\] ${parent_id} " "$todo_file" 2>/dev/null | head -1 || true)
local parent_model=""
if [[ -n "$parent_line" ]]; then
parent_model=$(echo "$parent_line" | grep -oE 'model:[a-zA-Z0-9/_.-]+' | head -1 | sed 's/^model://' || true)
fi

# Find open subtasks of this parent (tXXX.N pattern, any nesting depth)
local subtasks
subtasks=$(grep -E "^[[:space:]]*- \[ \] ${parent_id}\.[0-9]+" "$todo_file" 2>/dev/null || true)
if [[ -z "$subtasks" ]]; then
continue
fi

while IFS= read -r sub_line; do
[[ -z "$sub_line" ]] && continue
local sub_id
sub_id=$(echo "$sub_line" | grep -oE 't[0-9]+(\.[0-9]+)+' | head -1)
if [[ -z "$sub_id" ]]; then
continue
fi

# Skip if already picked up by Strategy 1 (has own #auto-dispatch tag)
if echo "$sub_line" | grep -qE '#auto-dispatch'; then
continue
fi

# Skip tasks with assignee: or started: fields
if echo "$sub_line" | grep -qE '(assignee:|started:)'; then
log_info " $sub_id: already claimed or in progress — skipping subtask pickup"
continue
fi

# Skip tasks with unresolved blocked-by dependencies
if _check_and_skip_if_blocked "$sub_line" "$sub_id" "$todo_file"; then
continue
fi

# Check if already in supervisor
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$sub_id")';" 2>/dev/null || true)
if [[ -n "$existing" ]]; then
if [[ "$existing" == "complete" || "$existing" == "cancelled" ]]; then
continue
fi
log_info " $sub_id: already tracked (status: $existing)"
continue
fi

# Pre-pickup check: skip tasks with merged PRs
if check_task_already_done "$sub_id" "$repo"; then
log_info " $sub_id: already completed (merged PR) — skipping subtask pickup"
continue
fi

# Propagate parent model tier if subtask has no explicit model:
local model_arg=""
if [[ -n "$parent_model" ]]; then
local sub_model
sub_model=$(echo "$sub_line" | grep -oE 'model:[a-zA-Z0-9/_.-]+' | head -1 || true)
if [[ -z "$sub_model" ]]; then
model_arg="--model $parent_model"
log_info " $sub_id: inheriting model:$parent_model from parent $parent_id"
fi
fi

# Add to supervisor (with optional model propagation)
# shellcheck disable=SC2086
if cmd_add "$sub_id" --repo "$repo" $model_arg; then
picked_up=$((picked_up + 1))
log_success " Auto-picked: $sub_id (subtask of #auto-dispatch parent $parent_id)"
fi
done <<<"$subtasks"
done <<<"$parent_ids"
fi

if [[ "$picked_up" -eq 0 ]]; then
log_info "No new tasks to pick up"
else
Expand Down
Loading