@erclx/aitk 3.11.0 → 3.11.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-address-review/SKILL.md +10 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +4 -1
- package/claude/skills/claude-orchestrate/scripts/poll.sh +59 -13
- package/claude/skills/claude-pr-review/SKILL.md +3 -1
- package/package.json +1 -1
|
@@ -194,3 +194,13 @@ Rebased PR #<number> onto origin/main. <N> files resolved by hand, <N> rebuilt b
|
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
Do not merge. Hand back to the orchestrator for re-review.
|
|
197
|
+
|
|
198
|
+
## Post-review findings
|
|
199
|
+
|
|
200
|
+
Not everything worth reaching the reviewing session surfaces inside the numbered flow above. A worker that settled a risk, filed a follow-up, or found something else worth reporting after Step 7 already closed the review posts it directly rather than waiting on a review pass that has nothing left to trigger it. Write the body the way Step 6 writes a reply: load `write-human` for voice, follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for the banned words, and run the `${CLAUDE_SKILL_DIR}/../../standards/publish.md` scan before posting.
|
|
201
|
+
|
|
202
|
+
Open with `## Post-review findings` rather than `## Review response`, since nothing on the thread is being answered. `claude-pr-review` states the full heading set this belongs to and routes it the same as a response: `claude-orchestrate`'s poll picks it up and sends the reviewing session back for a pass. Close the body with `🤖 Addressed by Claude Code` on its own line, matching the reply's footer.
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
gh pr comment <number> --body-file .claude/.tmp/address-review/reply-<number>.md
|
|
206
|
+
```
|
|
@@ -36,6 +36,7 @@ Poll GitHub for pull request movement by running <POLL_SCRIPT>, then act on what
|
|
|
36
36
|
- SEEN: report it and stop. A pass already covers that head, whether it arrived out of band or before the poll first saw the pull request, so no review follows.
|
|
37
37
|
- STALLED: read the last pass and report what it carried. The pass has sat open for hours with nothing following it, so a worker mid-task is already ruled out and the dispatch either never went out or the session holding it is gone. Confirm and re-send it under the dispatch rule below, whatever grades the pass carried. Do not re-run a review to correct the heading, since a pass on an unchanged head with no response behind it stops by design.
|
|
38
38
|
- CONFLICT: report it and stop. The branch owner rebases, not this session.
|
|
39
|
+
- UNMATCHED: report it and stop. A comment posted under a heading outside the known set reaches nobody automatically, so a person decides whether to answer it by hand or the set needs a sixth heading.
|
|
39
40
|
- GONE: report it, then sweep the board by invoking the aitk:claude-orchestrate skill and following its queue-refill sweep.
|
|
40
41
|
- A line starting `poll:`: report it verbatim and treat that pull request as unread this run. It is a failed query, not a state.
|
|
41
42
|
- Nothing changed: say exactly "No movement." and nothing else.
|
|
@@ -51,7 +52,9 @@ The script exits non-zero and classifies nothing when the open pull request list
|
|
|
51
52
|
|
|
52
53
|
The baseline lives at `.claude/.tmp/pr-poll/baseline.txt` under the main worktree root and is per-machine. A first run against a board already in flight reports each open pull request once before it settles.
|
|
53
54
|
|
|
54
|
-
The
|
|
55
|
+
The five review headings the script matches are written by `claude-pr-review` and `claude-address-review`, and the whole set is stated once in the first. A project that posts its reviews under different headings edits the jq filters in the script to match, or every pull request reads as never reviewed.
|
|
56
|
+
|
|
57
|
+
`UNMATCHED` is what a heading outside the five reaches, carried the same way `RESPONSE` is: a rising count against the baseline is what is new to this script, and the message names the heading so a person can tell whether to answer it by hand or add it to the set. It fires on a tracked pull request only, since a first sighting reports `SEEN` or `OPENED` and takes whatever count already sits on the thread as its starting baseline rather than flagging history the poll never watched.
|
|
55
58
|
|
|
56
59
|
`RESPONSE` is qualified by recency as well as by count, so it means a reply the last pass has not already answered rather than one this script has not seen before. A worker answers a finding and the reviewing session posts its close-out seconds later, which is the ordinary handback rather than a race, so a count on its own reported the answered thread on the next run and the re-review it routed to stopped at its own guard. The state now fires when the newest reply is stamped later than the last pass, and on a pull request carrying no pass at all, which is a worker talking to nobody and worth the turn. A reply landing inside the same second as the pass is dropped, matching the comparison `claude-pr-review` makes on the same two fields.
|
|
57
60
|
|
|
@@ -32,16 +32,19 @@ if [ -z "$BASE_REF" ]; then
|
|
|
32
32
|
fi
|
|
33
33
|
BASE_BRANCH="${BASE_REF#origin/}"
|
|
34
34
|
|
|
35
|
-
# These
|
|
36
|
-
# writes `## Review` and `## Review closed`, and
|
|
37
|
-
#
|
|
35
|
+
# These five strings are owned elsewhere and pinned here. `claude-pr-review`
|
|
36
|
+
# writes `## Review` and `## Review closed`, and states the full five-heading
|
|
37
|
+
# set once, beside the threshold it already states once. `claude-address-review`
|
|
38
|
+
# writes `## Review response`, `## Rebase`, and `## Post-review findings`, the
|
|
39
|
+
# last for a finding a worker produces after a close-out rather than in answer
|
|
40
|
+
# to one already on the thread. All three surfaces ship separately, so a
|
|
38
41
|
# heading added in either skill breaks a test here that no check reaches across.
|
|
39
42
|
#
|
|
40
|
-
# Both families match on the first line alone so the
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
43
|
+
# Both families match on the first line alone so the tests stay symmetric. The
|
|
44
|
+
# reply family carries `## Rebase` and `## Post-review findings` beside
|
|
45
|
+
# `## Review response` because neither answers a comment already on the thread,
|
|
46
|
+
# which is why both were kept outside the `## Review` family rather than folded
|
|
47
|
+
# into it.
|
|
45
48
|
JQ_LAST_REVIEWED_HEAD='
|
|
46
49
|
[ .reviews[]
|
|
47
50
|
| select((.body // "") | split("\n")[0] | rtrimstr("\r")
|
|
@@ -55,13 +58,37 @@ JQ_LAST_REVIEWED_HEAD='
|
|
|
55
58
|
JQ_REPLY_STATE='
|
|
56
59
|
[ .comments[]
|
|
57
60
|
| select((.body // "") | split("\n")[0] | rtrimstr("\r")
|
|
58
|
-
| . == "## Review response" or . == "## Rebase"
|
|
61
|
+
| . == "## Review response" or . == "## Rebase"
|
|
62
|
+
or . == "## Post-review findings")
|
|
59
63
|
] as $replies
|
|
60
64
|
| ($replies | length | tostring)
|
|
61
65
|
+ " "
|
|
62
66
|
+ ([ $replies[] | .createdAt // empty | fromdateiso8601 | floor ]
|
|
63
67
|
| max // 0 | tostring)
|
|
64
68
|
'
|
|
69
|
+
# A comment matching neither family above is the gap this filter exists to
|
|
70
|
+
# surface rather than absorb: a worker inventing a sixth heading used to reach
|
|
71
|
+
# this script as silence, indistinguishable from no comment at all. The count
|
|
72
|
+
# is read the same way the reply count is, a rising value against the baseline
|
|
73
|
+
# being new to this script, and the newest heading's text rides along for the
|
|
74
|
+
# report. It carries its spaces intact rather than encoded, since it is the
|
|
75
|
+
# last field on both sides of the pipe: `${unmatched_state#* }` below strips
|
|
76
|
+
# only the first space, and `read -r` further down hands its last named
|
|
77
|
+
# variable the rest of the line whole. Neither reads a heading's own spaces
|
|
78
|
+
# as a field separator, so a heading round-trips verbatim into the report a
|
|
79
|
+
# person reads when deciding whether to answer it by hand.
|
|
80
|
+
JQ_UNMATCHED_STATE='
|
|
81
|
+
[ .comments[]
|
|
82
|
+
| (.body // "") | split("\n")[0] | rtrimstr("\r")
|
|
83
|
+
| select(startswith("## "))
|
|
84
|
+
| select(. != "## Review" and . != "## Review closed"
|
|
85
|
+
and . != "## Review response" and . != "## Rebase"
|
|
86
|
+
and . != "## Post-review findings")
|
|
87
|
+
] as $unclassified
|
|
88
|
+
| ($unclassified | length | tostring)
|
|
89
|
+
+ " "
|
|
90
|
+
+ (($unclassified | last) // "none")
|
|
91
|
+
'
|
|
65
92
|
|
|
66
93
|
# `claude-pr-review` states the threshold and posts `## Review` exactly when a
|
|
67
94
|
# pass carries a finding, so the heading of the last review is what says whether
|
|
@@ -176,6 +203,11 @@ snapshot() {
|
|
|
176
203
|
# Three space-separated fields, so the line below carries them as its own
|
|
177
204
|
# sixth, seventh, and eighth rather than needing a split.
|
|
178
205
|
review_state=$(jq -r "$JQ_LAST_REVIEW_STATE" <<<"$payload")
|
|
206
|
+
# Split the same way as the reply state, carried as the line's tenth and
|
|
207
|
+
# eleventh fields.
|
|
208
|
+
unmatched_state=$(jq -r "$JQ_UNMATCHED_STATE" <<<"$payload")
|
|
209
|
+
unmatched_count=${unmatched_state%% *}
|
|
210
|
+
unmatched_heading=${unmatched_state#* }
|
|
179
211
|
|
|
180
212
|
# `gh pr view --json mergeable` reports UNKNOWN until GitHub finishes
|
|
181
213
|
# computing it, which is exactly when a poll asks. merge-tree answers
|
|
@@ -194,7 +226,7 @@ snapshot() {
|
|
|
194
226
|
merges=conflict
|
|
195
227
|
fi
|
|
196
228
|
|
|
197
|
-
echo "$n $head ${prior:-none} $resp $merges $review_state $reply_at"
|
|
229
|
+
echo "$n $head ${prior:-none} $resp $merges $review_state $reply_at $unmatched_count $unmatched_heading"
|
|
198
230
|
done
|
|
199
231
|
}
|
|
200
232
|
|
|
@@ -211,7 +243,7 @@ CHANGED=0
|
|
|
211
243
|
# would fire on every later run and the board would never read "No movement."
|
|
212
244
|
FINAL=""
|
|
213
245
|
|
|
214
|
-
while read -r n head prior resp merges heading age pass_at reply_at; do
|
|
246
|
+
while read -r n head prior resp merges heading age pass_at reply_at unmatched_count unmatched_heading; do
|
|
215
247
|
[ -z "$n" ] && continue
|
|
216
248
|
state=$heading
|
|
217
249
|
old=$(grep "^$n " "$STATE" || true)
|
|
@@ -229,7 +261,7 @@ while read -r n head prior resp merges heading age pass_at reply_at; do
|
|
|
229
261
|
echo "OPENED #$n at ${head:0:7}, $merges against $BASE_BRANCH"
|
|
230
262
|
fi
|
|
231
263
|
CHANGED=1
|
|
232
|
-
FINAL+="$n $head $prior $resp $merges $state $
|
|
264
|
+
FINAL+="$n $head $prior $resp $merges $state $unmatched_count"$'\n'
|
|
233
265
|
continue
|
|
234
266
|
fi
|
|
235
267
|
old_head=$(echo "$old" | cut -d' ' -f2)
|
|
@@ -240,6 +272,7 @@ while read -r n head prior resp merges heading age pass_at reply_at; do
|
|
|
240
272
|
# age decides the rest, so the first run after an upgrade needs no history and
|
|
241
273
|
# classifies a thread already past the threshold rather than waiting a run.
|
|
242
274
|
old_heading=$(echo "$old" | cut -d' ' -f6)
|
|
275
|
+
old_unmatched=$(echo "$old" | cut -d' ' -f7)
|
|
243
276
|
|
|
244
277
|
# A conflict arrives from the base moving, not from the branch, so it is
|
|
245
278
|
# reported on the transition rather than only when the head changes.
|
|
@@ -248,6 +281,19 @@ while read -r n head prior resp merges heading age pass_at reply_at; do
|
|
|
248
281
|
CHANGED=1
|
|
249
282
|
fi
|
|
250
283
|
|
|
284
|
+
# A rising count is what is new to this script, the same test RESPONSE
|
|
285
|
+
# below runs against the reply family. It fires on a tracked pull request
|
|
286
|
+
# only: a first sighting reports SEEN or OPENED and takes whatever count
|
|
287
|
+
# already sits on the thread as its starting baseline rather than flagging
|
|
288
|
+
# history retroactively. A carried line supplies neither, since
|
|
289
|
+
# carry_forward re-echoes the shorter baseline shape rather than a full
|
|
290
|
+
# snapshot line, so both sides default to zero the way old_unmatched
|
|
291
|
+
# already does.
|
|
292
|
+
if [ "${unmatched_count:-0}" -gt "${old_unmatched:-0}" ]; then
|
|
293
|
+
echo "UNMATCHED #$n posted under '$unmatched_heading'"
|
|
294
|
+
CHANGED=1
|
|
295
|
+
fi
|
|
296
|
+
|
|
251
297
|
if [ "$head" != "$old_head" ]; then
|
|
252
298
|
if [ "$prior" = "none" ]; then
|
|
253
299
|
echo "MOVED #$n -> ${head:0:7}, never reviewed"
|
|
@@ -312,7 +358,7 @@ while read -r n head prior resp merges heading age pass_at reply_at; do
|
|
|
312
358
|
# re-enters next run and STALLED oscillates instead of reporting once.
|
|
313
359
|
state=reported
|
|
314
360
|
fi
|
|
315
|
-
FINAL+="$n $head $prior $resp $merges $state"$'\n'
|
|
361
|
+
FINAL+="$n $head $prior $resp $merges $state $unmatched_count"$'\n'
|
|
316
362
|
done <<<"$NEW"
|
|
317
363
|
|
|
318
364
|
while read -r n _rest; do
|
|
@@ -170,7 +170,9 @@ A minor the dispatched worker declines is what needs a surface that survives the
|
|
|
170
170
|
|
|
171
171
|
Read the state off the most recent review comment rather than off the presence of a closed one. A close-out does not close the pull request, so a commit pushed after it gets its own pass, and that pass reopens the review under `## Review` when it raises a finding of any grade.
|
|
172
172
|
|
|
173
|
-
Both of this skill's headings anchor as a section distinct from human threads.
|
|
173
|
+
Both of this skill's headings anchor as a section distinct from human threads, and neither invents beyond what the whole set already states. That set is five headings across two families, stated here once so `claude-orchestrate`'s poll and every reply-posting skill cite it rather than carry a copy. The review family, `## Review` and `## Review closed`, belongs to this skill alone, and the reply family, `## Review response`, `## Rebase`, and `## Post-review findings`, belongs to `claude-address-review`.
|
|
174
|
+
|
|
175
|
+
The first reply heading answers a finding this skill posted, the second reports a stale branch resolved without one, and the third carries a finding a worker produces after a close-out rather than in answer to one already on the thread, since a finding produced late is still a finding. A comment posted under a heading outside these five reaches the poll as unclassified rather than as silence, so an invented sixth heading is a gap the next run reports instead of one it repeats. Do not append the PR number, which GitHub already renders above the comment.
|
|
174
176
|
|
|
175
177
|
Name the scope in every summary line after the first pass, since a reader cannot otherwise tell a narrow read from a full one. When the fallback in Step 2 fired, replace the commit count with `Re-reviewed the full change, the prior pass's commit is no longer on the branch`.
|
|
176
178
|
|