Files
clawhub/.github/workflows/update-skills.yml
T
2026-08-05 10:24:35 +08:00

179 lines
6.0 KiB
YAML

name: Update skills
on:
schedule:
- cron: "17 15 * * *"
workflow_dispatch:
permissions:
contents: write
concurrency:
group: update-skills
cancel-in-progress: false
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
- name: Update project skills
run: |
set -euo pipefail
# The committed .agents directory keeps updates in universal project scope.
output="$(npx --yes skills@1.5.16 update --project --yes 2>&1)"
# Headless agent detection emits extra mirrors; .agents is canonical here.
rm -rf agent/skills .claude/skills
rmdir agent .claude 2>/dev/null || true
printf '%s\n' "$output"
if grep -q "Failed to update" <<<"$output"; then
echo "One or more skills failed to update." >&2
exit 1
fi
- name: Refresh changed skill provenance
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
shopt -s nullglob
for provenance in .agents/skills/*.provenance.json; do
changed=false
while IFS= read -r skill; do
if ! git diff --quiet -- ".agents/skills/${skill}"; then
changed=true
break
fi
done < <(jq -r '.skills | keys[]' "$provenance")
if [[ "$changed" != "true" ]]; then
continue
fi
repository="$(jq -r '.repository' "$provenance")"
slug="${repository#https://github.com/}"
slug="${slug%.git}"
resolved_commit="$(gh api "repos/${slug}/commits/HEAD" --jq .sha)"
temporary="$(mktemp)"
jq --arg commit "$resolved_commit" \
'.resolvedCommit = $commit' \
"$provenance" > "$temporary"
mv "$temporary" "$provenance"
done
- name: Stage managed skill changes
id: changes
run: |
set -euo pipefail
git add skills-lock.json
while IFS= read -r skill; do
git add ".agents/skills/${skill}"
done < <(jq -r '.skills | keys[]' skills-lock.json)
shopt -s nullglob
provenance=(.agents/skills/*.provenance.json)
if (( ${#provenance[@]} )); then
git add "${provenance[@]}"
fi
unexpected="$(
git status --porcelain=v1 --untracked-files=all \
| awk 'substr($0, 1, 2) == "??" || substr($0, 2, 1) != " "'
)"
if [[ -n "$unexpected" ]]; then
echo "Unexpected unstaged paths changed:"
echo "$unexpected"
exit 1
fi
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Commit and push update branch
if: steps.changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
branch="automation/update-skills"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git fetch origin "refs/heads/${branch}:refs/remotes/origin/${branch}" || true
git switch -C "$branch"
git commit -m "chore: update skills"
git push --force-with-lease origin "$branch"
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
continue-on-error: true
if: steps.changes.outputs.changed == 'true'
with:
app-id: "2729701"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-pull-requests: write
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token-fallback
continue-on-error: true
if: steps.changes.outputs.changed == 'true' && steps.app-token.outcome == 'failure'
with:
app-id: "2971289"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY_FALLBACK }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-pull-requests: write
- name: Open or update pull request
if: steps.changes.outputs.changed == 'true'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token || steps.app-token-fallback.outputs.token }}
run: |
set -euo pipefail
if [[ -z "${GH_TOKEN:-}" ]]; then
echo "::error::Unable to create a Barnacle GitHub App token. Check the primary GH_APP_PRIVATE_KEY and fallback GH_APP_PRIVATE_KEY_FALLBACK credentials and their pull-request permissions." >&2
exit 1
fi
branch="automation/update-skills"
body="$RUNNER_TEMP/update-skills-pr.md"
{
echo "## Summary"
echo
echo "- refresh all project skills tracked by skills-lock.json"
echo "- update committed skill content, lockfile hashes, and existing provenance metadata"
echo
echo "Generated by the daily project skill updater."
} > "$body"
number="$(
gh pr list \
--head "$branch" \
--state open \
--json number \
--jq '.[0].number // empty'
)"
if [[ -n "$number" ]]; then
gh pr edit "$number" \
--title "chore: update project skills" \
--body-file "$body"
else
gh pr create \
--base main \
--head "$branch" \
--title "chore: update project skills" \
--body-file "$body"
fi