publish-package
Package registry publishing for npm, crates.io, PyPI, and Homebrew. Verifies prerequisites, runs the publish command, confirms success, and surfaces actionable error hints on failure.
- License 许可
- MIT
- 最近更新
- 2026-11-10
- Stars
- ★ 290
- Forks
- 24
01 前言 Front Matter
- name
- publish-package
- model
- sonnet
- description
- Package registry publishing for npm, crates.io, PyPI, and Homebrew. Verifies prerequisites, runs the publish command, confirms success, and surfaces actionable error hints on failure.
03 SKILL.md 正文
Publish Package
HARD GATE — Do not attempt to publish without verifying prerequisites. Missing auth tokens, stale builds, or duplicate versions cause CI failures that are hard to debug post-push.
HARD GATE — Always run
--dry-runfirst. Package registries are append-only — a bad publish cannot be fully undone on most registries.
Publish packages to language-specific registries. Detects package type from manifest files, verifies publish prerequisites, runs the registry-specific publish command, and confirms the version appears on the registry.
Process
1. Detect package type
Read the project root for manifest files to determine the package type:
| Manifest | Registry | Publish command |
|---|---|---|
package.json |
npm | npm publish --access public |
Cargo.toml |
crates.io | cargo publish |
setup.py / pyproject.toml |
PyPI | twine upload dist/* or flit publish |
Formula/<name>.rb |
Homebrew | brew bump-formula-pr |
| Multiple detected | Polyglot | Error: specify registry with `--registry <npm |
If no manifest is found, prompt the user to specify the type or pass --type <npm|crates.io|pypi|brew>.
2. Verify prerequisites
Before attempting any publish, run all applicable checks:
npm (package.json):
See REFERENCE.md
crates.io (Cargo.toml):
See REFERENCE.md
PyPI (setup.py / pyproject.toml):
See REFERENCE.md
3. Run publish
After all prerequisite checks pass, run the registry-specific command:
See REFERENCE.md
4. Verify publish success
After publish, confirm the version appears on the registry:
See REFERENCE.md
5. Error handling
On failure, surface actionable hints:
See REFERENCE.md
6. Dry-run mode (--dry-run)
Run --dry-run to verify all prerequisites without actually publishing:
See REFERENCE.md
7. Dry-run mode per registry
See REFERENCE.md
Verify
→ verify: test -f skills/publish-package/SKILL.md && test -f package.json
→ verify: grep -q publish-package SKILL-INDEX.md
Publish Package — Reference
Navigation
| Lines | Section |
|---|---|
| 1 | Title |
| 3–23 | Navigation |
| 24–35 | Options |
| 36–37 | Examples |
| 38–51 | Publish an npm package |
| 52–59 | Publish a Rust crate |
| 60–69 | Missing token scenario |
| 70–80 | Integration with release-branch |
| 81–121 | Reference block 1 |
| 122–143 | Reference block 2 |
| 144–162 | Reference block 3 |
| 163–180 | Reference block 4 |
| 181–195 | Reference block 5 |
| 196–230 | Reference block 6 |
| 231–248 | Reference block 7 |
| 249–260 | Reference block 8 |
Options
| Flag | Description |
|---|---|
--dry-run |
Verify prerequisites and show publish command without executing |
--registry <type> |
Force registry type (skip auto-detection) |
--otp <code> |
One-time password for npm 2FA |
--no-verify |
Skip prerequisite checks (use with caution) |
Examples
Publish an npm package
# Verify first
publish-package --dry-run
# Publish
publish-package
# Output:
# [npm] Publishing my-package v0.4.0...
# OK: npm publish confirmed (my-package@0.4.0 on registry)
Publish a Rust crate
export CARGO_REGISTRY_TOKEN=<token>
publish-package --dry-run
publish-package
Missing token scenario
$ publish-package
FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add to .npmrc
Integration with release-branch
When wired into release-branch, add a step after git push:
6a. Run publish-package to publish to package registries
→ verify: publish-package --dry-run && publish-package
Reference block 1
# Check auth token exists
if [ -z "${NPM_TOKEN:-}" ]; then
if [ ! -f ~/.npmrc ] || ! grep -q "_authToken" ~/.npmrc; then
echo "FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add //registry.npmjs.org/:_authToken=<token> to .npmrc"
exit 1
fi
fi
# Check version not already published
PACKAGE_NAME=$(node -p "require('./package.json').name")
CURRENT_VER=$(node -p "require('./package.json').version")
if npm view "$PACKAGE_NAME@$CURRENT_VER" version 2>/dev/null; then
echo "FAIL: Version $CURRENT_VER already published for $PACKAGE_NAME. Bump version first."
exit 1
fi
# Check build artifacts are fresh
if [ -d dist ] || [ -d lib ]; then
LATEST_BUILD=$(find dist lib 2>/dev/null -name "*.js" -o -name "*.cjs" -o -name "*.mjs" | xargs ls -t 2>/dev/null | head -1)
PACKAGE_MODIFIED=$(stat -f %m package.json 2>/dev/null || stat -c %Y package.json 2>/dev/null)
if [ -n "$LATEST_BUILD" ] && [ -n "$PACKAGE_MODIFIED" ]; then
BUILD_TIME=$(stat -f %m "$LATEST_BUILD" 2>/dev/null || stat -c %Y "$LATEST_BUILD" 2>/dev/null)
if [ "$BUILD_TIME" -lt "$PACKAGE_MODIFIED" ]; then
echo "WARNING: Build artifacts may be stale (package.json modified after last build). Run npm run build first."
fi
fi
fi
# Check CHANGELOG is updated
if [ -f CHANGELOG.md ]; then
if ! grep -q "$CURRENT_VER" CHANGELOG.md 2>/dev/null; then
echo "WARNING: Version $CURRENT_VER not found in CHANGELOG.md. Update changelog before publish."
fi
fi
Reference block 2
# Check auth token exists
if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
if [ ! -f ~/.cargo/config.toml ] || ! grep -q "token" ~/.cargo/config.toml; then
echo "FAIL: CARGO_REGISTRY_TOKEN not set. Set via: export CARGO_REGISTRY_TOKEN=<token> or add to ~/.cargo/config.toml"
exit 1
fi
fi
# Check version not already published
CRATE_NAME=$(grep '^name' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
CURRENT_VER=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
if cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\""; then
echo "FAIL: Version $CURRENT_VER already published for $CRATE_NAME. Bump version in Cargo.toml first."
exit 1
fi
Reference block 3
# Check auth token exists
if [ -z "${TWINE_PASSWORD:-}" ] && [ -z "${POETRY_PYPI_TOKEN_PYPI:-}" ]; then
if [ ! -f ~/.pypirc ]; then
echo "FAIL: PyPI token not configured. Set TWINE_PASSWORD or create ~/.pypirc"
exit 1
fi
fi
# Check for build artifacts
if [ ! -d dist ] || [ -z "$(ls dist/*.whl 2>/dev/null)" ]; then
echo "WARNING: No .whl files found in dist/. Run: python -m build"
fi
Reference block 4
# npm
npm publish --access public
# crates.io
cargo publish
# PyPI
python -m twine upload dist/* # or: poetry publish
# Homebrew (opens PR, does not publish directly)
brew bump-formula-pr --url=<tarball-url> <formula-name>
Reference block 5
# npm
npm view "$PACKAGE_NAME" versions --json 2>/dev/null | grep -q "\"$CURRENT_VER\"" && echo "OK: npm publish confirmed"
# crates.io
cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\"" && echo "OK: crates.io publish confirmed"
# PyPI
pip index versions "$PACKAGE_NAME" 2>/dev/null | grep -q "$CURRENT_VER" && echo "OK: PyPI publish confirmed"
Reference block 6
# Generic failure handler
if [ $? -ne 0 ]; then
case "$REGISTRY" in
npm)
echo "FAIL: npm publish failed."
echo " Common causes:"
echo " - NPM_TOKEN not set in secrets: add to GitHub repo secrets"
echo " - Version already published: bump version in package.json"
echo " - Two-factor auth required: use --otp=<code> flag"
echo " - Package scoped but not public: add --access public"
;;
crates.io)
echo "FAIL: cargo publish failed."
echo " Common causes:"
echo " - CARGO_REGISTRY_TOKEN not configured: see ~/.cargo/config.toml"
echo " - Version already published: bump version in Cargo.toml"
echo " - Local changes not committed: cargo publish requires clean working tree"
;;
pypi)
echo "FAIL: PyPI publish failed."
echo " Common causes:"
echo " - TWINE_PASSWORD not configured: set env var or ~/.pypirc"
echo " - Build artifacts missing: run python -m build first"
echo " - Version conflict: version already exists on PyPI"
;;
esac
exit 1
fi
Reference block 7
# Example output
$ publish-package --dry-run
[DRY-RUN] Detected package type: npm
[DRY-RUN] Package: my-package v0.4.0
[DRY-RUN] Checking NPM_TOKEN... OK
[DRY-RUN] Checking version 0.4.0 not already published... OK
[DRY-RUN] Checking build artifacts... WARNING: package.json modified after build
[DRY-RUN] Checking CHANGELOG... OK
[DRY-RUN] Would run: npm publish --access public
[DRY-RUN] Exiting without publishing.
Reference block 8
# npm dry-run
npm publish --access public --dry-run
# crates.io dry-run (cargo does not have a publish dry-run; use --dry-run flag for validation only)
cargo package --list 2>/dev/null
# PyPI dry-run
python -m twine upload --repository testpypi dist/* # test.pypi.org
04 同仓库更多 Skills
skill-verify-fail-open-fixture
Negative-path fixture for run-skill-verify.sh — must never PASS.
negative-path
暂无简介
write-document
Write, organize, and sync high-integrity technical documents using the BMAD methodology. Ensures every document is Bold, Minimal, Actionable, and Durable. Use when creating architectural docs, technical guides, or organizing the specs/ directory.
wire-observability
Add structured JSON logging, observability commands, and idempotent setup scripts to a project. Use when a project needs production-readiness instrumentation, when user wants structured logging, or as a production-readiness gate at any phase of development.
wire-ci
CI pipeline setup with bundled, forge-neutral templates and local validation. Detects the forge from the git remote, generates workflows for supported forges, and skips honestly for the rest. The CI equivalent of wire-observability.
visual-dashboard
Start a browser-based dashboard that visualizes architecture, implementation plans, and project status. Persists artifacts in .bigpowers/dashboard/. Reads specs/state.yaml, release-plan.yaml, epics, and planning-status via HTTP API or opencode panel.