bigpowers 2.87.6 → 2.87.8
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/.gemini/extensions/bigpowers/gemini-extension.json +1 -1
- package/.pi/package.json +1 -1
- package/CHANGELOG.md +14 -0
- package/README.md +19 -0
- package/bin/bigpowers.js +8 -0
- package/bin/init.js +39 -0
- package/docs/templates/AGENTS.md +89 -0
- package/docs/templates/ci/github/test-build-release-go.yml +68 -0
- package/docs/templates/ci/github/test-build-release-node.yml +87 -0
- package/docs/templates/ci/github/test-build-release-python.yml +74 -0
- package/docs/templates/ci/github/test-build-release-rust.yml +67 -0
- package/package.json +1 -1
- package/scripts/lib/__pycache__/link_utils.cpython-312.pyc +0 -0
- package/scripts/lib/__pycache__/srp_engine_links.cpython-312.pyc +0 -0
- package/scripts/lib/install-helpers.js +53 -1
- package/scripts/test-install-helpers.js +113 -0
package/.pi/package.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.87.8](https://github.com/danielvm-git/bigpowers/compare/v2.87.7...v2.87.8) (2026-09-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **cli:** bigpowers init provisions scripts/ + specs/ into consumer projects ([#117](https://github.com/danielvm-git/bigpowers/issues/117)) ([37bc0bf](https://github.com/danielvm-git/bigpowers/commit/37bc0bf72875cd66898d35138870982c8af2d310)), closes [#116](https://github.com/danielvm-git/bigpowers/issues/116) [#116](https://github.com/danielvm-git/bigpowers/issues/116) [#114](https://github.com/danielvm-git/bigpowers/issues/114) [#116](https://github.com/danielvm-git/bigpowers/issues/116) [#114](https://github.com/danielvm-git/bigpowers/issues/114)
|
|
7
|
+
|
|
8
|
+
## [2.87.7](https://github.com/danielvm-git/bigpowers/compare/v2.87.6...v2.87.7) (2026-09-01)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **packaging:** ship wire-ci CI templates in the npm tarball ([#115](https://github.com/danielvm-git/bigpowers/issues/115)) ([26df32b](https://github.com/danielvm-git/bigpowers/commit/26df32bc88310950863715dc26ca9c97dcaa4601)), closes [#113](https://github.com/danielvm-git/bigpowers/issues/113)
|
|
14
|
+
|
|
1
15
|
## [2.87.6](https://github.com/danielvm-git/bigpowers/compare/v2.87.5...v2.87.6) (2026-09-01)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -216,6 +216,25 @@ pi install .
|
|
|
216
216
|
pi install npm:bigpowers
|
|
217
217
|
```
|
|
218
218
|
|
|
219
|
+
### Provision a consumer project (`bigpowers init`)
|
|
220
|
+
|
|
221
|
+
pi's package contract registers **skills and prompts only** — it has no resource
|
|
222
|
+
type for arbitrary project files, and no lifecycle script runs on install. Skills
|
|
223
|
+
reference the package's `scripts/*.sh` tooling project-relative (e.g.
|
|
224
|
+
`bash scripts/run-skill-verify.sh`, verify gates like `test -f scripts/... &&
|
|
225
|
+
test -d specs/bugs`), so after installing the package, run **one command per
|
|
226
|
+
consumer project** to provision what the skills expect:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
cd <your-project>
|
|
230
|
+
npx bigpowers init # or: bigpowers init
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This symlinks `<project>/scripts` → the installed package's `scripts/` tree and
|
|
234
|
+
scaffolds `specs/bugs/` + `specs/verifications/`. It refuses (never clobbers) a
|
|
235
|
+
`scripts/` you already own; `bigpowers init --remove` undoes it. The same step
|
|
236
|
+
applies to `npm i -g bigpowers` / `npx bigpowers setup` consumers.
|
|
237
|
+
|
|
219
238
|
**What you get:**
|
|
220
239
|
- **pi skills** in `.pi/skills/` (one per SKILL.md) — loaded automatically into pi's system prompt as `<available_skills>`
|
|
221
240
|
- **pi prompt templates** in `.pi/prompts/` — slash commands like `/survey-context`, `/plan-work`
|
package/bin/bigpowers.js
CHANGED
|
@@ -75,6 +75,13 @@ if (cmd === 'setup' || cmd === 'install') {
|
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
if (cmd === 'init') {
|
|
79
|
+
// Provision the CURRENT project (cwd): scripts/ link + specs/ scaffolding (#116)
|
|
80
|
+
const initScript = path.join(ROOT, 'bin', 'init.js');
|
|
81
|
+
require(initScript);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
78
85
|
if (cmd === 'update') {
|
|
79
86
|
// Pull the newest release first (global installs), then re-sync + refresh symlinks.
|
|
80
87
|
selfUpdateGlobalPackage();
|
|
@@ -106,6 +113,7 @@ bigpowers — agent skills for spec-driven, test-first development
|
|
|
106
113
|
|
|
107
114
|
Commands:
|
|
108
115
|
bigpowers setup Install skills into ~/.claude/skills/
|
|
116
|
+
bigpowers init Provision the CURRENT project: scripts/ link + specs/ scaffolding (run per project)
|
|
109
117
|
bigpowers update Fetch the latest release (global installs) + re-sync and refresh symlinks
|
|
110
118
|
bigpowers status Show installed version and skill count (warns if a newer release exists)
|
|
111
119
|
bigpowers help This message
|
package/bin/init.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bigpowers init — provision the CURRENT project (cwd) for skill tooling.
|
|
3
|
+
// story: BUG-2026-08-31-pi-scripts-provisioning (#116)
|
|
4
|
+
//
|
|
5
|
+
// Package installs (pi install npm:bigpowers, npm i -g, npx) register skills
|
|
6
|
+
// but never provision a project-local scripts/ tree — pi's package contract
|
|
7
|
+
// has no resource type for project files and no lifecycle script runs — so
|
|
8
|
+
// SKILL.md commands (`bash scripts/*.sh`) and `→ verify:` gates fail in every
|
|
9
|
+
// consumer project. `bigpowers init` (or `npx bigpowers init`) links the
|
|
10
|
+
// package's scripts/ into the project and scaffolds specs/{bugs,verifications}.
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
const ROOT = path.dirname(path.dirname(__filename));
|
|
17
|
+
const { initProject, initProjectRemove } = require('../scripts/lib/install-helpers.js');
|
|
18
|
+
|
|
19
|
+
if (process.argv.includes('--remove')) {
|
|
20
|
+
initProjectRemove(ROOT);
|
|
21
|
+
console.log('bigpowers init --remove: removed the managed scripts/ link');
|
|
22
|
+
console.log(' (and specs/ scaffolding dirs only where untouched).');
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const result = initProject(ROOT);
|
|
28
|
+
if (result.skipped === 'cwd-is-package') {
|
|
29
|
+
console.log('bigpowers init: already inside the bigpowers package — nothing to provision.');
|
|
30
|
+
} else {
|
|
31
|
+
console.log('bigpowers init: linked scripts/ → package scripts tree.');
|
|
32
|
+
console.log('bigpowers init: ensured specs/bugs/ + specs/verifications/ scaffolding.');
|
|
33
|
+
console.log('Skill commands and verify gates (fix-bug, verify-work, wire-ci, …) now resolve here.');
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// e.g. Refusing to replace a user-owned scripts/ — surface it, don't stack-trace.
|
|
37
|
+
console.error(`bigpowers init: ${e.message}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# story: e37s01
|
|
2
|
+
# story: e45s21
|
|
3
|
+
# story: e81s01
|
|
4
|
+
# scenario: SC-e37s01-P1-01
|
|
5
|
+
# [Project Name] — AI Agents
|
|
6
|
+
|
|
7
|
+
> **Multi-agent context** — This file is the canonical project context for **Cline**, **Aider**, **OpenCode**, and other AGENTS.md-native tools. Claude Code and Cursor read it via the `CLAUDE.md` symlink.
|
|
8
|
+
|
|
9
|
+
Read CONVENTIONS.md before any GitHub or git operation.
|
|
10
|
+
|
|
11
|
+
<!-- BEGIN bigpowers:context-routing -->
|
|
12
|
+
## Context Routing
|
|
13
|
+
|
|
14
|
+
Load subdirectory context by file glob — see project-specific routing table (seeded by `seed-conventions`).
|
|
15
|
+
<!-- END bigpowers:context-routing -->
|
|
16
|
+
|
|
17
|
+
<!-- BEGIN bigpowers:learned-preferences -->
|
|
18
|
+
## Learned User Preferences
|
|
19
|
+
|
|
20
|
+
- (none yet — updated via `session-state`)
|
|
21
|
+
|
|
22
|
+
## Workspace Facts
|
|
23
|
+
|
|
24
|
+
- (none yet — durable facts discovered across sessions)
|
|
25
|
+
<!-- END bigpowers:learned-preferences -->
|
|
26
|
+
|
|
27
|
+
<!-- BEGIN bigpowers:project -->
|
|
28
|
+
## Project
|
|
29
|
+
|
|
30
|
+
[One sentence. What this codebase does.]
|
|
31
|
+
Stack: [language, framework, runtime]
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
| Action | Command |
|
|
36
|
+
|--------|---------|
|
|
37
|
+
| Run | `[cmd]` |
|
|
38
|
+
| Test | `[cmd]` or N/A |
|
|
39
|
+
| Build | `[cmd]` |
|
|
40
|
+
| Lint | `[cmd]` |
|
|
41
|
+
| Preflight | `[test && lint && build chain — or user-named full-green cmd]` |
|
|
42
|
+
| CI | `gh pr checks` (when a PR is open) |
|
|
43
|
+
|
|
44
|
+
## Test
|
|
45
|
+
|
|
46
|
+
`[cmd]` or N/A
|
|
47
|
+
|
|
48
|
+
## Lint
|
|
49
|
+
|
|
50
|
+
`[cmd]` or N/A
|
|
51
|
+
|
|
52
|
+
## Build
|
|
53
|
+
|
|
54
|
+
`[cmd]` or N/A
|
|
55
|
+
|
|
56
|
+
## Architecture
|
|
57
|
+
|
|
58
|
+
[1–2 sentences. Key modules and their relationships.]
|
|
59
|
+
|
|
60
|
+
## Conventions
|
|
61
|
+
|
|
62
|
+
- [e.g. Named exports only]
|
|
63
|
+
- [e.g. All queries go through the repository layer]
|
|
64
|
+
|
|
65
|
+
## Never
|
|
66
|
+
|
|
67
|
+
- Never dismiss reproducible gate failures as pre-existing or out of scope
|
|
68
|
+
- Never proceed on red Preflight or red CI — invoke quick-fix or fix-bug first
|
|
69
|
+
- [Hard stop — e.g. Never touch legacy/]
|
|
70
|
+
|
|
71
|
+
## Agent Rules
|
|
72
|
+
|
|
73
|
+
- **Workflow Mandate:** Use bigpowers skills (e.g. `plan-work`, `develop-tdd`) for structured work.
|
|
74
|
+
- **Always Green:** Preflight and CI must be green before forward work.
|
|
75
|
+
- Read specs/ and CONVENTIONS.md before writing code.
|
|
76
|
+
- Write the minimum code that solves the stated problem.
|
|
77
|
+
- Run tests after every change. Show evidence before declaring done.
|
|
78
|
+
- All planning output goes in specs/.
|
|
79
|
+
|
|
80
|
+
## Token Economy — Minimal Footprint
|
|
81
|
+
|
|
82
|
+
> Production-safe subset of the 8-rule AGENTS.md pattern (Vercel engineer, ~60B tokens).
|
|
83
|
+
> Rule 1 ("no backward compatibility") is excluded deliberately: it risks data loss in production.
|
|
84
|
+
|
|
85
|
+
1. **Check existing dependencies first.** DO inspect what your current dependencies already do before adding a package or writing your own code.
|
|
86
|
+
2. **Prefer mature, maintained libraries.** DO NOT rewrite a capability a maintained library provides without a documented reason.
|
|
87
|
+
3. **Copy validated patterns.** DO study how established products solve the same problem before inventing a new approach.
|
|
88
|
+
4. **Keep the simplest working implementation.** DO write the least code that satisfies the stated requirement. NEVER add preventive abstraction or unused config layers.
|
|
89
|
+
<!-- END bigpowers:project -->
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Bundled bigpowers CI template — Go. See test-build-release-node.yml for
|
|
2
|
+
# the override mechanism (BIGPOWERS_CI_TEMPLATES). GH #104.
|
|
3
|
+
name: Test Build Release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
lint:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
# Read the version from go.mod so `go vet` cannot drift from the module.
|
|
20
|
+
- uses: actions/setup-go@v5
|
|
21
|
+
with:
|
|
22
|
+
go-version-file: go.mod
|
|
23
|
+
cache: true
|
|
24
|
+
- run: go vet ./...
|
|
25
|
+
|
|
26
|
+
test:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
needs: lint
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v6
|
|
31
|
+
- uses: actions/setup-go@v5
|
|
32
|
+
with:
|
|
33
|
+
go-version-file: go.mod
|
|
34
|
+
cache: true
|
|
35
|
+
- run: go test ./... -race
|
|
36
|
+
|
|
37
|
+
build:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: test
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v6
|
|
42
|
+
- uses: actions/setup-go@v5
|
|
43
|
+
with:
|
|
44
|
+
go-version-file: go.mod
|
|
45
|
+
cache: true
|
|
46
|
+
- run: go build ./...
|
|
47
|
+
- uses: actions/upload-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: dist
|
|
50
|
+
path: bin/
|
|
51
|
+
if-no-files-found: ignore
|
|
52
|
+
|
|
53
|
+
release:
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
needs: build
|
|
56
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
57
|
+
permissions:
|
|
58
|
+
contents: write
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v6
|
|
61
|
+
with:
|
|
62
|
+
fetch-depth: 0
|
|
63
|
+
- uses: actions/download-artifact@v4
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: bin/
|
|
67
|
+
continue-on-error: true
|
|
68
|
+
- run: echo "Add your release step (goreleaser, gh release create, ...) here"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Bundled bigpowers CI template — Node.
|
|
2
|
+
# Ships inside the npm package so `wire-ci` has no network dependency on any
|
|
3
|
+
# third party's repository (GH #104). Override the source with
|
|
4
|
+
# BIGPOWERS_CI_TEMPLATES=/path/to/your/templates to use your own org templates.
|
|
5
|
+
#
|
|
6
|
+
# Keep `name:` as "Test Build Release" — deploy.yml listens for it via workflow_run.
|
|
7
|
+
name: Test Build Release
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
lint:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
- uses: actions/setup-node@v4
|
|
24
|
+
with:
|
|
25
|
+
node-version-file: .nvmrc
|
|
26
|
+
cache: npm
|
|
27
|
+
- run: npm ci
|
|
28
|
+
- run: npm run lint --if-present
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
needs: lint
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v6
|
|
35
|
+
- uses: actions/setup-node@v4
|
|
36
|
+
with:
|
|
37
|
+
node-version-file: .nvmrc
|
|
38
|
+
cache: npm
|
|
39
|
+
- run: npm ci
|
|
40
|
+
- run: npm test
|
|
41
|
+
|
|
42
|
+
build:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
needs: test
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v6
|
|
47
|
+
- uses: actions/setup-node@v4
|
|
48
|
+
with:
|
|
49
|
+
node-version-file: .nvmrc
|
|
50
|
+
cache: npm
|
|
51
|
+
- run: npm ci
|
|
52
|
+
- run: npm run build --if-present
|
|
53
|
+
- uses: actions/upload-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
if-no-files-found: ignore
|
|
58
|
+
|
|
59
|
+
release:
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
needs: build
|
|
62
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
63
|
+
permissions:
|
|
64
|
+
contents: write
|
|
65
|
+
issues: write
|
|
66
|
+
pull-requests: write
|
|
67
|
+
id-token: write
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v6
|
|
70
|
+
with:
|
|
71
|
+
fetch-depth: 0
|
|
72
|
+
- uses: actions/setup-node@v4
|
|
73
|
+
with:
|
|
74
|
+
node-version-file: .nvmrc
|
|
75
|
+
cache: npm
|
|
76
|
+
- run: npm ci
|
|
77
|
+
# Reuse the build output rather than rebuilding — a rebuilt binary is not
|
|
78
|
+
# the artifact that was tested.
|
|
79
|
+
- uses: actions/download-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: dist
|
|
82
|
+
path: dist/
|
|
83
|
+
continue-on-error: true
|
|
84
|
+
- run: npx semantic-release
|
|
85
|
+
env:
|
|
86
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
87
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Bundled bigpowers CI template — Python. See test-build-release-node.yml for
|
|
2
|
+
# the override mechanism (BIGPOWERS_CI_TEMPLATES). GH #104.
|
|
3
|
+
name: Test Build Release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
PYTHON_VERSION: '3.12'
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
25
|
+
cache: pip
|
|
26
|
+
- run: pip install -r requirements.txt
|
|
27
|
+
- run: ruff check .
|
|
28
|
+
|
|
29
|
+
test:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
needs: lint
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v6
|
|
34
|
+
- uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
37
|
+
cache: pip
|
|
38
|
+
- run: pip install -r requirements.txt
|
|
39
|
+
- run: pytest
|
|
40
|
+
|
|
41
|
+
build:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
needs: test
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v6
|
|
46
|
+
- uses: actions/setup-python@v5
|
|
47
|
+
with:
|
|
48
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
49
|
+
- run: pip install build
|
|
50
|
+
- run: python -m build
|
|
51
|
+
- uses: actions/upload-artifact@v4
|
|
52
|
+
with:
|
|
53
|
+
name: dist
|
|
54
|
+
path: dist/
|
|
55
|
+
if-no-files-found: ignore
|
|
56
|
+
|
|
57
|
+
release:
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
needs: build
|
|
60
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
61
|
+
permissions:
|
|
62
|
+
contents: write
|
|
63
|
+
id-token: write
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v6
|
|
66
|
+
with:
|
|
67
|
+
fetch-depth: 0
|
|
68
|
+
- uses: actions/download-artifact@v4
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/
|
|
72
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
73
|
+
with:
|
|
74
|
+
skip-existing: true
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Bundled bigpowers CI template — Rust. See test-build-release-node.yml for
|
|
2
|
+
# the override mechanism (BIGPOWERS_CI_TEMPLATES). GH #104.
|
|
3
|
+
name: Test Build Release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
CARGO_TERM_COLOR: always
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
23
|
+
with:
|
|
24
|
+
components: clippy, rustfmt
|
|
25
|
+
- uses: Swatinem/rust-cache@v2
|
|
26
|
+
- run: cargo fmt --check
|
|
27
|
+
# Pin clippy to the stable toolchain above: new nightly lints otherwise
|
|
28
|
+
# break CI on days nobody changed the code.
|
|
29
|
+
- run: cargo clippy --all-targets -- -D warnings
|
|
30
|
+
|
|
31
|
+
test:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
needs: lint
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v6
|
|
36
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
37
|
+
- uses: Swatinem/rust-cache@v2
|
|
38
|
+
- run: cargo test --all
|
|
39
|
+
|
|
40
|
+
build:
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
needs: test
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v6
|
|
45
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
46
|
+
- uses: Swatinem/rust-cache@v2
|
|
47
|
+
- run: cargo build --release
|
|
48
|
+
- uses: actions/upload-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: dist
|
|
51
|
+
path: target/release/
|
|
52
|
+
if-no-files-found: ignore
|
|
53
|
+
|
|
54
|
+
release:
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
needs: build
|
|
57
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
58
|
+
permissions:
|
|
59
|
+
contents: write
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v6
|
|
62
|
+
with:
|
|
63
|
+
fetch-depth: 0
|
|
64
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
65
|
+
- run: cargo publish --no-verify
|
|
66
|
+
env:
|
|
67
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -36,7 +36,11 @@ function assertReplaceable(dst) {
|
|
|
36
36
|
}
|
|
37
37
|
if (st.isSymbolicLink()) {
|
|
38
38
|
const target = fs.readlinkSync(dst);
|
|
39
|
-
|
|
39
|
+
// Path-separator boundary: a string-prefix sibling of the package root
|
|
40
|
+
// (e.g. <ROOT>-evil) is NOT managed by this package.
|
|
41
|
+
if (target === REPO_ROOT || target.startsWith(REPO_ROOT + path.sep)) {
|
|
42
|
+
return; // managed by bigpowers — safe to re-link
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
throw new Error(
|
|
42
46
|
`Refusing to replace ${dst}: it exists and is not a bigpowers-managed symlink. ` +
|
|
@@ -416,6 +420,52 @@ function installLocal(tool, repoRoot) {
|
|
|
416
420
|
}
|
|
417
421
|
}
|
|
418
422
|
|
|
423
|
+
// ── Project provisioning (bigpowers init) ────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
// Provision the CURRENT project (cwd) with the package's scripts/ tree and the
|
|
426
|
+
// specs/ scaffolding skill bodies assume. Package installs (pi, npm -g, npx)
|
|
427
|
+
// register skills but pi's package contract has no resource type for project
|
|
428
|
+
// files and no lifecycle script runs — so `bash scripts/*.sh` invocations and
|
|
429
|
+
// `→ verify:` gates in SKILL.md files fail outside a bigpowers checkout. (#116)
|
|
430
|
+
function initProject(repoRoot) {
|
|
431
|
+
const cwd = process.cwd();
|
|
432
|
+
if (path.resolve(cwd) === path.resolve(repoRoot)) {
|
|
433
|
+
return { skipped: 'cwd-is-package' };
|
|
434
|
+
}
|
|
435
|
+
linkDir(path.join(repoRoot, 'scripts'), path.join(cwd, 'scripts'));
|
|
436
|
+
const created = [];
|
|
437
|
+
for (const rel of [path.join('specs', 'bugs'), path.join('specs', 'verifications')]) {
|
|
438
|
+
const dir = path.join(cwd, rel);
|
|
439
|
+
if (!fs.existsSync(dir)) {
|
|
440
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
441
|
+
created.push(rel);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return { skipped: null, scriptsLinked: true, created };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Inverse of initProject: remove ONLY the managed scripts symlink and specs/
|
|
448
|
+
// scaffolding dirs we created (and only while untouched — user content survives).
|
|
449
|
+
function initProjectRemove(repoRoot) {
|
|
450
|
+
const cwd = process.cwd();
|
|
451
|
+
const scriptsLink = path.join(cwd, 'scripts');
|
|
452
|
+
try {
|
|
453
|
+
if (fs.lstatSync(scriptsLink).isSymbolicLink()
|
|
454
|
+
&& fs.readlinkSync(scriptsLink) === path.join(repoRoot, 'scripts')) {
|
|
455
|
+
fs.unlinkSync(scriptsLink);
|
|
456
|
+
}
|
|
457
|
+
} catch {}
|
|
458
|
+
for (const rel of [path.join('specs', 'bugs'), path.join('specs', 'verifications'), 'specs']) {
|
|
459
|
+
const dir = path.join(cwd, rel);
|
|
460
|
+
try {
|
|
461
|
+
if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()
|
|
462
|
+
&& fs.readdirSync(dir).length === 0) {
|
|
463
|
+
fs.rmdirSync(dir);
|
|
464
|
+
}
|
|
465
|
+
} catch {}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
419
469
|
// ── Uninstall per tool ───────────────────────────────────────────────────────
|
|
420
470
|
|
|
421
471
|
function uninstallTool(toolId, repoRoot) {
|
|
@@ -694,6 +744,8 @@ module.exports = {
|
|
|
694
744
|
linkHook,
|
|
695
745
|
installGlobal,
|
|
696
746
|
installLocal,
|
|
747
|
+
initProject,
|
|
748
|
+
initProjectRemove,
|
|
697
749
|
uninstallTool,
|
|
698
750
|
removeSymlink,
|
|
699
751
|
detectExistingInstall,
|
|
@@ -230,6 +230,7 @@ try {
|
|
|
230
230
|
'.cursor/rules',
|
|
231
231
|
'.pi/skills',
|
|
232
232
|
'skills/audit-code/SKILL.md',
|
|
233
|
+
'docs/templates/ci/github/test-build-release-node.yml',
|
|
233
234
|
];
|
|
234
235
|
const isIgnored = (p) =>
|
|
235
236
|
npmignore.some((pat) => {
|
|
@@ -244,6 +245,118 @@ try {
|
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
// story: #113 — wire-ci templates must actually ship in the npm tarball.
|
|
249
|
+
// The .npmignore pattern check above is necessary but not sufficient (it
|
|
250
|
+
// cannot model gitignore negation); prove it with a real pack listing.
|
|
251
|
+
{
|
|
252
|
+
const { execSync } = require('child_process');
|
|
253
|
+
const packOut = execSync('npm pack --dry-run 2>&1', {
|
|
254
|
+
cwd: ROOT,
|
|
255
|
+
encoding: 'utf8',
|
|
256
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
257
|
+
});
|
|
258
|
+
for (const tpl of [
|
|
259
|
+
'docs/templates/ci/github/test-build-release-node.yml',
|
|
260
|
+
'docs/templates/ci/github/test-build-release-rust.yml',
|
|
261
|
+
'docs/templates/ci/github/test-build-release-python.yml',
|
|
262
|
+
'docs/templates/ci/github/test-build-release-go.yml',
|
|
263
|
+
'docs/templates/AGENTS.md',
|
|
264
|
+
]) {
|
|
265
|
+
assert.ok(
|
|
266
|
+
packOut.includes(tpl),
|
|
267
|
+
`npm tarball must include ${tpl} (wire-ci templates, #113)`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// story: BUG-2026-08-31-pi-scripts-provisioning (#116)
|
|
273
|
+
// A package consumer project needs bigpowers' scripts/ + specs/ scaffolding
|
|
274
|
+
// so SKILL.md bodies ("bash scripts/run-skill-verify.sh") and verify gates
|
|
275
|
+
// ("test -f scripts/... && test -d specs/bugs") resolve outside a checkout.
|
|
276
|
+
{
|
|
277
|
+
const { initProject, initProjectRemove } = require('../scripts/lib/install-helpers.js');
|
|
278
|
+
const savedInitCwd = process.cwd();
|
|
279
|
+
const consumerDir = mkdtempSync(path.join(os.tmpdir(), 'bp-init-project-'));
|
|
280
|
+
try {
|
|
281
|
+
process.chdir(consumerDir);
|
|
282
|
+
|
|
283
|
+
// (a) init provisions scripts/ + specs/ scaffolding
|
|
284
|
+
initProject(ROOT);
|
|
285
|
+
assert.ok(
|
|
286
|
+
fs.lstatSync(path.join(consumerDir, 'scripts')).isSymbolicLink(),
|
|
287
|
+
'init must symlink scripts/ into the consumer project'
|
|
288
|
+
);
|
|
289
|
+
assert.strictEqual(
|
|
290
|
+
fs.readlinkSync(path.join(consumerDir, 'scripts')),
|
|
291
|
+
path.join(ROOT, 'scripts'),
|
|
292
|
+
'scripts symlink must point at the package scripts tree'
|
|
293
|
+
);
|
|
294
|
+
assert.ok(
|
|
295
|
+
fs.existsSync(path.join(consumerDir, 'scripts', 'run-skill-verify.sh')),
|
|
296
|
+
'scripts/run-skill-verify.sh must resolve through the link (skill verify gate)'
|
|
297
|
+
);
|
|
298
|
+
assert.ok(
|
|
299
|
+
fs.existsSync(path.join(consumerDir, 'specs', 'bugs')),
|
|
300
|
+
'init must scaffold specs/bugs (fix-bug verify gate probes it)'
|
|
301
|
+
);
|
|
302
|
+
assert.ok(
|
|
303
|
+
fs.existsSync(path.join(consumerDir, 'specs', 'verifications')),
|
|
304
|
+
'init must scaffold specs/verifications'
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
// (b) init --remove cleans managed artifacts only
|
|
308
|
+
initProjectRemove(ROOT);
|
|
309
|
+
assert.ok(
|
|
310
|
+
!fs.existsSync(path.join(consumerDir, 'scripts')),
|
|
311
|
+
'init --remove must remove the managed scripts symlink'
|
|
312
|
+
);
|
|
313
|
+
assert.ok(
|
|
314
|
+
!fs.existsSync(path.join(consumerDir, 'specs')),
|
|
315
|
+
'init --remove must remove the untouched scaffolded specs tree'
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// (c) refuses a pre-existing non-managed scripts/ (never clobbers)
|
|
319
|
+
fs.mkdirSync(path.join(consumerDir, 'scripts'));
|
|
320
|
+
fs.writeFileSync(path.join(consumerDir, 'scripts', 'mine.sh'), 'echo mine\n');
|
|
321
|
+
assert.throws(
|
|
322
|
+
() => initProject(ROOT),
|
|
323
|
+
/Refusing to replace/,
|
|
324
|
+
'init must refuse a user-owned scripts/ dir'
|
|
325
|
+
);
|
|
326
|
+
assert.ok(
|
|
327
|
+
fs.existsSync(path.join(consumerDir, 'scripts', 'mine.sh')),
|
|
328
|
+
'user-owned scripts/ content must survive the refusal'
|
|
329
|
+
);
|
|
330
|
+
} finally {
|
|
331
|
+
process.chdir(savedInitCwd);
|
|
332
|
+
rmSync(consumerDir, { recursive: true, force: true });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// (d) CLI dispatch drift guard: `bigpowers init` must stay wired
|
|
336
|
+
const bigpowersSrc = fs.readFileSync(path.join(ROOT, 'bin', 'bigpowers.js'), 'utf8');
|
|
337
|
+
assert.ok(
|
|
338
|
+
/'init'/.test(bigpowersSrc),
|
|
339
|
+
"bin/bigpowers.js must dispatch the 'init' command"
|
|
340
|
+
);
|
|
341
|
+
assert.ok(
|
|
342
|
+
fs.existsSync(path.join(ROOT, 'bin', 'init.js')),
|
|
343
|
+
'bin/init.js must exist'
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// story: BUG-2026-08-31-pi-scripts-provisioning (follow-up from PR #114 review)
|
|
348
|
+
// The managed-symlink check must not treat a string-prefix sibling of the
|
|
349
|
+
// package root (e.g. <ROOT>-evil) as managed — needs a path-separator boundary.
|
|
350
|
+
{
|
|
351
|
+
const dst = path.join(tmpHome, 'prefix-boundary-hook.sh');
|
|
352
|
+
fs.symlinkSync(path.join(`${ROOT}-evil`, 'x.sh'), dst); // dangling foreign link
|
|
353
|
+
assert.throws(
|
|
354
|
+
() => linkHook(rtkSrc, dst),
|
|
355
|
+
/Refusing to replace/,
|
|
356
|
+
'managed-symlink check must require a path-separator boundary (prefix sibling is NOT managed)'
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
247
360
|
console.log('test-install-helpers: ALL PASS');
|
|
248
361
|
} finally {
|
|
249
362
|
rmSync(tmpHome, { recursive: true, force: true });
|