jonah-fleet 1.6.0 → 1.9.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/CHANGELOG.md +130 -0
- package/README.md +25 -2
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/labels.d.ts +11 -0
- package/dist/commands/labels.d.ts.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/telemetry.d.ts.map +1 -1
- package/dist/index.js +2527 -519
- package/dist/lib/daemon-keys.d.ts +103 -0
- package/dist/lib/daemon-keys.d.ts.map +1 -0
- package/dist/lib/daemon.d.ts +8 -2
- package/dist/lib/daemon.d.ts.map +1 -1
- package/dist/lib/fleet-query.d.ts.map +1 -1
- package/dist/lib/labels.d.ts +68 -0
- package/dist/lib/labels.d.ts.map +1 -0
- package/dist/lib/manifest.d.ts +6 -0
- package/dist/lib/manifest.d.ts.map +1 -1
- package/dist/lib/presets.d.ts +52 -1
- package/dist/lib/presets.d.ts.map +1 -1
- package/dist/lib/runner.d.ts +114 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/terminal-card.d.ts +24 -1
- package/dist/lib/terminal-card.d.ts.map +1 -1
- package/package.json +1 -1
- package/schema.json +74 -1
- package/templates/prompts/ORCHESTRATION.md +84 -41
- package/templates/prompts/_prompt-template.md +10 -13
- package/templates/prompts/analytics-review.md +4 -2
- package/templates/prompts/autowork.md +76 -35
- package/templates/prompts/dependency-update-security-check.md +4 -2
- package/templates/prompts/design-review.md +125 -0
- package/templates/prompts/issues-housekeeping.md +10 -8
- package/templates/prompts/optimizer.md +31 -12
- package/templates/prompts/peer-review.md +42 -7
- package/templates/prompts/product-planning.md +14 -10
- package/templates/workflows/autowork-cron.yml +137 -38
- package/templates/workflows/dependency-check-cron.yml +127 -2
- package/templates/workflows/design-review-cron.yml +221 -0
- package/templates/workflows/issues-housekeeping-cron.yml +127 -2
- package/templates/workflows/prompt-optimizer-cron.yml +134 -9
- package/templates/workflows/sync-fleet.yml +4 -0
- package/templates/workflows/trigger-autowork-manual.yml +154 -11
- package/templates/workflows/trigger-autowork-on-bug.yml +177 -9
- package/templates/workflows/trigger-autowork-on-merge.yml +178 -9
- package/templates/workflows/trigger-review-routine.yml +162 -22
|
@@ -4,18 +4,17 @@ on:
|
|
|
4
4
|
pull_request:
|
|
5
5
|
types: [closed]
|
|
6
6
|
|
|
7
|
-
concurrency:
|
|
8
|
-
group: autowork-merge-pr-${{ github.event.pull_request.number }}
|
|
9
|
-
cancel-in-progress: true
|
|
10
|
-
|
|
11
7
|
jobs:
|
|
12
8
|
fire-autowork:
|
|
13
9
|
if: >-
|
|
14
10
|
github.event.pull_request.merged == true &&
|
|
15
11
|
github.event.pull_request.base.ref == 'main' &&
|
|
16
12
|
github.event.pull_request.head.repo.full_name == github.repository
|
|
13
|
+
concurrency:
|
|
14
|
+
group: autowork-merge-pr-${{ github.event.pull_request.number }}
|
|
15
|
+
cancel-in-progress: true
|
|
17
16
|
runs-on: ubuntu-latest
|
|
18
|
-
timeout-minutes:
|
|
17
|
+
timeout-minutes: 70
|
|
19
18
|
permissions:
|
|
20
19
|
contents: write
|
|
21
20
|
issues: write
|
|
@@ -50,7 +49,7 @@ jobs:
|
|
|
50
49
|
with:
|
|
51
50
|
fetch-depth: 0
|
|
52
51
|
token: ${{ secrets.GH_PAT || github.token }}
|
|
53
|
-
|
|
52
|
+
persist-credentials: false
|
|
54
53
|
|
|
55
54
|
- name: Setup Node.js
|
|
56
55
|
if: steps.pick.outputs.skip != 'true'
|
|
@@ -60,10 +59,13 @@ jobs:
|
|
|
60
59
|
|
|
61
60
|
- name: Configure Git author identity
|
|
62
61
|
if: steps.pick.outputs.skip != 'true'
|
|
62
|
+
env:
|
|
63
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
63
64
|
run: |
|
|
64
65
|
git config --global user.name "github-actions[bot]"
|
|
65
66
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
66
67
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
68
|
+
gh auth setup-git
|
|
67
69
|
|
|
68
70
|
- name: Cache Antigravity CLI
|
|
69
71
|
if: steps.pick.outputs.skip != 'true'
|
|
@@ -110,15 +112,84 @@ jobs:
|
|
|
110
112
|
fi
|
|
111
113
|
echo "skills_prompt=$SKILLS_PROMPT" >> "$GITHUB_OUTPUT"
|
|
112
114
|
|
|
115
|
+
- name: Resolve routine configuration
|
|
116
|
+
if: steps.pick.outputs.skip != 'true'
|
|
117
|
+
id: routine-config
|
|
118
|
+
run: |
|
|
119
|
+
ROUTINE="autowork"
|
|
120
|
+
DEFAULT_MODEL="gemini-3.8-flash-high"
|
|
121
|
+
DEFAULT_TIMEOUT="60"
|
|
122
|
+
|
|
123
|
+
MODEL="$DEFAULT_MODEL"
|
|
124
|
+
TIMEOUT="$DEFAULT_TIMEOUT"
|
|
125
|
+
|
|
126
|
+
if [ -f "agents-manifest.json" ]; then
|
|
127
|
+
CONFIG_JSON=$(node -e '
|
|
128
|
+
try {
|
|
129
|
+
const fs = require("fs");
|
|
130
|
+
const m = JSON.parse(fs.readFileSync("agents-manifest.json", "utf8"));
|
|
131
|
+
const r = process.argv[1];
|
|
132
|
+
const model = m.models?.[r] || m.models?.default;
|
|
133
|
+
const timeout = m.budgets?.timeoutMinutes?.[r] || m.budgets?.timeoutMinutes?.default;
|
|
134
|
+
console.log(JSON.stringify({ model: model || "", timeout: timeout ? String(timeout) : "" }));
|
|
135
|
+
} catch (e) {
|
|
136
|
+
console.log(JSON.stringify({ model: "", timeout: "" }));
|
|
137
|
+
}
|
|
138
|
+
' "$ROUTINE")
|
|
139
|
+
|
|
140
|
+
RESOLVED_MODEL=$(node -e "try { console.log(JSON.parse(process.argv[1]).model || ''); } catch {}" "$CONFIG_JSON")
|
|
141
|
+
RESOLVED_TIMEOUT=$(node -e "try { console.log(JSON.parse(process.argv[1]).timeout || ''); } catch {}" "$CONFIG_JSON")
|
|
142
|
+
|
|
143
|
+
if [ -n "$RESOLVED_MODEL" ]; then
|
|
144
|
+
MODEL="$RESOLVED_MODEL"
|
|
145
|
+
fi
|
|
146
|
+
if [ -n "$RESOLVED_TIMEOUT" ]; then
|
|
147
|
+
TIMEOUT="$RESOLVED_TIMEOUT"
|
|
148
|
+
fi
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
echo "model=$MODEL" >> "$GITHUB_OUTPUT"
|
|
152
|
+
echo "print_timeout=${TIMEOUT}m" >> "$GITHUB_OUTPUT"
|
|
153
|
+
echo "Resolved routine configuration: model=$MODEL, timeout=${TIMEOUT}m"
|
|
154
|
+
|
|
155
|
+
- name: Initialize Routine Run Issue
|
|
156
|
+
if: steps.pick.outputs.skip != 'true'
|
|
157
|
+
id: run-issue
|
|
158
|
+
env:
|
|
159
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
160
|
+
PR_NUM: ${{ github.event.pull_request.number }}
|
|
161
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
162
|
+
RUN_ID: ${{ github.run_id }}
|
|
163
|
+
SERVER_URL: ${{ github.server_url }}
|
|
164
|
+
REPOSITORY: ${{ github.repository }}
|
|
165
|
+
run: |
|
|
166
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
|
|
167
|
+
TITLE="[autowork] run ${TIMESTAMP} (on PR #${PR_NUM} merge)"
|
|
168
|
+
BODY="### Autonomous Routine Execution in Progress
|
|
169
|
+
- **Routine**: \`autowork\`
|
|
170
|
+
- **Timestamp**: \`${TIMESTAMP}\`
|
|
171
|
+
- **Trigger**: \`${EVENT_NAME}\` (PR #${PR_NUM} merged)
|
|
172
|
+
- **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
|
|
176
|
+
ISSUE_URL=$(gh issue create --title "$TITLE" --body "$BODY" --label "routine-log,routine:autowork,status:running,runner:github-actions")
|
|
177
|
+
ISSUE_NUMBER=$(echo "$ISSUE_URL" | grep -oE '[0-9]+$')
|
|
178
|
+
echo "issue_number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
|
|
179
|
+
echo "ROUTINE_ISSUE_NUMBER=$ISSUE_NUMBER" >> "$GITHUB_ENV"
|
|
180
|
+
|
|
113
181
|
- name: Run Autowork
|
|
114
182
|
if: steps.pick.outputs.skip != 'true'
|
|
115
|
-
timeout-minutes:
|
|
183
|
+
timeout-minutes: 60
|
|
116
184
|
env:
|
|
117
185
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
118
186
|
GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
119
187
|
ANTIGRAVITY_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
120
188
|
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
189
|
+
ROUTINE_ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
|
|
121
190
|
SKILLS_PROMPT: ${{ steps.skills.outputs.skills_prompt }}
|
|
191
|
+
MODEL: ${{ steps.routine-config.outputs.model || 'gemini-3.8-flash-high' }}
|
|
192
|
+
PRINT_TIMEOUT: ${{ steps.routine-config.outputs.print_timeout || '60m' }}
|
|
122
193
|
GITHUB_SERVER_URL: ${{ github.server_url }}
|
|
123
194
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
124
195
|
GITHUB_RUN_ID: ${{ github.run_id }}
|
|
@@ -126,7 +197,105 @@ jobs:
|
|
|
126
197
|
PROMPT="You are the Autowork routine for this repository. A PR was recently merged. Read and follow .github/prompts/autowork.md. ${SKILLS_PROMPT} You are in Scan mode: converge on open PRs, close merged issues, and pick the next unblocked priority issue."
|
|
127
198
|
|
|
128
199
|
agy -p "$PROMPT" \
|
|
129
|
-
--model
|
|
200
|
+
--model "$MODEL" \
|
|
130
201
|
--output-format text \
|
|
131
|
-
--print-timeout
|
|
202
|
+
--print-timeout "$PRINT_TIMEOUT" \
|
|
132
203
|
--dangerously-skip-permissions
|
|
204
|
+
|
|
205
|
+
- name: Emit run summary
|
|
206
|
+
if: always() && steps.pick.outputs.skip != 'true'
|
|
207
|
+
run: |
|
|
208
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
209
|
+
if [ -f "$REPORT_FILE" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
|
|
210
|
+
cat "$REPORT_FILE" >> "$GITHUB_STEP_SUMMARY"
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
- name: Emit Fleet Telemetry (Opt-in)
|
|
214
|
+
if: always() && steps.pick.outputs.skip != 'true'
|
|
215
|
+
env:
|
|
216
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
217
|
+
TELEMETRY_ENDPOINT: ${{ secrets.JONAH_FLEET_TELEMETRY_ENDPOINT }}
|
|
218
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
219
|
+
GITHUB_RUN_ID: ${{ github.run_id }}
|
|
220
|
+
GITHUB_RUN_NUMBER: ${{ github.run_number }}
|
|
221
|
+
run: |
|
|
222
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
223
|
+
if [ -f "$REPORT_FILE" ]; then
|
|
224
|
+
npx --yes jonah-fleet telemetry --emit --log "$REPORT_FILE" --endpoint "$TELEMETRY_ENDPOINT" || true
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
- name: Verify Atomic Handoff Invariant (PR Existence Guard)
|
|
228
|
+
if: always() && steps.pick.outputs.skip != 'true'
|
|
229
|
+
env:
|
|
230
|
+
GH_TOKEN: ${{ github.token }}
|
|
231
|
+
run: |
|
|
232
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
233
|
+
if [ -f "$REPORT_FILE" ]; then
|
|
234
|
+
if grep -q "Result.*SUCCESS" "$REPORT_FILE"; then
|
|
235
|
+
WORKED_BRANCH=$(grep -E '^\s*-\s*(Pushed branch|Branch):' "$REPORT_FILE" | head -n 1 | sed -E 's/.*`([^`]+)`.*/\1/')
|
|
236
|
+
if [ -n "$WORKED_BRANCH" ] && [[ "$WORKED_BRANCH" =~ (feat|fix)/ ]]; then
|
|
237
|
+
echo "Verifying PR existence for branch: $WORKED_BRANCH"
|
|
238
|
+
PR_COUNT=$(gh pr list --head "$WORKED_BRANCH" --state all --json number --jq 'length' 2>/dev/null || echo "0")
|
|
239
|
+
if [ "$PR_COUNT" -eq 0 ]; then
|
|
240
|
+
echo "::error::Atomic Handoff Invariant Violated: Branch '$WORKED_BRANCH' was implemented and pushed, but no pull request exists on GitHub!" >&2
|
|
241
|
+
exit 1
|
|
242
|
+
fi
|
|
243
|
+
echo "✓ Verified pull request exists on GitHub for branch: $WORKED_BRANCH"
|
|
244
|
+
fi
|
|
245
|
+
fi
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
- name: Reconcile Routine Run Issue
|
|
249
|
+
if: always() && steps.pick.outputs.skip != 'true'
|
|
250
|
+
env:
|
|
251
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
252
|
+
ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
|
|
253
|
+
JOB_STATUS: ${{ job.status }}
|
|
254
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
255
|
+
RUN_ID: ${{ github.run_id }}
|
|
256
|
+
SERVER_URL: ${{ github.server_url }}
|
|
257
|
+
REPOSITORY: ${{ github.repository }}
|
|
258
|
+
run: |
|
|
259
|
+
if [ -z "$ISSUE_NUMBER" ]; then
|
|
260
|
+
echo "No routine issue to reconcile."
|
|
261
|
+
exit 0
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
265
|
+
|
|
266
|
+
if [ -f "$REPORT_FILE" ]; then
|
|
267
|
+
BODY_CONTENT=$(cat "$REPORT_FILE")
|
|
268
|
+
else
|
|
269
|
+
BODY_CONTENT="### Autonomous Routine Execution Completed (${JOB_STATUS})
|
|
270
|
+
- **Routine**: \`autowork\`
|
|
271
|
+
- **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
|
|
272
|
+
- **Trigger**: \`${EVENT_NAME}\`"
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
FINAL_BODY="${BODY_CONTENT}
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
|
|
279
|
+
|
|
280
|
+
TEMP_BODY=$(mktemp)
|
|
281
|
+
echo "$FINAL_BODY" > "$TEMP_BODY"
|
|
282
|
+
gh issue edit "$ISSUE_NUMBER" --body-file "$TEMP_BODY"
|
|
283
|
+
rm -f "$TEMP_BODY"
|
|
284
|
+
|
|
285
|
+
if [ "$JOB_STATUS" = "success" ]; then
|
|
286
|
+
gh issue edit "$ISSUE_NUMBER" --add-label "status:success" --remove-label "status:running"
|
|
287
|
+
gh issue close "$ISSUE_NUMBER" --reason completed
|
|
288
|
+
echo "✓ Routine run issue #$ISSUE_NUMBER closed as completed."
|
|
289
|
+
else
|
|
290
|
+
INTERRUPTION_BODY="### ❌ Milestone: Run Interrupted / Failed
|
|
291
|
+
- **Routine**: \`autowork\`
|
|
292
|
+
- **Status**: Workflow job failed or timed out (\`${JOB_STATUS}\`)
|
|
293
|
+
- **Step**: Actions execution halted before normal completion
|
|
294
|
+
- **Action Log**: [View GitHub Actions Run](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
|
|
298
|
+
gh issue comment "$ISSUE_NUMBER" --body "$INTERRUPTION_BODY" || true
|
|
299
|
+
gh issue edit "$ISSUE_NUMBER" --add-label "status:failure,needs-attention" --remove-label "status:running"
|
|
300
|
+
echo "⚠️ Routine run issue #$ISSUE_NUMBER left open for triage (status: $JOB_STATUS)."
|
|
301
|
+
fi
|
|
@@ -3,8 +3,6 @@ name: Trigger Review Routine
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
5
|
types: [ready_for_review, opened, reopened, synchronize, review_requested]
|
|
6
|
-
paths-ignore:
|
|
7
|
-
- '.github/prompts/logs/**'
|
|
8
6
|
schedule:
|
|
9
7
|
# Periodic scan sweep every 2 hours to catch and recover any orphaned or unreviewed ready PRs
|
|
10
8
|
- cron: '45 */2 * * *'
|
|
@@ -17,10 +15,6 @@ on:
|
|
|
17
15
|
issue_comment:
|
|
18
16
|
types: [created]
|
|
19
17
|
|
|
20
|
-
concurrency:
|
|
21
|
-
group: review-routine-pr-${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number || 'scan' }}
|
|
22
|
-
cancel-in-progress: true
|
|
23
|
-
|
|
24
18
|
jobs:
|
|
25
19
|
trigger-routine:
|
|
26
20
|
if: >-
|
|
@@ -42,8 +36,11 @@ jobs:
|
|
|
42
36
|
contains(github.event.comment.body, '/peer-review') ||
|
|
43
37
|
contains(github.event.comment.body, '/retrigger') ||
|
|
44
38
|
contains(github.event.comment.body, '/re-review')))
|
|
39
|
+
concurrency:
|
|
40
|
+
group: review-routine-pr-${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number || 'scan' }}
|
|
41
|
+
cancel-in-progress: true
|
|
45
42
|
runs-on: ubuntu-latest
|
|
46
|
-
timeout-minutes:
|
|
43
|
+
timeout-minutes: 65
|
|
47
44
|
permissions:
|
|
48
45
|
contents: write
|
|
49
46
|
actions: read
|
|
@@ -56,12 +53,14 @@ jobs:
|
|
|
56
53
|
env:
|
|
57
54
|
GH_TOKEN: ${{ github.token }}
|
|
58
55
|
PR_NUM: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
|
|
56
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
57
|
+
REPOSITORY: ${{ github.repository }}
|
|
59
58
|
run: |
|
|
60
59
|
if [ -z "$PR_NUM" ]; then
|
|
61
|
-
if [ "$
|
|
62
|
-
open_prs=$(gh api "repos/${
|
|
60
|
+
if [ "$EVENT_NAME" = "schedule" ]; then
|
|
61
|
+
open_prs=$(gh api "repos/${REPOSITORY}/pulls?state=open&per_page=1" --jq 'length' 2>/dev/null || echo "0")
|
|
63
62
|
if [ "$open_prs" -eq "0" ]; then
|
|
64
|
-
echo "No open PRs found in ${
|
|
63
|
+
echo "No open PRs found in ${REPOSITORY} — skipping scheduled review routine scan."
|
|
65
64
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
66
65
|
exit 0
|
|
67
66
|
fi
|
|
@@ -87,7 +86,7 @@ jobs:
|
|
|
87
86
|
return 1
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
if ! pr=$(gh_api_retry "repos/${
|
|
89
|
+
if ! pr=$(gh_api_retry "repos/${REPOSITORY}/pulls/${PR_NUM}"); then
|
|
91
90
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
92
91
|
exit 0
|
|
93
92
|
fi
|
|
@@ -110,7 +109,7 @@ jobs:
|
|
|
110
109
|
# Strict allowlist: only trigger immediate cloud review if explicitly labeled priority/P0 or priority/P1.
|
|
111
110
|
# Untagged PRs and lower-priority PRs (P2/P3) skip immediate cloud review and are handled by local peer-review daemons
|
|
112
111
|
# (cloud scheduled watchdog sweep will catch up if unreviewed > 48h).
|
|
113
|
-
if [ "$
|
|
112
|
+
if [ "$EVENT_NAME" = "pull_request" ]; then
|
|
114
113
|
labels=$(echo "$pr" | jq -r '.labels[].name' 2>/dev/null || echo "")
|
|
115
114
|
if ! echo "$labels" | grep -qE '^priority/P[01]$'; then
|
|
116
115
|
echo "PR is not explicitly labeled priority/P0 or priority/P1 — skipping immediate cloud review for local peer-review daemon."
|
|
@@ -126,6 +125,7 @@ jobs:
|
|
|
126
125
|
uses: actions/checkout@v4
|
|
127
126
|
with:
|
|
128
127
|
fetch-depth: 0
|
|
128
|
+
persist-credentials: false
|
|
129
129
|
|
|
130
130
|
- name: Setup Node.js
|
|
131
131
|
if: steps.guard.outputs.skip != 'true'
|
|
@@ -135,10 +135,13 @@ jobs:
|
|
|
135
135
|
|
|
136
136
|
- name: Configure Git author identity
|
|
137
137
|
if: steps.guard.outputs.skip != 'true'
|
|
138
|
+
env:
|
|
139
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
138
140
|
run: |
|
|
139
141
|
git config --global user.name "github-actions[bot]"
|
|
140
142
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
141
143
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
144
|
+
gh auth setup-git
|
|
142
145
|
|
|
143
146
|
- name: Cache Antigravity CLI
|
|
144
147
|
if: steps.guard.outputs.skip != 'true'
|
|
@@ -171,9 +174,79 @@ jobs:
|
|
|
171
174
|
printf '%s' "$ANTIGRAVITY_OAUTH_TOKEN" > "$HOME/.gemini/antigravity-cli/antigravity-oauth-token"
|
|
172
175
|
chmod 600 "$HOME/.gemini/antigravity-cli/antigravity-oauth-token"
|
|
173
176
|
|
|
177
|
+
- name: Resolve routine configuration
|
|
178
|
+
if: steps.guard.outputs.skip != 'true'
|
|
179
|
+
id: routine-config
|
|
180
|
+
run: |
|
|
181
|
+
ROUTINE="peer-review"
|
|
182
|
+
DEFAULT_MODEL="gemini-3.8-flash-high"
|
|
183
|
+
DEFAULT_TIMEOUT="55"
|
|
184
|
+
|
|
185
|
+
MODEL="$DEFAULT_MODEL"
|
|
186
|
+
TIMEOUT="$DEFAULT_TIMEOUT"
|
|
187
|
+
|
|
188
|
+
if [ -f "agents-manifest.json" ]; then
|
|
189
|
+
CONFIG_JSON=$(node -e '
|
|
190
|
+
try {
|
|
191
|
+
const fs = require("fs");
|
|
192
|
+
const m = JSON.parse(fs.readFileSync("agents-manifest.json", "utf8"));
|
|
193
|
+
const r = process.argv[1];
|
|
194
|
+
const model = m.models?.[r] || m.models?.default;
|
|
195
|
+
const timeout = m.budgets?.timeoutMinutes?.[r] || m.budgets?.timeoutMinutes?.default;
|
|
196
|
+
console.log(JSON.stringify({ model: model || "", timeout: timeout ? String(timeout) : "" }));
|
|
197
|
+
} catch (e) {
|
|
198
|
+
console.log(JSON.stringify({ model: "", timeout: "" }));
|
|
199
|
+
}
|
|
200
|
+
' "$ROUTINE")
|
|
201
|
+
|
|
202
|
+
RESOLVED_MODEL=$(node -e "try { console.log(JSON.parse(process.argv[1]).model || ''); } catch {}" "$CONFIG_JSON")
|
|
203
|
+
RESOLVED_TIMEOUT=$(node -e "try { console.log(JSON.parse(process.argv[1]).timeout || ''); } catch {}" "$CONFIG_JSON")
|
|
204
|
+
|
|
205
|
+
if [ -n "$RESOLVED_MODEL" ]; then
|
|
206
|
+
MODEL="$RESOLVED_MODEL"
|
|
207
|
+
fi
|
|
208
|
+
if [ -n "$RESOLVED_TIMEOUT" ]; then
|
|
209
|
+
TIMEOUT="$RESOLVED_TIMEOUT"
|
|
210
|
+
fi
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
echo "model=$MODEL" >> "$GITHUB_OUTPUT"
|
|
214
|
+
echo "print_timeout=${TIMEOUT}m" >> "$GITHUB_OUTPUT"
|
|
215
|
+
echo "Resolved routine configuration: model=$MODEL, timeout=${TIMEOUT}m"
|
|
216
|
+
|
|
217
|
+
- name: Initialize Routine Run Issue
|
|
218
|
+
if: steps.guard.outputs.skip != 'true'
|
|
219
|
+
id: run-issue
|
|
220
|
+
env:
|
|
221
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
222
|
+
PR_ARG: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
|
|
223
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
224
|
+
RUN_ID: ${{ github.run_id }}
|
|
225
|
+
SERVER_URL: ${{ github.server_url }}
|
|
226
|
+
REPOSITORY: ${{ github.repository }}
|
|
227
|
+
run: |
|
|
228
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
|
|
229
|
+
if [ -n "$PR_ARG" ]; then
|
|
230
|
+
TITLE="[peer-review] run ${TIMESTAMP} (PR #${PR_ARG})"
|
|
231
|
+
else
|
|
232
|
+
TITLE="[peer-review] run ${TIMESTAMP}"
|
|
233
|
+
fi
|
|
234
|
+
BODY="### Autonomous Routine Execution in Progress
|
|
235
|
+
- **Routine**: \`peer-review\`
|
|
236
|
+
- **Timestamp**: \`${TIMESTAMP}\`
|
|
237
|
+
- **Trigger**: \`${EVENT_NAME}\`
|
|
238
|
+
- **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
|
|
242
|
+
ISSUE_URL=$(gh issue create --title "$TITLE" --body "$BODY" --label "routine-log,routine:peer-review,status:running,runner:github-actions")
|
|
243
|
+
ISSUE_NUMBER=$(echo "$ISSUE_URL" | grep -oE '[0-9]+$')
|
|
244
|
+
echo "issue_number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
|
|
245
|
+
echo "ROUTINE_ISSUE_NUMBER=$ISSUE_NUMBER" >> "$GITHUB_ENV"
|
|
246
|
+
|
|
174
247
|
- name: Run Peer Review
|
|
175
248
|
if: steps.guard.outputs.skip != 'true'
|
|
176
|
-
timeout-minutes:
|
|
249
|
+
timeout-minutes: 55
|
|
177
250
|
env:
|
|
178
251
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
179
252
|
GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
@@ -181,6 +254,9 @@ jobs:
|
|
|
181
254
|
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
182
255
|
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
|
|
183
256
|
PR_URL: ${{ github.event.pull_request.html_url || github.event.issue.html_url }}
|
|
257
|
+
ROUTINE_ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
|
|
258
|
+
MODEL: ${{ steps.routine-config.outputs.model || 'gemini-3.8-flash-high' }}
|
|
259
|
+
PRINT_TIMEOUT: ${{ steps.routine-config.outputs.print_timeout || '55m' }}
|
|
184
260
|
GITHUB_SERVER_URL: ${{ github.server_url }}
|
|
185
261
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
186
262
|
GITHUB_RUN_ID: ${{ github.run_id }}
|
|
@@ -194,10 +270,14 @@ jobs:
|
|
|
194
270
|
PROMPT="You are the Peer Review routine for this repository. Read and follow the instructions in .github/prompts/peer-review.md exactly. You are in Scan mode: check open PRs and select the highest-priority PR to review."
|
|
195
271
|
fi
|
|
196
272
|
|
|
273
|
+
if [ -n "$ROUTINE_ISSUE_NUMBER" ]; then
|
|
274
|
+
PROMPT="$PROMPT Tracking run log issue: #${ROUTINE_ISSUE_NUMBER}."
|
|
275
|
+
fi
|
|
276
|
+
|
|
197
277
|
agy -p "$PROMPT" \
|
|
198
|
-
--model
|
|
278
|
+
--model "$MODEL" \
|
|
199
279
|
--output-format text \
|
|
200
|
-
--print-timeout
|
|
280
|
+
--print-timeout "$PRINT_TIMEOUT" \
|
|
201
281
|
--dangerously-skip-permissions
|
|
202
282
|
|
|
203
283
|
- name: Handle Review Failure & PR Notification
|
|
@@ -205,12 +285,17 @@ jobs:
|
|
|
205
285
|
env:
|
|
206
286
|
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
207
287
|
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
|
|
288
|
+
ROUTINE_ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
|
|
208
289
|
GITHUB_SERVER_URL: ${{ github.server_url }}
|
|
209
290
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
210
291
|
GITHUB_RUN_ID: ${{ github.run_id }}
|
|
211
292
|
run: |
|
|
212
293
|
if [ -n "$PR_NUMBER" ]; then
|
|
213
|
-
|
|
294
|
+
LOG_REF=""
|
|
295
|
+
if [ -n "$ROUTINE_ISSUE_NUMBER" ]; then
|
|
296
|
+
LOG_REF=" · [Run Log #${ROUTINE_ISSUE_NUMBER}](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/issues/${ROUTINE_ISSUE_NUMBER})"
|
|
297
|
+
fi
|
|
298
|
+
gh pr comment "$PR_NUMBER" --body "⚠️ **Peer Review Routine Notice**: The automated review session encountered an execution error (e.g., API rate/quota limit or runner interruption)${LOG_REF}. The review will be retried automatically on the next scheduled scan sweep or can be re-triggered immediately by commenting \`/review\` on this PR.
|
|
214
299
|
|
|
215
300
|
_Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})_" || true
|
|
216
301
|
fi
|
|
@@ -218,9 +303,9 @@ jobs:
|
|
|
218
303
|
- name: Emit run summary
|
|
219
304
|
if: always() && steps.guard.outputs.skip != 'true'
|
|
220
305
|
run: |
|
|
221
|
-
|
|
222
|
-
if [ -
|
|
223
|
-
cat "$
|
|
306
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
307
|
+
if [ -f "$REPORT_FILE" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
|
|
308
|
+
cat "$REPORT_FILE" >> "$GITHUB_STEP_SUMMARY"
|
|
224
309
|
fi
|
|
225
310
|
|
|
226
311
|
- name: Emit Fleet Telemetry (Opt-in)
|
|
@@ -232,7 +317,62 @@ jobs:
|
|
|
232
317
|
GITHUB_RUN_ID: ${{ github.run_id }}
|
|
233
318
|
GITHUB_RUN_NUMBER: ${{ github.run_number }}
|
|
234
319
|
run: |
|
|
235
|
-
|
|
236
|
-
if [ -
|
|
237
|
-
npx --yes jonah-fleet telemetry --emit --log "$
|
|
320
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
321
|
+
if [ -f "$REPORT_FILE" ]; then
|
|
322
|
+
npx --yes jonah-fleet telemetry --emit --log "$REPORT_FILE" --endpoint "$TELEMETRY_ENDPOINT" || true
|
|
323
|
+
fi
|
|
324
|
+
|
|
325
|
+
- name: Reconcile Routine Run Issue
|
|
326
|
+
if: always() && steps.guard.outputs.skip != 'true'
|
|
327
|
+
env:
|
|
328
|
+
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
|
|
329
|
+
ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
|
|
330
|
+
JOB_STATUS: ${{ job.status }}
|
|
331
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
332
|
+
RUN_ID: ${{ github.run_id }}
|
|
333
|
+
SERVER_URL: ${{ github.server_url }}
|
|
334
|
+
REPOSITORY: ${{ github.repository }}
|
|
335
|
+
run: |
|
|
336
|
+
if [ -z "$ISSUE_NUMBER" ]; then
|
|
337
|
+
echo "No routine issue to reconcile."
|
|
338
|
+
exit 0
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
REPORT_FILE=".jonah-fleet/run-report.md"
|
|
342
|
+
|
|
343
|
+
if [ -f "$REPORT_FILE" ]; then
|
|
344
|
+
BODY_CONTENT=$(cat "$REPORT_FILE")
|
|
345
|
+
else
|
|
346
|
+
BODY_CONTENT="### Autonomous Routine Execution Completed (${JOB_STATUS})
|
|
347
|
+
- **Routine**: \`peer-review\`
|
|
348
|
+
- **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
|
|
349
|
+
- **Trigger**: \`${EVENT_NAME}\`"
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
FINAL_BODY="${BODY_CONTENT}
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
|
|
356
|
+
|
|
357
|
+
TEMP_BODY=$(mktemp)
|
|
358
|
+
echo "$FINAL_BODY" > "$TEMP_BODY"
|
|
359
|
+
gh issue edit "$ISSUE_NUMBER" --body-file "$TEMP_BODY"
|
|
360
|
+
rm -f "$TEMP_BODY"
|
|
361
|
+
|
|
362
|
+
if [ "$JOB_STATUS" = "success" ]; then
|
|
363
|
+
gh issue edit "$ISSUE_NUMBER" --add-label "status:success" --remove-label "status:running"
|
|
364
|
+
gh issue close "$ISSUE_NUMBER" --reason completed
|
|
365
|
+
echo "✓ Routine run issue #$ISSUE_NUMBER closed as completed."
|
|
366
|
+
else
|
|
367
|
+
INTERRUPTION_BODY="### ❌ Milestone: Run Interrupted / Failed
|
|
368
|
+
- **Routine**: \`peer-review\`
|
|
369
|
+
- **Status**: Workflow job failed or timed out (\`${JOB_STATUS}\`)
|
|
370
|
+
- **Step**: Actions execution halted before normal completion
|
|
371
|
+
- **Action Log**: [View GitHub Actions Run](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
|
|
375
|
+
gh issue comment "$ISSUE_NUMBER" --body "$INTERRUPTION_BODY" || true
|
|
376
|
+
gh issue edit "$ISSUE_NUMBER" --add-label "status:failure,needs-attention" --remove-label "status:running"
|
|
377
|
+
echo "⚠️ Routine run issue #$ISSUE_NUMBER left open for triage (status: $JOB_STATUS)."
|
|
238
378
|
fi
|