Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions .claude/skills/coordinate/scripts/coord.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ files_of() { # issue
grep -v '^$' || true
}

in_scope() { # path, newline-separated Files entries -> true if an entry covers the path
# Mirrors coord.ps1: a wildcard match either way, or a prefix match on the
# entry with trailing '*' and '/' trimmed. String matching only (no regex, no
# pathname expansion), so it behaves the same with BSD and GNU tools.
local p="$1" a pre
while IFS= read -r a; do
[ -n "$a" ] || continue
pre="${a%"${a##*[!*]}"}"; pre="${pre%"${pre##*[!/]}"}"
# shellcheck disable=SC2053 # unquoted right-hand sides: glob matching on purpose
if [[ $p == $a || $a == $p || $p == "$pre"* ]]; then return 0; fi
done <<< "$2"
return 1
}

# Issue numbers referenced as #N anywhere in a body (unique, first-ref order).
referenced_issues() { # body
printf '%s' "$1" | grep -o '#[0-9]\+' | tr -d '#' | awk '!seen[$0]++' || true
Expand Down Expand Up @@ -292,8 +306,9 @@ cmd_claim() {
[ -n "$o" ] || continue
their="$(files_of "$o")"
[ -n "$their" ] || continue
clash="$(printf '%s\n' $scope | sort -u | while read -r p; do
printf '%s\n' $their | grep -qx "$p" && echo "$p"
clash="$(printf '%s\n' "$scope" | sort -u | while IFS= read -r p; do
# if/fi, not &&: a final non-match must not leave status 1 for set -e to trip on.
if printf '%s\n' "$their" | grep -qxF -- "$p"; then echo "$p"; fi
done)"
[ -n "$clash" ] || continue
if gh issue view "$o" --repo "$REPO" --json body --jq '.body // ""' | grep -q '^split:'; then
Expand All @@ -306,7 +321,7 @@ cmd_claim() {
[ -n "$common" ] && continue
die "#$N scope overlaps #$o on: $(printf '%s' "$clash" | paste -sd, -) - record a split on one of the issues or hand off ownership first"
done < <(gh issue list --repo "$REPO" --state open --limit 100 --json number,labels,body \
--jq '.[] | select(((.labels // []) | map(.name) | index("hub")) | not) | select(.number != '"$N"') | "\(.number)\t\(.body // "")"')
--jq '.[] | select(((.labels // []) | map(.name) | index("hub")) | not) | select(.number != '"$N"') | .number')
comment "$N" CLAIM "plan: ${OPT_plan:-_(none given)_}"$'\n'"eta: ${OPT_eta:-_(none given)_}"
gh issue edit "$N" --repo "$REPO" --add-assignee "@me" >/dev/null
set_status "$N" claimed
Expand Down Expand Up @@ -445,8 +460,8 @@ cmd_review() {
if [ -n "$allowed" ]; then
local undeclared p
undeclared="$(gh pr view "$prn" --repo "$REPO" --json files --jq '.files[].path' |
while read -r p; do
printf '%s\n' $allowed | grep -qF "$p" || echo "$p"
while IFS= read -r p; do
in_scope "$p" "$allowed" || echo "$p"
done)"
if [ -n "$undeclared" ]; then
die "PR #$prn touches paths outside the linked issues' Files scope: $(printf '%s' "$undeclared" | paste -sd, -) - update the issues' Files or drop the paths"
Expand Down
Loading