bigpowers 2.7.5 → 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/prompts/wire-ci.md +307 -0
- package/.pi/skills/publish-package/SKILL.md +262 -0
- package/.pi/skills/wire-ci/SKILL.md +309 -0
- package/CHANGELOG.md +14 -0
- package/SKILL-INDEX.md +38 -36
- package/package.json +1 -1
- package/publish-package/SKILL.md +261 -0
- package/scripts/generate-skill-index.sh +2 -0
- package/skills-lock.json +10 -0
- package/wire-ci/SKILL.md +308 -0
|
@@ -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"`
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wire-ci
|
|
3
|
+
description: "\"CI pipeline setup with pre-built templates and local validation. Generates GitHub Actions workflows, validates YAML syntax and permissions, supports dry-run via act/gh. The CI equivalent of wire-observability.\""
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Wire CI
|
|
9
|
+
|
|
10
|
+
> **HARD GATE** — Do not ship a project without CI. Run this skill before first merge to main or when adding CI to an existing project.
|
|
11
|
+
>
|
|
12
|
+
> **HARD GATE** — CI that is untestable locally will break every cycle. Always run `--validate` after generating workflows and `--dry-run` before pushing.
|
|
13
|
+
|
|
14
|
+
Generate, validate, and test CI workflows. Detects your project type, produces platform-appropriate GitHub Actions configurations, and provides local verification to catch auth, permissions, and syntax issues before they reach CI.
|
|
15
|
+
|
|
16
|
+
## What this sets up
|
|
17
|
+
|
|
18
|
+
1. **CI workflow** — `.github/workflows/ci.yaml` with test, lint, typecheck, build steps
|
|
19
|
+
2. **Release workflow** — `.github/workflows/release.yaml` with semantic-release (if applicable)
|
|
20
|
+
3. **`--validate` mode** — checks YAML syntax, workflow permissions, required secrets, and common pitfalls
|
|
21
|
+
4. **`--dry-run` mode** — runs workflows locally via `act` or `gh workflow run` to prove correctness before push
|
|
22
|
+
5. **Failure pattern documentation** — common CI failure categories and their fixes
|
|
23
|
+
|
|
24
|
+
## Process
|
|
25
|
+
|
|
26
|
+
### 1. Detect project type
|
|
27
|
+
|
|
28
|
+
Read the project root for manifest files to determine which template to use:
|
|
29
|
+
|
|
30
|
+
| Manifest | Type | Template |
|
|
31
|
+
|----------|------|----------|
|
|
32
|
+
| `Cargo.toml` | Rust | Rust CI: test, clippy, fmt, build |
|
|
33
|
+
| `package.json` | Node | Node CI: test, lint, typecheck, build |
|
|
34
|
+
| `setup.py` / `pyproject.toml` | Python | Python CI: pytest, ruff/mypy/flake8, build |
|
|
35
|
+
| `go.mod` | Go | Go CI: test, vet, staticcheck, build |
|
|
36
|
+
| `CMakeLists.txt` | C/C++ | C/C++ CI: cmake build, ctest |
|
|
37
|
+
| Multiple detected | Polyglot | Combined workflows or error if ambiguous |
|
|
38
|
+
|
|
39
|
+
If no manifest is found, prompt the user to specify the type or pass `--type <rust|node|python|go|cpp>`.
|
|
40
|
+
|
|
41
|
+
### 2. Generate CI workflow
|
|
42
|
+
|
|
43
|
+
Create `.github/workflows/ci.yaml` with standard steps derived from the project type and its manifest:
|
|
44
|
+
|
|
45
|
+
**Rust template (`Cargo.toml`):**
|
|
46
|
+
```yaml
|
|
47
|
+
name: CI
|
|
48
|
+
on: [push, pull_request]
|
|
49
|
+
jobs:
|
|
50
|
+
test:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v4
|
|
54
|
+
- uses: actions-rust/toolchain@v1
|
|
55
|
+
with:
|
|
56
|
+
toolchain: stable
|
|
57
|
+
components: clippy, rustfmt
|
|
58
|
+
- run: cargo fmt --all -- --check
|
|
59
|
+
- run: cargo clippy -- -D warnings
|
|
60
|
+
- run: cargo test
|
|
61
|
+
- run: cargo build --release
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Node template (`package.json`):**
|
|
65
|
+
```yaml
|
|
66
|
+
name: CI
|
|
67
|
+
on: [push, pull_request]
|
|
68
|
+
jobs:
|
|
69
|
+
test:
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v4
|
|
73
|
+
- uses: actions/setup-node@v4
|
|
74
|
+
with:
|
|
75
|
+
node-version: 20
|
|
76
|
+
cache: npm
|
|
77
|
+
- run: npm ci
|
|
78
|
+
- run: npm test
|
|
79
|
+
- run: npm run lint 2>/dev/null || true
|
|
80
|
+
- run: npm run typecheck 2>/dev/null || true
|
|
81
|
+
- run: npm run build 2>/dev/null || true
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Python template (`setup.py` / `pyproject.toml`):**
|
|
85
|
+
```yaml
|
|
86
|
+
name: CI
|
|
87
|
+
on: [push, pull_request]
|
|
88
|
+
jobs:
|
|
89
|
+
test:
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
steps:
|
|
92
|
+
- uses: actions/checkout@v4
|
|
93
|
+
- uses: actions/setup-python@v5
|
|
94
|
+
with:
|
|
95
|
+
python-version: "3.12"
|
|
96
|
+
cache: pip
|
|
97
|
+
- run: pip install -e ".[dev]" || pip install -e .
|
|
98
|
+
- run: pip install pytest ruff mypy
|
|
99
|
+
- run: ruff check .
|
|
100
|
+
- run: mypy . 2>/dev/null || true
|
|
101
|
+
- run: pytest
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Go template (`go.mod`):**
|
|
105
|
+
```yaml
|
|
106
|
+
name: CI
|
|
107
|
+
on: [push, pull_request]
|
|
108
|
+
jobs:
|
|
109
|
+
test:
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v4
|
|
113
|
+
- uses: actions/setup-go@v5
|
|
114
|
+
with:
|
|
115
|
+
go-version: stable
|
|
116
|
+
cache: true
|
|
117
|
+
- run: go vet ./...
|
|
118
|
+
- run: go test ./...
|
|
119
|
+
- run: go build ./...
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**C/C++ template (`CMakeLists.txt`):**
|
|
123
|
+
```yaml
|
|
124
|
+
name: CI
|
|
125
|
+
on: [push, pull_request]
|
|
126
|
+
jobs:
|
|
127
|
+
test:
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
steps:
|
|
130
|
+
- uses: actions/checkout@v4
|
|
131
|
+
- run: cmake -B build
|
|
132
|
+
- run: cmake --build build
|
|
133
|
+
- run: ctest --test-dir build
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 3. Generate release workflow (if semantic-release detected)
|
|
137
|
+
|
|
138
|
+
If the project has semantic-release configured (in `package.json`, `.releaserc`, or `release.config.js`), also generate `.github/workflows/release.yaml`:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
name: Release
|
|
142
|
+
on:
|
|
143
|
+
push:
|
|
144
|
+
branches: [main]
|
|
145
|
+
jobs:
|
|
146
|
+
release:
|
|
147
|
+
runs-on: ubuntu-latest
|
|
148
|
+
permissions:
|
|
149
|
+
contents: write
|
|
150
|
+
issues: write
|
|
151
|
+
pull-requests: write
|
|
152
|
+
id-token: write
|
|
153
|
+
steps:
|
|
154
|
+
- uses: actions/checkout@v4
|
|
155
|
+
with:
|
|
156
|
+
fetch-depth: 0
|
|
157
|
+
- uses: actions/setup-node@v4
|
|
158
|
+
with:
|
|
159
|
+
node-version: 20
|
|
160
|
+
cache: npm
|
|
161
|
+
- run: npm ci
|
|
162
|
+
- run: npm run build 2>/dev/null || true
|
|
163
|
+
- run: npx semantic-release
|
|
164
|
+
env:
|
|
165
|
+
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
166
|
+
NPM_TOKEN: \${{ secrets.NPM_TOKEN }}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
> **NPM_TOKEN is required** for publishing to npm. Without it, semantic-release will fail at the publish step. See `--validate` to check this.
|
|
170
|
+
|
|
171
|
+
### 4. Validate workflows (`--validate`)
|
|
172
|
+
|
|
173
|
+
Run `wire-ci --validate` to check all generated workflow files:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Validate YAML syntax
|
|
177
|
+
for f in .github/workflows/*.yaml; do
|
|
178
|
+
python3 -c "import yaml; yaml.safe_load(open('$f'))" || echo "FAIL: $f has YAML syntax errors"
|
|
179
|
+
done
|
|
180
|
+
|
|
181
|
+
# Check permissions block presence
|
|
182
|
+
for f in .github/workflows/*.yaml; do
|
|
183
|
+
if grep -q "permissions:" "$f"; then
|
|
184
|
+
echo "OK: $f has permissions block"
|
|
185
|
+
else
|
|
186
|
+
echo "WARNING: $f missing permissions block — add one for security"
|
|
187
|
+
fi
|
|
188
|
+
done
|
|
189
|
+
|
|
190
|
+
# Check for npm publish without NPM_TOKEN
|
|
191
|
+
for f in .github/workflows/*.yaml; do
|
|
192
|
+
if grep -q "npm publish\|npx semantic-release" "$f"; then
|
|
193
|
+
if ! grep -q "NPM_TOKEN" "$f"; then
|
|
194
|
+
echo "WARNING: $f has npm publish/semantic-release but no NPM_TOKEN secret"
|
|
195
|
+
fi
|
|
196
|
+
fi
|
|
197
|
+
done
|
|
198
|
+
|
|
199
|
+
# Check for hardcoded Node versions
|
|
200
|
+
for f in .github/workflows/*.yaml; do
|
|
201
|
+
if grep -q "node-version: [0-9]" "$f" && grep -qv "node-version-file\|\.nvmrc" "$f"; then
|
|
202
|
+
echo "NOTE: $f has hardcoded Node version — consider using .nvmrc instead"
|
|
203
|
+
fi
|
|
204
|
+
done
|
|
205
|
+
|
|
206
|
+
# Check for common secrets reference errors
|
|
207
|
+
for f in .github/workflows/*.yaml; do
|
|
208
|
+
# Secrets referencing something that doesn't exist in the workflow
|
|
209
|
+
grep -oP 'secrets\.\w+' "$f" | sort -u | while read -r secret; do
|
|
210
|
+
echo "REF: $f references $secret"
|
|
211
|
+
done
|
|
212
|
+
done
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Exit codes:**
|
|
216
|
+
- `0` — all checks pass (no errors)
|
|
217
|
+
- `1` — YAML syntax errors found
|
|
218
|
+
- `2` — validation warnings only (missing permissions, secrets, etc.)
|
|
219
|
+
|
|
220
|
+
### 5. Dry-run workflows (`--dry-run`)
|
|
221
|
+
|
|
222
|
+
Attempt to run the generated workflows locally to catch errors before push:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Option A: Use act (recommended)
|
|
226
|
+
if command -v act &>/dev/null; then
|
|
227
|
+
act push --dry-run
|
|
228
|
+
echo "OK: act dry-run completed"
|
|
229
|
+
elif command -v gh &>/dev/null; then
|
|
230
|
+
# Option B: Use gh workflow run (remote test, no local docker)
|
|
231
|
+
gh workflow run ci.yaml --ref "$(git branch --show-current)"
|
|
232
|
+
echo "OK: CI workflow dispatched. Check status: gh run list"
|
|
233
|
+
else
|
|
234
|
+
echo "NOTE: Install act (https://github.com/nektos/act) for full local dry-run"
|
|
235
|
+
echo " Install gh CLI for remote dry-run"
|
|
236
|
+
fi
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
> **act** runs workflows in a local Docker environment — the most accurate pre-push validation.
|
|
240
|
+
> **gh workflow run** sends the workflow to GitHub but doesn't execute locally — useful for checking YAML parsing but not for testing the actual steps.
|
|
241
|
+
|
|
242
|
+
### 6. Document common CI failure patterns
|
|
243
|
+
|
|
244
|
+
Add the following to the project's documentation or CLAUDE.md after setup:
|
|
245
|
+
|
|
246
|
+
| Failure | Cause | Fix |
|
|
247
|
+
|---------|-------|-----|
|
|
248
|
+
| `npm publish` fails | `NPM_TOKEN` not set as repo secret | Add `NPM_TOKEN` to GitHub repo secrets |
|
|
249
|
+
| `semantic-release` fails on push | Missing `permissions: contents: write` | Add `permissions: contents: write` to release job |
|
|
250
|
+
| `cargo publish` auth fail | `CARGO_REGISTRY_TOKEN` not set | Add token to `~/.cargo/config.toml` or env |
|
|
251
|
+
| `go vet` fails | Go version mismatch | Match `go.mod` `go` directive with setup-go version |
|
|
252
|
+
| `cargo clippy` errors | New lints in Rust nightly | `cargo clippy --fix` or allow specific lints |
|
|
253
|
+
| `act` not found | Docker not running or act not installed | `brew install act` / `docker ps` to verify Docker |
|
|
254
|
+
| Hardcoded Node version stale | `.nvmrc` exists but workflow uses hardcoded version | Use `node-version-file: .nvmrc` instead |
|
|
255
|
+
|
|
256
|
+
## Examples
|
|
257
|
+
|
|
258
|
+
### Create CI for a Rust project
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Detect from Cargo.toml, generate workflows
|
|
262
|
+
wire-ci
|
|
263
|
+
|
|
264
|
+
# Validate generated workflows
|
|
265
|
+
wire-ci --validate
|
|
266
|
+
|
|
267
|
+
# Run locally with act
|
|
268
|
+
wire-ci --dry-run
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Create CI for a Node project with semantic-release
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
wire-ci
|
|
275
|
+
wire-ci --validate
|
|
276
|
+
# Expect warning: "npm publish step found but no NPM_TOKEN in secrets"
|
|
277
|
+
# Fix: add NPM_TOKEN to repo secrets
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Validate existing workflows (no generation)
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
wire-ci --validate --check-only
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Options
|
|
287
|
+
|
|
288
|
+
| Flag | Description |
|
|
289
|
+
|------|-------------|
|
|
290
|
+
| `--validate` | Check YAML syntax, permissions, secrets, common pitfalls |
|
|
291
|
+
| `--dry-run` | Run workflows locally via `act` or dispatch via `gh` |
|
|
292
|
+
| `--check-only` | Only validate, do not generate new files |
|
|
293
|
+
| `--type <type>` | Force project type (skip auto-detection) |
|
|
294
|
+
| `--force` | Overwrite existing workflow files |
|
|
295
|
+
| `--no-release` | Skip release workflow generation even if semantic-release detected |
|
|
296
|
+
|
|
297
|
+
## Integration with build-epic
|
|
298
|
+
|
|
299
|
+
When `wire-ci` is used as part of `build-epic`:
|
|
300
|
+
|
|
301
|
+
1. **During develop-tdd**: If the task modifies `.github/workflows/`, run `wire-ci --validate` as a CI dry-run sub-step
|
|
302
|
+
2. **During release-branch**: After push, run `gh run list --limit 1 --branch main --json status,conclusion` to verify CI passes
|
|
303
|
+
|
|
304
|
+
## Verify
|
|
305
|
+
|
|
306
|
+
→ verify: `test -f wire-ci/SKILL.md && echo "OK: skill file exists" || echo "FAIL: no skill file"`
|
|
307
|
+
→ verify: `grep -q "name: wire-ci" wire-ci/SKILL.md && echo "OK: frontmatter" || echo "FAIL: frontmatter"`
|
|
308
|
+
→ verify: `grep -ci "template\|workflow\|validate\|dry.run" wire-ci/SKILL.md | awk '{if($1>=3) print "OK: semantics"; else print "FAIL: missing"}'`
|
|
309
|
+
→ verify: `grep -q "wire-ci" SKILL-INDEX.md && echo "OK: in SKILL-INDEX" || echo "FAIL: not indexed"`
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
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
|
+
|
|
8
|
+
# [2.8.0](https://github.com/danielvm-git/bigpowers/compare/v2.7.5...v2.8.0) (2026-06-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **skills:** add wire-ci CI pipeline skill ([7196579](https://github.com/danielvm-git/bigpowers/commit/71965799376ec894f48a957626455142beb5080b))
|
|
14
|
+
|
|
1
15
|
## [2.7.5](https://github.com/danielvm-git/bigpowers/compare/v2.7.4...v2.7.5) (2026-06-20)
|
|
2
16
|
|
|
3
17
|
|