@plainconceptsplatform/workflows 0.4.12 → 0.4.15
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/loops/actions/classify-route/classify-route.sh +20 -12
- package/loops/workflows/agent-apply-review.md +1 -0
- package/loops/workflows/agent-direct.md +1 -0
- package/loops/workflows/agent-implement.md +1 -0
- package/loops/workflows/agent-merge-gate.md +32 -3
- package/loops/workflows/agent-refine.md +1 -0
- package/loops/workflows/authorize-bot-work.yml +81 -0
- package/package.json +1 -1
|
@@ -35,19 +35,27 @@ classify_route() {
|
|
|
35
35
|
issues)
|
|
36
36
|
if [ "${ACTION:-}" = "labeled" ]; then
|
|
37
37
|
case "${LABEL:-}" in
|
|
38
|
-
|
|
39
|
-
route
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
bot-working)
|
|
39
|
+
# Bot adds bot-working → route based on which work label is present
|
|
40
|
+
if has_label implement; then
|
|
41
|
+
route="implement"
|
|
42
|
+
issue_number="${EVENT_ISSUE_NUMBER:-}"
|
|
43
|
+
elif has_label refine; then
|
|
44
|
+
route="refine"
|
|
45
|
+
refine_mode="first"
|
|
46
|
+
issue_number="${EVENT_ISSUE_NUMBER:-}"
|
|
47
|
+
elif has_label direct; then
|
|
48
|
+
route="direct"
|
|
49
|
+
direct_mode="first"
|
|
50
|
+
issue_number="${EVENT_ISSUE_NUMBER:-}"
|
|
51
|
+
else
|
|
52
|
+
error="bot-working added but no work label (implement/refine/direct) found"
|
|
53
|
+
fi
|
|
46
54
|
;;
|
|
47
|
-
direct)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
refine | implement | direct)
|
|
56
|
+
# Human adds work label → authorize-bot-work.yml handles this
|
|
57
|
+
# Route to none here; the bot will add bot-working which triggers the actual work
|
|
58
|
+
error="waiting for bot to add bot-working label"
|
|
51
59
|
;;
|
|
52
60
|
esac
|
|
53
61
|
fi
|
|
@@ -7,6 +7,7 @@ env:
|
|
|
7
7
|
REVIEW_MARKER: "<!-- agent-apply-review -->"
|
|
8
8
|
INCOMPLETE_COMMENT: "Automated review feedback ended without an outcome. The issue remains for a retry."
|
|
9
9
|
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
|
|
10
|
+
GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
|
|
10
11
|
GIT_AUTHOR_NAME: "github-actions[bot]"
|
|
11
12
|
GIT_AUTHOR_EMAIL: "github-actions[bot]@users.noreply.github.com"
|
|
12
13
|
GIT_COMMITTER_NAME: "github-actions[bot]"
|
|
@@ -8,6 +8,7 @@ env:
|
|
|
8
8
|
DIRECT_MARKER: "<!-- agent-direct -->"
|
|
9
9
|
INCOMPLETE_COMMENT: "Automated direct execution ended without an outcome. The direct label remains for a retry."
|
|
10
10
|
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
|
|
11
|
+
GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
|
|
11
12
|
description: |
|
|
12
13
|
Executes a free-form instruction from an issue body and posts the results back on the same
|
|
13
14
|
issue. The issue body IS the prompt — the agent does whatever the maintainer asked for and
|
|
@@ -12,6 +12,7 @@ env:
|
|
|
12
12
|
IMPLEMENT_MARKER: "<!-- agent-implement -->"
|
|
13
13
|
INCOMPLETE_COMMENT: "Automated implementation ended without an outcome. The implement label remains for a retry."
|
|
14
14
|
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/implementation-context.json
|
|
15
|
+
GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
|
|
15
16
|
description: |
|
|
16
17
|
Implements an issue and opens a pull request. Stops there: the merge decision belongs to
|
|
17
18
|
`agent-merge-gate.md`, which runs once CI has reported. Replaces the `impl-*` chain in
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
# Managed by @plainconceptsplatform/workflows. Source: loops/workflows/agent-merge-gate.md. Update with `workflows update --force`; consumer edits may be overwritten.
|
|
3
3
|
env:
|
|
4
|
-
|
|
4
|
+
VERIFY_COMMANDS: "dotnet restore apps/api/Numa.slnx && dotnet build apps/api/Numa.slnx -c Release --no-restore && dotnet test apps/api/tests/Numa.UnitTests/Numa.UnitTests.csproj -c Release --no-build && dotnet test apps/api/tests/Numa.ParityTests/Numa.ParityTests.csproj -c Release --no-build"
|
|
5
|
+
REPO_RULES: "Make a risk-based merge decision for the selected bot pull request. Merge only when CI is green and no risk indicators are present. Risk indicators for Numa: changes to QuoteCalculator or calculation waterfall, audit appender or hash chain, JWT issuance or permission checks, EF migrations or entity configurations, decimal precision or money handling, quote lifecycle transitions. Any of these require human review. Do not merge protected file changes."
|
|
5
6
|
WORKING_LABEL: bot-working
|
|
6
7
|
IMPLEMENT_LABEL: implement
|
|
7
8
|
REVIEW_LABEL: review
|
|
8
9
|
GATE_MARKER: "<!-- agent-merge-gate -->"
|
|
9
10
|
INCOMPLETE_COMMENT: "Automated CI failure remediation ended without an outcome. The issue remains for a retry."
|
|
10
11
|
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
|
|
12
|
+
GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
|
|
11
13
|
GIT_AUTHOR_NAME: "github-actions[bot]"
|
|
12
14
|
GIT_AUTHOR_EMAIL: "github-actions[bot]@users.noreply.github.com"
|
|
13
15
|
GIT_COMMITTER_NAME: "github-actions[bot]"
|
|
@@ -152,7 +154,7 @@ jobs:
|
|
|
152
154
|
body: |
|
|
153
155
|
${{ env.GATE_MARKER }}
|
|
154
156
|
PR #${{ needs.subject.outputs.pr }} changes protected files and cannot be auto-merged.
|
|
155
|
-
|
|
157
|
+
The `review` label is set: a human must merge this PR manually.
|
|
156
158
|
|
|
157
159
|
Protected files:
|
|
158
160
|
${{ needs.protected_changes.outputs.files }}
|
|
@@ -164,6 +166,7 @@ jobs:
|
|
|
164
166
|
permissions:
|
|
165
167
|
contents: read
|
|
166
168
|
issues: write
|
|
169
|
+
pull-requests: read
|
|
167
170
|
steps:
|
|
168
171
|
- name: Checkout workflow actions
|
|
169
172
|
if: needs.subject.outputs.conclusion == 'failure'
|
|
@@ -177,7 +180,22 @@ jobs:
|
|
|
177
180
|
with:
|
|
178
181
|
client-id: ${{ secrets.BOT_APP_ID }}
|
|
179
182
|
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
180
|
-
- name:
|
|
183
|
+
- name: Check for merge conflicts
|
|
184
|
+
if: needs.subject.outputs.conclusion == 'failure'
|
|
185
|
+
id: conflicts
|
|
186
|
+
env:
|
|
187
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
188
|
+
REPO: ${{ github.repository }}
|
|
189
|
+
PR: ${{ needs.subject.outputs.pr }}
|
|
190
|
+
run: |
|
|
191
|
+
set -euo pipefail
|
|
192
|
+
mergeable=$(gh pr view "$PR" --repo "$REPO" --json mergeable --jq '.mergeable')
|
|
193
|
+
if [ "$mergeable" = "CONFLICTING" ]; then
|
|
194
|
+
echo "has_conflicts=true" >> "$GITHUB_OUTPUT"
|
|
195
|
+
else
|
|
196
|
+
echo "has_conflicts=false" >> "$GITHUB_OUTPUT"
|
|
197
|
+
fi
|
|
198
|
+
- name: Mark the issue as in progress
|
|
181
199
|
if: needs.subject.outputs.conclusion == 'failure'
|
|
182
200
|
uses: ./.github/actions/add-issue-labels
|
|
183
201
|
with:
|
|
@@ -191,6 +209,16 @@ jobs:
|
|
|
191
209
|
token: ${{ steps.app-token.outputs.token }}
|
|
192
210
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
193
211
|
labels: ${{ env.REVIEW_LABEL }}
|
|
212
|
+
- name: Comment on issue - problems found, solving them
|
|
213
|
+
if: needs.subject.outputs.conclusion == 'failure'
|
|
214
|
+
uses: ./.github/actions/create-issue-comment
|
|
215
|
+
with:
|
|
216
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
217
|
+
issue-number: ${{ needs.subject.outputs.issue }}
|
|
218
|
+
body: |
|
|
219
|
+
${{ env.GATE_MARKER }}
|
|
220
|
+
Problems found in PR #${{ needs.subject.outputs.pr }}. ${{ steps.conflicts.outputs.has_conflicts == 'true' && 'Merge conflicts detected.' || '' }} CI concluded with **${{ needs.subject.outputs.conclusion }}**.
|
|
221
|
+
Bot is working on fixing it.
|
|
194
222
|
conclude:
|
|
195
223
|
needs: [activation, subject, protected_changes, agent, safe_outputs]
|
|
196
224
|
if: >
|
|
@@ -270,6 +298,7 @@ jobs:
|
|
|
270
298
|
issue-number: ${{ needs.subject.outputs.issue }}
|
|
271
299
|
body: |
|
|
272
300
|
${{ env.GATE_MARKER }}
|
|
301
|
+
Bot could not resolve PR #${{ needs.subject.outputs.pr }} automatically. The `review` label is set: a human must take over.
|
|
273
302
|
${{ env.INCOMPLETE_COMMENT }}
|
|
274
303
|
[View this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
275
304
|
|
|
@@ -13,6 +13,7 @@ env:
|
|
|
13
13
|
INCOMPLETE_COMMENT: "Automated refinement ended without an outcome. The refine label remains for a retry."
|
|
14
14
|
SAFE_OUTPUT_COMMENT_PREFIX: "Refinement update"
|
|
15
15
|
ISSUE_CONTEXT_PATH: /tmp/gh-aw/agent/issue-context.json
|
|
16
|
+
GH_AW_ALLOWED_BOTS: "platform-devbox[bot],github-actions[bot]"
|
|
16
17
|
REFINE_ISSUE_PATH: /tmp/gh-aw/refine-issue.json
|
|
17
18
|
REFINE_COMMENTS_PATH: /tmp/gh-aw/refine-comments.json
|
|
18
19
|
GIT_AUTHOR_NAME: "github-actions[bot]"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Human adds implement/refine/direct label → validates permission → bot adds bot-working
|
|
2
|
+
# This ensures the bot is the actor for all agentic workflows.
|
|
3
|
+
name: "Authorize Bot Work"
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
issues:
|
|
7
|
+
types: [labeled]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
authorize:
|
|
14
|
+
# Only trigger for implement/refine/direct labels, and only if bot-working is NOT already present
|
|
15
|
+
if: >
|
|
16
|
+
(github.event.label.name == 'implement' ||
|
|
17
|
+
github.event.label.name == 'refine' ||
|
|
18
|
+
github.event.label.name == 'direct') &&
|
|
19
|
+
!contains(github.event.issue.labels.*.name, 'bot-working')
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 5
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
issues: write
|
|
25
|
+
steps:
|
|
26
|
+
- name: Check actor permission
|
|
27
|
+
id: check
|
|
28
|
+
env:
|
|
29
|
+
GH_TOKEN: ${{ github.token }}
|
|
30
|
+
ACTOR: ${{ github.actor }}
|
|
31
|
+
run: |
|
|
32
|
+
set -euo pipefail
|
|
33
|
+
|
|
34
|
+
# Bots don't need validation - they're already authorized
|
|
35
|
+
if [[ "$ACTOR" == *"[bot]"* ]]; then
|
|
36
|
+
echo "authorized=true" >> "$GITHUB_OUTPUT"
|
|
37
|
+
echo "::notice::Bot actor ($ACTOR) - skipping permission check"
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
permission=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$ACTOR/permission" \
|
|
42
|
+
--jq '.permission' 2>/dev/null || echo "none")
|
|
43
|
+
|
|
44
|
+
case "$permission" in
|
|
45
|
+
admin | maintain | write)
|
|
46
|
+
echo "authorized=true" >> "$GITHUB_OUTPUT"
|
|
47
|
+
echo "::notice::$ACTOR has $permission permission - authorized"
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
echo "authorized=false" >> "$GITHUB_OUTPUT"
|
|
51
|
+
echo "::warning::$ACTOR has '$permission' permission - not authorized"
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
|
|
55
|
+
- name: Checkout for App token action
|
|
56
|
+
if: steps.check.outputs.authorized == 'true'
|
|
57
|
+
uses: actions/checkout@v4
|
|
58
|
+
with:
|
|
59
|
+
persist-credentials: false
|
|
60
|
+
|
|
61
|
+
- name: Generate App token
|
|
62
|
+
if: steps.check.outputs.authorized == 'true'
|
|
63
|
+
id: app-token
|
|
64
|
+
uses: actions/create-github-app-token@v1
|
|
65
|
+
with:
|
|
66
|
+
app-id: ${{ secrets.BOT_APP_ID }}
|
|
67
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
|
68
|
+
|
|
69
|
+
- name: Bot adds bot-working label
|
|
70
|
+
if: steps.check.outputs.authorized == 'true'
|
|
71
|
+
env:
|
|
72
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
73
|
+
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
|
74
|
+
LABEL: ${{ github.event.label.name }}
|
|
75
|
+
run: |
|
|
76
|
+
set -euo pipefail
|
|
77
|
+
|
|
78
|
+
echo "Adding bot-working label to issue #$ISSUE_NUMBER (triggered by $LABEL)"
|
|
79
|
+
gh issue edit "$ISSUE_NUMBER" --add-label "bot-working"
|
|
80
|
+
|
|
81
|
+
echo "::notice::bot-working label added - bot will now own the $LABEL workflow"
|