| name | release-extension |
| description | Use when the Chrome extension (chrome-extension/) changed and needs to ship — packaging a new build and publishing it as a GitHub release for users to download or reload. Triggers on "發 extension release", "extension 新版本", "publish extension", "package extension", "ext-v", "extension release", "更新 extension". |
Release the Chrome Extension
The extension is distributed as a GitHub release (tag ext-vX.Y.Z), NOT via the
Chrome Web Store. manifest.json has no update_url, so users do not auto-update —
they download the zip from the release (or reload the unpacked folder). Every user-facing
extension change therefore needs a fresh release, or users stay on the old build.
This is separate from bash scripts/deploy.sh (bot + edge function + DB). The deploy skill
must invoke this workflow whenever chrome-extension/ differs from the latest ext-v* tag.
If a change touches both, deploy the backend first (so new edge-function routes exist), then
release the extension before declaring the deploy complete.
When to Use
- After merging any change under
chrome-extension/ that users should get.
- Right after
deploy when the extension side of a feature also changed (e.g. the ingest
trigger button — backend route + extension button ship together).
- Not for backend-only changes (bot, edge function, migrations) — use
deploy.
Steps
1. Bump the manifest version (if not already bumped in the merged PR)
chrome-extension/manifest.json → "version" must be a new semver higher than the
latest ext-v* release. Package + release use this value verbatim for the zip name and tag.
grep '"version"' chrome-extension/manifest.json
gh release list | head -3
If it still matches the latest release, bump it (patch for fixes, minor for features),
commit, and push before releasing — a duplicate tag will fail.
2. Package the zip
bash scripts/package_extension.sh
Prints the output path: dist/ai-poker-wizard-gtow-sync-v${VERSION}.zip. The script
validates that every required file exists (manifest, JS, popup, README, all four icons)
and fails loudly if one is missing — do not hand-zip around a failure.
3. Publish the GitHub release
An explicit request to deploy changes that include an extension diff authorizes this matching
release; do not ask for a redundant second confirmation. For a standalone release request,
the request itself is also authorization. Ask only when the intended version or release scope
is genuinely ambiguous.
gh release create ext-v${VERSION} \
"dist/ai-poker-wizard-gtow-sync-v${VERSION}.zip" \
--title "AI Poker Wizard GTOW 自動同步 Extension v${VERSION}" \
--notes "$NOTES"
Tag convention: ext-vX.Y.Z (matches the manifest version). Asset: the packaged zip.
Release notes follow the prior release's shape (gh release view ext-v2.0.0 for the
template) — Traditional Chinese, sections: ## 新功能 (what changed, derived from
git diff --stat ext-v<prev>..HEAD -- chrome-extension/ + the popup/manifest text) and
## 安裝方式 (download → chrome://extensions → 開發人員模式 → 載入未封裝項目; existing
users can just hit reload). Close with the token-privacy line.
4. Verify
gh release view ext-v${VERSION}
Then tell the user how to update: reload the unpacked extension at chrome://extensions
(fastest for the owner) or download+unzip the new asset.
Quick Reference
| Item | Value |
|---|
| Tag format | ext-vX.Y.Z (= manifest version) |
| Zip | dist/ai-poker-wizard-gtow-sync-v${VERSION}.zip |
| Package script | scripts/package_extension.sh |
| Prior release (notes template) | gh release view ext-v2.0.0 |
| Auto-update? | No update_url — manual download/reload |
Common Mistakes
- Deploying the backend and forgetting the extension. The deploy is incomplete while
git diff <latest-ext-tag>..HEAD -- chrome-extension/ is non-empty and no newer ext-v*
release exists.
- Reusing the current version.
gh release create fails on a duplicate tag; bump
manifest.json first.
- Asking twice after deploy authorization. A deploy request covering extension changes
already authorizes the matching public extension release.
- Hand-editing the zip. Let
package_extension.sh build it so the required-file check
runs; a missing icon or JS file ships a broken extension.