@plainconceptsplatform/workflows 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog-installation.d.ts +12 -0
- package/dist/catalog-installation.js +81 -0
- package/dist/catalog-installation.test.d.ts +1 -0
- package/dist/catalog-installation.test.js +85 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +57 -0
- package/dist/repository-inspection.d.ts +23 -0
- package/dist/repository-inspection.js +91 -0
- package/dist/repository-state.d.ts +18 -0
- package/dist/repository-state.js +77 -0
- package/dist/repository-state.test.d.ts +1 -0
- package/dist/repository-state.test.js +96 -0
- package/dist/workflow-catalog.d.ts +17 -0
- package/dist/workflow-catalog.js +39 -0
- package/dist/workflow-catalog.test.d.ts +1 -0
- package/dist/workflow-catalog.test.js +14 -0
- package/loops/actions/add-issue-labels/action.yml +29 -0
- package/loops/actions/agent-output.cjs +16 -0
- package/loops/actions/apply-agent-bundle/action.yml +23 -0
- package/loops/actions/apply-agent-bundle/apply-bundle.sh +45 -0
- package/loops/actions/apply-agent-comments/action.yml +41 -0
- package/loops/actions/apply-agent-labels/action.yml +54 -0
- package/loops/actions/apply-agent-output/action.yml +107 -0
- package/loops/actions/audit-close/action.yml +103 -0
- package/loops/actions/classify-route/action.yml +90 -0
- package/loops/actions/classify-route/classify-route.sh +172 -0
- package/loops/actions/cleanup-artifacts/action.yml +64 -0
- package/loops/actions/close-agent-issues/action.yml +42 -0
- package/loops/actions/create-agent-issues/action.yml +51 -0
- package/loops/actions/create-issue-comment/action.yml +28 -0
- package/loops/actions/download-agent-output/action.yml +52 -0
- package/loops/actions/identify-gate-subject/action.yml +96 -0
- package/loops/actions/link-pr-to-issue/action.yml +39 -0
- package/loops/actions/list-open-issues/action.yml +32 -0
- package/loops/actions/load-issue-context/action.yml +42 -0
- package/loops/actions/merge-agent-pr/action.yml +35 -0
- package/loops/actions/push-agent-branch/action.yml +44 -0
- package/loops/actions/remove-issue-labels/action.yml +34 -0
- package/loops/actions/stale-recovery/action.yml +287 -0
- package/loops/actions/update-agent-issues/action.yml +57 -0
- package/loops/actions/validate-refine-output/action.yml +43 -0
- package/loops/actions/validate-refine-output/validate-refine-output.sh +46 -0
- package/loops/actions/verify-composite-actions/action.yml +8 -0
- package/loops/actions/verify-composite-actions/verify-composite-actions.sh +50 -0
- package/loops/actions/verify-refine-output/action.yml +8 -0
- package/loops/actions/verify-refine-output/verify-refine-output.sh +65 -0
- package/loops/actions/verify-route-matrix/action.yml +8 -0
- package/loops/actions/verify-route-matrix/verify-route-matrix.sh +212 -0
- package/loops/aw/repo-config.md +12 -0
- package/loops/scripts/compile-agent-workflows.mjs +13 -0
- package/loops/workflows/agent-apply-review.md +372 -0
- package/loops/workflows/agent-audit.md +197 -0
- package/loops/workflows/agent-direct.md +362 -0
- package/loops/workflows/agent-implement.md +329 -0
- package/loops/workflows/agent-merge-gate.md +470 -0
- package/loops/workflows/agent-propose.md +342 -0
- package/loops/workflows/agent-refine.md +338 -0
- package/loops/workflows/shared/opencode-ci.md +26 -0
- package/loops/workflows/shared/platform-defaults.md +14 -0
- package/loops/workflows/work-router.yml +391 -0
- package/package.json +28 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
---
|
|
2
|
+
env:
|
|
3
|
+
WORKING_LABEL: bot-working
|
|
4
|
+
IMPLEMENT_LABEL: implement
|
|
5
|
+
REVIEW_LABEL: review
|
|
6
|
+
GATE_MARKER: "<!-- agent-merge-gate -->"
|
|
7
|
+
INCOMPLETE_COMMENT: "Automated CI failure remediation ended without an outcome. The issue remains for a retry."
|
|
8
|
+
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
|
|
9
|
+
GIT_AUTHOR_NAME: "github-actions[bot]"
|
|
10
|
+
GIT_AUTHOR_EMAIL: "github-actions[bot]@users.noreply.github.com"
|
|
11
|
+
GIT_COMMITTER_NAME: "github-actions[bot]"
|
|
12
|
+
GIT_COMMITTER_EMAIL: "github-actions[bot]@users.noreply.github.com"
|
|
13
|
+
description: |
|
|
14
|
+
Decides what happens to a bot-authored pull request once CI has reported: merge when the
|
|
15
|
+
risk assessment is clean, hand to a human when it is not, fix CI when it failed. Called by
|
|
16
|
+
the Work Router; does not trigger on public events.
|
|
17
|
+
|
|
18
|
+
The router supplies the CI conclusion and run ID as facts, so there is no polling and no
|
|
19
|
+
timeout branch. The conclusion is read from the inputs instead of filtered at the trigger.
|
|
20
|
+
|
|
21
|
+
name: "Agent: Merge Gate"
|
|
22
|
+
|
|
23
|
+
# Router-only worker. The Work Router owns triggers, classification, and rung 1-2 checks.
|
|
24
|
+
# This workflow receives the classified inputs and runs rung 3+.
|
|
25
|
+
imports:
|
|
26
|
+
- shared/platform-defaults.md
|
|
27
|
+
- shared/opencode-ci.md
|
|
28
|
+
- shared/repo-config.md
|
|
29
|
+
|
|
30
|
+
on:
|
|
31
|
+
workflow_call:
|
|
32
|
+
inputs:
|
|
33
|
+
pr-number:
|
|
34
|
+
description: Pull request number to gate.
|
|
35
|
+
required: true
|
|
36
|
+
type: string
|
|
37
|
+
linked-issue:
|
|
38
|
+
description: Issue number the pull request closes. May be empty.
|
|
39
|
+
required: false
|
|
40
|
+
type: string
|
|
41
|
+
ci-conclusion:
|
|
42
|
+
description: CI conclusion (success, failure, action_required, cancelled, etc.).
|
|
43
|
+
required: true
|
|
44
|
+
type: string
|
|
45
|
+
ci-run-id:
|
|
46
|
+
description: CI workflow run ID for fetching failing logs.
|
|
47
|
+
required: false
|
|
48
|
+
type: string
|
|
49
|
+
|
|
50
|
+
# Rung 4. Router has classified the event; identify-gate-subject validates PR ownership,
|
|
51
|
+
# resolves the closing issue, and confirms the CI verdict.
|
|
52
|
+
# A custom job, not `on.steps`, because the prompt and the precompute step need these
|
|
53
|
+
# values and `on.steps` outputs do not reach the agent job.
|
|
54
|
+
jobs:
|
|
55
|
+
subject:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
permissions:
|
|
58
|
+
contents: read
|
|
59
|
+
issues: read
|
|
60
|
+
pull-requests: read
|
|
61
|
+
actions: read
|
|
62
|
+
outputs:
|
|
63
|
+
found: ${{ steps.subject.outputs.found }}
|
|
64
|
+
pr: ${{ steps.subject.outputs.pr }}
|
|
65
|
+
issue: ${{ steps.subject.outputs.issue }}
|
|
66
|
+
conclusion: ${{ steps.subject.outputs.conclusion }}
|
|
67
|
+
steps:
|
|
68
|
+
- name: Checkout workflow actions
|
|
69
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
70
|
+
with:
|
|
71
|
+
persist-credentials: false
|
|
72
|
+
- name: Identify the pull request, its issue, and the CI verdict
|
|
73
|
+
id: subject
|
|
74
|
+
uses: ./.github/actions/identify-gate-subject
|
|
75
|
+
with:
|
|
76
|
+
token: ${{ github.token }}
|
|
77
|
+
pr-number: ${{ inputs.pr-number }}
|
|
78
|
+
ci-conclusion: ${{ inputs.ci-conclusion }}
|
|
79
|
+
linked-issue: ${{ inputs.linked-issue }}
|
|
80
|
+
require-label: ${{ env.IMPLEMENT_LABEL }}
|
|
81
|
+
|
|
82
|
+
protected_changes:
|
|
83
|
+
needs: subject
|
|
84
|
+
if: needs.subject.outputs.found == 'true'
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
permissions:
|
|
87
|
+
pull-requests: read
|
|
88
|
+
outputs:
|
|
89
|
+
requires_review: ${{ steps.files.outputs.requires_review }}
|
|
90
|
+
files: ${{ steps.files.outputs.files }}
|
|
91
|
+
steps:
|
|
92
|
+
- name: Require review for protected pull request files
|
|
93
|
+
id: files
|
|
94
|
+
env:
|
|
95
|
+
GH_TOKEN: ${{ github.token }}
|
|
96
|
+
REPO: ${{ github.repository }}
|
|
97
|
+
PR: ${{ needs.subject.outputs.pr }}
|
|
98
|
+
run: |
|
|
99
|
+
set -euo pipefail
|
|
100
|
+
files=$(gh api --paginate "repos/$REPO/pulls/$PR/files?per_page=100" --jq '.[].filename')
|
|
101
|
+
protected=$(printf '%s\n' "$files" | grep -E '^(\.|AGENTS\.md$|ARCHITECTURE\.md$|DESIGN\.md$|opencode\.jsonc$|package\.json$|pnpm-lock\.yaml$|Directory\.Packages\.props$|global\.json$)' || true)
|
|
102
|
+
|
|
103
|
+
if [ -n "$protected" ]; then
|
|
104
|
+
echo "requires_review=true" >> "$GITHUB_OUTPUT"
|
|
105
|
+
{
|
|
106
|
+
echo 'files<<EOF'
|
|
107
|
+
printf '%s\n' "$protected"
|
|
108
|
+
echo EOF
|
|
109
|
+
} >> "$GITHUB_OUTPUT"
|
|
110
|
+
else
|
|
111
|
+
echo "requires_review=false" >> "$GITHUB_OUTPUT"
|
|
112
|
+
echo "files=" >> "$GITHUB_OUTPUT"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
review_required:
|
|
116
|
+
needs: [subject, protected_changes]
|
|
117
|
+
if: needs.subject.outputs.found == 'true' && needs.protected_changes.outputs.requires_review == 'true'
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
permissions:
|
|
120
|
+
contents: read
|
|
121
|
+
issues: write
|
|
122
|
+
steps:
|
|
123
|
+
- name: Checkout workflow actions
|
|
124
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
125
|
+
with:
|
|
126
|
+
persist-credentials: false
|
|
127
|
+
- name: Create bot token
|
|
128
|
+
id: app-token
|
|
129
|
+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
|
130
|
+
with:
|
|
131
|
+
client-id: ${{ secrets.BOT_APP_ID }}
|
|
132
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
133
|
+
- name: Release the issue
|
|
134
|
+
uses: ./.github/actions/remove-issue-labels
|
|
135
|
+
with:
|
|
136
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
137
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
138
|
+
labels: ${{ env.WORKING_LABEL }}
|
|
139
|
+
- name: Flag human review
|
|
140
|
+
uses: ./.github/actions/add-issue-labels
|
|
141
|
+
with:
|
|
142
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
143
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
144
|
+
labels: ${{ env.REVIEW_LABEL }}
|
|
145
|
+
- name: Explain the merge hold
|
|
146
|
+
uses: ./.github/actions/create-issue-comment
|
|
147
|
+
with:
|
|
148
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
149
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
150
|
+
body: |
|
|
151
|
+
${{ env.GATE_MARKER }}
|
|
152
|
+
PR #${{ needs.subject.outputs.pr }} changes protected files and cannot be auto-merged.
|
|
153
|
+
Review the pull request before merging it manually.
|
|
154
|
+
|
|
155
|
+
Protected files:
|
|
156
|
+
${{ needs.protected_changes.outputs.files }}
|
|
157
|
+
|
|
158
|
+
reserve:
|
|
159
|
+
needs: subject
|
|
160
|
+
if: needs.subject.outputs.found == 'true'
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
permissions:
|
|
163
|
+
contents: read
|
|
164
|
+
issues: write
|
|
165
|
+
steps:
|
|
166
|
+
- name: Checkout workflow actions
|
|
167
|
+
if: needs.subject.outputs.conclusion == 'failure'
|
|
168
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
169
|
+
with:
|
|
170
|
+
persist-credentials: false
|
|
171
|
+
- name: Create bot token
|
|
172
|
+
if: needs.subject.outputs.conclusion == 'failure'
|
|
173
|
+
id: app-token
|
|
174
|
+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
|
175
|
+
with:
|
|
176
|
+
client-id: ${{ secrets.BOT_APP_ID }}
|
|
177
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
178
|
+
- name: Mark the failed implementation issue as in progress
|
|
179
|
+
if: needs.subject.outputs.conclusion == 'failure'
|
|
180
|
+
uses: ./.github/actions/add-issue-labels
|
|
181
|
+
with:
|
|
182
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
183
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
184
|
+
labels: ${{ env.WORKING_LABEL }}
|
|
185
|
+
- name: Clear the human-needed flag
|
|
186
|
+
if: needs.subject.outputs.conclusion == 'failure'
|
|
187
|
+
uses: ./.github/actions/remove-issue-labels
|
|
188
|
+
with:
|
|
189
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
190
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
191
|
+
labels: ${{ env.REVIEW_LABEL }}
|
|
192
|
+
conclude:
|
|
193
|
+
needs: [activation, subject, protected_changes, agent, safe_outputs]
|
|
194
|
+
if: >
|
|
195
|
+
needs.agent.result == 'success' &&
|
|
196
|
+
needs.safe_outputs.result == 'success' &&
|
|
197
|
+
needs.protected_changes.outputs.requires_review != 'true'
|
|
198
|
+
runs-on: ubuntu-latest
|
|
199
|
+
permissions:
|
|
200
|
+
contents: write
|
|
201
|
+
issues: write
|
|
202
|
+
pull-requests: write
|
|
203
|
+
steps:
|
|
204
|
+
- name: Create bot token
|
|
205
|
+
id: app-token
|
|
206
|
+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
|
207
|
+
with:
|
|
208
|
+
client-id: ${{ secrets.BOT_APP_ID }}
|
|
209
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
210
|
+
- name: Checkout repository
|
|
211
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
212
|
+
with:
|
|
213
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
214
|
+
fetch-depth: 0
|
|
215
|
+
- name: Verify pull request closes the source issue
|
|
216
|
+
continue-on-error: true
|
|
217
|
+
uses: ./.github/actions/link-pr-to-issue
|
|
218
|
+
with:
|
|
219
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
220
|
+
pr-number: ${{ needs.subject.outputs.pr }}
|
|
221
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
222
|
+
- name: Apply agent output
|
|
223
|
+
uses: ./.github/actions/apply-agent-output
|
|
224
|
+
with:
|
|
225
|
+
artifact-name: ${{ needs.activation.outputs.artifact_prefix }}agent
|
|
226
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
227
|
+
merge-pull-request: 'true'
|
|
228
|
+
push-to-branch: 'true'
|
|
229
|
+
close-issues: 'true'
|
|
230
|
+
incomplete:
|
|
231
|
+
needs: [subject, protected_changes, agent, safe_outputs]
|
|
232
|
+
if: >
|
|
233
|
+
always() &&
|
|
234
|
+
needs.subject.outputs.found == 'true' &&
|
|
235
|
+
needs.protected_changes.outputs.requires_review != 'true' &&
|
|
236
|
+
needs.agent.result != 'success'
|
|
237
|
+
runs-on: ubuntu-latest
|
|
238
|
+
permissions:
|
|
239
|
+
contents: read
|
|
240
|
+
issues: write
|
|
241
|
+
steps:
|
|
242
|
+
- name: Checkout workflow actions
|
|
243
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
244
|
+
with:
|
|
245
|
+
persist-credentials: false
|
|
246
|
+
- name: Create bot token
|
|
247
|
+
id: app-token
|
|
248
|
+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
|
249
|
+
with:
|
|
250
|
+
client-id: ${{ secrets.BOT_APP_ID }}
|
|
251
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
252
|
+
- name: Release the issue
|
|
253
|
+
uses: ./.github/actions/remove-issue-labels
|
|
254
|
+
with:
|
|
255
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
256
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
257
|
+
labels: ${{ env.WORKING_LABEL }}
|
|
258
|
+
- name: Flag for human review
|
|
259
|
+
uses: ./.github/actions/add-issue-labels
|
|
260
|
+
with:
|
|
261
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
262
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
263
|
+
labels: ${{ env.REVIEW_LABEL }}
|
|
264
|
+
- name: Report missing remediation outcome
|
|
265
|
+
uses: ./.github/actions/create-issue-comment
|
|
266
|
+
with:
|
|
267
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
268
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
269
|
+
body: |
|
|
270
|
+
${{ env.GATE_MARKER }}
|
|
271
|
+
${{ env.INCOMPLETE_COMMENT }}
|
|
272
|
+
[View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
273
|
+
|
|
274
|
+
agent:
|
|
275
|
+
needs: protected_changes
|
|
276
|
+
if: needs.protected_changes.outputs.requires_review != 'true'
|
|
277
|
+
|
|
278
|
+
if: needs.subject.outputs.found == 'true' && needs.protected_changes.outputs.requires_review != 'true'
|
|
279
|
+
|
|
280
|
+
runs-on: ubuntu-latest
|
|
281
|
+
runs-on-slim: ubuntu-latest
|
|
282
|
+
|
|
283
|
+
secrets:
|
|
284
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
285
|
+
|
|
286
|
+
engine:
|
|
287
|
+
id: opencode
|
|
288
|
+
version: "1.2.14"
|
|
289
|
+
env:
|
|
290
|
+
OPENAI_BASE_URL: https://forge.plainconcepts.com/v1
|
|
291
|
+
|
|
292
|
+
model: openai/glm-5-2
|
|
293
|
+
|
|
294
|
+
max-turns: 300
|
|
295
|
+
max-turn-cache-misses: 3000
|
|
296
|
+
max-ai-credits: 5000
|
|
297
|
+
|
|
298
|
+
permissions: read-all
|
|
299
|
+
|
|
300
|
+
# push-to-pull-request-branch with target "*" cannot reach a branch the shallow clone
|
|
301
|
+
# does not have.
|
|
302
|
+
checkout:
|
|
303
|
+
fetch: ["*"]
|
|
304
|
+
fetch-depth: 0
|
|
305
|
+
|
|
306
|
+
# Rung 3. The diff is what the risk assessment reads, and the failing logs are what a fix
|
|
307
|
+
# starts from. Both are known from the inputs, so neither costs the agent a turn.
|
|
308
|
+
steps:
|
|
309
|
+
- name: Load the issue context
|
|
310
|
+
uses: ./.github/actions/load-issue-context
|
|
311
|
+
with:
|
|
312
|
+
token: ${{ github.token }}
|
|
313
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
314
|
+
output-path: ${{ env.ISSUE_CONTEXT_PATH }}
|
|
315
|
+
- name: Fetch the diff and any failing job logs
|
|
316
|
+
env:
|
|
317
|
+
GH_TOKEN: ${{ github.token }}
|
|
318
|
+
REPO: ${{ github.repository }}
|
|
319
|
+
PR: ${{ needs.subject.outputs.pr }}
|
|
320
|
+
RUN_ID: ${{ inputs.ci-run-id }}
|
|
321
|
+
CONCLUSION: ${{ needs.subject.outputs.conclusion }}
|
|
322
|
+
run: |
|
|
323
|
+
set -euo pipefail
|
|
324
|
+
mkdir -p /tmp/gh-aw/agent
|
|
325
|
+
gh pr diff "$PR" --repo "$REPO" > /tmp/gh-aw/agent/diff.patch
|
|
326
|
+
gh pr view "$PR" --repo "$REPO" --json title,body,files,additions,deletions \
|
|
327
|
+
> /tmp/gh-aw/agent/pr.json
|
|
328
|
+
if [ "$CONCLUSION" = "failure" ]; then
|
|
329
|
+
gh run view "$RUN_ID" --repo "$REPO" --log-failed \
|
|
330
|
+
> /tmp/gh-aw/agent/failed-logs.txt 2>/dev/null || \
|
|
331
|
+
echo "logs unavailable" > /tmp/gh-aw/agent/failed-logs.txt
|
|
332
|
+
gh run view "$RUN_ID" --repo "$REPO" --json jobs \
|
|
333
|
+
--jq '[.jobs[] | select(.conclusion == "failure") | {name, conclusion}]' \
|
|
334
|
+
> /tmp/gh-aw/agent/failed-jobs.json
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
safe-outputs:
|
|
338
|
+
staged: true
|
|
339
|
+
threat-detection: false
|
|
340
|
+
merge-pull-request:
|
|
341
|
+
push-to-pull-request-branch:
|
|
342
|
+
close-issue:
|
|
343
|
+
add-comment:
|
|
344
|
+
add-labels:
|
|
345
|
+
remove-labels:
|
|
346
|
+
|
|
347
|
+
timeout-minutes: 60
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
1. You are gating pull request **#${{ needs.subject.outputs.pr }}**, which closes issue
|
|
351
|
+
**#${{ needs.subject.outputs.issue }}**. CI concluded
|
|
352
|
+
**${{ needs.subject.outputs.conclusion }}**.
|
|
353
|
+
|
|
354
|
+
It has already been confirmed that this is an open pull request we authored, that it closes
|
|
355
|
+
an issue, and that the issue carries `implement`. Do not re-check any of that, and do not
|
|
356
|
+
poll for checks: the conclusion above is the answer.
|
|
357
|
+
|
|
358
|
+
2. Read `${{ env.ISSUE_CONTEXT_PATH }}`. It contains the issue body and its discussion. When
|
|
359
|
+
running `/repo-verify`, the acceptance criteria there define what the implementation must
|
|
360
|
+
satisfy.
|
|
361
|
+
|
|
362
|
+
3. Branch on the conclusion.
|
|
363
|
+
|
|
364
|
+
- **success** → step 4.
|
|
365
|
+
- **action_required** → CI did not run because the workflow needs approval.
|
|
366
|
+
Call `remove_labels` to remove `bot-working` (item_number:
|
|
367
|
+
${{ needs.subject.outputs.issue }}), then `add_labels` to add `review`
|
|
368
|
+
(item_number: ${{ needs.subject.outputs.issue }}), and `add_comment`
|
|
369
|
+
(item_number: ${{ needs.subject.outputs.issue }}) saying CI requires
|
|
370
|
+
workflow approval before it can run, and a maintainer must approve the
|
|
371
|
+
pending run. Then stop , do not attempt to merge or fix.
|
|
372
|
+
- **failure** → step 7.
|
|
373
|
+
- **cancelled, timed_out, or anything else** → call `add_comment` with
|
|
374
|
+
`item_number: ${{ needs.subject.outputs.issue }}` saying CI did not produce a verdict,
|
|
375
|
+
then `add_labels` to add `review` (item_number: the issue), and stop.
|
|
376
|
+
A cancelled or unknown run is not evidence of anything.
|
|
377
|
+
|
|
378
|
+
Apply these repository-specific rules when assessing or remediating the pull request:
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
$${{ env.REPO_RULES }}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
4. Assess the risk of merging, as a reviewer would. Read `/tmp/gh-aw/agent/diff.patch` in full
|
|
385
|
+
and `/tmp/gh-aw/agent/pr.json` for the shape of the change. Flag it as risky when any of
|
|
386
|
+
these hold, and say which:
|
|
387
|
+
|
|
388
|
+
- It touches authentication, authorization, secrets, credentials, or security boundaries.
|
|
389
|
+
- It changes a repository-defined integration or cross-platform boundary.
|
|
390
|
+
- It changes a public API or a published package's contract.
|
|
391
|
+
- It deletes or weakens a test, or lowers a threshold.
|
|
392
|
+
- It changes CI, CD or a workflow file.
|
|
393
|
+
- It changes a protected file. This is normally handled before you run, but never merge one
|
|
394
|
+
if it reaches this gate.
|
|
395
|
+
- The diff is materially larger than the issue implied.
|
|
396
|
+
- You are simply not confident. Low confidence is itself a flag.
|
|
397
|
+
|
|
398
|
+
5. **Clean assessment** → call `merge_pull_request` (pr_number:
|
|
399
|
+
${{ needs.subject.outputs.pr }}), then `close_issue` (item_number:
|
|
400
|
+
${{ needs.subject.outputs.issue }}), then `remove_labels` (item_number:
|
|
401
|
+
${{ needs.subject.outputs.issue }}) to remove `implement`, `bot-working`, and `review`.
|
|
402
|
+
Call `add_comment` (item_number: ${{ needs.subject.outputs.issue }}):
|
|
403
|
+
`Auto-merged. PR #${{ needs.subject.outputs.pr }} closed.`
|
|
404
|
+
|
|
405
|
+
6. **Flagged** → do not merge. Call `remove_labels` to remove `bot-working`
|
|
406
|
+
(item_number: ${{ needs.subject.outputs.issue }}), then `add_labels` to add `review`
|
|
407
|
+
(item_number: ${{ needs.subject.outputs.issue }}), and `add_comment`
|
|
408
|
+
(item_number: ${{ needs.subject.outputs.issue }}) explaining exactly which criterion
|
|
409
|
+
tripped and what a reviewer should look at. Then `add_comment`
|
|
410
|
+
(item_number: ${{ needs.subject.outputs.pr }}) on the PR with the same message.
|
|
411
|
+
Leave `implement` in place: the work is not finished until a human merges it.
|
|
412
|
+
|
|
413
|
+
7. **CI failed** → read `/tmp/gh-aw/agent/failed-jobs.json` and
|
|
414
|
+
`/tmp/gh-aw/agent/failed-logs.txt`, which are already on disk. Load only skills required to
|
|
415
|
+
fix the actual cause. Run these verification commands before a push. Do not weaken a test,
|
|
416
|
+
disable a check, or push an unverified guess.
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
$${{ env.VERIFY_COMMANDS }}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Call `push_to_pull_request_branch` (pr_number: ${{ needs.subject.outputs.pr }}) to push
|
|
423
|
+
the fix, then `remove_labels` (item_number: ${{ needs.subject.outputs.issue }}) to remove
|
|
424
|
+
`bot-working`. CI will run again and trigger you again with the new result.
|
|
425
|
+
|
|
426
|
+
If you cannot fix it, or the logs show you have already tried on this same head commit,
|
|
427
|
+
stop looping: `remove_labels` (item_number: ${{ needs.subject.outputs.issue }}) to remove
|
|
428
|
+
`implement` and `bot-working`, `add_labels` (item_number:
|
|
429
|
+
${{ needs.subject.outputs.issue }}) to add `review`, and `add_comment` (item_number:
|
|
430
|
+
${{ needs.subject.outputs.issue }}) with the failure and what you tried. Per #167
|
|
431
|
+
decision 2, a human decides from there.
|
|
432
|
+
|
|
433
|
+
8. Never merge with administrator privileges and never bypass a required check. If the merge
|
|
434
|
+
is refused, that refusal is the answer: `add_labels` to add `review`
|
|
435
|
+
(item_number: ${{ needs.subject.outputs.issue }}), `add_comment`
|
|
436
|
+
(item_number: ${{ needs.subject.outputs.issue }}) with the refusal, and leave it for a human.
|
|
437
|
+
|
|
438
|
+
## Diagram
|
|
439
|
+
|
|
440
|
+
```mermaid
|
|
441
|
+
flowchart TD
|
|
442
|
+
gateStart("Work Router<br/>merge-gate route<br/>(CI completed)") --> gateSubject
|
|
443
|
+
gateSubject["Subject (rung 4)<br/>Our PR? Closes an implement issue?"] -->|✓| gateFacts
|
|
444
|
+
gateSubject -.->|✗| gateIdle
|
|
445
|
+
gateFacts("Facts (rung 3)<br/>Diff, PR shape, failing logs") --> gateCi
|
|
446
|
+
gateCi["CI<br/>What did it conclude?"] -->|success| gateRisk
|
|
447
|
+
gateCi -.->|failure| gateFix
|
|
448
|
+
gateCi -.->|no verdict| gateHuman
|
|
449
|
+
gateRisk["Risk<br/>Auth, schema, API, tests, CI, size, doubt"] -->|clean| gateMerge
|
|
450
|
+
gateRisk -.->|flagged| gateHuman
|
|
451
|
+
gateFix("Fix<br/>Read logs, fix the cause, /repo-verify") -->|pushed| gateWait
|
|
452
|
+
gateFix -.->|cannot fix| gateHuman
|
|
453
|
+
gateMerge(("Merged<br/>Issue closed, review+labels removed"))
|
|
454
|
+
gateWait(("Pushed<br/>CI will re-run and re-trigger via Router"))
|
|
455
|
+
gateHuman(("Review<br/>review label, reason explained"))
|
|
456
|
+
gateIdle(("Idle<br/>Not our pull request"))
|
|
457
|
+
|
|
458
|
+
classDef start fill:#ffffff,stroke:#172033,stroke-width:2px,color:#172033
|
|
459
|
+
classDef action fill:#eef0ff,stroke:#554cff,stroke-width:2px,color:#172033
|
|
460
|
+
classDef decision fill:#fff8e8,stroke:#c75b00,stroke-width:2px,color:#172033
|
|
461
|
+
classDef idle fill:#202c40,stroke:#738198,stroke-width:2px,color:#ffffff
|
|
462
|
+
classDef failure fill:#fff0f0,stroke:#ef2929,stroke-width:2px,color:#8b1a1a
|
|
463
|
+
classDef success fill:#e8f8ec,stroke:#18883c,stroke-width:2px,color:#145a32
|
|
464
|
+
class gateStart start
|
|
465
|
+
class gateFacts,gateFix action
|
|
466
|
+
class gateSubject,gateCi,gateRisk decision
|
|
467
|
+
class gateIdle,gateWait idle
|
|
468
|
+
class gateHuman failure
|
|
469
|
+
class gateMerge success
|
|
470
|
+
```
|