@rtorcato/repo-tooling 3.22.0 → 3.22.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "3.22.0",
3
+ "version": "3.22.1",
4
4
  "description": "One CLI to scaffold, audit and fix your repo's whole toolchain — linting, tests, commits, releases & CI.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -409,8 +409,11 @@ it behind a hidden marker and upsert:
409
409
 
410
410
  ```bash
411
411
  MARKER='<!-- ai-issue-loop:decision -->'
412
+ ME=$(gh api user --jq .login) # the identity every loop agent posts as
412
413
  ID=$(gh api "repos/$OWNER_REPO/issues/<N>/comments" \
413
- --jq "[.[] | select((.body // \"\") | startswith(\"$MARKER\"))] | .[0].id // empty")
414
+ | jq -r --arg me "$ME" --arg marker "$MARKER" \
415
+ '[.[] | select(.user.login == $me and ((.body // "") | startswith($marker)))]
416
+ | .[0].id // empty')
414
417
  if [ -n "$ID" ]; then
415
418
  gh api -X PATCH "repos/$OWNER_REPO/issues/comments/$ID" -f body="$MARKER
416
419
  $TEXT"
@@ -420,10 +423,24 @@ $TEXT"
420
423
  fi
421
424
  ```
422
425
 
426
+ **The author gate is the same one Pass 3's verdict read uses, and for the same
427
+ reason.** Anyone can comment on a public PR, so selecting by marker prefix alone
428
+ lets a stranger who posts `<!-- ai-issue-loop:decision -->` first own the slot
429
+ forever: `.[0]` takes the *oldest* match, the token has repo-write so the `PATCH`
430
+ succeeds, and every decision this loop ever reaches lands inside a
431
+ stranger-authored comment while the loop never posts one of its own. `.user.login`
432
+ against `gh api user`, not `author_association`, for the reason spelled out in
433
+ Pass 3.
434
+
423
435
  `// empty` is load-bearing: `.[0].id` on an empty array is `null`, which `jq -r`
424
436
  prints as the four characters `null` — a non-empty string that passes `[ -n ]` and
425
437
  sends the `PATCH` to comment id `null`. The upsert would then never post anything,
426
- silently, which is the one failure mode worse than duplicates.
438
+ silently, which is the one failure mode worse than duplicates. `(.body // "")` is
439
+ load-bearing for the mirror-image reason: a null body throws, aborting the filter
440
+ and emptying `ID`, which re-enters the duplicate-comment branch this whole section
441
+ exists to prevent. Both values come in through `--arg` rather than shell
442
+ interpolation, so the marker and login are jq *data* and cannot be parsed as
443
+ filter syntax.
427
444
 
428
445
  One comment per PR, edited in place, so the timeline shows the *current* reason
429
446
  rather than a log of every tick that ever ran. What it says — and whether to say
@@ -1185,9 +1202,19 @@ does not stack duplicates:
1185
1202
 
1186
1203
  ```bash
1187
1204
  gh issue view <N> --json comments \
1188
- --jq '[.comments[] | select(.body | startswith("🤖 *Automated — triage"))] | length'
1205
+ | jq -r --arg me "$(gh api user --jq .login)" \
1206
+ '[.comments[]
1207
+ | select(.author.login == $me and ((.body // "") | startswith("🤖 *Automated — triage")))]
1208
+ | length'
1189
1209
  ```
1190
1210
 
1211
+ Gated on the loop's own login for the same reason as the decision upsert above,
1212
+ inverted: anyone can comment on a public issue, so ungated a stranger who opens
1213
+ with that header *suppresses* the decline comment and the issue is left labelled
1214
+ with nothing on the timeline saying why. `.author.login` here, not `.user.login`
1215
+ — `gh issue view --json` is GraphQL and names the field differently from the REST
1216
+ payload the upsert reads.
1217
+
1191
1218
  Take the first `slots` issues. For each, **claim it first** so a concurrent tick
1192
1219
  can't double-pick:
1193
1220