superpowers-manager 0.1.4 → 0.1.6
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/README.md +121 -78
- package/bin/superpowers-manager.js +22 -13
- package/package.json +2 -1
- package/scripts/adapters/codex/adapter +598 -0
- package/scripts/adapters/codex/lib.sh +391 -0
- package/scripts/{validate-generated-plugin.py → adapters/codex/validate-generated-plugin.py} +3 -3
- package/scripts/core/adapter.sh +92 -0
- package/scripts/core/common.sh +35 -0
- package/scripts/core/lifecycle.sh +127 -0
- package/scripts/core/provenance.sh +135 -0
- package/scripts/core/status.sh +27 -0
- package/scripts/core/upstream.sh +146 -0
- package/scripts/core/validate-adapter-response.py +245 -0
- package/scripts/install +29 -27
- package/scripts/prepare +33 -43
- package/scripts/probe +29 -18
- package/scripts/uninstall +33 -50
- package/scripts/update +3 -8
- package/scripts/lib.sh +0 -651
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ and explicit install/update/probe/uninstall lifecycle control.
|
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
33
|
npx superpowers-wrapper@0.1.1 uninstall
|
|
34
|
-
npx superpowers-manager
|
|
34
|
+
npx superpowers-manager install
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
The manager detects legacy wrapper-owned Codex state and stops before mutation.
|
|
@@ -55,14 +55,15 @@ manager does not run automatic or background updates.
|
|
|
55
55
|
|
|
56
56
|
- Resolves an upstream ref, defaulting to the latest stable `vX.Y.Z` release
|
|
57
57
|
tag.
|
|
58
|
-
- Clones
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
- Validates the
|
|
65
|
-
|
|
58
|
+
- Clones/fetches upstream at that commit and assembles a Codex plugin tree under
|
|
59
|
+
`plugins/superpowers/` (skills, assets, license/readme, and manifest;
|
|
60
|
+
upstream's `hooks/` directory is deliberately excluded).
|
|
61
|
+
- Stamps the generated manifest with a ref-aware manager version ending in
|
|
62
|
+
`+manager.<short-sha>` and writes the upstream provenance to
|
|
63
|
+
`.superpowers-upstream.json`.
|
|
64
|
+
- Validates the generated tree with the manager's shipped, Python-standard-library
|
|
65
|
+
contract validator before swapping it into place (a failed run never destroys
|
|
66
|
+
a previously generated tree).
|
|
66
67
|
- Registers the `superpowers-manager` marketplace and installs or refreshes
|
|
67
68
|
`superpowers@superpowers-manager` in Codex.
|
|
68
69
|
|
|
@@ -73,31 +74,28 @@ claim about how Superpowers should be packaged for future or other harnesses.
|
|
|
73
74
|
Changing the hook-free policy requires a separate design and current
|
|
74
75
|
compatibility evidence.
|
|
75
76
|
|
|
76
|
-
##
|
|
77
|
+
## Runtime architecture
|
|
77
78
|
|
|
78
|
-
`
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
the
|
|
79
|
+
- `scripts/core/` owns the shared lifecycle, status, and protocol validation.
|
|
80
|
+
- `scripts/adapters/codex/` owns build, inspection, reconciliation, and Codex
|
|
81
|
+
mutation.
|
|
82
|
+
- Codex is the only supported adapter today; no public harness selector ships
|
|
83
|
+
yet.
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
Validation checks the manager-owned manifest overlay, generated-tree structure,
|
|
86
|
+
skill frontmatter envelope, known local paths, and provenance. It deliberately
|
|
87
|
+
does not implement a general YAML parser or mirror every Codex ingestion rule;
|
|
88
|
+
upstream owns skill semantics and Codex owns its evolving schema.
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```sh
|
|
92
|
-
SUPERPOWERS_REF=v6.0.3 npx superpowers-manager prepare
|
|
93
|
-
SUPERPOWERS_REF=main npx superpowers-manager probe
|
|
94
|
-
SUPERPOWERS_REF=feature/foo npx superpowers-manager install
|
|
95
|
-
SUPERPOWERS_REF=latest-release npx superpowers-manager update
|
|
96
|
-
```
|
|
90
|
+
`SUPERPOWERS_VALIDATOR=/path/to/validator.py` adds an optional Python validator
|
|
91
|
+
after the built-in check. It receives the candidate plugin root as its only
|
|
92
|
+
argument. It cannot replace or bypass built-in validation, and either check
|
|
93
|
+
failing prevents the tree swap and all Codex mutation.
|
|
97
94
|
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
Direct `scripts/install` keeps harness-specific validation in the Codex adapter:
|
|
96
|
+
phase 1 prepares the exact candidate first, then the adapter performs its Codex
|
|
97
|
+
and refresh-mode preflight before any Codex mutation. The Node dispatcher keeps
|
|
98
|
+
its existing Codex preflight before dispatching to the shell lifecycle.
|
|
101
99
|
|
|
102
100
|
## Provider ownership
|
|
103
101
|
|
|
@@ -130,74 +128,119 @@ manager will not remove it for you.
|
|
|
130
128
|
| `npx superpowers-manager uninstall` | Marketplace and plugin state | Remove only manager-owned Codex state and verify removal |
|
|
131
129
|
|
|
132
130
|
Calling `npx superpowers-manager` without a subcommand is equivalent to
|
|
133
|
-
`update`. `probe` is read-only. Install and update
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
`update`. `probe` is read-only. Install and update stop before prepare or Codex
|
|
132
|
+
mutation when legacy state is present. Uninstall removes only manager-owned
|
|
133
|
+
state and reports any legacy residue without modifying it. These commands fail
|
|
134
|
+
closed when required state cannot be inspected and refuse to report success
|
|
135
|
+
when resulting manager state cannot be verified.
|
|
137
136
|
|
|
138
|
-
|
|
137
|
+
## Choosing the upstream version
|
|
139
138
|
|
|
140
|
-
`
|
|
139
|
+
`SUPERPOWERS_REF` selects a stable release tag, full commit SHA, branch, or
|
|
140
|
+
other resolvable upstream ref for that invocation. The stateless npx package
|
|
141
|
+
records the requested ref, resolved ref, and exact commit, but does not persist
|
|
142
|
+
the selection for a later invocation that omits `SUPERPOWERS_REF`.
|
|
141
143
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- `remove-add` removes only the manager-owned plugin before adding it again.
|
|
144
|
+
Without `SUPERPOWERS_REF`, the manager reads `config/upstream-ref`, which ships
|
|
145
|
+
as `latest-release`. Accepted values include:
|
|
145
146
|
|
|
146
|
-
|
|
147
|
+
- `latest-release` — highest stable `vX.Y.Z` tag (prereleases are excluded).
|
|
148
|
+
- A specific tag, e.g. `v6.0.3`.
|
|
149
|
+
- A full 40-character commit SHA.
|
|
150
|
+
- Any other ref upstream resolves (e.g. a branch name).
|
|
147
151
|
|
|
148
152
|
```sh
|
|
149
|
-
|
|
153
|
+
SUPERPOWERS_REF=v6.0.3 npx superpowers-manager prepare
|
|
154
|
+
SUPERPOWERS_REF=main npx superpowers-manager probe
|
|
155
|
+
SUPERPOWERS_REF=feature/foo npx superpowers-manager install
|
|
156
|
+
SUPERPOWERS_REF=latest-release npx superpowers-manager update
|
|
150
157
|
```
|
|
151
158
|
|
|
152
|
-
|
|
159
|
+
`SUPERPOWERS_CACHE_DIR` may point to a persistent upstream clone cache to avoid
|
|
160
|
+
re-cloning between package materializations. It caches Git objects; it does not
|
|
161
|
+
persist ref selection or trigger updates.
|
|
162
|
+
|
|
163
|
+
## How versioning works
|
|
164
|
+
|
|
165
|
+
- **Upstream manifest first:** when upstream provides
|
|
166
|
+
`.codex-plugin/plugin.json`, `prepare` uses it as the generated manifest base
|
|
167
|
+
so future upstream metadata fields are preserved by default.
|
|
168
|
+
- **Fallback template:** `plugins/superpowers/.codex-plugin/plugin.template.json`
|
|
169
|
+
is committed as a minimal fallback for older upstream refs that do not ship a
|
|
170
|
+
Codex manifest. It carries the placeholder version
|
|
171
|
+
`0.0.0+manager.template`.
|
|
172
|
+
- **Manager overlay:** `prepare` replaces the version with a ref-aware manager
|
|
173
|
+
version, forces `skills` to `./skills/`, and enforces the manager's current
|
|
174
|
+
hook-free policy: no manifest `hooks` key and no copied `hooks/` directory.
|
|
175
|
+
Unknown upstream manifest fields remain preserved.
|
|
176
|
+
- Stable tags generate release-looking versions such as
|
|
177
|
+
`6.0.3+manager.896224c`; explicit prerelease tags generate versions such as
|
|
178
|
+
`6.1.0-beta.1+manager.abc1234`.
|
|
179
|
+
- Branch builds deliberately stay below real releases:
|
|
180
|
+
`main` generates `0.0.0-main+manager.<short-sha>` and other named refs
|
|
181
|
+
generate `0.0.0-ref-<sanitized-ref>+manager.<short-sha>`.
|
|
182
|
+
- Raw 40-character commit SHAs generate `0.0.0+manager.<short-sha>`.
|
|
183
|
+
- **`.superpowers-upstream.json`** records the authoritative provenance:
|
|
184
|
+
`source`, `requested_ref`, `resolved_ref`, `commit`, and the upstream manifest
|
|
185
|
+
version. The generated manifest version is for human readability and Codex
|
|
186
|
+
package identity; the upstream `commit` is what `probe`/`update` compare
|
|
187
|
+
against.
|
|
188
|
+
|
|
189
|
+
## Refresh modes
|
|
153
190
|
|
|
154
|
-
|
|
155
|
-
manifest base and preserves unknown upstream fields.
|
|
156
|
-
- The committed fallback template supports older refs without an upstream
|
|
157
|
-
manifest and uses the placeholder version `0.0.0+manager.template`.
|
|
158
|
-
- Stable tags produce versions such as `6.0.3+manager.896224c`; explicit
|
|
159
|
-
prereleases produce versions such as `6.1.0-beta.1+manager.abc1234`.
|
|
160
|
-
- `main` produces `0.0.0-main+manager.<short-sha>`; other named refs produce
|
|
161
|
-
`0.0.0-ref-<sanitized-ref>+manager.<short-sha>`.
|
|
162
|
-
- Full commit SHAs produce `0.0.0+manager.<short-sha>`.
|
|
191
|
+
`install` and `update` accept `SUPERPOWERS_INSTALL_REFRESH_MODE`:
|
|
163
192
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
193
|
+
- `add-only` (default) — `plugin add` re-reads the local source, which refreshes
|
|
194
|
+
a mutated tree. Verified sufficient for local marketplaces.
|
|
195
|
+
- `remove-add` — removes the manager's own plugin first, then re-adds it. Use
|
|
196
|
+
only if a refresh ever fails to take:
|
|
167
197
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
check failing prevents replacement and Codex mutation.
|
|
198
|
+
```sh
|
|
199
|
+
SUPERPOWERS_INSTALL_REFRESH_MODE=remove-add npx superpowers-manager update
|
|
200
|
+
```
|
|
172
201
|
|
|
173
202
|
## Tests
|
|
174
203
|
|
|
175
204
|
```sh
|
|
176
|
-
sh tests/run.sh
|
|
177
|
-
sh tests/container.sh
|
|
205
|
+
sh tests/run.sh # Layers 1-3: host-side hermetic checks while iterating
|
|
206
|
+
sh tests/container.sh # Layers 1-4: blocking Docker acceptance command
|
|
207
|
+
sh tests/manual/codex-behavior-probe.sh # optional native-only compatibility residue
|
|
178
208
|
```
|
|
179
209
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
210
|
+
Layers 1-3 stay offline and hermetic: they use a fake local upstream repo plus
|
|
211
|
+
host-side fixtures, and they perform no mutation of the developer's or runner's
|
|
212
|
+
real Codex state.
|
|
213
|
+
|
|
214
|
+
Layer 4 is the Docker acceptance path. It is the required completion command
|
|
215
|
+
because the isolated-container Codex probe graduated from a temporary
|
|
216
|
+
nonblocking spike to a blocking acceptance gate. `sh tests/container.sh` runs
|
|
217
|
+
the inner `sh tests/run.sh` suite and then the real Codex offline probe inside
|
|
218
|
+
an isolated container home with networking disabled. That container run may
|
|
219
|
+
mutate the throwaway container-local Codex state, but it still performs no
|
|
220
|
+
mutation of the developer's or runner's real Codex state.
|
|
221
|
+
|
|
222
|
+
The manual probe is opt-in and covers native-only compatibility residue such as
|
|
223
|
+
path/cache behavior against an intentionally real local Codex install. It is
|
|
224
|
+
not part of acceptance. GitHub Actions runs the blocking container acceptance
|
|
225
|
+
command on pull requests and pushes to `main`.
|
|
184
226
|
|
|
185
227
|
## Repository layout
|
|
186
228
|
|
|
187
|
-
```
|
|
188
|
-
.agents/plugins/marketplace.json
|
|
189
|
-
|
|
190
|
-
config/upstream-ref # default upstream ref
|
|
229
|
+
```
|
|
230
|
+
.agents/plugins/marketplace.json # local marketplace definition (tracked)
|
|
231
|
+
config/upstream-ref # which upstream ref to track (tracked)
|
|
191
232
|
plugins/superpowers/
|
|
192
|
-
.codex-plugin/plugin.template.json #
|
|
193
|
-
.codex-plugin/plugin.json # generated manifest
|
|
194
|
-
skills/ assets/ LICENSE ... # generated from upstream
|
|
195
|
-
.superpowers-upstream.json # generated provenance
|
|
196
|
-
scripts/
|
|
197
|
-
|
|
198
|
-
|
|
233
|
+
.codex-plugin/plugin.template.json # fallback manifest template (tracked)
|
|
234
|
+
.codex-plugin/plugin.json # generated manifest (gitignored)
|
|
235
|
+
skills/ assets/ LICENSE ... # generated from upstream (gitignored)
|
|
236
|
+
.superpowers-upstream.json # generated provenance (gitignored)
|
|
237
|
+
scripts/
|
|
238
|
+
adapters/codex/ # Codex adapter entrypoint + validator helpers
|
|
239
|
+
core/ # shared lifecycle/provenance/status modules
|
|
240
|
+
prepare probe install update uninstall # user-facing shell entrypoints
|
|
241
|
+
tests/ # hermetic suite + manual Codex probe
|
|
242
|
+
.cache/upstream/ # upstream clone cache (gitignored)
|
|
199
243
|
```
|
|
200
244
|
|
|
201
|
-
Everything under `plugins/superpowers/` except the fallback manifest template
|
|
202
|
-
|
|
203
|
-
content; regenerate it instead.
|
|
245
|
+
Everything under `plugins/superpowers/` except the fallback manifest template is
|
|
246
|
+
generated by `prepare` and ignored by Git; re-run `prepare` to regenerate it.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// @ts-check
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import * as fs from 'node:fs';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {'prepare' | 'probe' | 'install' | 'update' | 'uninstall'} Subcommand
|
|
@@ -57,14 +57,24 @@ function resolvePackageRoot(scriptPath) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} moduleFilename
|
|
62
|
+
* @param {string | undefined} argvPath
|
|
63
|
+
* @returns {boolean}
|
|
64
|
+
*/
|
|
65
|
+
function isMain(moduleFilename, argvPath) {
|
|
66
|
+
if (!argvPath) return false;
|
|
67
|
+
return moduleFilename === fs.realpathSync(argvPath);
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
/**
|
|
61
71
|
* @param {string[]} argv
|
|
62
72
|
* @returns {ParseResult}
|
|
63
73
|
*/
|
|
64
74
|
function parseArgs(argv) {
|
|
65
|
-
if (argv.length === 0) return { kind: 'run', cmd: 'update', args: [] };
|
|
66
75
|
/** @type {string | undefined} */
|
|
67
76
|
const first = argv[0];
|
|
77
|
+
if (argv.length === 0) return { kind: 'run', cmd: 'update', args: [] };
|
|
68
78
|
if (first === '--help' || first === '-h') return { kind: 'help' };
|
|
69
79
|
if (first === '--version') return { kind: 'version' };
|
|
70
80
|
if (first && SUBCOMMANDS.includes(first)) {
|
|
@@ -117,8 +127,8 @@ function discoverShell(env, platform) {
|
|
|
117
127
|
return findTool('bash', env, platform);
|
|
118
128
|
}
|
|
119
129
|
|
|
120
|
-
// Tool preflight; never touches Codex state. codex is required for
|
|
121
|
-
//
|
|
130
|
+
// Tool preflight; never touches Codex state. codex is required only for the
|
|
131
|
+
// subcommands that mutate or read Codex.
|
|
122
132
|
/**
|
|
123
133
|
* @param {Subcommand} cmd
|
|
124
134
|
* @param {NodeJS.ProcessEnv} env
|
|
@@ -148,9 +158,8 @@ function preflight(cmd, env, platform) {
|
|
|
148
158
|
errors.push(`required command not found: ${codexBin} — install the Codex CLI or set SUPERPOWERS_CODEX`);
|
|
149
159
|
}
|
|
150
160
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
: { ok: true, shell: /** @type {string} */ (shell) };
|
|
161
|
+
if (errors.length) return { ok: false, errors };
|
|
162
|
+
return { ok: true, shell: /** @type {string} */ (shell) };
|
|
154
163
|
}
|
|
155
164
|
|
|
156
165
|
// POSIX executes the script directly (#!/bin/sh shebang); Windows cannot
|
|
@@ -196,7 +205,7 @@ function main() {
|
|
|
196
205
|
console.log(usage());
|
|
197
206
|
process.exit(0);
|
|
198
207
|
}
|
|
199
|
-
const root = resolvePackageRoot(
|
|
208
|
+
const root = resolvePackageRoot(import.meta.filename);
|
|
200
209
|
if (!root) {
|
|
201
210
|
console.error('error: cannot resolve the superpowers-manager package root');
|
|
202
211
|
process.exit(1);
|
|
@@ -230,6 +239,6 @@ function main() {
|
|
|
230
239
|
process.exit(res.status === null ? 1 : res.status);
|
|
231
240
|
}
|
|
232
241
|
|
|
233
|
-
|
|
242
|
+
export { resolvePackageRoot, isMain, parseArgs, findTool, discoverShell, preflight, buildSpawn, usage };
|
|
234
243
|
|
|
235
|
-
if (
|
|
244
|
+
if (isMain(import.meta.filename, process.argv[1])) main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superpowers-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Install and update the latest stable obra/superpowers release directly from upstream, without waiting for agent marketplaces to catch up. Codex supported today.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"superpowers",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"updater"
|
|
18
18
|
],
|
|
19
19
|
"license": "MIT",
|
|
20
|
+
"type": "module",
|
|
20
21
|
"repository": {
|
|
21
22
|
"type": "git",
|
|
22
23
|
"url": "git+https://github.com/j7an/superpowers-manager.git"
|