jonah-fleet 1.23.1 → 1.24.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 CHANGED
@@ -5,6 +5,13 @@ All notable changes to `jonah-fleet` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.24.0](https://github.com/juliendurandeu/jonah-fleet/compare/v1.23.1...v1.24.0) (2026-09-23)
9
+
10
+
11
+ ### Features
12
+
13
+ * **workflows:** support triggering autowork on issue assignment to bot/persona ([#339](https://github.com/juliendurandeu/jonah-fleet/issues/339)) ([7a976f3](https://github.com/juliendurandeu/jonah-fleet/commit/7a976f32defa9ebc464df40702986d32db8508bc))
14
+
8
15
  ## [1.23.1](https://github.com/juliendurandeu/jonah-fleet/compare/v1.23.0...v1.23.1) (2026-09-20)
9
16
 
10
17
 
@@ -35,6 +42,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
35
42
 
36
43
  ## [Unreleased]
37
44
 
45
+ ### Features
46
+
47
+ * **workflows:** support triggering autowork on issue assignment to bot persona ([#19](https://github.com/juliendurandeu/jonah-fleet/issues/19))
48
+
38
49
  ### Bug Fixes
39
50
 
40
51
  * **runner:** prevent routine tracking issues from being mistakenly claimed as target issues via `excludeIssueNumber` and `isRoutineRunTitle` guardrails.
package/dist/index.js CHANGED
@@ -115,7 +115,8 @@ var ROUTINE_TO_WORKFLOW_MAP = {
115
115
  "autowork-cron.yml",
116
116
  "trigger-autowork-on-merge.yml",
117
117
  "trigger-autowork-on-bug.yml",
118
- "trigger-autowork-manual.yml"
118
+ "trigger-autowork-manual.yml",
119
+ "trigger-autowork-on-assign.yml"
119
120
  ],
120
121
  "peer-review": ["trigger-review-routine.yml"],
121
122
  optimizer: ["prompt-optimizer-cron.yml"],
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/lib/presets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/lib/presets.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jonah-fleet",
3
- "version": "1.23.1",
3
+ "version": "1.24.0",
4
4
  "description": "Standalone autonomous agent fleet with Symphony orchestration, claim protocols, and continuous improvement loops",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -69,6 +69,12 @@ tests/ # Test suites
69
69
 
70
70
  ## Autonomous Agent Dispatch (Targeted Autowork)
71
71
 
72
+ ### 1-Click Assignment Trigger
73
+
74
+ Assigning any issue in GitHub's native sidebar Assignees dropdown to the designated fleet bot account (configured via `vars.AGENT_BOT_LOGIN` or machine user) automatically triggers Autowork in Targeted mode via `trigger-autowork-on-assign.yml`.
75
+
76
+ ### Manual Dispatch & Badge Link
77
+
72
78
  To trigger the Autowork routine manually on any specific issue, use the GitHub Actions `workflow_dispatch` trigger or embed this badge link in issue templates/descriptions:
73
79
 
74
80
  ```markdown
@@ -21,6 +21,7 @@ Dispatch is both **scheduled** and **event-driven**. All routines run as ephemer
21
21
  - `trigger-review-routine.yml` fires Peer Review automatically when a PR is marked ready for review, updated, or review is requested (`ready_for_review`, `opened`, `reopened`, `synchronize`, `review_requested`). It can also be manually (re)triggered via `workflow_dispatch` (with optional `pr_number` for Targeted mode or blank for Scan mode) or by commenting `/review`, `/peer-review`, `/retrigger`, or `/re-review` on any open pull request.
22
22
  - `trigger-autowork-on-merge.yml` fires Autowork in **Targeted mode** when a PR merges to `main` and unblocks the next unit of chained work.
23
23
  - `trigger-autowork-on-bug.yml` fires Autowork when an issue becomes a high-priority bug.
24
+ - `trigger-autowork-on-assign.yml` fires Autowork in **Targeted mode** when an issue is assigned to a designated bot account or persona (`vars.AGENT_BOT_LOGIN`).
24
25
  - `trigger-autowork-manual.yml` fires Autowork manually via `workflow_dispatch` or badge link click on a specific issue in **Targeted mode**.
25
26
 
26
27
  Autowork triggers pass the target issue via environment variables (`TARGET_ISSUE`, `ISSUE_NUMBER`, `ISSUE_URL`), putting autowork.md into **Targeted mode** (working the named issue ahead of Phase 1 convergence). Single-flight per issue is strictly enforced across scheduled, event-driven, and manually triggered runs.
@@ -271,7 +272,7 @@ How closed-loop feedback from product telemetry and measurement trackers drives
271
272
  How agent routines are partitioned between cloud GitHub Actions (24/7 cloud runners for fast time-to-resolution) and local machine agents (`jonah-fleet run` / `jonah-fleet daemon` for zero cloud quota consumption):
272
273
 
273
274
  1. **Priority Routing Rules**:
274
- - **`priority/P0` & `priority/P1` & Bugs**: Processed immediately by cloud GitHub Actions upon event trigger (`issues`, `pull_request`, `schedule`).
275
+ - **`priority/P0` & `priority/P1` & Bugs & Persona Assignment**: Processed immediately by cloud GitHub Actions upon event trigger (`issues`, `pull_request`, `schedule`).
275
276
  - **`priority/P2` & `priority/P3` (Lower Priority)**: Handled primarily by local machine agents in isolated Git worktrees. Cloud Actions skips immediate event triggers on P2/P3 items to conserve Actions quota.
276
277
  - **Cloud Catchup Sweep (48h Fallback)**: If a P2/P3 issue or PR remains unclaimed/unreviewed for $>48\text{ hours}$ (e.g. because local machines were offline), the scheduled cloud Actions scan sweep automatically picks it up to prevent work starvation.
277
278
  2. **PR Priority Mirroring**: When Autowork opens a PR, it automatically mirrors the parent issue's priority labels (`priority/P0`..`P3`) onto the pull request so downstream review workflows can filter triggers without extra API overhead.
@@ -70,17 +70,17 @@ If any criterion cannot be met, stop immediately and log FAILURE with the reason
70
70
 
71
71
  This routine runs in two modes, decided here before any other work:
72
72
 
73
- - **Targeted mode** — an environment variable `$ISSUE_NUMBER` (or explicit issue payload) names a target issue. Work _that_ issue as the run's objective, **ahead of** Phase 1 convergence and the normal priority scan.
73
+ - **Targeted mode** — an environment variable `$TARGET_ISSUE` or `$ISSUE_NUMBER` (or explicit issue payload / persona assignment trigger) names a target issue. Work _that_ issue as the run's objective, **ahead of** Phase 1 convergence and the normal priority scan.
74
74
  - **Scan mode** — no issue is named (a scheduled cron run). Run Phase 1, then select an issue by priority in Phase 2.
75
75
 
76
- Check if `$ISSUE_NUMBER` environment variable is set (or scan invocation text for `#<number>` / `/issues/<number>`):
76
+ Check if `$TARGET_ISSUE` or `$ISSUE_NUMBER` environment variable is set (or scan invocation text for `#<number>` / `/issues/<number>`):
77
77
 
78
78
  - **Found one → Targeted mode.** Record it as this run's target issue and proceed to Step 0.5.
79
79
  - **None found → Scan mode.** Proceed as a scheduled run: Phase 1, then normal priority selection in Phase 2.
80
80
 
81
81
  ### Step 0.5: Targeted mode — work the target issue first (only when Step 0 found one)
82
82
 
83
- a. **Read the target issue and check eligibility.** Eligible = open, unassigned or reclaimable stale claim, no open PR (`Closes #N`), no unclosed inward blocking dependencies (`Blocked by #N` or `Depends on #N` where `#N` is open), and not carrying `needs-human` or `needs-design`.
83
+ a. **Read the target issue and check eligibility.** Eligible = open, unassigned or assigned to designated bot persona (`vars.AGENT_BOT_LOGIN`) or reclaimable stale claim, no open PR (`Closes #N`), no unclosed inward blocking dependencies (`Blocked by #N` or `Depends on #N` where `#N` is open), and not carrying `needs-human` or `needs-design`.
84
84
 
85
85
  - **Ineligible** → fall back to Phase 1 and run the normal Scan flow.
86
86
  b. **Eligible → claim, then implement.** Call `get_me` once to learn your own login (step 7), reclaim stale claim if applicable (step 10a), run Claim protocol (step 11), evaluate and implement per steps 12–13, open draft PR, and run in-session review wait (step 15).
@@ -167,6 +167,7 @@ _Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/ru
167
167
 
168
168
  6. Count open PRs authored by automated sessions representing live reviewable work (excluding log-only PRs). If 3 or more non-log PRs are open, STOP — run is SUCCESS with "Too many open PRs, converging first".
169
169
  7. Call `get_me` once to learn your own GitHub account (`login`).
170
+ - **Persona & Bot Login Matching**: In environments with designated machine user accounts or persona assignment triggers (`vars.AGENT_BOT_LOGIN`), ensure `get_me` identity matching respects both your authenticated account and the configured bot persona. An issue or PR assigned to the bot persona is treated as self-assigned for claim and ownership checks.
170
171
  8. List open issues sorted by priority labels (P1 > P2 > P3). Within the same priority tier, order by type (`bug`/`security` before others), then oldest first.
171
172
  - **Selective Server-Side Querying**: To prevent tool buffer truncation and avoid ingesting un-actionable issues, query GitHub with server-side exclusion filters rather than dumping all issues. E.g.:
172
173
  `gh issue list --state open --search "no:assignee -label:measurement -label:needs-human -label:needs-design -label:wontfix -label:needs-info" --limit 30`
@@ -190,7 +191,7 @@ _Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/ru
190
191
  10. If the candidate should be closed already (work done, merged PR found in git history or via `gh pr list --state merged --search "<ISSUE_NUMBER>"`), close it immediately (`gh issue close <ISSUE_NUMBER> --comment "Closed: work already merged in PR #<PR_NUMBER>.\n\n_Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID:-})_"`), close any lingering past failed routine run issues (`PAST_FAILURES=$(gh issue list --label routine-log --search "Issue #<ISSUE_NUMBER>" --state open --json number --jq '.[].number' || true); for p in $PAST_FAILURES; do if [ -n "$p" ] && [ "$p" != "$ROUTINE_ISSUE_NUMBER" ]; then gh issue comment "$p" --body "Resolved: work already merged in PR #<PR_NUMBER>.\n\n_Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID:-})_" || true; gh issue close "$p" --reason completed || true; fi; done`), and return to step 8.
191
192
  10a. **Stale-claim reclamation:** If candidate is a stale claim per `ORCHESTRATION.md`, re-read immediately before writing, unassign the dead owner, post reclamation comment, and proceed to claim.
192
193
  11. **Claim protocol:**
193
- a. Re-read candidate issue immediately before claiming (`issue_read`). If assigned, abort and pick next candidate.
194
+ a. Re-read candidate issue immediately before claiming (`issue_read`). If assigned to a user other than yourself or the configured bot persona (`vars.AGENT_BOT_LOGIN`), abort and pick next candidate.
194
195
  b. Claim atomically: assign yourself (`login` from step 7) AND post claim comment:
195
196
  - In **Cloud Actions**: `🔒 Claimed by autowork run {run_url} {timestamp}`
196
197
  - In **Local Agent**: `🔒 Claimed by local autowork session (host: {hostname}) {timestamp}`
@@ -0,0 +1,327 @@
1
+ name: Trigger Autowork on Assignment
2
+
3
+ on:
4
+ issues:
5
+ types: [assigned]
6
+
7
+ jobs:
8
+ fire-autowork:
9
+ if: github.event.assignee.login == vars.AGENT_BOT_LOGIN || github.event.assignee.login == 'jonah-fleet-bot'
10
+ concurrency:
11
+ group: autowork-assign-${{ github.event.issue.number }}
12
+ cancel-in-progress: true
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 70
15
+ permissions:
16
+ contents: write
17
+ issues: write
18
+ pull-requests: write
19
+ statuses: write
20
+ actions: read
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0
26
+ token: ${{ secrets.GH_PAT || github.token }}
27
+ persist-credentials: false
28
+
29
+ - name: Setup Node.js
30
+ uses: actions/setup-node@v4
31
+ with:
32
+ node-version: 22
33
+
34
+ - name: Configure Git author identity
35
+ env:
36
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
37
+ run: |
38
+ git config --global user.name "github-actions[bot]"
39
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
40
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
41
+ gh auth setup-git
42
+
43
+ - name: Cache Antigravity CLI
44
+ id: cache-agy
45
+ uses: actions/cache@v4
46
+ with:
47
+ path: ~/.local/bin/agy
48
+ key: agy-cli-linux-amd64-v1
49
+
50
+ - name: Install Antigravity CLI
51
+ if: steps.cache-agy.outputs.cache-hit != 'true'
52
+ run: |
53
+ curl -fsSL https://antigravity.google/cli/install.sh | bash
54
+
55
+ - name: Add Antigravity CLI to PATH
56
+ run: echo "$HOME/.local/bin" >> $GITHUB_PATH
57
+
58
+ - name: Write Antigravity OAuth Token
59
+ env:
60
+ ANTIGRAVITY_OAUTH_TOKEN: ${{ secrets.ANTIGRAVITY_OAUTH_TOKEN || secrets.GEMINI_API_KEY }}
61
+ run: |
62
+ if [ -z "$ANTIGRAVITY_OAUTH_TOKEN" ]; then
63
+ echo "::error::Neither ANTIGRAVITY_OAUTH_TOKEN nor GEMINI_API_KEY secret is set; cannot authenticate Antigravity CLI." >&2
64
+ exit 1
65
+ fi
66
+ mkdir -p "$HOME/.gemini/antigravity-cli"
67
+ chmod 700 "$HOME/.gemini/antigravity-cli"
68
+ printf '%s' "$ANTIGRAVITY_OAUTH_TOKEN" > "$HOME/.gemini/antigravity-cli/antigravity-oauth-token"
69
+ chmod 600 "$HOME/.gemini/antigravity-cli/antigravity-oauth-token"
70
+
71
+ - name: Discover domain skills
72
+ id: skills
73
+ run: |
74
+ SKILLS_PROMPT=""
75
+ if [ -d ".agents/skills" ]; then
76
+ for skill_path in .agents/skills/*/SKILL.md; do
77
+ if [ -f "$skill_path" ]; then
78
+ SKILLS_PROMPT="${SKILLS_PROMPT}Read and follow ${skill_path}. "
79
+ fi
80
+ done
81
+ fi
82
+ echo "skills_prompt=$SKILLS_PROMPT" >> "$GITHUB_OUTPUT"
83
+
84
+ - name: Resolve routine configuration
85
+ id: routine-config
86
+ run: |
87
+ ROUTINE="autowork"
88
+ DEFAULT_MODEL="gemini-3.8-flash-high"
89
+ DEFAULT_TIMEOUT="60"
90
+
91
+ MODEL="$DEFAULT_MODEL"
92
+ TIMEOUT="$DEFAULT_TIMEOUT"
93
+
94
+ if [ -f "agents-manifest.json" ]; then
95
+ CONFIG_JSON=$(node -e '
96
+ try {
97
+ const fs = require("fs");
98
+ const m = JSON.parse(fs.readFileSync("agents-manifest.json", "utf8"));
99
+ const r = process.argv[1];
100
+ const model = m.models?.[r] || m.models?.default;
101
+ const timeout = m.budgets?.timeoutMinutes?.[r] || m.budgets?.timeoutMinutes?.default;
102
+ console.log(JSON.stringify({ model: model || "", timeout: timeout ? String(timeout) : "" }));
103
+ } catch (e) {
104
+ console.log(JSON.stringify({ model: "", timeout: "" }));
105
+ }
106
+ ' "$ROUTINE")
107
+
108
+ RESOLVED_MODEL=$(node -e "try { console.log(JSON.parse(process.argv[1]).model || ''); } catch {}" "$CONFIG_JSON")
109
+ RESOLVED_TIMEOUT=$(node -e "try { console.log(JSON.parse(process.argv[1]).timeout || ''); } catch {}" "$CONFIG_JSON")
110
+
111
+ if [ -n "$RESOLVED_MODEL" ]; then
112
+ MODEL="$RESOLVED_MODEL"
113
+ fi
114
+ if [ -n "$RESOLVED_TIMEOUT" ]; then
115
+ TIMEOUT="$RESOLVED_TIMEOUT"
116
+ fi
117
+ fi
118
+
119
+ echo "model=$MODEL" >> "$GITHUB_OUTPUT"
120
+ echo "print_timeout=${TIMEOUT}m" >> "$GITHUB_OUTPUT"
121
+ echo "Resolved routine configuration: model=$MODEL, timeout=${TIMEOUT}m"
122
+
123
+ - name: Initialize Routine Run Issue
124
+ id: run-issue
125
+ env:
126
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
127
+ ISSUE_NUM: ${{ github.event.issue.number }}
128
+ EVENT_NAME: ${{ github.event_name }}
129
+ RUN_ID: ${{ github.run_id }}
130
+ SERVER_URL: ${{ github.server_url }}
131
+ REPOSITORY: ${{ github.repository }}
132
+ run: |
133
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
134
+ TITLE="[autowork] run ${TIMESTAMP} (Issue #${ISSUE_NUM})"
135
+ BODY="### Autonomous Routine Execution in Progress
136
+ - **Routine**: \`autowork\`
137
+ - **Timestamp**: \`${TIMESTAMP}\`
138
+ - **Trigger**: \`${EVENT_NAME}\` (Issue assignment to @${{ github.event.assignee.login }})
139
+ - **Target**: Issue #${ISSUE_NUM}
140
+ - **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
141
+
142
+ ---
143
+ _Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
144
+ ISSUE_URL=$(gh issue create --title "$TITLE" --body "$BODY" --label "routine-log,routine:autowork,status:running,runner:github-actions")
145
+ ISSUE_NUMBER=$(echo "$ISSUE_URL" | grep -oE '[0-9]+$')
146
+ echo "issue_number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
147
+ echo "ROUTINE_ISSUE_NUMBER=$ISSUE_NUMBER" >> "$GITHUB_ENV"
148
+
149
+ - name: Run Autowork
150
+ timeout-minutes: 60
151
+ env:
152
+ GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
153
+ GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
154
+ ANTIGRAVITY_API_KEY: ${{ secrets.GEMINI_API_KEY }}
155
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
156
+ ROUTINE: autowork
157
+ TARGET_ISSUE: ${{ github.event.issue.number }}
158
+ ROUTINE_ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
159
+ SKILLS_PROMPT: ${{ steps.skills.outputs.skills_prompt }}
160
+ MODEL: ${{ steps.routine-config.outputs.model || 'gemini-3.8-flash-high' }}
161
+ PRINT_TIMEOUT: ${{ steps.routine-config.outputs.print_timeout || '60m' }}
162
+ GITHUB_SERVER_URL: ${{ github.server_url }}
163
+ GITHUB_REPOSITORY: ${{ github.repository }}
164
+ GITHUB_RUN_ID: ${{ github.run_id }}
165
+ run: |
166
+ PROMPT="You are the Autowork routine for this repository. An issue was assigned to this agent persona. Read and follow .github/prompts/autowork.md. ${SKILLS_PROMPT} Your target is issue #${TARGET_ISSUE}. You are in Targeted mode: work issue #${TARGET_ISSUE} directly."
167
+
168
+ set +e
169
+ node .github/scripts/run-with-loop-guard.js \
170
+ -p "$PROMPT" \
171
+ --model "$MODEL" \
172
+ --output-format text \
173
+ --print-timeout "$PRINT_TIMEOUT" \
174
+ --dangerously-skip-permissions 2>&1 | tee /tmp/agy.log
175
+ AGY_EXIT_CODE="${PIPESTATUS[0]}"
176
+ set -e
177
+
178
+ if [ "$AGY_EXIT_CODE" -ne 0 ]; then
179
+ if grep -qiE "Individual quota reached|quota reached" /tmp/agy.log; then
180
+ RESET_INFO=$(grep -oE "Resets in [^.]+" /tmp/agy.log | head -n 1 || echo "Resets in future window")
181
+ echo "QUOTA_PAUSED=true" >> "$GITHUB_ENV"
182
+ echo "QUOTA_RESET_INFO=$RESET_INFO" >> "$GITHUB_ENV"
183
+ echo "⚠️ LLM quota limit reached ($RESET_INFO). Pausing routine gracefully until next sweep."
184
+ exit 0
185
+ fi
186
+ exit "$AGY_EXIT_CODE"
187
+ fi
188
+
189
+ - name: Emit run summary
190
+ if: always()
191
+ run: |
192
+ if [ "$QUOTA_PAUSED" = "true" ]; then
193
+ echo "### ⏸️ Milestone: Routine Execution Quota-Paused" >> "$GITHUB_STEP_SUMMARY"
194
+ echo "- **Status**: LLM quota reached (\`${QUOTA_RESET_INFO}\`)" >> "$GITHUB_STEP_SUMMARY"
195
+ echo "- **Next Action**: Routine execution paused cleanly. Work will resume automatically on the next scheduled sweep after the quota window resets." >> "$GITHUB_STEP_SUMMARY"
196
+ else
197
+ REPORT_FILE=".jonah-fleet/run-report.md"
198
+ if [ -f "$REPORT_FILE" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
199
+ cat "$REPORT_FILE" >> "$GITHUB_STEP_SUMMARY"
200
+ fi
201
+ fi
202
+
203
+ - name: Emit Fleet Telemetry (Opt-in)
204
+ if: always()
205
+ env:
206
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
207
+ TELEMETRY_ENDPOINT: ${{ secrets.JONAH_FLEET_TELEMETRY_ENDPOINT }}
208
+ GITHUB_REPOSITORY: ${{ github.repository }}
209
+ GITHUB_RUN_ID: ${{ github.run_id }}
210
+ GITHUB_RUN_NUMBER: ${{ github.run_number }}
211
+ run: |
212
+ REPORT_FILE=".jonah-fleet/run-report.md"
213
+ if [ -f "$REPORT_FILE" ]; then
214
+ npx --yes jonah-fleet telemetry --emit --log "$REPORT_FILE" --endpoint "$TELEMETRY_ENDPOINT" || true
215
+ fi
216
+
217
+ - name: Verify Atomic Handoff Invariant (PR Existence Guard)
218
+ if: always()
219
+ env:
220
+ GH_TOKEN: ${{ github.token }}
221
+ run: |
222
+ REPORT_FILE=".jonah-fleet/run-report.md"
223
+ if [ -f "$REPORT_FILE" ]; then
224
+ if grep -q "Result.*SUCCESS" "$REPORT_FILE"; then
225
+ WORKED_BRANCH=$(grep -E '^\s*-\s*(Pushed branch|Branch):' "$REPORT_FILE" | head -n 1 | sed -E 's/.*`([^`]+)`.*/\1/')
226
+ if [ -n "$WORKED_BRANCH" ] && [[ "$WORKED_BRANCH" =~ (feat|fix)/ ]]; then
227
+ echo "Verifying PR existence for branch: $WORKED_BRANCH"
228
+ PR_COUNT=$(gh pr list --head "$WORKED_BRANCH" --state all --json number --jq 'length' 2>/dev/null || echo "0")
229
+ if [ "$PR_COUNT" -eq 0 ]; then
230
+ echo "::error::Atomic Handoff Invariant Violated: Branch '$WORKED_BRANCH' was implemented and pushed, but no pull request exists on GitHub!" >&2
231
+ exit 1
232
+ fi
233
+ echo "✓ Verified pull request exists on GitHub for branch: $WORKED_BRANCH"
234
+ fi
235
+ fi
236
+ fi
237
+
238
+ - name: Reconcile Routine Run Issue
239
+ if: always()
240
+ env:
241
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
242
+ ISSUE_NUMBER: ${{ steps.run-issue.outputs.issue_number }}
243
+ JOB_STATUS: ${{ job.status }}
244
+ EVENT_NAME: ${{ github.event_name }}
245
+ RUN_ID: ${{ github.run_id }}
246
+ SERVER_URL: ${{ github.server_url }}
247
+ REPOSITORY: ${{ github.repository }}
248
+ QUOTA_PAUSED: ${{ env.QUOTA_PAUSED }}
249
+ QUOTA_RESET_INFO: ${{ env.QUOTA_RESET_INFO }}
250
+ run: |
251
+ if [ -z "$ISSUE_NUMBER" ]; then
252
+ echo "No routine issue to reconcile."
253
+ exit 0
254
+ fi
255
+
256
+ if [ "$QUOTA_PAUSED" = "true" ]; then
257
+ RESET_STR="${QUOTA_RESET_INFO:-Resets in upcoming window}"
258
+ PAUSE_BODY="### ⏸️ Autonomous Routine Execution Quota-Paused
259
+ - **Routine**: \`autowork\`
260
+ - **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
261
+ - **Trigger**: \`${EVENT_NAME}\`
262
+ - **Status**: LLM quota reached (\`${RESET_STR}\`)
263
+ - **Next Action**: Routine execution paused cleanly. Work will resume automatically on the next scheduled sweep after the quota window resets.
264
+
265
+ ---
266
+ _Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
267
+
268
+ TEMP_BODY=$(mktemp)
269
+ echo "$PAUSE_BODY" > "$TEMP_BODY"
270
+ gh issue edit "$ISSUE_NUMBER" --body-file "$TEMP_BODY"
271
+ rm -f "$TEMP_BODY"
272
+
273
+ PAUSE_COMMENT=$(printf '%s\n' \
274
+ "### ⏸️ Milestone: Routine Execution Quota-Paused" \
275
+ "- **Routine**: \`autowork\`" \
276
+ "- **Status**: LLM quota reached (\`${RESET_STR}\`)" \
277
+ "- **Action Log**: [View GitHub Actions Run](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})" \
278
+ "- **Next Action**: Execution paused cleanly. The routine will resume automatically on the next scheduled sweep." \
279
+ "" \
280
+ "---" \
281
+ "_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_")
282
+ gh issue comment "$ISSUE_NUMBER" --body "$PAUSE_COMMENT" || true
283
+ gh issue edit "$ISSUE_NUMBER" --add-label "status:quota-paused" --remove-label "status:running"
284
+ gh issue close "$ISSUE_NUMBER" --reason completed
285
+ echo "⏸️ Routine run issue #$ISSUE_NUMBER closed with status:quota-paused."
286
+ exit 0
287
+ fi
288
+
289
+ REPORT_FILE=".jonah-fleet/run-report.md"
290
+
291
+ if [ -f "$REPORT_FILE" ]; then
292
+ BODY_CONTENT=$(cat "$REPORT_FILE")
293
+ else
294
+ BODY_CONTENT="### Autonomous Routine Execution Completed (${JOB_STATUS})
295
+ - **Routine**: \`autowork\`
296
+ - **Run ID**: [\`${RUN_ID}\`](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})
297
+ - **Trigger**: \`${EVENT_NAME}\`"
298
+ fi
299
+
300
+ FINAL_BODY="${BODY_CONTENT}
301
+
302
+ ---
303
+ _Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_"
304
+
305
+ TEMP_BODY=$(mktemp)
306
+ echo "$FINAL_BODY" > "$TEMP_BODY"
307
+ gh issue edit "$ISSUE_NUMBER" --body-file "$TEMP_BODY"
308
+ rm -f "$TEMP_BODY"
309
+
310
+ if [ "$JOB_STATUS" = "success" ]; then
311
+ gh issue edit "$ISSUE_NUMBER" --add-label "status:success" --remove-label "status:running"
312
+ gh issue close "$ISSUE_NUMBER" --reason completed
313
+ echo "✓ Routine run issue #$ISSUE_NUMBER closed as completed."
314
+ else
315
+ INTERRUPTION_BODY=$(printf '%s\n' \
316
+ "### ❌ Milestone: Run Interrupted / Failed" \
317
+ "- **Routine**: \`autowork\`" \
318
+ "- **Status**: Workflow job failed or timed out (\`${JOB_STATUS}\`)" \
319
+ "- **Step**: Actions execution halted before normal completion" \
320
+ "- **Action Log**: [View GitHub Actions Run](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})" \
321
+ "" \
322
+ "---" \
323
+ "_Generated by [Antigravity](${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID})_")
324
+ gh issue comment "$ISSUE_NUMBER" --body "$INTERRUPTION_BODY" || true
325
+ gh issue edit "$ISSUE_NUMBER" --add-label "status:failure,needs-attention" --remove-label "status:running"
326
+ echo "⚠️ Routine run issue #$ISSUE_NUMBER left open for triage (status: $JOB_STATUS)."
327
+ fi