@biffo/cli 0.247.8 → 0.248.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/package.json +1 -1
- package/scripts/claim.sh +112 -8
package/package.json
CHANGED
package/scripts/claim.sh
CHANGED
|
@@ -91,6 +91,9 @@ set -u
|
|
|
91
91
|
|
|
92
92
|
ISSUE=""
|
|
93
93
|
REPO=""
|
|
94
|
+
HOLDER=""
|
|
95
|
+
RELEASE=""
|
|
96
|
+
HOLDER_MARK="claim-holder:"
|
|
94
97
|
CHECK_ONLY=""
|
|
95
98
|
GUARD_BRANCH=""
|
|
96
99
|
|
|
@@ -106,6 +109,15 @@ while [ $# -gt 0 ]; do
|
|
|
106
109
|
shift 2
|
|
107
110
|
;;
|
|
108
111
|
--check) CHECK_ONLY=1; shift ;;
|
|
112
|
+
--as)
|
|
113
|
+
HOLDER="${2:-}"
|
|
114
|
+
shift 2
|
|
115
|
+
;;
|
|
116
|
+
--release)
|
|
117
|
+
HOLDER="${2:-}"
|
|
118
|
+
RELEASE=1
|
|
119
|
+
shift 2
|
|
120
|
+
;;
|
|
109
121
|
--guard)
|
|
110
122
|
GUARD_BRANCH="${2:-}"
|
|
111
123
|
shift 2
|
|
@@ -128,6 +140,46 @@ gh_issue() { if [ -n "$REPO" ]; then gh issue "$@" --repo "$REPO"; else gh issue
|
|
|
128
140
|
gh_pr() { if [ -n "$REPO" ]; then gh pr "$@" --repo "$REPO"; else gh pr "$@"; fi; }
|
|
129
141
|
gh_label() { if [ -n "$REPO" ]; then gh label "$@" --repo "$REPO"; else gh label "$@"; fi; }
|
|
130
142
|
|
|
143
|
+
# Does the newest claim comment on $1 carry holder token $2? (#1279)
|
|
144
|
+
#
|
|
145
|
+
# Reads the LAST claim comment rather than any, so a re-claim by a different
|
|
146
|
+
# session supersedes an older one rather than both matching for ever. Returns
|
|
147
|
+
# non-zero when it cannot tell -- an unreadable comment list must never read as
|
|
148
|
+
# "yours", or the flag becomes a way to steal a claim by guessing.
|
|
149
|
+
claim_held_by() {
|
|
150
|
+
_c=$(gh_issue view "$1" --json comments \
|
|
151
|
+
--jq "[.comments[]? | select(.body | contains(\"$HOLDER_MARK\"))] | last | .body // \"\"" \
|
|
152
|
+
2>/dev/null) || return 1
|
|
153
|
+
[ -n "$_c" ] || return 1
|
|
154
|
+
case "$_c" in
|
|
155
|
+
*"$HOLDER_MARK$2"*) return 0 ;;
|
|
156
|
+
*) return 1 ;;
|
|
157
|
+
esac
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# This repo as `owner/name`, so a closing reference can be checked against it.
|
|
161
|
+
# GitHub records a CROSS-REPO closing reference in the same list as a local one
|
|
162
|
+
# -- tabsii-lms#43 closes tabsii-platform#553 -- so the number alone is not an
|
|
163
|
+
# answer, and matching on it reproduces the very defect this replaces (#1281).
|
|
164
|
+
#
|
|
165
|
+
# Resolved LAZILY, on first use. Computing it at load cost a `gh repo view` on
|
|
166
|
+
# every single push, including the overwhelmingly common case where `--guard`
|
|
167
|
+
# skips silently because the branch names no issue -- a guard that is meant to
|
|
168
|
+
# touch nothing was suddenly making a network call per push.
|
|
169
|
+
SLUG=""
|
|
170
|
+
SLUG_RESOLVED=""
|
|
171
|
+
repo_slug() {
|
|
172
|
+
if [ -z "$SLUG_RESOLVED" ]; then
|
|
173
|
+
SLUG_RESOLVED=1
|
|
174
|
+
if [ -n "$REPO" ]; then
|
|
175
|
+
SLUG="$REPO"
|
|
176
|
+
else
|
|
177
|
+
SLUG=$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || echo "")
|
|
178
|
+
fi
|
|
179
|
+
fi
|
|
180
|
+
printf '%s' "$SLUG"
|
|
181
|
+
}
|
|
182
|
+
|
|
131
183
|
# `git ls-remote --heads ""` fails outright ("fatal: bad repository ''") rather
|
|
132
184
|
# than falling back to the default remote — `${REPO:+url}` expands to an empty
|
|
133
185
|
# STRING ARGUMENT when $REPO is unset, not to no argument at all. That silently
|
|
@@ -144,11 +196,51 @@ remote_branches() {
|
|
|
144
196
|
}
|
|
145
197
|
|
|
146
198
|
LABEL=in-progress
|
|
199
|
+
|
|
200
|
+
# --- holder identity (#1279) -------------------------------------------------
|
|
201
|
+
#
|
|
202
|
+
# A claim used to record WHEN and WHO, and every session on a workstation claims
|
|
203
|
+
# under the same GitHub actor. So a delegated agent could not distinguish
|
|
204
|
+
# "my orchestrator claimed this for me" from "a stranger claimed it 90 seconds
|
|
205
|
+
# ago", and the safe reading is to stop. On 2026-08-04 four agents were
|
|
206
|
+
# dispatched onto pre-claimed issues; one ran the check first and correctly
|
|
207
|
+
# refused to start, producing nothing. Whether a delegate works or stalls
|
|
208
|
+
# depended on whether it happened to check before starting.
|
|
209
|
+
#
|
|
210
|
+
# `--as <token>` makes the claim answerable: an existing claim carrying the same
|
|
211
|
+
# token reads as YOUR claim and returns free. `--release <token>` refuses to
|
|
212
|
+
# clear somebody else's.
|
|
213
|
+
#
|
|
214
|
+
# The token is opaque and never a secret -- it identifies a session, not a
|
|
215
|
+
# person, and appears in a public comment.
|
|
216
|
+
|
|
147
217
|
TAKEN=0
|
|
148
218
|
REASONS=""
|
|
149
219
|
|
|
150
220
|
note() { REASONS="${REASONS} $1\n"; TAKEN=1; }
|
|
151
221
|
|
|
222
|
+
# --- --release <token>: only the holder clears it (#1279) --------------------
|
|
223
|
+
#
|
|
224
|
+
# A claim nobody can prove ownership of is one anybody can clear, and a stale
|
|
225
|
+
# label left behind by a crashed session is indistinguishable from a live one.
|
|
226
|
+
# Refusing a mismatched release is what makes the token worth recording.
|
|
227
|
+
if [ -n "$RELEASE" ]; then
|
|
228
|
+
if claim_held_by "$ISSUE" "$HOLDER"; then
|
|
229
|
+
gh_issue edit "$ISSUE" --remove-label "$LABEL" >/dev/null 2>&1 || {
|
|
230
|
+
echo "${RED}claim: could not remove the '$LABEL' label.${OFF}" >&2
|
|
231
|
+
exit 2
|
|
232
|
+
}
|
|
233
|
+
echo "${GREEN}Released.${OFF} ${DIM}(held by $HOLDER)${OFF}"
|
|
234
|
+
exit 0
|
|
235
|
+
fi
|
|
236
|
+
echo "${RED}claim: #$ISSUE is not held by '$HOLDER' — refusing to release it.${OFF}" >&2
|
|
237
|
+
echo "${DIM} Clearing somebody else's claim is how two sessions end up on one issue.${OFF}" >&2
|
|
238
|
+
echo "${DIM} If the claim is genuinely stale (AGENTS.md: over an hour, no branch, no PR),${OFF}" >&2
|
|
239
|
+
echo "${DIM} remove the label by hand and say so in a comment.${OFF}" >&2
|
|
240
|
+
exit 1
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
|
|
152
244
|
# --- --guard <branch>: the enforced pre-push gate -----------------------------
|
|
153
245
|
#
|
|
154
246
|
# Deliberately short-circuits before any of the four-signal machinery below —
|
|
@@ -171,9 +263,11 @@ if [ -n "$GUARD_BRANCH" ]; then
|
|
|
171
263
|
cannot_tell_reasons=""
|
|
172
264
|
|
|
173
265
|
# --- an open PR referencing the issue, excluding our own branch's PR --------
|
|
266
|
+
slug=$(repo_slug)
|
|
174
267
|
pr_err=$(mktemp)
|
|
175
|
-
|
|
176
|
-
|
|
268
|
+
slug=$(repo_slug)
|
|
269
|
+
open_prs=$(gh_pr list --state open --limit 100 --json number,headRefName,closingIssuesReferences \
|
|
270
|
+
--jq "[.[] | select(([.closingIssuesReferences[]? | select(.number == $guard_issue and ((.repository.owner.login + \"/\" + .repository.name) == \"$slug\"))] | length > 0) or (.headRefName | test(\"(^|[^0-9])$guard_issue([^0-9]|\$)\")))] | .[] | select(.headRefName != \"$GUARD_BRANCH\") | \"#\(.number) \(.headRefName)\"" \
|
|
177
271
|
2>"$pr_err")
|
|
178
272
|
pr_status=$?
|
|
179
273
|
pr_err_text=$(cat "$pr_err")
|
|
@@ -265,7 +359,15 @@ fi
|
|
|
265
359
|
case ",$labels," in
|
|
266
360
|
*",$LABEL,"*)
|
|
267
361
|
updated=$(gh_issue view "$ISSUE" --json updatedAt --jq .updatedAt 2>/dev/null)
|
|
268
|
-
|
|
362
|
+
# Whose claim is it? (#1279) A claim carrying OUR token is not a collision --
|
|
363
|
+
# it is the orchestrator that dispatched us. Without this a delegated agent
|
|
364
|
+
# cannot tell its own reservation from a stranger's and correctly refuses to
|
|
365
|
+
# start, which is the failure this flag exists to remove.
|
|
366
|
+
if [ -n "$HOLDER" ] && claim_held_by "$ISSUE" "$HOLDER"; then
|
|
367
|
+
echo "${DIM}label carries '$LABEL', held by ${HOLDER} — that is you${OFF}"
|
|
368
|
+
else
|
|
369
|
+
note "${YELLOW}label${OFF} carries '$LABEL' (issue last updated $updated)"
|
|
370
|
+
fi
|
|
269
371
|
;;
|
|
270
372
|
esac
|
|
271
373
|
|
|
@@ -275,8 +377,9 @@ esac
|
|
|
275
377
|
# Matches the issue number in the title or body as a whole number, so #118 does
|
|
276
378
|
# not match #1188.
|
|
277
379
|
|
|
278
|
-
|
|
279
|
-
|
|
380
|
+
slug=$(repo_slug)
|
|
381
|
+
open_prs=$(gh_pr list --state open --limit 100 --json number,headRefName,closingIssuesReferences \
|
|
382
|
+
--jq "[.[] | select(([.closingIssuesReferences[]? | select(.number == $ISSUE and ((.repository.owner.login + \"/\" + .repository.name) == \"$slug\"))] | length > 0) or (.headRefName | test(\"(^|[^0-9])$ISSUE([^0-9]|\$)\")))] | .[] | \"#\(.number) \(.headRefName)\"" 2>/dev/null)
|
|
280
383
|
|
|
281
384
|
if [ -n "$open_prs" ]; then
|
|
282
385
|
printf '%s\n' "$open_prs" | while IFS= read -r pr; do
|
|
@@ -305,8 +408,9 @@ fi
|
|
|
305
408
|
# Not "taken" — "possibly already done". #1165 was built and merged in three
|
|
306
409
|
# minutes; the only trace afterwards is a merged PR.
|
|
307
410
|
|
|
308
|
-
|
|
309
|
-
|
|
411
|
+
slug=$(repo_slug)
|
|
412
|
+
merged=$(gh_pr list --state merged --limit 30 --json number,mergedAt,closingIssuesReferences \
|
|
413
|
+
--jq "[.[] | select(([.closingIssuesReferences[]? | select(.number == $ISSUE and ((.repository.owner.login + \"/\" + .repository.name) == \"$slug\"))] | length > 0))] | .[0] | select(. != null) | \"#\(.number) merged \(.mergedAt[0:16])\"" 2>/dev/null)
|
|
310
414
|
|
|
311
415
|
if [ -n "$merged" ]; then
|
|
312
416
|
echo " ${YELLOW}merged${OFF} $merged"
|
|
@@ -361,7 +465,7 @@ gh_issue edit "$ISSUE" --add-label "$LABEL" >/dev/null 2>&1 || {
|
|
|
361
465
|
exit 2
|
|
362
466
|
}
|
|
363
467
|
gh_issue comment "$ISSUE" \
|
|
364
|
-
--body "Claimed at $(date -u +%FT%TZ) by \`$(git config user.name 2>/dev/null || echo agent)
|
|
468
|
+
--body "Claimed at $(date -u +%FT%TZ) by \`$(git config user.name 2>/dev/null || echo agent)\`.${HOLDER:+ ${HOLDER_MARK}${HOLDER}} Release it — remove the label — on merge, or if you stop." \
|
|
365
469
|
>/dev/null 2>&1
|
|
366
470
|
|
|
367
471
|
echo "${GREEN}Claimed.${OFF}"
|