Add plugins/ship-it/scripts/tea-ci-watch.sh, a blocking watcher for Gitea commit status. It polls the combined /commits/{sha}/status endpoint through tea api, so it needs no separate token or host configuration.
Replace the free-standing "CI Verification & Merge Pipeline Protocol" section in the skill with two numbered phases:
Phase 3: CI Verification. Wait on the PR head commit with a single background watcher, act on its exit code, report, then stop so the user merges.
Phase 4: Post-Merge Sync. Runs only when the user says the PR is merged or asks for a merge. The merge SHA comes from the PR rather than origin/main.
On GitHub, use gh pr checks --watch --fail-fast instead of gh run list + gh run watch.
Bump ship-it to 1.2.0.
Watcher exit codes
Exit
Meaning
0
All checks passed (success, warning, or skipped)
1
A check failed; failing jobs and their URLs are printed
2
Usage, dependency, or API error
3
No checks registered within the grace period (TEA_CI_WATCH_GRACE, default 60s)
124
Timed out with checks still pending
Fixes over the first draft
The draft read .state from each status entry, but Gitea stores it in .status, so every run reported success on the first poll.
The /statuses list keeps every historical entry, including old pending ones, so even with the field fixed it would never have finished. The combined /status endpoint reports the latest state of each check.
A commit with no workflows reports pending with zero checks, which previously waited out the full timeout.
The token fallback parsed the box-drawn tea login list table and always came back empty.
curl -sf ... || true hid 401/404 errors, so a wrong repo or SHA waited silently until the timeout.
Testing
shellcheck is clean, and generate_plugins.py --check passes locally.
Tested against real fish-config commits: a passing commit (exit 0), a failing commit (exit 1, failing job printed), a commit with no CI (exit 3), a wrong repo (exit 2), and missing arguments (exit 2).
The in-progress path is tested against this PR's own validate run.
## Summary
- Add `plugins/ship-it/scripts/tea-ci-watch.sh`, a blocking watcher for Gitea commit status. It polls the combined `/commits/{sha}/status` endpoint through `tea api`, so it needs no separate token or host configuration.
- Replace the free-standing "CI Verification & Merge Pipeline Protocol" section in the skill with two numbered phases:
- **Phase 3: CI Verification.** Wait on the PR head commit with a single background watcher, act on its exit code, report, then stop so the user merges.
- **Phase 4: Post-Merge Sync.** Runs only when the user says the PR is merged or asks for a merge. The merge SHA comes from the PR rather than `origin/main`.
- On GitHub, use `gh pr checks --watch --fail-fast` instead of `gh run list` + `gh run watch`.
- Bump ship-it to 1.2.0.
## Watcher exit codes
| Exit | Meaning |
|------|---------|
| 0 | All checks passed (success, warning, or skipped) |
| 1 | A check failed; failing jobs and their URLs are printed |
| 2 | Usage, dependency, or API error |
| 3 | No checks registered within the grace period (`TEA_CI_WATCH_GRACE`, default 60s) |
| 124 | Timed out with checks still pending |
## Fixes over the first draft
- The draft read `.state` from each status entry, but Gitea stores it in `.status`, so every run reported success on the first poll.
- The `/statuses` list keeps every historical entry, including old `pending` ones, so even with the field fixed it would never have finished. The combined `/status` endpoint reports the latest state of each check.
- A commit with no workflows reports `pending` with zero checks, which previously waited out the full timeout.
- The token fallback parsed the box-drawn `tea login list` table and always came back empty.
- `curl -sf ... || true` hid 401/404 errors, so a wrong repo or SHA waited silently until the timeout.
## Testing
- `shellcheck` is clean, and `generate_plugins.py --check` passes locally.
- Tested against real `fish-config` commits: a passing commit (exit 0), a failing commit (exit 1, failing job printed), a commit with no CI (exit 3), a wrong repo (exit 2), and missing arguments (exit 2).
- The in-progress path is tested against this PR's own `validate` run.
Add tea-ci-watch, a blocking watcher for Gitea commit status that polls
the combined status endpoint via `tea api` and exits with a distinct code
per outcome (0 pass, 1 fail, 2 API error, 3 no CI, 124 timeout).
Replace the free-standing CI protocol in the skill with Phase 3 (wait for
PR CI via a single background watcher, then stop for the user to merge)
and Phase 4 (post-merge sync, only when the user says the PR is merged or
asks for a merge). Use `gh pr checks --watch` on GitHub and take the merge
SHA from the PR rather than origin/main.
The generator copies only known plugin entries into dist/, so a
plugin-root scripts/ directory never reached either target and the skill
depended on a manual ~/.local/bin symlink.
Move the script to skills/ship-it/scripts/, which the skill copytree
already ships to claude-code and agy (plugin and bundle), and have the
skill run it by path relative to its own SKILL.md. Make --check reject
unknown plugin-root entries so a dropped file fails the PR gate.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
plugins/ship-it/scripts/tea-ci-watch.sh, a blocking watcher for Gitea commit status. It polls the combined/commits/{sha}/statusendpoint throughtea api, so it needs no separate token or host configuration.origin/main.gh pr checks --watch --fail-fastinstead ofgh run list+gh run watch.Watcher exit codes
TEA_CI_WATCH_GRACE, default 60s)Fixes over the first draft
.statefrom each status entry, but Gitea stores it in.status, so every run reported success on the first poll./statuseslist keeps every historical entry, including oldpendingones, so even with the field fixed it would never have finished. The combined/statusendpoint reports the latest state of each check.pendingwith zero checks, which previously waited out the full timeout.tea login listtable and always came back empty.curl -sf ... || truehid 401/404 errors, so a wrong repo or SHA waited silently until the timeout.Testing
shellcheckis clean, andgenerate_plugins.py --checkpasses locally.fish-configcommits: a passing commit (exit 0), a failing commit (exit 1, failing job printed), a commit with no CI (exit 3), a wrong repo (exit 2), and missing arguments (exit 2).validaterun.