






















@@ -1,16 +1,15 @@
11name: Docs Agent
2233on:
4-workflow_run: # zizmor: ignore[dangerous-triggers] main-only docs repair after trusted CI; job gates repository, event, branch, actor, conclusion, and exact current main SHA before using write token
4+workflow_run: # zizmor: ignore[dangerous-triggers] main-only docs repair after trusted CI; job gates repository, event, branch, actor, conclusion, exact current main SHA, and hourly cadence before using write token
55workflows:
66 - CI
77types:
88 - completed
9-schedule:
10- - cron: "17 5 * * *"
119workflow_dispatch:
12101311permissions:
12+actions: read
1413contents: write
15141615concurrency:
@@ -41,17 +40,24 @@ jobs:
4140persist-credentials: false
4241submodules: false
434244- - name: Skip superseded workflow runs
45-id: superseded
43+ - name: Gate trusted main activity and hourly cadence
44+id: gate
4645env:
4746EVENT_NAME: ${{ github.event_name }}
47+GH_TOKEN: ${{ github.token }}
4848WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
4949run: |
5050 set -euo pipefail
51515252 if [ "$EVENT_NAME" != "workflow_run" ]; then
53- echo "run_agent=true" >> "$GITHUB_OUTPUT"
54- echo "base_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
53+ head_sha="$(git rev-parse HEAD)"
54+ review_base="$(git rev-parse "${head_sha}^" 2>/dev/null || printf '%s' "$head_sha")"
55+ {
56+ echo "run_agent=true"
57+ echo "base_sha=${head_sha}"
58+ echo "review_base_sha=${review_base}"
59+ echo "review_head_sha=${head_sha}"
60+ } >> "$GITHUB_OUTPUT"
5561 exit 0
5662 fi
5763@@ -73,17 +79,65 @@ jobs:
7379 exit 0
7480 fi
758176- echo "run_agent=true" >> "$GITHUB_OUTPUT"
77- echo "base_sha=${remote_main}" >> "$GITHUB_OUTPUT"
82+ runs_json="$RUNNER_TEMP/docs-agent-runs.json"
83+ gh api --method GET "repos/${GITHUB_REPOSITORY}/actions/workflows/docs-agent.yml/runs" \
84+ -f branch=main \
85+ -f event=workflow_run \
86+ -f per_page=100 > "$runs_json"
87+88+ one_hour_ago="$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)"
89+ recent_runs="$(
90+ jq -r \
91+ --argjson current_run_id "$GITHUB_RUN_ID" \
92+ --arg one_hour_ago "$one_hour_ago" \
93+ '.workflow_runs[]
94+ | select(.database_id != $current_run_id)
95+ | select(.created_at >= $one_hour_ago)
96+ | select(.status != "cancelled")
97+ | select((.conclusion // "") != "skipped")
98+ | [.database_id, .status, (.conclusion // ""), .created_at, .head_sha]
99+ | @tsv' "$runs_json"
100+ )"
101+102+ if [ -n "$recent_runs" ]; then
103+ echo "Docs agent already ran or is running within the last hour; skipping."
104+ printf '%s\n' "$recent_runs"
105+ echo "run_agent=false" >> "$GITHUB_OUTPUT"
106+ exit 0
107+ fi
108+109+ review_base="$(
110+ jq -r \
111+ --argjson current_run_id "$GITHUB_RUN_ID" \
112+ --arg remote_main "$remote_main" \
113+ '.workflow_runs[]
114+ | select(.database_id != $current_run_id)
115+ | select(.status != "cancelled")
116+ | select((.conclusion // "") != "skipped")
117+ | .head_sha
118+ | select(. != null and . != "")
119+ | select(. != $remote_main)
120+ ' "$runs_json" | head -n 1
121+ )"
122+ if [ -z "$review_base" ] || ! git cat-file -e "${review_base}^{commit}" 2>/dev/null; then
123+ review_base="$(git rev-parse "${remote_main}^" 2>/dev/null || printf '%s' "$remote_main")"
124+ fi
125+126+ {
127+ echo "run_agent=true"
128+ echo "base_sha=${remote_main}"
129+ echo "review_base_sha=${review_base}"
130+ echo "review_head_sha=${remote_main}"
131+ } >> "$GITHUB_OUTPUT"
7813279133 - name: Setup Node environment
80-if: steps.superseded.outputs.run_agent == 'true'
134+if: steps.gate.outputs.run_agent == 'true'
81135uses: ./.github/actions/setup-node-env
82136with:
83137install-bun: "false"
8413885139 - name: Ensure docs agent key exists
86-if: steps.superseded.outputs.run_agent == 'true'
140+if: steps.gate.outputs.run_agent == 'true'
87141env:
88142OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
89143run: |
@@ -94,8 +148,11 @@ jobs:
94148 fi
9514996150 - name: Run Codex docs agent
97-if: steps.superseded.outputs.run_agent == 'true'
151+if: steps.gate.outputs.run_agent == 'true'
98152uses: openai/codex-action@v1
153+env:
154+DOCS_AGENT_BASE_SHA: ${{ steps.gate.outputs.review_base_sha }}
155+DOCS_AGENT_HEAD_SHA: ${{ steps.gate.outputs.review_head_sha }}
99156with:
100157openai-api-key: ${{ secrets.OPENCLAW_DOCS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
101158prompt-file: .github/codex/prompts/docs-agent.md
@@ -106,7 +163,7 @@ jobs:
106163codex-args: '["--full-auto"]'
107164108165 - name: Enforce existing-docs-only patch
109-if: steps.superseded.outputs.run_agent == 'true'
166+if: steps.gate.outputs.run_agent == 'true'
110167run: |
111168 set -euo pipefail
112169@@ -139,8 +196,8 @@ jobs:
139196 fi
140197141198 - name: Restore Node 24 path
142-if: steps.superseded.outputs.run_agent == 'true'
143-run: |
199+if: steps.gate.outputs.run_agent == 'true'
200+run: | # zizmor: ignore[github-env] NODE_BIN is set by the trusted local setup-node-env action in this same job
144201 set -euo pipefail
145202 export PATH="${NODE_BIN}:${PATH}"
146203 echo "${NODE_BIN}" >> "$GITHUB_PATH"
@@ -149,13 +206,13 @@ jobs:
149206 pnpm -v
150207151208 - name: Check docs
152-if: steps.superseded.outputs.run_agent == 'true'
209+if: steps.gate.outputs.run_agent == 'true'
153210run: pnpm check:docs
154211155212 - name: Commit docs updates
156-if: steps.superseded.outputs.run_agent == 'true'
213+if: steps.gate.outputs.run_agent == 'true'
157214env:
158-BASE_SHA: ${{ steps.superseded.outputs.base_sha }}
215+BASE_SHA: ${{ steps.gate.outputs.base_sha }}
159216GITHUB_TOKEN: ${{ github.token }}
160217TARGET_BRANCH: main
161218run: |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。