From b2e46ee8db94695f7672a70ebfc1e4d371a937e4 Mon Sep 17 00:00:00 2001 From: Victor Kuznetsov Date: Fri, 11 Sep 2026 10:19:25 -0700 Subject: [PATCH] Automate Space pin and lengthen the ComfyUI waiter --- .github/workflows/distribute.yml | 135 ++++++++++++++++++++++++++++++- docs/agent-skill.md | 59 ++++++++------ docs/release-and-distribution.md | 37 ++++++--- tests/test_release_workflows.py | 13 +++ 4 files changed, 206 insertions(+), 38 deletions(-) diff --git a/.github/workflows/distribute.yml b/.github/workflows/distribute.yml index e768e2a..5e5e14e 100644 --- a/.github/workflows/distribute.yml +++ b/.github/workflows/distribute.yml @@ -114,10 +114,100 @@ jobs: needs: resolve runs-on: ubuntu-latest steps: - - name: Factory-rebuild the HuggingFace Space + - name: Bump the Space pin, then factory-rebuild env: + GH_TOKEN: ${{ secrets.RAIW_HF_SPACE_TOKEN }} HF_TOKEN: ${{ secrets.HF_TOKEN }} + VERSION: ${{ needs.resolve.outputs.version }} run: | + set -euo pipefail + repo=wiltodelta/raiw-hf-space + workflow=pin-library.yml + + if [ -z "${GH_TOKEN:-}" ]; then + echo "RAIW_HF_SPACE_TOKEN secret is not set; skipping the pin bump." + else + dispatched_at=$(date -u +%Y-%m-%dT%H:%M:%SZ) + gh workflow run "$workflow" \ + --repo "$repo" \ + --ref main \ + --raw-field library_version="$VERSION" + + run_id="" + for attempt in $(seq 1 30); do + run_id=$( + gh run list \ + --repo "$repo" \ + --workflow "$workflow" \ + --event workflow_dispatch \ + --limit 10 \ + --json databaseId,createdAt \ + | python3 -c ' + import json + import sys + + dispatched_at = sys.argv[1] + runs = json.load(sys.stdin) + print(next( + (run["databaseId"] for run in runs if run["createdAt"] >= dispatched_at), + "", + )) + ' "$dispatched_at" + ) + if [ -n "$run_id" ]; then + break + fi + echo "Space pin run not visible yet (attempt $attempt), waiting..." + sleep 2 + done + if [ -z "$run_id" ]; then + echo "::error::The dispatched Space pin run did not appear" + exit 1 + fi + for attempt in $(seq 1 180); do + read -r status conclusion <<< "$( + gh run view "$run_id" \ + --repo "$repo" \ + --json status,conclusion \ + --jq '[.status, (.conclusion // "")] | @tsv' + )" + if [ "$status" = "completed" ]; then + if [ "$conclusion" = "success" ]; then + echo "Space pin run $run_id succeeded" + break + fi + echo "::error::Space pin run $run_id completed with $conclusion" + exit 1 + fi + echo "Space pin run $run_id is $status (attempt $attempt), waiting..." + sleep 5 + done + if [ "${status:-}" != "completed" ]; then + echo "::error::Space pin run $run_id did not finish in time" + exit 1 + fi + + echo "Waiting for the Space requirements pin to show $VERSION..." + pinned="" + for attempt in $(seq 1 40); do + reqs=$(curl -fsSL \ + "https://huggingface.co/spaces/wiltodelta/remove-ai-watermarks/raw/main/requirements.txt" \ + || true) + pinned=$(printf '%s\n' "$reqs" \ + | sed -n 's/^remove-ai-watermarks==\([0-9][0-9a-zA-Z.]*\).*/\1/p' \ + | head -1) + echo " attempt $attempt: Space pin=$pinned" + if [ "$pinned" = "$VERSION" ]; then + break + fi + sleep 15 + done + if [ "$pinned" != "$VERSION" ]; then + echo "::error::Space requirements.txt still pinned to ${pinned:-}, not $VERSION" + exit 1 + fi + fi + python3 -m pip install --quiet huggingface_hub python3 - <<'PY' import os @@ -217,7 +307,12 @@ jobs: exit 1 fi - for attempt in $(seq 1 180); do + # 0.40.0's node sync finished after this waiter: 180 * 5s is 15 min, + # and the node suite plus registry upload ran longer. Keep the + # workflow wait, then accept a registry row for this library version + # so a late-but-published node is not reported as a missing release. + version="${{ needs.resolve.outputs.version }}" + for attempt in $(seq 1 360); do read -r status conclusion <<< "$( gh run view "$run_id" \ --repo "$repo" \ @@ -235,5 +330,39 @@ jobs: echo "ComfyUI sync run $run_id is $status (attempt $attempt), waiting..." sleep 5 done - echo "::error::ComfyUI sync run $run_id did not finish in time" + echo "ComfyUI sync run $run_id did not finish in time; checking the registry." + python3 -m pip install --quiet packaging + if curl -fsSL "https://api.comfy.org/nodes/remove-ai-watermarks/versions" \ + | VERSION="$version" python3 -c ' + import json, os, sys + from packaging.requirements import InvalidRequirement, Requirement + from packaging.utils import canonicalize_name + from packaging.version import Version + version = os.environ["VERSION"] + target = Version(version) + def requires_release(value): + try: + requirement = Requirement(value) + except InvalidRequirement: + return False + return ( + canonicalize_name(requirement.name) == "remove-ai-watermarks" + and requirement.url is None + and requirement.marker is None + and target in requirement.specifier + and any(s.operator == ">=" and Version(s.version) == target for s in requirement.specifier) + ) + matches = [ + v for v in json.load(sys.stdin) + if any(requires_release(d) for d in (v.get("dependencies") or [])) + ] + if not matches: + sys.exit(1) + newest = max(matches, key=lambda v: v.get("createdAt") or "") + print("%s %s" % (newest.get("version"), newest.get("status"))) + '; then + echo "Registry already lists a node for $version; the wait timed out after publish." + exit 0 + fi + echo "::error::ComfyUI sync run $run_id did not finish in time and the registry has no node for $version" exit 1 diff --git a/docs/agent-skill.md b/docs/agent-skill.md index 470f02a..4bef4fe 100644 --- a/docs/agent-skill.md +++ b/docs/agent-skill.md @@ -49,10 +49,14 @@ Do these in order after the skill is on the default branch. 4. **Awesome-list PRs.** Hand-curated GitHub lists are how people browse skills today. One accurate PR per list, with the scope sentence intact. - `ComposioHQ/awesome-claude-skills`: submitted 2026-09-05 as PR 1841 - (Creative & Media); no maturity bar in its contribution rules. + (Creative & Media); no maturity bar in its contribution rules. Rechecked + 2026-09-11: still open, CI green, no review comments, waiting on the + list maintainers. - `heilcheng/awesome-agent-skills`: submitted 2026-09-09 as PR 483 under Community Skills > Media. The skill's three concrete input/output examples - satisfy the list's working-example requirement. + satisfy the list's working-example requirement. Rechecked 2026-09-11: + still open; the only check failure is their Vercel deploy authorization, + which a contributor cannot grant. - `VoltAgent/awesome-agent-skills`: DEFERRED. Its CONTRIBUTING rejects brand-new skills ("give your skill time to mature and gain users before submitting"). The skill now has real installs and shipped releases, but @@ -67,29 +71,31 @@ Do these in order after the skill is on the default branch. with `claude plugin validate` first. SUBMITTED 2026-09-07 for Claude Code only (strict validation passed; Apache 2.0; description carries the scope boundary; platform selection limited to Claude Code because Cowork - was not tested). Pending review; the team may reach out by email. The - official Anthropic marketplace is - curated and has no application. + was not tested). Pending review; the team may reach out by email. + Rechecked 2026-09-11: `platform.claude.com/plugins` is 404, and + `claude.ai/directory` is the MCP connector catalog, not plugins; a search + there does not list this skill. Do not open a second submission. The + official Anthropic marketplace is curated and has no application. 6. **ClawHub.** `clawhub login` then `clawhub skill publish` from - `skills/remove-ai-watermarks/`. LISTED 2026-09-09: versions 1.0.5 and 1.0.6, - submitted by the `clawhub` job in `distribute.yml` during the 0.39.0 and - 0.39.1 releases, are public. A green job proves only a submission, so read - the catalog itself: + `skills/remove-ai-watermarks/`. LISTED 2026-09-09: versions 1.0.5, 1.0.6, + and 1.0.8, submitted by the `clawhub` job in `distribute.yml` during the + 0.39.0, 0.39.1, and 0.40.0 releases, are public. A green job proves only a + submission, so read the catalog itself: `clawhub search remove-ai-watermarks` returns the row and `https://clawhub.ai/api/v1/skills/remove-ai-watermarks` reports - `latestVersion.version` 1.0.6, while its `/versions` endpoint returns those - two published versions. The earlier 1.0.3 and 1.0.4 submissions never became + `latestVersion.version` 1.0.8, while its `/versions` endpoint returns + 1.0.5, 1.0.6, and 1.0.8. The earlier 1.0.3 and 1.0.4 submissions never became public and do not appear in that version list, so they were bypassed rather - than recovered. The issue that tracked - them, openclaw/clawhub#3643, was closed by the reporter on 2026-09-09 once + than recovered. 1.0.7 was a post-0.39.1 bump that never reached ClawHub. + The issue that tracked 1.0.3 and 1.0.4, openclaw/clawhub#3643, was closed + by the reporter on 2026-09-09 once 1.0.5 went through; nothing upstream was confirmed fixed, and it is the fifth report of this shape (#3624, #3466, #3351, #3284), so treat a stalled submission as recurring and file a fresh one rather than assuming the pipeline is repaired. Release-time publishing is automated (see [release-and-distribution.md](release-and-distribution.md)), and the job fires only on a published GitHub Release: a skill version bumped after a - release reaches ClawHub with the next one. 0.40.0 publishes 1.0.8; 1.0.7 was - the post-0.39.1 bump and is not a ClawHub version. Do not publish by + release reaches ClawHub with the next one. Do not publish by hand to close that gap. The listing records the license as MIT-0 while `SKILL.md` declares Apache-2.0, and that is not a listing error to repair: MIT-0 is a platform-wide constant in ClawHub's own client @@ -114,16 +120,23 @@ Do these in order after the skill is on the default branch. [Submit your Claude Code plugin to OpenAI](https://developers.openai.com/plugins/guides/submit-claude-plugin). 8. **AgenticSkills.** SUBMITTED 2026-09-09 as review issue 174 under AI/ML Development. The submission carries the user-owned-content boundary and - links to the repository rather than hosting a separate copy. + links to the repository rather than hosting a separate copy. Rechecked + 2026-09-11: the public index still does not list it (`/skills/remove-ai-watermarks` + is 404; search for `wiltodelta` returns 0 of 192). Their form promises a + 48-hour review; that window has passed. Issue 174 is not a public GitHub + issue. Do not open a second submission. Followed up 2026-09-11 through + their contact form as a listing correction. 9. **AI Skills Catalog.** SUBMITTED 2026-09-09 as reference 2 under Video Media, with Codex as the primary agent and every supported harness marked compatible. - The catalog reviews source quality, security, license, and compatibility - before publication. Once accepted, treat material skill-version updates as - manual because the catalog stores compatible packages in addition to source - metadata and does not promise that a GitHub change refreshes those packages. - Use the update route supplied with acceptance; if none is supplied, contact - the catalog or resubmit, then verify the live result. Do not open a duplicate - while the initial review is pending. + Rechecked 2026-09-11: the public catalog at skillscatalog.ai shows 0 skills + from 0 publishers, `/api/featured` returns 401, and `/api/auth/session` + returns 500, so a stranger cannot confirm the listing. Do not open a + duplicate while that initial review is pending. Once accepted, treat + material skill-version updates as manual because the catalog stores + compatible packages in addition to source metadata and does not promise + that a GitHub change refreshes those packages. Use the update route + supplied with acceptance; if none is supplied, contact the catalog or + resubmit, then verify the live result. The conditional update actions for every catalog are part of the canonical release checklist in diff --git a/docs/release-and-distribution.md b/docs/release-and-distribution.md index a78582c..9efa96c 100644 --- a/docs/release-and-distribution.md +++ b/docs/release-and-distribution.md @@ -11,7 +11,7 @@ A release is complete only after all four published surfaces are verified: |---|---|---| | PyPI | The `remove-ai-watermarks` wheel and source distribution | `publish.yml` | | Homebrew | The `remove-ai-watermarks` formula in `wiltodelta/homebrew-tap` | `distribute.yml` | -| Hugging Face Space | The Space demo deployed on the new release through a requirements-pin bump in `wiltodelta/raiw-hf-space` | `raiw-hf-space` sync workflow; the pin bump is manual, `distribute.yml` only re-installs the pinned version | +| Hugging Face Space | The Space demo deployed on the new release through a requirements-pin bump in `wiltodelta/raiw-hf-space` | `distribute.yml` dispatches `pin-library.yml` in that repo, waits for the Hub `requirements.txt` pin, then factory-rebuilds; `sync-to-hf.yml` mirrors the pin onto the Space | | ComfyUI Registry | A compatible release of `wiltodelta/ComfyUI-remove-ai-watermarks` with its own node version | `distribute.yml` and the node repository's workflows | The GitHub Release is the trigger and release record for this flow. Conda is @@ -62,16 +62,20 @@ PyPI API token from the repository. waits for the matching source distribution to appear on PyPI, then: - updates the Homebrew tap formula URL and SHA-256; -- triggers a factory rebuild of the Hugging Face Space: this re-installs the - version pinned in the Space repo, it does NOT upgrade the demo; +- bumps the Hugging Face Space pin and factory-rebuilds the demo on that pin; - synchronizes, tests, versions, and publishes the ComfyUI nodes. -Upgrading the Hugging Face Space is a separate, manual step: bump -`remove-ai-watermarks[visible,heif]` in `wiltodelta/raiw-hf-space` (`pyproject.toml`, -`uv lock`, and the re-exported `requirements.txt`), then push. That repository's -`sync-to-hf.yml` mirrors the files onto the Space, which rebuilds on the new -pin. Its callback smoke tests run in that repository's CI on every push; they -are the scenario check for the demo surface. +Upgrading the Hugging Face Space is dispatched from `distribute.yml`: it runs +`pin-library.yml` in `wiltodelta/raiw-hf-space`, which bumps +`remove-ai-watermarks[visible,heif]` in `pyproject.toml`, refreshes `uv.lock`, +and pushes. That repository's `sync-to-hf.yml` then mirrors the files onto the +Space. `distribute.yml` waits for the Hub `requirements.txt` pin to match, +then factory-rebuilds. The `RAIW_HF_SPACE_TOKEN` repository secret is a +fine-grained token limited to the Space repository, with Contents write and +Actions write. Without the secret the pin bump is skipped and only the +factory rebuild runs, which reinstalls whatever version is already pinned. +The Space repo's callback smoke tests still run on every push; they are the +scenario check for the demo surface. The Hugging Face **model** `wiltodelta/raiw-photo-classify` is not part of that release fan-out. It holds the photo-classify freeze weights. The library extra @@ -253,9 +257,18 @@ failure. The ComfyUI sync run can fail the same way on its own: it resolves the version from the PyPI JSON API (which updates first) but installs the test dependency -with pip against the simple index, whose CDN edges lag by minutes. Rerun the -failed `distribute.yml` comfyui job once the simple index lists the release; -nothing about the release itself is wrong. +with pip against the simple index, whose CDN edges lag by minutes. The +`distribute.yml` waiter also has a clock: 0.40.0's node suite finished after +the 15-minute poll, so the job now waits 30 minutes and then accepts a +registry row that already requires this library version. Rerun the failed +`comfyui` job only when the registry still has no such row. + +The automatic `verify-release.yml` run after `distribute.yml` checks the +Hugging Face Space pin. When `RAIW_HF_SPACE_TOKEN` is set, that pin lands +during distribution. Without the secret, bump the pin by dispatching +`pin-library.yml` in `wiltodelta/raiw-hf-space` and then dispatch +`verify-release.yml` with the release version. Do not read a missing Space +pin as a broken PyPI or Homebrew publish. If the release changed CLI routing, extras, exit codes, mark keys, or the intended-use boundary, confirm `skills/remove-ai-watermarks/` still matches. diff --git a/tests/test_release_workflows.py b/tests/test_release_workflows.py index 44352fa..1aeea83 100644 --- a/tests/test_release_workflows.py +++ b/tests/test_release_workflows.py @@ -164,6 +164,19 @@ def test_distributed_version_reads_the_flat_single_artifact_layout(tmp_path: Pat assert "version=0.37.0" in (tmp_path / "output").read_text() +def test_comfyui_waiter_outlasts_the_node_suite_then_reads_the_registry() -> None: + script = _step("distribute.yml", "comfyui", "Sync and publish the ComfyUI nodes")["run"] + assert "seq 1 360" in script + assert "api.comfy.org/nodes/remove-ai-watermarks/versions" in script + + +def test_space_pin_is_dispatched_before_the_factory_rebuild() -> None: + script = _step("distribute.yml", "hf-space", "Bump the Space pin, then factory-rebuild")["run"] + assert "pin-library.yml" in script + assert "RAIW_HF_SPACE_TOKEN secret is not set" in script + assert "restart_space" in script + + @pytest.mark.skipif(os.name != "posix" or shutil.which("bash") is None, reason="Executes an Ubuntu Bash workflow") def test_clawhub_uses_local_install(tmp_path: Path) -> None: script = _step("distribute.yml", "clawhub", "Publish the agent skill when its version moved")["run"]