diff --git a/.gitea/workflows/agent.yml b/.gitea/workflows/agent.yml index ec73452..4d1dd40 100644 --- a/.gitea/workflows/agent.yml +++ b/.gitea/workflows/agent.yml @@ -219,7 +219,17 @@ jobs: 'yes' / 'go' / 'proceed' / 'start building' answering your ready-to-build question) do you end your reply with a 'DELEGATE: @' line to hand off. Never present a plan and delegate on the same turn. If anything is unclear or needs a decision, - START your reply with '@ffaerber', ask specific questions, and do NOT delegate." + START your reply with '@ffaerber', ask specific questions, and do NOT delegate. + BREAKDOWN (for a feature too big for one PR): first PLAN — propose a milestone name and the list + of sub-tasks (title + one line each), then ask '@ffaerber create these N sub-issues? reply yes.' + Do NOT emit the block yet. ONLY after the maintainer approves, end your reply with EXACTLY: + BEGIN_SUBTASKS + milestone: + - :: + - :: + END_SUBTASKS + The automation creates the milestone + one sub-issue per line (each linked to this issue). It + does NOT auto-start any dev — the maintainer @mentions an agent on each sub-issue when ready." fi else ACTION="You start on git branch '${BRANCH}', with git and push credentials already configured. @@ -302,8 +312,14 @@ jobs: post() { curl -sS -w 'comment -> HTTP %{http_code}\n' -X POST "${hdr[@]}" \ "$API/issues/$NUM/comments" -d "$(jq -nc --arg b "$1" '{body:$b}')"; } - # drop the machine-readable marker lines (DELEGATE / CLOSE_ISSUE) from the human-facing reply - reply=$(grep -viE '^[[:space:]]*(DELEGATE:[[:space:]]*@|CLOSE_ISSUE[[:space:]]*$)' /tmp/agent_out.md 2>/dev/null) + # drop machine-readable markers (DELEGATE / CLOSE_ISSUE / the BEGIN_SUBTASKS..END_SUBTASKS block) + reply=$(awk ' + /^[[:space:]]*BEGIN_SUBTASKS/{s=1} + /^[[:space:]]*DELEGATE:[[:space:]]*@/{next} + /^[[:space:]]*CLOSE_ISSUE[[:space:]]*$/{next} + s{ if(/^[[:space:]]*END_SUBTASKS/){s=0}; next } + {print} + ' /tmp/agent_out.md 2>/dev/null) [ -z "$reply" ] && reply="_(Made changes without a text summary — see the diff below.)_" # Prefer the agent's clean delimited PR description; fall back to the whole reply. prdesc=$(awk '/BEGIN_PR_DESCRIPTION/{f=1;next} /END_PR_DESCRIPTION/{f=0} f' /tmp/agent_out.md) @@ -324,6 +340,37 @@ jobs: curl -sS -X PATCH "${hdr[@]}" "$API/issues/$NUM" \ -d '{"state":"closed"}' -w '\nclose -> HTTP %{http_code}\n' || true fi + # BREAKDOWN: from a BEGIN_SUBTASKS block, create a milestone + one sub-issue per line + # (linked to this issue). Sub-issues are NOT auto-started — maintainer mentions agents later. + if grep -qiE '^[[:space:]]*BEGIN_SUBTASKS' /tmp/agent_out.md; then + block=$(awk '/^[[:space:]]*BEGIN_SUBTASKS/{f=1;next} /^[[:space:]]*END_SUBTASKS/{f=0} f' /tmp/agent_out.md) + ms=$(printf '%s\n' "$block" | sed -nE 's/^[[:space:]]*milestone:[[:space:]]*//Ip' | head -1) + msid="" + if [ -n "$ms" ]; then + msid=$(curl -sS "${hdr[@]}" "$API/milestones?state=open&limit=100" | jq -r --arg t "$ms" 'if type=="array" then ([.[]|select(.title==$t)][0].id // empty) else empty end') + [ -z "$msid" ] && msid=$(curl -sS -X POST "${hdr[@]}" "$API/milestones" -d "$(jq -nc --arg t "$ms" '{title:$t}')" | jq -r '.id // empty') + echo "milestone '$ms' -> id ${msid:-?}" + fi + printf '%s\n' "$block" | grep -E '^[[:space:]]*-[[:space:]]' > /tmp/subtasks.txt || true + links="" + while IFS= read -r line; do + item=$(printf '%s' "$line" | sed -E 's/^[[:space:]]*-[[:space:]]*//') + title=${item%%::*}; body=${item#*::}; [ "$body" = "$item" ] && body="" + title=$(printf '%s' "$title" | sed -E 's/[[:space:]]*$//') + body=$(printf '%s' "$body" | sed -E 's/^[[:space:]]*//') + [ -z "$title" ] && continue + ibody=$(printf 'Part of #%s\n\n%s' "$NUM" "$body") + if [ -n "$msid" ]; then + payload=$(jq -nc --arg t "$title" --arg b "$ibody" --argjson m "$msid" '{title:$t,body:$b,milestone:$m}') + else + payload=$(jq -nc --arg t "$title" --arg b "$ibody" '{title:$t,body:$b}') + fi + n=$(curl -sS -X POST "${hdr[@]}" "$API/issues" -d "$payload" | jq -r '.number // empty') + echo "created sub-issue #${n:-?}: $title" + [ -n "$n" ] && links="$links\n- #$n — $title" + done < /tmp/subtasks.txt + post "$(printf '🤖 **@%s** — created sub-issues%s (mention an agent on each when ready):%b' "$NAME" "${ms:+ under milestone **$ms**}" "$links")" + fi # Auto-delegate: if the plan names a teammate, trigger them via AGENT_TOKEN (a PAT, so it # fires a new workflow run — the built-in token cannot). Never targets @pm or self, so the # chain always terminates at a dev. The '🤖' guard on the trigger stops status-comment loops.