bigpowers 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi/package.json +2 -2
- package/.pi/prompts/publish-package.md +260 -0
- package/.pi/skills/publish-package/SKILL.md +262 -0
- package/CHANGELOG.md +7 -0
- package/SKILL-INDEX.md +38 -37
- package/package.json +1 -1
- package/publish-package/SKILL.md +261 -0
- package/scripts/generate-skill-index.sh +1 -0
- package/skills-lock.json +5 -0
package/.pi/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bigpowers",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.9.0",
|
|
4
|
+
"description": "64 skills — 61 agent skills for spec-driven, test-first software development by solo developers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
7
7
|
],
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
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."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Publish Package
|
|
7
|
+
|
|
8
|
+
> **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.
|
|
9
|
+
>
|
|
10
|
+
> **HARD GATE** — Always run `--dry-run` first. Package registries are append-only — a bad publish cannot be fully undone on most registries.
|
|
11
|
+
|
|
12
|
+
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.
|
|
13
|
+
|
|
14
|
+
## Process
|
|
15
|
+
|
|
16
|
+
### 1. Detect package type
|
|
17
|
+
|
|
18
|
+
Read the project root for manifest files to determine the package type:
|
|
19
|
+
|
|
20
|
+
| Manifest | Registry | Publish command |
|
|
21
|
+
|----------|----------|----------------|
|
|
22
|
+
| `package.json` | npm | `npm publish --access public` |
|
|
23
|
+
| `Cargo.toml` | crates.io | `cargo publish` |
|
|
24
|
+
| `setup.py` / `pyproject.toml` | PyPI | `twine upload dist/*` or `flit publish` |
|
|
25
|
+
| `Formula/<name>.rb` | Homebrew | `brew bump-formula-pr` |
|
|
26
|
+
| Multiple detected | Polyglot | Error: specify registry with `--registry <npm|crates.io|pypi|brew>` |
|
|
27
|
+
|
|
28
|
+
If no manifest is found, prompt the user to specify the type or pass `--type <npm|crates.io|pypi|brew>`.
|
|
29
|
+
|
|
30
|
+
### 2. Verify prerequisites
|
|
31
|
+
|
|
32
|
+
Before attempting any publish, run all applicable checks:
|
|
33
|
+
|
|
34
|
+
**npm (`package.json`):**
|
|
35
|
+
```bash
|
|
36
|
+
# Check auth token exists
|
|
37
|
+
if [ -z "${NPM_TOKEN:-}" ]; then
|
|
38
|
+
if [ ! -f ~/.npmrc ] || ! grep -q "_authToken" ~/.npmrc; then
|
|
39
|
+
echo "FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add //registry.npmjs.org/:_authToken=<token> to .npmrc"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Check version not already published
|
|
45
|
+
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
46
|
+
CURRENT_VER=$(node -p "require('./package.json').version")
|
|
47
|
+
if npm view "$PACKAGE_NAME@$CURRENT_VER" version 2>/dev/null; then
|
|
48
|
+
echo "FAIL: Version $CURRENT_VER already published for $PACKAGE_NAME. Bump version first."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Check build artifacts are fresh
|
|
53
|
+
if [ -d dist ] || [ -d lib ]; then
|
|
54
|
+
LATEST_BUILD=$(find dist lib 2>/dev/null -name "*.js" -o -name "*.cjs" -o -name "*.mjs" | xargs ls -t 2>/dev/null | head -1)
|
|
55
|
+
PACKAGE_MODIFIED=$(stat -f %m package.json 2>/dev/null || stat -c %Y package.json 2>/dev/null)
|
|
56
|
+
if [ -n "$LATEST_BUILD" ] && [ -n "$PACKAGE_MODIFIED" ]; then
|
|
57
|
+
BUILD_TIME=$(stat -f %m "$LATEST_BUILD" 2>/dev/null || stat -c %Y "$LATEST_BUILD" 2>/dev/null)
|
|
58
|
+
if [ "$BUILD_TIME" -lt "$PACKAGE_MODIFIED" ]; then
|
|
59
|
+
echo "WARNING: Build artifacts may be stale (package.json modified after last build). Run npm run build first."
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Check CHANGELOG is updated
|
|
65
|
+
if [ -f CHANGELOG.md ]; then
|
|
66
|
+
if ! grep -q "$CURRENT_VER" CHANGELOG.md 2>/dev/null; then
|
|
67
|
+
echo "WARNING: Version $CURRENT_VER not found in CHANGELOG.md. Update changelog before publish."
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**crates.io (`Cargo.toml`):**
|
|
73
|
+
```bash
|
|
74
|
+
# Check auth token exists
|
|
75
|
+
if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
|
|
76
|
+
if [ ! -f ~/.cargo/config.toml ] || ! grep -q "token" ~/.cargo/config.toml; then
|
|
77
|
+
echo "FAIL: CARGO_REGISTRY_TOKEN not set. Set via: export CARGO_REGISTRY_TOKEN=<token> or add to ~/.cargo/config.toml"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Check version not already published
|
|
83
|
+
CRATE_NAME=$(grep '^name' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
84
|
+
CURRENT_VER=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
85
|
+
if cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\""; then
|
|
86
|
+
echo "FAIL: Version $CURRENT_VER already published for $CRATE_NAME. Bump version in Cargo.toml first."
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**PyPI (`setup.py` / `pyproject.toml`):**
|
|
92
|
+
```bash
|
|
93
|
+
# Check auth token exists
|
|
94
|
+
if [ -z "${TWINE_PASSWORD:-}" ] && [ -z "${POETRY_PYPI_TOKEN_PYPI:-}" ]; then
|
|
95
|
+
if [ ! -f ~/.pypirc ]; then
|
|
96
|
+
echo "FAIL: PyPI token not configured. Set TWINE_PASSWORD or create ~/.pypirc"
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Check for build artifacts
|
|
102
|
+
if [ ! -d dist ] || [ -z "$(ls dist/*.whl 2>/dev/null)" ]; then
|
|
103
|
+
echo "WARNING: No .whl files found in dist/. Run: python -m build"
|
|
104
|
+
fi
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 3. Run publish
|
|
108
|
+
|
|
109
|
+
After all prerequisite checks pass, run the registry-specific command:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# npm
|
|
113
|
+
npm publish --access public
|
|
114
|
+
|
|
115
|
+
# crates.io
|
|
116
|
+
cargo publish
|
|
117
|
+
|
|
118
|
+
# PyPI
|
|
119
|
+
python -m twine upload dist/* # or: poetry publish
|
|
120
|
+
|
|
121
|
+
# Homebrew (opens PR, does not publish directly)
|
|
122
|
+
brew bump-formula-pr --url=<tarball-url> <formula-name>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4. Verify publish success
|
|
126
|
+
|
|
127
|
+
After publish, confirm the version appears on the registry:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# npm
|
|
131
|
+
npm view "$PACKAGE_NAME" versions --json 2>/dev/null | grep -q "\"$CURRENT_VER\"" && echo "OK: npm publish confirmed"
|
|
132
|
+
|
|
133
|
+
# crates.io
|
|
134
|
+
cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\"" && echo "OK: crates.io publish confirmed"
|
|
135
|
+
|
|
136
|
+
# PyPI
|
|
137
|
+
pip index versions "$PACKAGE_NAME" 2>/dev/null | grep -q "$CURRENT_VER" && echo "OK: PyPI publish confirmed"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 5. Error handling
|
|
141
|
+
|
|
142
|
+
On failure, surface actionable hints:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Generic failure handler
|
|
146
|
+
if [ $? -ne 0 ]; then
|
|
147
|
+
case "$REGISTRY" in
|
|
148
|
+
npm)
|
|
149
|
+
echo "FAIL: npm publish failed."
|
|
150
|
+
echo " Common causes:"
|
|
151
|
+
echo " - NPM_TOKEN not set in secrets: add to GitHub repo secrets"
|
|
152
|
+
echo " - Version already published: bump version in package.json"
|
|
153
|
+
echo " - Two-factor auth required: use --otp=<code> flag"
|
|
154
|
+
echo " - Package scoped but not public: add --access public"
|
|
155
|
+
;;
|
|
156
|
+
crates.io)
|
|
157
|
+
echo "FAIL: cargo publish failed."
|
|
158
|
+
echo " Common causes:"
|
|
159
|
+
echo " - CARGO_REGISTRY_TOKEN not configured: see ~/.cargo/config.toml"
|
|
160
|
+
echo " - Version already published: bump version in Cargo.toml"
|
|
161
|
+
echo " - Local changes not committed: cargo publish requires clean working tree"
|
|
162
|
+
;;
|
|
163
|
+
pypi)
|
|
164
|
+
echo "FAIL: PyPI publish failed."
|
|
165
|
+
echo " Common causes:"
|
|
166
|
+
echo " - TWINE_PASSWORD not configured: set env var or ~/.pypirc"
|
|
167
|
+
echo " - Build artifacts missing: run python -m build first"
|
|
168
|
+
echo " - Version conflict: version already exists on PyPI"
|
|
169
|
+
;;
|
|
170
|
+
esac
|
|
171
|
+
exit 1
|
|
172
|
+
fi
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 6. Dry-run mode (`--dry-run`)
|
|
176
|
+
|
|
177
|
+
Run `--dry-run` to verify all prerequisites without actually publishing:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Example output
|
|
181
|
+
$ publish-package --dry-run
|
|
182
|
+
|
|
183
|
+
[DRY-RUN] Detected package type: npm
|
|
184
|
+
[DRY-RUN] Package: my-package v0.4.0
|
|
185
|
+
[DRY-RUN] Checking NPM_TOKEN... OK
|
|
186
|
+
[DRY-RUN] Checking version 0.4.0 not already published... OK
|
|
187
|
+
[DRY-RUN] Checking build artifacts... WARNING: package.json modified after build
|
|
188
|
+
[DRY-RUN] Checking CHANGELOG... OK
|
|
189
|
+
[DRY-RUN] Would run: npm publish --access public
|
|
190
|
+
[DRY-RUN] Exiting without publishing.
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 7. Dry-run mode per registry
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# npm dry-run
|
|
197
|
+
npm publish --access public --dry-run
|
|
198
|
+
|
|
199
|
+
# crates.io dry-run (cargo does not have a publish dry-run; use --dry-run flag for validation only)
|
|
200
|
+
cargo package --list 2>/dev/null
|
|
201
|
+
|
|
202
|
+
# PyPI dry-run
|
|
203
|
+
python -m twine upload --repository testpypi dist/* # test.pypi.org
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Options
|
|
207
|
+
|
|
208
|
+
| Flag | Description |
|
|
209
|
+
|------|-------------|
|
|
210
|
+
| `--dry-run` | Verify prerequisites and show publish command without executing |
|
|
211
|
+
| `--registry <type>` | Force registry type (skip auto-detection) |
|
|
212
|
+
| `--otp <code>` | One-time password for npm 2FA |
|
|
213
|
+
| `--no-verify` | Skip prerequisite checks (use with caution) |
|
|
214
|
+
|
|
215
|
+
## Examples
|
|
216
|
+
|
|
217
|
+
### Publish an npm package
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Verify first
|
|
221
|
+
publish-package --dry-run
|
|
222
|
+
|
|
223
|
+
# Publish
|
|
224
|
+
publish-package
|
|
225
|
+
|
|
226
|
+
# Output:
|
|
227
|
+
# [npm] Publishing my-package v0.4.0...
|
|
228
|
+
# OK: npm publish confirmed (my-package@0.4.0 on registry)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Publish a Rust crate
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
export CARGO_REGISTRY_TOKEN=<token>
|
|
235
|
+
publish-package --dry-run
|
|
236
|
+
publish-package
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Missing token scenario
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
$ publish-package
|
|
243
|
+
FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add to .npmrc
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Integration with release-branch
|
|
247
|
+
|
|
248
|
+
When wired into `release-branch`, add a step after git push:
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
6a. Run publish-package to publish to package registries
|
|
252
|
+
→ verify: publish-package --dry-run && publish-package
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Verify
|
|
256
|
+
|
|
257
|
+
→ verify: `test -f publish-package/SKILL.md && echo "OK: skill file exists" || echo "FAIL: no skill file"`
|
|
258
|
+
→ verify: `grep -q "name: publish-package" publish-package/SKILL.md && echo "OK: frontmatter" || echo "FAIL: frontmatter"`
|
|
259
|
+
→ verify: `grep -ci "npm\|crates.io\|pypi\|publish\|registry" publish-package/SKILL.md | awk '{if($1>=4) print "OK: semantics"; else print "FAIL: missing"}'`
|
|
260
|
+
→ verify: `grep -q "publish-package" SKILL-INDEX.md && echo "OK: in SKILL-INDEX" || echo "FAIL: not indexed"`
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish-package
|
|
3
|
+
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.\""
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Publish Package
|
|
9
|
+
|
|
10
|
+
> **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.
|
|
11
|
+
>
|
|
12
|
+
> **HARD GATE** — Always run `--dry-run` first. Package registries are append-only — a bad publish cannot be fully undone on most registries.
|
|
13
|
+
|
|
14
|
+
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.
|
|
15
|
+
|
|
16
|
+
## Process
|
|
17
|
+
|
|
18
|
+
### 1. Detect package type
|
|
19
|
+
|
|
20
|
+
Read the project root for manifest files to determine the package type:
|
|
21
|
+
|
|
22
|
+
| Manifest | Registry | Publish command |
|
|
23
|
+
|----------|----------|----------------|
|
|
24
|
+
| `package.json` | npm | `npm publish --access public` |
|
|
25
|
+
| `Cargo.toml` | crates.io | `cargo publish` |
|
|
26
|
+
| `setup.py` / `pyproject.toml` | PyPI | `twine upload dist/*` or `flit publish` |
|
|
27
|
+
| `Formula/<name>.rb` | Homebrew | `brew bump-formula-pr` |
|
|
28
|
+
| Multiple detected | Polyglot | Error: specify registry with `--registry <npm|crates.io|pypi|brew>` |
|
|
29
|
+
|
|
30
|
+
If no manifest is found, prompt the user to specify the type or pass `--type <npm|crates.io|pypi|brew>`.
|
|
31
|
+
|
|
32
|
+
### 2. Verify prerequisites
|
|
33
|
+
|
|
34
|
+
Before attempting any publish, run all applicable checks:
|
|
35
|
+
|
|
36
|
+
**npm (`package.json`):**
|
|
37
|
+
```bash
|
|
38
|
+
# Check auth token exists
|
|
39
|
+
if [ -z "${NPM_TOKEN:-}" ]; then
|
|
40
|
+
if [ ! -f ~/.npmrc ] || ! grep -q "_authToken" ~/.npmrc; then
|
|
41
|
+
echo "FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add //registry.npmjs.org/:_authToken=<token> to .npmrc"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Check version not already published
|
|
47
|
+
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
48
|
+
CURRENT_VER=$(node -p "require('./package.json').version")
|
|
49
|
+
if npm view "$PACKAGE_NAME@$CURRENT_VER" version 2>/dev/null; then
|
|
50
|
+
echo "FAIL: Version $CURRENT_VER already published for $PACKAGE_NAME. Bump version first."
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Check build artifacts are fresh
|
|
55
|
+
if [ -d dist ] || [ -d lib ]; then
|
|
56
|
+
LATEST_BUILD=$(find dist lib 2>/dev/null -name "*.js" -o -name "*.cjs" -o -name "*.mjs" | xargs ls -t 2>/dev/null | head -1)
|
|
57
|
+
PACKAGE_MODIFIED=$(stat -f %m package.json 2>/dev/null || stat -c %Y package.json 2>/dev/null)
|
|
58
|
+
if [ -n "$LATEST_BUILD" ] && [ -n "$PACKAGE_MODIFIED" ]; then
|
|
59
|
+
BUILD_TIME=$(stat -f %m "$LATEST_BUILD" 2>/dev/null || stat -c %Y "$LATEST_BUILD" 2>/dev/null)
|
|
60
|
+
if [ "$BUILD_TIME" -lt "$PACKAGE_MODIFIED" ]; then
|
|
61
|
+
echo "WARNING: Build artifacts may be stale (package.json modified after last build). Run npm run build first."
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Check CHANGELOG is updated
|
|
67
|
+
if [ -f CHANGELOG.md ]; then
|
|
68
|
+
if ! grep -q "$CURRENT_VER" CHANGELOG.md 2>/dev/null; then
|
|
69
|
+
echo "WARNING: Version $CURRENT_VER not found in CHANGELOG.md. Update changelog before publish."
|
|
70
|
+
fi
|
|
71
|
+
fi
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**crates.io (`Cargo.toml`):**
|
|
75
|
+
```bash
|
|
76
|
+
# Check auth token exists
|
|
77
|
+
if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
|
|
78
|
+
if [ ! -f ~/.cargo/config.toml ] || ! grep -q "token" ~/.cargo/config.toml; then
|
|
79
|
+
echo "FAIL: CARGO_REGISTRY_TOKEN not set. Set via: export CARGO_REGISTRY_TOKEN=<token> or add to ~/.cargo/config.toml"
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Check version not already published
|
|
85
|
+
CRATE_NAME=$(grep '^name' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
86
|
+
CURRENT_VER=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
87
|
+
if cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\""; then
|
|
88
|
+
echo "FAIL: Version $CURRENT_VER already published for $CRATE_NAME. Bump version in Cargo.toml first."
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**PyPI (`setup.py` / `pyproject.toml`):**
|
|
94
|
+
```bash
|
|
95
|
+
# Check auth token exists
|
|
96
|
+
if [ -z "${TWINE_PASSWORD:-}" ] && [ -z "${POETRY_PYPI_TOKEN_PYPI:-}" ]; then
|
|
97
|
+
if [ ! -f ~/.pypirc ]; then
|
|
98
|
+
echo "FAIL: PyPI token not configured. Set TWINE_PASSWORD or create ~/.pypirc"
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Check for build artifacts
|
|
104
|
+
if [ ! -d dist ] || [ -z "$(ls dist/*.whl 2>/dev/null)" ]; then
|
|
105
|
+
echo "WARNING: No .whl files found in dist/. Run: python -m build"
|
|
106
|
+
fi
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Run publish
|
|
110
|
+
|
|
111
|
+
After all prerequisite checks pass, run the registry-specific command:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# npm
|
|
115
|
+
npm publish --access public
|
|
116
|
+
|
|
117
|
+
# crates.io
|
|
118
|
+
cargo publish
|
|
119
|
+
|
|
120
|
+
# PyPI
|
|
121
|
+
python -m twine upload dist/* # or: poetry publish
|
|
122
|
+
|
|
123
|
+
# Homebrew (opens PR, does not publish directly)
|
|
124
|
+
brew bump-formula-pr --url=<tarball-url> <formula-name>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 4. Verify publish success
|
|
128
|
+
|
|
129
|
+
After publish, confirm the version appears on the registry:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# npm
|
|
133
|
+
npm view "$PACKAGE_NAME" versions --json 2>/dev/null | grep -q "\"$CURRENT_VER\"" && echo "OK: npm publish confirmed"
|
|
134
|
+
|
|
135
|
+
# crates.io
|
|
136
|
+
cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\"" && echo "OK: crates.io publish confirmed"
|
|
137
|
+
|
|
138
|
+
# PyPI
|
|
139
|
+
pip index versions "$PACKAGE_NAME" 2>/dev/null | grep -q "$CURRENT_VER" && echo "OK: PyPI publish confirmed"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 5. Error handling
|
|
143
|
+
|
|
144
|
+
On failure, surface actionable hints:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Generic failure handler
|
|
148
|
+
if [ $? -ne 0 ]; then
|
|
149
|
+
case "$REGISTRY" in
|
|
150
|
+
npm)
|
|
151
|
+
echo "FAIL: npm publish failed."
|
|
152
|
+
echo " Common causes:"
|
|
153
|
+
echo " - NPM_TOKEN not set in secrets: add to GitHub repo secrets"
|
|
154
|
+
echo " - Version already published: bump version in package.json"
|
|
155
|
+
echo " - Two-factor auth required: use --otp=<code> flag"
|
|
156
|
+
echo " - Package scoped but not public: add --access public"
|
|
157
|
+
;;
|
|
158
|
+
crates.io)
|
|
159
|
+
echo "FAIL: cargo publish failed."
|
|
160
|
+
echo " Common causes:"
|
|
161
|
+
echo " - CARGO_REGISTRY_TOKEN not configured: see ~/.cargo/config.toml"
|
|
162
|
+
echo " - Version already published: bump version in Cargo.toml"
|
|
163
|
+
echo " - Local changes not committed: cargo publish requires clean working tree"
|
|
164
|
+
;;
|
|
165
|
+
pypi)
|
|
166
|
+
echo "FAIL: PyPI publish failed."
|
|
167
|
+
echo " Common causes:"
|
|
168
|
+
echo " - TWINE_PASSWORD not configured: set env var or ~/.pypirc"
|
|
169
|
+
echo " - Build artifacts missing: run python -m build first"
|
|
170
|
+
echo " - Version conflict: version already exists on PyPI"
|
|
171
|
+
;;
|
|
172
|
+
esac
|
|
173
|
+
exit 1
|
|
174
|
+
fi
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 6. Dry-run mode (`--dry-run`)
|
|
178
|
+
|
|
179
|
+
Run `--dry-run` to verify all prerequisites without actually publishing:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Example output
|
|
183
|
+
$ publish-package --dry-run
|
|
184
|
+
|
|
185
|
+
[DRY-RUN] Detected package type: npm
|
|
186
|
+
[DRY-RUN] Package: my-package v0.4.0
|
|
187
|
+
[DRY-RUN] Checking NPM_TOKEN... OK
|
|
188
|
+
[DRY-RUN] Checking version 0.4.0 not already published... OK
|
|
189
|
+
[DRY-RUN] Checking build artifacts... WARNING: package.json modified after build
|
|
190
|
+
[DRY-RUN] Checking CHANGELOG... OK
|
|
191
|
+
[DRY-RUN] Would run: npm publish --access public
|
|
192
|
+
[DRY-RUN] Exiting without publishing.
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 7. Dry-run mode per registry
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# npm dry-run
|
|
199
|
+
npm publish --access public --dry-run
|
|
200
|
+
|
|
201
|
+
# crates.io dry-run (cargo does not have a publish dry-run; use --dry-run flag for validation only)
|
|
202
|
+
cargo package --list 2>/dev/null
|
|
203
|
+
|
|
204
|
+
# PyPI dry-run
|
|
205
|
+
python -m twine upload --repository testpypi dist/* # test.pypi.org
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Options
|
|
209
|
+
|
|
210
|
+
| Flag | Description |
|
|
211
|
+
|------|-------------|
|
|
212
|
+
| `--dry-run` | Verify prerequisites and show publish command without executing |
|
|
213
|
+
| `--registry <type>` | Force registry type (skip auto-detection) |
|
|
214
|
+
| `--otp <code>` | One-time password for npm 2FA |
|
|
215
|
+
| `--no-verify` | Skip prerequisite checks (use with caution) |
|
|
216
|
+
|
|
217
|
+
## Examples
|
|
218
|
+
|
|
219
|
+
### Publish an npm package
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Verify first
|
|
223
|
+
publish-package --dry-run
|
|
224
|
+
|
|
225
|
+
# Publish
|
|
226
|
+
publish-package
|
|
227
|
+
|
|
228
|
+
# Output:
|
|
229
|
+
# [npm] Publishing my-package v0.4.0...
|
|
230
|
+
# OK: npm publish confirmed (my-package@0.4.0 on registry)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Publish a Rust crate
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
export CARGO_REGISTRY_TOKEN=<token>
|
|
237
|
+
publish-package --dry-run
|
|
238
|
+
publish-package
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Missing token scenario
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
$ publish-package
|
|
245
|
+
FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add to .npmrc
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Integration with release-branch
|
|
249
|
+
|
|
250
|
+
When wired into `release-branch`, add a step after git push:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
6a. Run publish-package to publish to package registries
|
|
254
|
+
→ verify: publish-package --dry-run && publish-package
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Verify
|
|
258
|
+
|
|
259
|
+
→ verify: `test -f publish-package/SKILL.md && echo "OK: skill file exists" || echo "FAIL: no skill file"`
|
|
260
|
+
→ verify: `grep -q "name: publish-package" publish-package/SKILL.md && echo "OK: frontmatter" || echo "FAIL: frontmatter"`
|
|
261
|
+
→ verify: `grep -ci "npm\|crates.io\|pypi\|publish\|registry" publish-package/SKILL.md | awk '{if($1>=4) print "OK: semantics"; else print "FAIL: missing"}'`
|
|
262
|
+
→ verify: `grep -q "publish-package" SKILL-INDEX.md && echo "OK: in SKILL-INDEX" || echo "FAIL: not indexed"`
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [2.9.0](https://github.com/danielvm-git/bigpowers/compare/v2.8.0...v2.9.0) (2026-06-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **skills:** add publish-package skill for multi-registry publishing ([945a481](https://github.com/danielvm-git/bigpowers/commit/945a481cef07335c59277c82137e4a6bec78655a))
|
|
7
|
+
|
|
1
8
|
# [2.8.0](https://github.com/danielvm-git/bigpowers/compare/v2.7.5...v2.8.0) (2026-06-20)
|
|
2
9
|
|
|
3
10
|
|
package/SKILL-INDEX.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
> **DO NOT EDIT** — This file is auto-generated by `scripts/generate-skill-index.sh`.
|
|
4
4
|
> Edit `SKILL.md` source files or `skills-lock.json` instead. Run `bash scripts/sync-skills.sh` to regenerate.
|
|
5
5
|
|
|
6
|
-
**Generated:** 2026-06-20T21:
|
|
7
|
-
**Skills:**
|
|
6
|
+
**Generated:** 2026-06-20T21:29:33Z
|
|
7
|
+
**Skills:** 64
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
| Discover | 6 | `elaborate-spec, map-codebase, research-first, search-skills, survey-context, using-bigpowers` |
|
|
16
16
|
| Design | 7 | `deepen-architecture, define-language, define-success, design-interface, grill-me, grill-with-docs, model-domain` |
|
|
17
17
|
| Plan | 9 | `assess-impact, change-request, plan-refactor, plan-release, plan-work, run-planning, scope-work, seed-conventions, slice-tasks` |
|
|
18
|
-
| Build |
|
|
18
|
+
| Build | 14 | `align-grid, build-epic, craft-skill, develop-tdd, execute-plan, guard-git, hook-commits, kickoff-branch, orchestrate-project, publish-package, setup-environment, spike-prototype, wire-ci, wire-observability` |
|
|
19
19
|
| Verify | 12 | `audit-code, diagnose-root, enforce-first, fix-bug, inspect-quality, investigate-bug, request-review, respond-review, run-evals, trace-requirement, validate-fix, verify-work` |
|
|
20
20
|
| Release | 2 | `commit-message, release-branch` |
|
|
21
21
|
| Sustain | 13 | `compose-workflow, delegate-task, dispatch-agents, edit-document, evolve-skill, migrate-spec, organize-workspace, reset-baseline, session-state, simulate-agents, stocktake-skills, terse-mode, write-document` |
|
|
22
|
-
| **TOTAL** | **
|
|
22
|
+
| **TOTAL** | **63** | |
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -58,39 +58,40 @@
|
|
|
58
58
|
| 29 | Build | `hook-commits` | Set up pre-commit hooks with lint-staged (Prettier), type checking, and tests in | ✅ Active |
|
|
59
59
|
| 30 | Build | `kickoff-branch` | Create a git worktree and feature branch, then verify a clean test baseline befo | ✅ Active |
|
|
60
60
|
| 31 | Build | `orchestrate-project` | Meta-skill that enforces the 6-phase core loop (discover → elaborate → plan | ✅ Active |
|
|
61
|
-
| 32 | Build | `
|
|
62
|
-
| 33 | Build | `
|
|
63
|
-
| 34 | Build | `
|
|
64
|
-
| 35 | Build | `wire-
|
|
65
|
-
| 36 |
|
|
66
|
-
| 37 | Verify | `
|
|
67
|
-
| 38 | Verify | `
|
|
68
|
-
| 39 | Verify | `
|
|
69
|
-
| 40 | Verify | `
|
|
70
|
-
| 41 | Verify | `
|
|
71
|
-
| 42 | Verify | `
|
|
72
|
-
| 43 | Verify | `
|
|
73
|
-
| 44 | Verify | `
|
|
74
|
-
| 45 | Verify | `
|
|
75
|
-
| 46 | Verify | `
|
|
76
|
-
| 47 | Verify | `
|
|
77
|
-
| 48 |
|
|
78
|
-
| 49 | Release | `
|
|
79
|
-
| 50 |
|
|
80
|
-
| 51 | Sustain | `
|
|
81
|
-
| 52 | Sustain | `
|
|
82
|
-
| 53 | Sustain | `
|
|
83
|
-
| 54 | Sustain | `
|
|
84
|
-
| 55 | Sustain | `
|
|
85
|
-
| 56 | Sustain | `
|
|
86
|
-
| 57 | Sustain | `
|
|
87
|
-
| 58 | Sustain | `
|
|
88
|
-
| 59 | Sustain | `
|
|
89
|
-
| 60 | Sustain | `
|
|
90
|
-
| 61 | Sustain | `
|
|
91
|
-
| 62 | Sustain | `
|
|
92
|
-
|
|
93
|
-
|
|
61
|
+
| 32 | Build | `publish-package` | "Package registry publishing for npm, crates.io, PyPI, and Homebrew. Verifies pr | ✅ Active |
|
|
62
|
+
| 33 | Build | `setup-environment` | Pre-install dependencies and configure tools before development work begins. Use | ✅ Active |
|
|
63
|
+
| 34 | Build | `spike-prototype` | Throw-away prototype for unknown problem spaces. Output is learning notes in spe | ✅ Active |
|
|
64
|
+
| 35 | Build | `wire-ci` | "CI pipeline setup with pre-built templates and local validation. Generates GitH | ✅ Active |
|
|
65
|
+
| 36 | Build | `wire-observability` | Add structured JSON logging, observability commands, and idempotent setup script | ✅ Active |
|
|
66
|
+
| 37 | Verify | `audit-code` | Self-review checklist for the coding agent to run before dispatching a reviewer. | ✅ Active |
|
|
67
|
+
| 38 | Verify | `diagnose-root` | Run 4-phase root cause analysis — reproduce, isolate, hypothesize, verify. Use | ✅ Active |
|
|
68
|
+
| 39 | Verify | `enforce-first` | Apply the F.I.R.S.T test quality rubric (Fast, Independent, Repeatable, Self-Val | ✅ Active |
|
|
69
|
+
| 40 | Verify | `fix-bug` | Bug fix orchestrator — active_flow fix_bug; reads specs/bugs/BUG-*.md; chains | ✅ Active |
|
|
70
|
+
| 41 | Verify | `inspect-quality` | Interactive QA session where user reports bugs or issues conversationally, and t | ✅ Active |
|
|
71
|
+
| 42 | Verify | `investigate-bug` | Investigate a bug or issue by exploring the codebase to find root cause, then wr | ✅ Active |
|
|
72
|
+
| 43 | Verify | `request-review` | Dispatch a fresh reviewer agent with a clean context to critique the code after | ✅ Active |
|
|
73
|
+
| 44 | Verify | `respond-review` | Act on a reviewer agent's feedback systematically — categorize findings, apply | ✅ Active |
|
|
74
|
+
| 45 | Verify | `run-evals` | Eval-Driven Development — define capability and regression evals before buildi | ✅ Active |
|
|
75
|
+
| 46 | Verify | `trace-requirement` | Link story IDs from specs/release-plan.yaml + epic capsule directories to the im | ✅ Active |
|
|
76
|
+
| 47 | Verify | `validate-fix` | Prove a fix works before declaring done — re-run the failing test, run the ful | ✅ Active |
|
|
77
|
+
| 48 | Verify | `verify-work` | Multi-phase UAT gate — cold-start smoke, build, typecheck, lint, tests, step-b | ✅ Active |
|
|
78
|
+
| 49 | Release | `commit-message` | Reviews working-tree changes, then drafts a Conventional Commits title/body and | ✅ Active |
|
|
79
|
+
| 50 | Release | `release-branch` | Make the merge/PR/keep/discard decision for a feature branch, verify coverage ga | ✅ Active |
|
|
80
|
+
| 51 | Sustain | `compose-workflow` | Chain multiple bigpowers skills into a custom workflow recipe saved in specs/. U | ✅ Active |
|
|
81
|
+
| 52 | Sustain | `delegate-task` | Delegate one complex task to a single subagent, review its work in two stages be | ✅ Active |
|
|
82
|
+
| 53 | Sustain | `dispatch-agents` | Dispatch multiple subagents in parallel on independent tasks. No waiting between | ✅ Active |
|
|
83
|
+
| 54 | Sustain | `edit-document` | Edit and improve documents by restructuring sections, improving clarity, and tig | ✅ Active |
|
|
84
|
+
| 55 | Sustain | `evolve-skill` | Benchmark-gated skill evolution — consume bigpowers-benchmark report, propose | ✅ Active |
|
|
85
|
+
| 56 | Sustain | `migrate-spec` | Detect GSD, spec-kit, or BMAD spec artifacts and transform them into bigpowers Y | ✅ Active |
|
|
86
|
+
| 57 | Sustain | `organize-workspace` | Scans the active workspace for disposable artifacts—logs, caches, stale build | ✅ Active |
|
|
87
|
+
| 58 | Sustain | `reset-baseline` | Restore the project to a known clean state between agent runs or experiments. Us | ✅ Active |
|
|
88
|
+
| 59 | Sustain | `session-state` | Track implementation decisions and progress in specs/state.yaml to prevent conte | ✅ Active |
|
|
89
|
+
| 60 | Sustain | `simulate-agents` | Run Mock User and Auditor agents against a feature in fresh contexts before huma | ✅ Active |
|
|
90
|
+
| 61 | Sustain | `stocktake-skills` | Sequential subagent batch audit of the bigpowers skill catalog — Quick Scan (c | ✅ Active |
|
|
91
|
+
| 62 | Sustain | `terse-mode` | Fallback ultra-compressed communication mode. Cuts token usage ~75% by dropping | ✅ Active |
|
|
92
|
+
| 63 | Sustain | `write-document` | Write, organize, and sync high-integrity technical documents using the BMAD meth | ✅ Active |
|
|
93
|
+
|
|
94
|
+
**Total: 63 active skills.**
|
|
94
95
|
|
|
95
96
|
---
|
|
96
97
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish-package
|
|
3
|
+
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."
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Publish Package
|
|
8
|
+
|
|
9
|
+
> **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.
|
|
10
|
+
>
|
|
11
|
+
> **HARD GATE** — Always run `--dry-run` first. Package registries are append-only — a bad publish cannot be fully undone on most registries.
|
|
12
|
+
|
|
13
|
+
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.
|
|
14
|
+
|
|
15
|
+
## Process
|
|
16
|
+
|
|
17
|
+
### 1. Detect package type
|
|
18
|
+
|
|
19
|
+
Read the project root for manifest files to determine the package type:
|
|
20
|
+
|
|
21
|
+
| Manifest | Registry | Publish command |
|
|
22
|
+
|----------|----------|----------------|
|
|
23
|
+
| `package.json` | npm | `npm publish --access public` |
|
|
24
|
+
| `Cargo.toml` | crates.io | `cargo publish` |
|
|
25
|
+
| `setup.py` / `pyproject.toml` | PyPI | `twine upload dist/*` or `flit publish` |
|
|
26
|
+
| `Formula/<name>.rb` | Homebrew | `brew bump-formula-pr` |
|
|
27
|
+
| Multiple detected | Polyglot | Error: specify registry with `--registry <npm|crates.io|pypi|brew>` |
|
|
28
|
+
|
|
29
|
+
If no manifest is found, prompt the user to specify the type or pass `--type <npm|crates.io|pypi|brew>`.
|
|
30
|
+
|
|
31
|
+
### 2. Verify prerequisites
|
|
32
|
+
|
|
33
|
+
Before attempting any publish, run all applicable checks:
|
|
34
|
+
|
|
35
|
+
**npm (`package.json`):**
|
|
36
|
+
```bash
|
|
37
|
+
# Check auth token exists
|
|
38
|
+
if [ -z "${NPM_TOKEN:-}" ]; then
|
|
39
|
+
if [ ! -f ~/.npmrc ] || ! grep -q "_authToken" ~/.npmrc; then
|
|
40
|
+
echo "FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add //registry.npmjs.org/:_authToken=<token> to .npmrc"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Check version not already published
|
|
46
|
+
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
47
|
+
CURRENT_VER=$(node -p "require('./package.json').version")
|
|
48
|
+
if npm view "$PACKAGE_NAME@$CURRENT_VER" version 2>/dev/null; then
|
|
49
|
+
echo "FAIL: Version $CURRENT_VER already published for $PACKAGE_NAME. Bump version first."
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Check build artifacts are fresh
|
|
54
|
+
if [ -d dist ] || [ -d lib ]; then
|
|
55
|
+
LATEST_BUILD=$(find dist lib 2>/dev/null -name "*.js" -o -name "*.cjs" -o -name "*.mjs" | xargs ls -t 2>/dev/null | head -1)
|
|
56
|
+
PACKAGE_MODIFIED=$(stat -f %m package.json 2>/dev/null || stat -c %Y package.json 2>/dev/null)
|
|
57
|
+
if [ -n "$LATEST_BUILD" ] && [ -n "$PACKAGE_MODIFIED" ]; then
|
|
58
|
+
BUILD_TIME=$(stat -f %m "$LATEST_BUILD" 2>/dev/null || stat -c %Y "$LATEST_BUILD" 2>/dev/null)
|
|
59
|
+
if [ "$BUILD_TIME" -lt "$PACKAGE_MODIFIED" ]; then
|
|
60
|
+
echo "WARNING: Build artifacts may be stale (package.json modified after last build). Run npm run build first."
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Check CHANGELOG is updated
|
|
66
|
+
if [ -f CHANGELOG.md ]; then
|
|
67
|
+
if ! grep -q "$CURRENT_VER" CHANGELOG.md 2>/dev/null; then
|
|
68
|
+
echo "WARNING: Version $CURRENT_VER not found in CHANGELOG.md. Update changelog before publish."
|
|
69
|
+
fi
|
|
70
|
+
fi
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**crates.io (`Cargo.toml`):**
|
|
74
|
+
```bash
|
|
75
|
+
# Check auth token exists
|
|
76
|
+
if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
|
|
77
|
+
if [ ! -f ~/.cargo/config.toml ] || ! grep -q "token" ~/.cargo/config.toml; then
|
|
78
|
+
echo "FAIL: CARGO_REGISTRY_TOKEN not set. Set via: export CARGO_REGISTRY_TOKEN=<token> or add to ~/.cargo/config.toml"
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Check version not already published
|
|
84
|
+
CRATE_NAME=$(grep '^name' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
85
|
+
CURRENT_VER=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
|
86
|
+
if cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\""; then
|
|
87
|
+
echo "FAIL: Version $CURRENT_VER already published for $CRATE_NAME. Bump version in Cargo.toml first."
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**PyPI (`setup.py` / `pyproject.toml`):**
|
|
93
|
+
```bash
|
|
94
|
+
# Check auth token exists
|
|
95
|
+
if [ -z "${TWINE_PASSWORD:-}" ] && [ -z "${POETRY_PYPI_TOKEN_PYPI:-}" ]; then
|
|
96
|
+
if [ ! -f ~/.pypirc ]; then
|
|
97
|
+
echo "FAIL: PyPI token not configured. Set TWINE_PASSWORD or create ~/.pypirc"
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Check for build artifacts
|
|
103
|
+
if [ ! -d dist ] || [ -z "$(ls dist/*.whl 2>/dev/null)" ]; then
|
|
104
|
+
echo "WARNING: No .whl files found in dist/. Run: python -m build"
|
|
105
|
+
fi
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 3. Run publish
|
|
109
|
+
|
|
110
|
+
After all prerequisite checks pass, run the registry-specific command:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# npm
|
|
114
|
+
npm publish --access public
|
|
115
|
+
|
|
116
|
+
# crates.io
|
|
117
|
+
cargo publish
|
|
118
|
+
|
|
119
|
+
# PyPI
|
|
120
|
+
python -m twine upload dist/* # or: poetry publish
|
|
121
|
+
|
|
122
|
+
# Homebrew (opens PR, does not publish directly)
|
|
123
|
+
brew bump-formula-pr --url=<tarball-url> <formula-name>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 4. Verify publish success
|
|
127
|
+
|
|
128
|
+
After publish, confirm the version appears on the registry:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# npm
|
|
132
|
+
npm view "$PACKAGE_NAME" versions --json 2>/dev/null | grep -q "\"$CURRENT_VER\"" && echo "OK: npm publish confirmed"
|
|
133
|
+
|
|
134
|
+
# crates.io
|
|
135
|
+
cargo search "$CRATE_NAME" 2>/dev/null | grep -q "^${CRATE_NAME}.*\"$CURRENT_VER\"" && echo "OK: crates.io publish confirmed"
|
|
136
|
+
|
|
137
|
+
# PyPI
|
|
138
|
+
pip index versions "$PACKAGE_NAME" 2>/dev/null | grep -q "$CURRENT_VER" && echo "OK: PyPI publish confirmed"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5. Error handling
|
|
142
|
+
|
|
143
|
+
On failure, surface actionable hints:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Generic failure handler
|
|
147
|
+
if [ $? -ne 0 ]; then
|
|
148
|
+
case "$REGISTRY" in
|
|
149
|
+
npm)
|
|
150
|
+
echo "FAIL: npm publish failed."
|
|
151
|
+
echo " Common causes:"
|
|
152
|
+
echo " - NPM_TOKEN not set in secrets: add to GitHub repo secrets"
|
|
153
|
+
echo " - Version already published: bump version in package.json"
|
|
154
|
+
echo " - Two-factor auth required: use --otp=<code> flag"
|
|
155
|
+
echo " - Package scoped but not public: add --access public"
|
|
156
|
+
;;
|
|
157
|
+
crates.io)
|
|
158
|
+
echo "FAIL: cargo publish failed."
|
|
159
|
+
echo " Common causes:"
|
|
160
|
+
echo " - CARGO_REGISTRY_TOKEN not configured: see ~/.cargo/config.toml"
|
|
161
|
+
echo " - Version already published: bump version in Cargo.toml"
|
|
162
|
+
echo " - Local changes not committed: cargo publish requires clean working tree"
|
|
163
|
+
;;
|
|
164
|
+
pypi)
|
|
165
|
+
echo "FAIL: PyPI publish failed."
|
|
166
|
+
echo " Common causes:"
|
|
167
|
+
echo " - TWINE_PASSWORD not configured: set env var or ~/.pypirc"
|
|
168
|
+
echo " - Build artifacts missing: run python -m build first"
|
|
169
|
+
echo " - Version conflict: version already exists on PyPI"
|
|
170
|
+
;;
|
|
171
|
+
esac
|
|
172
|
+
exit 1
|
|
173
|
+
fi
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 6. Dry-run mode (`--dry-run`)
|
|
177
|
+
|
|
178
|
+
Run `--dry-run` to verify all prerequisites without actually publishing:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Example output
|
|
182
|
+
$ publish-package --dry-run
|
|
183
|
+
|
|
184
|
+
[DRY-RUN] Detected package type: npm
|
|
185
|
+
[DRY-RUN] Package: my-package v0.4.0
|
|
186
|
+
[DRY-RUN] Checking NPM_TOKEN... OK
|
|
187
|
+
[DRY-RUN] Checking version 0.4.0 not already published... OK
|
|
188
|
+
[DRY-RUN] Checking build artifacts... WARNING: package.json modified after build
|
|
189
|
+
[DRY-RUN] Checking CHANGELOG... OK
|
|
190
|
+
[DRY-RUN] Would run: npm publish --access public
|
|
191
|
+
[DRY-RUN] Exiting without publishing.
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 7. Dry-run mode per registry
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# npm dry-run
|
|
198
|
+
npm publish --access public --dry-run
|
|
199
|
+
|
|
200
|
+
# crates.io dry-run (cargo does not have a publish dry-run; use --dry-run flag for validation only)
|
|
201
|
+
cargo package --list 2>/dev/null
|
|
202
|
+
|
|
203
|
+
# PyPI dry-run
|
|
204
|
+
python -m twine upload --repository testpypi dist/* # test.pypi.org
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Options
|
|
208
|
+
|
|
209
|
+
| Flag | Description |
|
|
210
|
+
|------|-------------|
|
|
211
|
+
| `--dry-run` | Verify prerequisites and show publish command without executing |
|
|
212
|
+
| `--registry <type>` | Force registry type (skip auto-detection) |
|
|
213
|
+
| `--otp <code>` | One-time password for npm 2FA |
|
|
214
|
+
| `--no-verify` | Skip prerequisite checks (use with caution) |
|
|
215
|
+
|
|
216
|
+
## Examples
|
|
217
|
+
|
|
218
|
+
### Publish an npm package
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Verify first
|
|
222
|
+
publish-package --dry-run
|
|
223
|
+
|
|
224
|
+
# Publish
|
|
225
|
+
publish-package
|
|
226
|
+
|
|
227
|
+
# Output:
|
|
228
|
+
# [npm] Publishing my-package v0.4.0...
|
|
229
|
+
# OK: npm publish confirmed (my-package@0.4.0 on registry)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Publish a Rust crate
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
export CARGO_REGISTRY_TOKEN=<token>
|
|
236
|
+
publish-package --dry-run
|
|
237
|
+
publish-package
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Missing token scenario
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
$ publish-package
|
|
244
|
+
FAIL: NPM_TOKEN not set. Set via: export NPM_TOKEN=<token> or add to .npmrc
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Integration with release-branch
|
|
248
|
+
|
|
249
|
+
When wired into `release-branch`, add a step after git push:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
6a. Run publish-package to publish to package registries
|
|
253
|
+
→ verify: publish-package --dry-run && publish-package
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Verify
|
|
257
|
+
|
|
258
|
+
→ verify: `test -f publish-package/SKILL.md && echo "OK: skill file exists" || echo "FAIL: no skill file"`
|
|
259
|
+
→ verify: `grep -q "name: publish-package" publish-package/SKILL.md && echo "OK: frontmatter" || echo "FAIL: frontmatter"`
|
|
260
|
+
→ verify: `grep -ci "npm\|crates.io\|pypi\|publish\|registry" publish-package/SKILL.md | awk '{if($1>=4) print "OK: semantics"; else print "FAIL: missing"}'`
|
|
261
|
+
→ verify: `grep -q "publish-package" SKILL-INDEX.md && echo "OK: in SKILL-INDEX" || echo "FAIL: not indexed"`
|
package/skills-lock.json
CHANGED
|
@@ -186,6 +186,11 @@
|
|
|
186
186
|
"sha256": "12d45efb07a36e94",
|
|
187
187
|
"path": "plan-work/SKILL.md"
|
|
188
188
|
},
|
|
189
|
+
"publish-package": {
|
|
190
|
+
"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.\"",
|
|
191
|
+
"sha256": "25ead1dd4d174d54",
|
|
192
|
+
"path": "publish-package/SKILL.md"
|
|
193
|
+
},
|
|
189
194
|
"release-branch": {
|
|
190
195
|
"description": "Make the merge/PR/keep/discard decision for a feature branch, verify coverage gates, create the PR with gh, and clean up the worktree. Use when a feature is done and ready to ship, or when user says \"release\", \"merge\", or \"open a PR\".",
|
|
191
196
|
"sha256": "70fc37ac4e22143d",
|