ci / lint (push) Skipped
Fixes from a full repo review: - fetch-thread.sh: attribute每 comment to its REAL author (@pm/@qa/… — agents post as their own users now); the old "🤖 @name line at the top" hint pointed at headers we removed, leaving every teammate comment anonymous. Also strip the hidden loop-prevention marker from bodies (prompt noise). - agent.yml: per-issue concurrency group (queued, no cancel) — two quick comments on one issue no longer race the same ai/issue-N branch. - rescue-pr.sh: after opening a rescue PR, hand it back into the flow with an unmarked @pm trigger (the pm→qa choreography previously stalled silently on any rescued run); drop the old "🤖 **@name**" header style; add ops to the token case; mark the status note with the hidden marker. - README: token table said "@qa merges / TOKEN_QA needs write:repository" — inverted since the PM-orchestrated flow (@pm merges, autopilot only; @qa is read-only). Updated the agent table (descs, node1-ssh moved to homelab) and added a "How a task flows" section. - agents.json: pm/qa descs now describe the orchestrator/reviewer roles (these feed the roster prompt agents route by). - NEW ci.yml: bash -n + shellcheck(-S error) on every script, YAML-parse on every workflow, agents.json schema check — the ${x:-{}} brace bug would have been caught here before it shipped. - install-opencode.sh: pin opencode (default 1.17.13, override via OPENCODE_VERSION) — a breaking release no longer takes down every agent. - build-activity-log.sh: ollama/ollama-cloud models are subscription-billed (no $/token exists) — label the footer "subscription" instead of a misleading $0.0000; metered (anthropic) models keep the real dollar cost. - route.sh: document that mention-priority is list-order and load-bearing for the flow's trigger comments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
3.9 KiB
Bash
Executable File
71 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Failure-safe rescue: when a run FAILED after a dev agent already pushed commits, the normal
|
|
# Publish step never ran and the work would be stranded on the branch with no PR (issue #33).
|
|
# This opens a PR for the pushed branch so nothing is silently lost. It is strictly best-effort:
|
|
# every failure here is swallowed (the caller also appends `|| true`) so it can never itself break
|
|
# the run. Comment-only roles (pm/qa) push nothing, so they are skipped.
|
|
#
|
|
# Required env (provided by the workflow step):
|
|
# GT TOKEN_PM TOKEN_SENIOR TOKEN_JUNIOR TOKEN_LEAD TOKEN_QA TOKEN_OPS
|
|
# NAME MODE NUM TITLE BRANCH GITHUB_SERVER_URL GITHUB_REPOSITORY
|
|
set +e
|
|
|
|
# Only dev agents (mode=pr) ever push a branch to rescue.
|
|
[ "${MODE:-}" = "pr" ] || { echo "rescue: comment-mode agent, nothing to rescue"; exit 0; }
|
|
[ -n "${BRANCH:-}" ] || { echo "rescue: no branch known, skipping"; exit 0; }
|
|
|
|
# Post/PR as the agent's OWN Gitea user when its token is configured; else the built-in bot.
|
|
case "$NAME" in
|
|
pm) TOK="$TOKEN_PM";; senior) TOK="$TOKEN_SENIOR";; junior) TOK="$TOKEN_JUNIOR";;
|
|
lead) TOK="$TOKEN_LEAD";; qa) TOK="$TOKEN_QA";; ops) TOK="$TOKEN_OPS";; *) TOK="";;
|
|
esac
|
|
[ -z "$TOK" ] && TOK="$GT"
|
|
# Trigger token: the @pm hand-back below must FIRE a new run, which the built-in token cannot.
|
|
TTOK="$TOK"; [ "$TTOK" = "$GT" ] && TTOK=""
|
|
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
|
|
hdr=(-H "Authorization: token $TOK" -H "Content-Type: application/json")
|
|
|
|
git fetch -q origin 2>/dev/null || true
|
|
|
|
# Nothing to rescue unless the branch exists on the remote with commits beyond main.
|
|
ahead=$(git rev-list --count "origin/main..origin/$BRANCH" 2>/dev/null || echo 0)
|
|
if [ "${ahead:-0}" -eq 0 ]; then
|
|
echo "rescue: no pushed commits on origin/$BRANCH beyond main — nothing to rescue"
|
|
exit 0
|
|
fi
|
|
echo "rescue: origin/$BRANCH is $ahead commit(s) ahead of main — ensuring a PR exists"
|
|
|
|
# Idempotent: Gitea ignores ?head=, so match the head branch client-side.
|
|
resp=$(curl -sS "${hdr[@]}" "$API/pulls?state=open&limit=50" \
|
|
| jq -r --arg br "$BRANCH" 'if type=="array" then (map(select(.head.ref==$br)) | .[0] // empty) else empty end' 2>/dev/null)
|
|
url=$(printf '%s' "$resp" | jq -r '.html_url // empty' 2>/dev/null)
|
|
if [ -z "$url" ]; then
|
|
body=$(printf 'The run failed before it could publish, but pushed work exists on this branch — opening a PR so it is not lost.\n\n---\nResolves #%s (auto-rescued after a failed run)' "$NUM")
|
|
resp=$(curl -sS -X POST "${hdr[@]}" "$API/pulls" \
|
|
-d "$(jq -nc --arg t "@$NAME: $TITLE" --arg h "$BRANCH" --arg b "$body" \
|
|
'{title:$t, head:$h, base:"main", body:$b}')")
|
|
echo "rescue PR create ($BRANCH): $resp"
|
|
url=$(printf '%s' "$resp" | jq -r '.html_url // empty' 2>/dev/null)
|
|
prnum=$(printf '%s' "$resp" | jq -r '.number // empty' 2>/dev/null)
|
|
else
|
|
prnum=$(printf '%s' "$resp" | jq -r '.number // empty' 2>/dev/null)
|
|
fi
|
|
|
|
if [ -n "$url" ]; then
|
|
# Status note on the issue (marked — must not trigger)…
|
|
curl -sS -X POST "${hdr[@]}" "$API/issues/$NUM/comments" \
|
|
-d "$(jq -nc --arg b "$(printf '⚠️ The run failed, but the pushed work was not lost — a PR was opened for branch \`%s\`:\n- %s\n\n<!-- 🤖 agent reply — do not trigger -->' "$BRANCH" "$url")" '{body:$b}')" \
|
|
-w '\nrescue comment -> HTTP %{http_code}\n' || true
|
|
# …then hand the rescued PR back into the flow: without this, the pm→qa choreography would stall
|
|
# here (the normal "PR ready" trigger never fired). Unmarked + PAT so it starts @pm's run.
|
|
if [ -n "$TTOK" ]; then
|
|
curl -sS -X POST -H "Authorization: token $TTOK" -H "Content-Type: application/json" \
|
|
"$API/issues/$NUM/comments" \
|
|
-d "$(jq -nc --arg b "@pm — PR #${prnum:-?} was auto-rescued after a failed run (issue #$NUM). Please route it for review." '{body:$b}')" \
|
|
-w '\nrescue trigger @pm -> HTTP %{http_code}\n' || true
|
|
fi
|
|
else
|
|
echo "rescue: could not open/find a PR for $BRANCH"
|
|
fi
|
|
exit 0
|