superpowers-manager 0.2.0 → 0.4.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.
Files changed (68) hide show
  1. package/README.md +340 -66
  2. package/dist/adapter-result.js +204 -0
  3. package/dist/adapter.js +690 -0
  4. package/dist/atomic.js +142 -0
  5. package/dist/cli-arguments.js +32 -0
  6. package/dist/cli.js +313 -0
  7. package/dist/codex-harness.js +271 -0
  8. package/dist/codex-json.js +89 -0
  9. package/dist/codex-prepare.js +199 -0
  10. package/dist/codex-presentation.js +259 -0
  11. package/dist/codex-state.js +78 -0
  12. package/dist/commands/context.js +1 -0
  13. package/dist/commands/install.js +291 -0
  14. package/dist/commands/pin.js +79 -0
  15. package/dist/commands/prepare.js +420 -0
  16. package/dist/commands/probe.js +257 -0
  17. package/dist/commands/track-latest.js +44 -0
  18. package/dist/commands/uninstall.js +217 -0
  19. package/dist/commands/unpin.js +95 -0
  20. package/dist/commands/update.js +79 -0
  21. package/dist/domain/fingerprint.js +4 -0
  22. package/dist/domain/refs.js +37 -0
  23. package/dist/effective-selection.js +123 -0
  24. package/dist/generated-plugin.js +748 -0
  25. package/dist/git.js +38 -0
  26. package/dist/harness.js +1 -0
  27. package/dist/hooks.js +290 -0
  28. package/dist/lifecycle.js +135 -0
  29. package/dist/manifest-overlay.js +125 -0
  30. package/dist/provenance.js +111 -0
  31. package/dist/python-json-format.js +83 -0
  32. package/dist/python-json.js +29 -0
  33. package/dist/python-text.js +74 -0
  34. package/dist/safe-path.js +137 -0
  35. package/dist/safety-error.js +10 -0
  36. package/dist/selection-state-cli.js +85 -0
  37. package/dist/selection-store.js +172 -0
  38. package/dist/selection.js +200 -0
  39. package/dist/status.js +24 -0
  40. package/dist/strict-json.js +248 -0
  41. package/dist/upstream-cli.js +110 -0
  42. package/dist/upstream-version.js +40 -0
  43. package/dist/upstream.js +253 -0
  44. package/dist/validate-generated-plugin-cli.js +118 -0
  45. package/dist/validator.js +317 -0
  46. package/dist/workspace.js +139 -0
  47. package/package.json +25 -4
  48. package/bin/superpowers-manager.js +0 -290
  49. package/scripts/adapters/codex/adapter +0 -603
  50. package/scripts/adapters/codex/lib.sh +0 -449
  51. package/scripts/adapters/codex/validate-generated-plugin.py +0 -314
  52. package/scripts/core/adapter.sh +0 -103
  53. package/scripts/core/common.sh +0 -59
  54. package/scripts/core/lifecycle.sh +0 -141
  55. package/scripts/core/provenance.sh +0 -135
  56. package/scripts/core/selection-state.py +0 -414
  57. package/scripts/core/selection.sh +0 -168
  58. package/scripts/core/status.sh +0 -27
  59. package/scripts/core/upstream.sh +0 -280
  60. package/scripts/core/validate-adapter-response.py +0 -284
  61. package/scripts/install +0 -59
  62. package/scripts/pin +0 -51
  63. package/scripts/prepare +0 -117
  64. package/scripts/probe +0 -82
  65. package/scripts/track-latest +0 -30
  66. package/scripts/uninstall +0 -35
  67. package/scripts/unpin +0 -41
  68. package/scripts/update +0 -34
package/README.md CHANGED
@@ -16,16 +16,21 @@ npx superpowers-manager probe
16
16
  npx superpowers-manager update
17
17
  ```
18
18
 
19
- Use the official marketplace for the simplest native Codex installation. Use
20
- Superpowers Manager when you want immediate stable-upstream freshness after a
21
- user-triggered install/update, per-invocation release or commit selection,
22
- recorded upstream provenance, diagnostics, Codex-specific hook-free packaging,
23
- and explicit install/update/probe/uninstall lifecycle control.
19
+ Use Superpowers Manager to follow the latest stable Superpowers release directly
20
+ from upstream and apply updates with one command. By default, `install` and
21
+ `update` resolve the highest stable `vX.Y.Z` tag when invoked; saved pins and
22
+ invocation overrides take precedence. `probe` reports whether your installation
23
+ matches that selection without changing Codex state. Updates are user-triggered.
24
24
 
25
- | Choose | Best fit |
26
- |---|---|
27
- | Official marketplace | Simplest Codex-native installation and marketplace-managed cadence |
28
- | `superpowers-manager` | Direct stable-upstream freshness when invoked, exact ref selection, provenance, diagnostics, and lifecycle control |
25
+ | Choose | Version source | Best fit |
26
+ |---|---|---|
27
+ | `superpowers-manager` | Latest stable upstream tag by default, or your saved/overridden selection | Follow upstream stable with drift reporting and verified updates |
28
+ | Direct upstream repository | The configured Git ref, or the repository's default branch | Use Codex's native Git marketplace support |
29
+ | `superpowers@openai-curated` | The copy distributed in the curated marketplace | Use the curated integration and its refresh policy |
30
+
31
+ See [Comparing installation routes](#comparing-installation-routes) for commands
32
+ and update behavior. Use one provider at a time; see
33
+ [Provider ownership](#provider-ownership) before switching.
29
34
 
30
35
  ### Moving from `superpowers-wrapper`
31
36
 
@@ -39,14 +44,33 @@ It never removes the legacy provider automatically.
39
44
 
40
45
  ## Requirements and platforms
41
46
 
42
- Superpowers Manager requires Node 24+, `git`, Python 3, and a POSIX `sh`.
43
- Codex CLI is required for `probe`, `install`, `update`, and `uninstall`;
44
- `prepare`, `pin`, `track-latest`, and `unpin` do not require it. Codex is the
45
- only supported integration today.
47
+ The installed Superpowers Manager package requires Node >=24. Native source,
48
+ tests, and packaging tooling require Node >=24.12.0. Codex is the only supported
49
+ integration today. Every other requirement is per command, enforced by
50
+ preflight before any dispatch. This table is checked against production by
51
+ `tests/bin/readme-requirements.test.ts`; edit it when a command's requirements
52
+ change, in the same pull request.
53
+
54
+ <!-- requirements:begin -->
55
+ | Command | git | Python 3 | Codex CLI |
56
+ |---|---|---|---|
57
+ | `pin` | yes | no | no |
58
+ | `track-latest` | no | no | no |
59
+ | `unpin` | no | no | no |
60
+ | `prepare` | yes | only with SUPERPOWERS_VALIDATOR | no |
61
+ | `probe` | yes | no | yes |
62
+ | `install` | yes | no | yes |
63
+ | `update` | yes | no | yes |
64
+ | `uninstall` | no | no | yes |
65
+ <!-- requirements:end -->
66
+
67
+ See `docs/baseline/behavioral-inventory.md`'s `CLI-PREFLIGHT-01` for the
68
+ behaviour this table describes.
46
69
 
47
70
  macOS and Linux are tested. WSL2 is supported. The native Windows path is
48
- untested; the launcher looks for Git Bash, `git`, and `python3`, but path
49
- handling between MSYS and Codex remains a known risk area.
71
+ untested; the launcher no longer looks for Git Bash at all — every command runs
72
+ in-process, so no POSIX shell is discovered or required — but path handling
73
+ between MSYS and Codex remains a known risk area.
50
74
 
51
75
  Network needs depend on the saved policy. `pin` verifies its target;
52
76
  `track-latest` and invocation overrides resolve from upstream when applied; and
@@ -55,35 +79,119 @@ of a saved exact pin can reuse its recorded identity without upstream access.
55
79
  Updates remain user-triggered; the manager does not run automatic or background
56
80
  updates.
57
81
 
82
+ ## Comparing installation routes
83
+
84
+ ### Getting the latest stable release
85
+
86
+ The manager selects the highest stable upstream `vX.Y.Z` tag when its effective
87
+ policy is `latest-release`. It does not require the curated marketplace to
88
+ publish that release first. Saved pins and environment overrides can select a
89
+ different version or source; see [Choosing the upstream version](#choosing-the-upstream-version).
90
+
91
+ The direct repository route uses the Git ref you configure. Adding the repository
92
+ without `--ref` uses its default branch, which is not a latest-stable release
93
+ policy. The curated route uses the
94
+ [copy in `openai/plugins`](https://github.com/openai/plugins/tree/main/plugins/superpowers).
95
+ Refreshing that snapshot does not independently resolve the latest stable tag
96
+ from `obra/superpowers`; curated may match upstream or lag behind it.
97
+
98
+ The native CLI examples below were checked against Codex `0.153.3`. Upstream's
99
+ [marketplace manifest](https://github.com/obra/superpowers/blob/main/.agents/plugins/marketplace.json)
100
+ names its marketplace `superpowers-dev`.
101
+
102
+ ### First install
103
+
104
+ These are alternative routes; do not run both to install duplicate providers.
105
+
106
+ | Step | Superpowers Manager | Direct upstream repository |
107
+ |---|---|---|
108
+ | 1 | `npx superpowers-manager install` | `codex plugin marketplace add https://github.com/obra/superpowers` |
109
+ | 2 | — | `codex plugin add superpowers@superpowers-dev` |
110
+
111
+ The manager follows upstream stable by default. For a specific release on the
112
+ direct route, choose its tag and add `--ref TAG` to the marketplace-add command.
113
+
114
+ ### Staying current
115
+
116
+ | Action | Superpowers Manager | Direct upstream repository |
117
+ |---|---|---|
118
+ | Explicit update | `npx superpowers-manager update` | `codex plugin marketplace upgrade superpowers-dev` |
119
+ | Optional inspection | `npx superpowers-manager probe` | `codex plugin list` |
120
+
121
+ The manager probes first, skips prepare/install when current and update control
122
+ is valid, and verifies the resulting installed state after a refresh. `probe`
123
+ reports requested and resolved refs, desired/generated/installed commits, and
124
+ status. With a saved pin, "current" means matching that pin, not necessarily
125
+ matching the latest upstream release. See [Lifecycle commands](#lifecycle-commands).
126
+
127
+ Native marketplace upgrade follows its configured ref. In the checked Codex
128
+ version, it can skip unchanged snapshots and refreshes installed plugins when
129
+ the marketplace changes; a second `plugin add` is not required for that refresh.
130
+ Codex also has an automatic refresh path for configured Git marketplaces.
131
+ See the [native upgrade implementation](https://github.com/openai/codex/blob/rust-v0.153.3/codex-rs/core-plugins/src/manager.rs).
132
+ `plugin list` shows installed versions; comparing them with upstream stable is
133
+ separate inspection work, not a prerequisite for running an update.
134
+
135
+ ### Changing the selected version
136
+
137
+ Replace `TAG` below with the exact release tag you want. For an already registered
138
+ direct marketplace, remove/add is a CLI route to changing its ref:
139
+
140
+ | Step | Superpowers Manager | Direct upstream repository |
141
+ |---|---|---|
142
+ | 1 | `npx superpowers-manager pin TAG` | `codex plugin marketplace remove superpowers-dev` |
143
+ | 2 | `npx superpowers-manager update` | `codex plugin marketplace add https://github.com/obra/superpowers --ref TAG` |
144
+ | 3 | — | `codex plugin add superpowers@superpowers-dev` |
145
+
146
+ The manager's `pin` saves verified intent without changing Codex state; `update`
147
+ applies it. To resume following stable releases, run
148
+ `npx superpowers-manager track-latest`, then `npx superpowers-manager update`.
149
+ The native sequence changes marketplace configuration immediately. In the checked
150
+ CLI, `marketplace upgrade` has no `--ref` option, and adding the same marketplace
151
+ name with a different ref is rejected. This sequence does not imply that editing
152
+ native configuration is impossible.
153
+
58
154
  ## What it does
59
155
 
60
156
  - Resolves an upstream ref, defaulting to the latest stable `vX.Y.Z` release
61
157
  tag.
62
158
  - Clones/fetches upstream at that commit and assembles a Codex plugin tree under
63
- `plugins/superpowers/` (skills, assets, license/readme, and manifest;
64
- upstream's `hooks/` directory is deliberately excluded).
159
+ `plugins/superpowers/` (skills, assets, license/readme, manifest, and any
160
+ hook files that the upstream manifest allows).
65
161
  - Stamps the generated manifest with a ref-aware manager version ending in
66
162
  `+manager.<short-sha>` and writes the upstream provenance to
67
163
  `.superpowers-upstream.json`.
68
- - Validates the generated tree with the manager's shipped, Python-standard-library
69
- contract validator before swapping it into place (a failed run never destroys
70
- a previously generated tree).
164
+ - Validates the generated tree with the manager's shipped contract validator
165
+ before swapping it into place (a failed run never destroys a previously
166
+ generated tree).
71
167
  - Registers the `superpowers-manager` marketplace and installs or refreshes
72
168
  `superpowers@superpowers-manager` in Codex.
73
169
 
74
- The generated plugin carries upstream skills, assets, and documentation. The
75
- manager excludes upstream `hooks/`, removes the manifest `hooks` field, and
76
- validates that both stay absent. This is a Codex-specific adapter policy, not a
77
- claim about how Superpowers should be packaged for future or other harnesses.
78
- Changing the hook-free policy requires a separate design and current
79
- compatibility evidence.
170
+ The generated plugin carries upstream skills, assets, documentation, and the
171
+ upstream-owned hook policy. When upstream provides a Codex manifest, its
172
+ `hooks` declaration is preserved: exact `{}` suppresses the `hooks/` subtree;
173
+ active declarations conditionally materialize the upstream hook files; and a
174
+ missing `hooks` key or explicit empty array (`[]`) declaration uses Codex's
175
+ default discovery only when upstream ships `hooks/hooks.json`. Manifest-less
176
+ fallback refs use the committed minimal template and generate neither a manifest
177
+ `hooks` key nor a `hooks/` directory.
178
+ The manager never creates its own hooks or mutates Codex trust state.
179
+
180
+ Review upstream hook command definitions with Codex's `/hooks` flow. Codex
181
+ trust applies to a command definition, not to the contents of scripts that the
182
+ definition references. An explicit update of an older pin can therefore change
183
+ the contents of a trusted referenced script, or reveal a newly untrusted
184
+ upstream definition; review it before trusting or running it. This policy
185
+ eliminates latent hook-policy drift.
80
186
 
81
187
  ## Runtime architecture
82
188
 
83
- - `scripts/core/` owns the shared lifecycle, status, and protocol validation;
84
- see the [version-1 adapter response protocol](https://github.com/j7an/superpowers-manager/blob/main/docs/adapter-protocol.md).
85
- - `scripts/adapters/codex/` owns build, inspection, reconciliation, and Codex
86
- mutation.
189
+ - The in-process TypeScript runtime under `src/` owns lifecycle dispatch,
190
+ status, and adapter-result handling;
191
+ see the [in-process adapter result contract](https://github.com/j7an/superpowers-manager/blob/main/docs/adapter-result-contract.md).
192
+ - Developers extending that runtime should start with the
193
+ [internal harness interface](https://github.com/j7an/superpowers-manager/blob/main/docs/harness-interface.md).
194
+ - `src/adapter.ts` owns build, inspection, reconciliation, and Codex mutation.
87
195
  - Codex is the only supported adapter today; no public harness selector ships
88
196
  yet.
89
197
 
@@ -97,10 +205,33 @@ after the built-in check. It receives the candidate plugin root as its only
97
205
  argument. It cannot replace or bypass built-in validation, and either check
98
206
  failing prevents the tree swap and all Codex mutation.
99
207
 
100
- Direct `scripts/install` keeps harness-specific validation in the Codex adapter:
101
- phase 1 prepares the exact candidate first, then the adapter performs its Codex
102
- and refresh-mode preflight before any Codex mutation. The Node dispatcher keeps
103
- its existing Codex preflight before dispatching to the shell lifecycle.
208
+ `SUPERPOWERS_VALIDATOR_EXECUTABLE=/path/to/validator` adds an optional external
209
+ validator after the built-in check. It names an executable, receiving the
210
+ candidate plugin root as its only argument. The manager constructs no shell
211
+ command string and supplies argv directly. On Linux, `execvp` may hand that
212
+ same argv to `/bin/sh` after `ENOEXEC`, and the values are preserved rather
213
+ than re-parsed, so a candidate path containing spaces or shell metacharacters
214
+ is passed through intact and cannot inject a command — on either platform. A
215
+ file with the exec bit set but no valid executable format is handled by the
216
+ platform's own `execvp` fallback, not by the manager: on Linux, `/bin/sh` runs
217
+ it as shell source; on darwin, it is
218
+ rejected outright as not runnable. Give the validator a shebang line or make
219
+ it a real binary, or its behavior will differ by platform. Exit 0 accepts;
220
+ any nonzero exit rejects and prevents the tree swap. The manager stops
221
+ waiting after 30 seconds and keeps at most 64 KiB of each of its output
222
+ streams. It cannot replace or bypass built-in validation, and it is not a
223
+ security boundary: it runs with the manager's own privileges, by design.
224
+
225
+ `SUPERPOWERS_VALIDATOR` is deprecated in favor of `SUPERPOWERS_VALIDATOR_EXECUTABLE`
226
+ and continues to work unchanged. The legacy variable requires `python3`; the
227
+ executable hook does not. Setting both is rejected at preflight, before any
228
+ network or Codex access, rather than silently resolved. Removal of the legacy
229
+ variable is deferred to a future major release.
230
+
231
+ The in-process install command keeps harness-specific validation in the Codex
232
+ adapter: phase 1 prepares the exact candidate first, then the adapter performs
233
+ its Codex and refresh-mode preflight before any Codex mutation. The CLI runs
234
+ its Codex preflight before invoking the lifecycle handler.
104
235
 
105
236
  ## Provider ownership
106
237
 
@@ -218,15 +349,17 @@ updates the official provider or any other provider automatically.
218
349
 
219
350
  - **Upstream manifest first:** when upstream provides
220
351
  `.codex-plugin/plugin.json`, `prepare` uses it as the generated manifest base
221
- so future upstream metadata fields are preserved by default.
352
+ so future upstream metadata fields, including its hook declaration, are
353
+ preserved by default.
222
354
  - **Fallback template:** `plugins/superpowers/.codex-plugin/plugin.template.json`
223
355
  is committed as a minimal fallback for older upstream refs that do not ship a
224
356
  Codex manifest. It carries the placeholder version
225
- `0.0.0+manager.template`.
357
+ `0.0.0+manager.template`, declares no hooks, and produces no `hooks/`
358
+ directory.
226
359
  - **Manager overlay:** `prepare` replaces the version with a ref-aware manager
227
- version, forces `skills` to `./skills/`, and enforces the manager's current
228
- hook-free policy: no manifest `hooks` key and no copied `hooks/` directory.
229
- Unknown upstream manifest fields remain preserved.
360
+ version and forces `skills` to `./skills/`. Unknown upstream manifest fields,
361
+ including `hooks`, remain preserved; the adapter materializes hook files only
362
+ according to the upstream declaration.
230
363
  - Stable tags generate release-looking versions such as
231
364
  `6.0.3+manager.896224c`; explicit prerelease tags generate versions such as
232
365
  `6.1.0-beta.1+manager.abc1234`.
@@ -253,49 +386,190 @@ updates the official provider or any other provider automatically.
253
386
  SUPERPOWERS_INSTALL_REFRESH_MODE=remove-add npx superpowers-manager update
254
387
  ```
255
388
 
389
+ ## pnpm updates
390
+
391
+ A weekly Monday workflow (06:00 UTC), also available through manual dispatch,
392
+ opens or refreshes a dedicated pull request updating only `package.json`'s
393
+ `packageManager` pin. It selects a newer, non-deprecated stable pnpm release
394
+ within the pinned major after five days. If the current pin is deprecated,
395
+ the shared updater bypasses that waiting period and discloses it in the PR.
396
+ Major upgrades remain a manual decision; the lockfile is not updated by this
397
+ workflow.
398
+
399
+ The caller forwards only `RELEASE_BOT_PRIVATE_KEY` and uses
400
+ `vars.RELEASE_BOT_APP_ID` for App-authored PRs that can trigger CI. Keep both
401
+ configured. After adopting the caller, verify a manual run's App authentication
402
+ and inspect any resulting PR before treating live integration as validated.
403
+
256
404
  ## Tests
257
405
 
406
+ Install once, run the static gate before submission, and choose the package
407
+ script that matches the scope you are iterating on:
408
+
409
+ ```sh
410
+ pnpm install --frozen-lockfile
411
+ pnpm run check:static
412
+ pnpm test
413
+ pnpm run test:unit
414
+ pnpm run test:integration
415
+ pnpm run test:harness:codex
416
+ pnpm run test:acceptance
417
+ ```
418
+
419
+ The package scripts above are alternative iteration selectors; do not run every
420
+ row sequentially as a substitute for acceptance. `pnpm test` runs all shared
421
+ suites once, while the unit and integration scripts select one shared group.
422
+ `test:harness:codex` runs only the isolated Docker Codex probe. Complete
423
+ acceptance is `pnpm run check:static` followed by `pnpm run test:acceptance`
424
+ with explicit evidence for the package's minimum Node runtime.
425
+
426
+ To compare shared-suite scheduling while iterating, use:
427
+
428
+ ```sh
429
+ sh tests/run.sh --concurrency 1
430
+ sh tests/run.sh --concurrency 2
431
+ ```
432
+
433
+ Every normally completed shared run emits both `run-node-suites: complete
434
+ status=<status>` and `tests/run.sh: complete failed=<count>`. Either sentinel
435
+ may report failure; if either is absent, the run was interrupted and is
436
+ incomplete.
437
+
438
+ Use a Homebrew-managed local pnpm by command name; do not use Corepack.
439
+ `check:static` checks formatting, lints, and typechecks production and tests without
440
+ emitting JavaScript. Run the maintained CLI directly with `node src/cli.ts`.
441
+ Tests and their subprocesses execute TypeScript against `src/` with no checkout
442
+ build. Future production coverage covers `src/`, including `src/cli.ts`; emitted
443
+ distribution files, tests, and packaging tools are outside that source scope.
444
+ No coverage collection is enabled by this migration.
445
+
446
+ On macOS, reuse an existing exact package-minimum Node executable when one is
447
+ already available:
448
+
449
+ ```sh
450
+ export SPW_PACKAGE_NODE=/absolute/path/to/node-v24.0.0
451
+ export SPW_PACKAGE_NODE_VERSION=24.0.0
452
+ test "$("$SPW_PACKAGE_NODE" -p 'process.versions.node')" = "$SPW_PACKAGE_NODE_VERSION"
453
+ ```
454
+
455
+ Otherwise, run this prerequisite setup from the worktree while a supported
456
+ native Node remains on `PATH`. It downloads an official Node archive into a
457
+ new temporary directory and verifies the selected checksum before extraction:
458
+
459
+ ```sh
460
+ spw_runtime_dir=$(mktemp -d)
461
+ SPW_PACKAGE_NODE_VERSION=$(node -p 'const e=require("./package.json").engines.node; const m=/^>=(\d+)$/.exec(e); if(!m) throw Error("unsupported engines.node"); `${m[1]}.0.0`')
462
+ case "$(uname -m)" in
463
+ arm64) spw_node_arch=arm64 ;;
464
+ x86_64) spw_node_arch=x64 ;;
465
+ *) echo "unsupported macOS architecture" >&2; exit 1 ;;
466
+ esac
467
+ spw_node_archive="node-v${SPW_PACKAGE_NODE_VERSION}-darwin-${spw_node_arch}.tar.gz"
468
+ (
469
+ set -eu
470
+ cd "$spw_runtime_dir"
471
+ curl --fail --location --remote-name "https://nodejs.org/dist/v${SPW_PACKAGE_NODE_VERSION}/${spw_node_archive}"
472
+ curl --fail --location --remote-name "https://nodejs.org/dist/v${SPW_PACKAGE_NODE_VERSION}/SHASUMS256.txt"
473
+ rg -F " ${spw_node_archive}" SHASUMS256.txt > selected-sha256.txt
474
+ test "$(wc -l < selected-sha256.txt)" -eq 1
475
+ read -r spw_node_sha spw_selected_archive < selected-sha256.txt
476
+ test "$spw_selected_archive" = "$spw_node_archive"
477
+ shasum -a 256 -c selected-sha256.txt
478
+ tar -xzf "$spw_node_archive"
479
+ ) || exit 1
480
+ SPW_PACKAGE_NODE="$spw_runtime_dir/node-v${SPW_PACKAGE_NODE_VERSION}-darwin-${spw_node_arch}/bin/node"
481
+ export SPW_PACKAGE_NODE SPW_PACKAGE_NODE_VERSION
482
+ ```
483
+
484
+ The native runtime on `PATH` remains unchanged. With the package runtime
485
+ variables exported, complete acceptance is:
486
+
258
487
  ```sh
259
- sh tests/run.sh # Layers 1-3: host-side hermetic checks while iterating
260
- sh tests/container.sh # Layers 1-4: blocking Docker acceptance command
261
- sh tests/manual/codex-behavior-probe.sh # optional native-only compatibility residue
488
+ pnpm install --frozen-lockfile
489
+ pnpm run check:static
490
+ pnpm run test:acceptance
262
491
  ```
263
492
 
493
+ After the checks, remove only the temporary directory created by this
494
+ invocation and clear its variables:
495
+
496
+ ```sh
497
+ rm -rf -- "$spw_runtime_dir"
498
+ unset SPW_PACKAGE_NODE SPW_PACKAGE_NODE_VERSION spw_node_arch spw_node_archive spw_runtime_dir
499
+ ```
500
+
501
+ Linux CI provisions the exact package runtime with `actions/setup-node`.
502
+ Downloads happen only during prerequisite setup, never inside the hermetic test
503
+ cases.
504
+
505
+ Packaging compiles only production source into fresh external temporary staging:
506
+
507
+ ```sh
508
+ node tests/tools/pack.ts --out-dir /absolute/existing/temporary/output
509
+ ```
510
+
511
+ Allocate the existing output directory outside the checkout before running this
512
+ command. It returns npm-compatible JSON for one validated tarball and removes its
513
+ own staging. Bare checkout `npm pack` always fails with this command's guidance,
514
+ even if stale `dist/` exists. Maintained or manager-generated JavaScript must not
515
+ remain in the checkout; dependencies and generated upstream plugin content have
516
+ separate ownership. This developer command does not authorize publication; follow
517
+ `RELEASING.md` for the protected release procedure.
518
+
264
519
  Layers 1-3 stay offline and hermetic: they use a fake local upstream repo plus
265
520
  host-side fixtures, and they perform no mutation of the developer's or runner's
266
521
  real Codex state.
267
522
 
268
- Layer 4 is the Docker acceptance path. It is the required completion command
269
- because the isolated-container Codex probe graduated from a temporary
270
- nonblocking spike to a blocking acceptance gate. `sh tests/container.sh` runs
271
- the inner `sh tests/run.sh` suite and then the real Codex offline probe inside
272
- an isolated container home with networking disabled. That container run may
273
- mutate the throwaway container-local Codex state, but it still performs no
274
- mutation of the developer's or runner's real Codex state.
523
+ Layer 4 is the Docker acceptance path. `pnpm run test:harness:codex` runs the
524
+ real Codex offline probe inside an isolated container home with networking
525
+ disabled. `pnpm run test:acceptance` composes one host-side shared run with that
526
+ probe. The container may mutate its throwaway container-local Codex state, but
527
+ it performs no mutation of the developer's or runner's real Codex state.
528
+
529
+ Release validation deliberately retains the combined shared-plus-Codex path at
530
+ both native endpoints:
531
+
532
+ ```sh
533
+ SPW_NATIVE_NODE_VERSION=24.12.0 sh tests/container.sh
534
+ SPW_NATIVE_NODE_VERSION=24 sh tests/container.sh
535
+ ```
275
536
 
276
- The manual probe is opt-in and covers native-only compatibility residue such as
277
- path/cache behavior against an intentionally real local Codex install. It is
278
- not part of acceptance. GitHub Actions runs the blocking container acceptance
279
- command on pull requests and pushes to `main`.
537
+ The container probe uses Codex's `hooks/list` only as compatibility evidence
538
+ for the tested Codex build. It is not a stable Superpowers Manager API.
539
+
540
+ `sh tests/manual/codex-behavior-probe.sh` remains opt-in and covers native-only compatibility residue such as
541
+ path/cache and version-precedence behavior against an intentionally real local
542
+ Codex install. It is not part of acceptance. GitHub Actions runs two focused
543
+ `toolchain` entries and one blocking Codex integration job on pull requests
544
+ and pushes to `main`. The Node 24.12.0 toolchain entry checks native source
545
+ loading, the suite runner/assertion preload, and package-producer success and
546
+ failure. The latest-24 toolchain entry alone runs `pnpm run check:static` and
547
+ the full shared suite with package-minimum evidence. The independent `test` job
548
+ runs only the Codex offline probe on latest Node 24.x. Release acceptance still
549
+ runs the combined shared and Codex paths at both native endpoints, and the
550
+ installed npm executable is tested with Node 24.0.0. These runtime selectors
551
+ are separate from the Homebrew-managed local commands above.
280
552
 
281
553
  ## Repository layout
282
554
 
283
555
  ```
284
556
  .agents/plugins/marketplace.json # local marketplace definition (tracked)
285
- config/upstream-ref # which upstream ref to track (tracked)
557
+ .github/ # CI, security, dependency, and release workflows (tracked)
558
+ config/upstream-ref # packaged upstream fallback policy (tracked)
559
+ docs/ # adapter result contract and baseline evidence (tracked)
560
+ package.json pnpm-lock.yaml tsconfig.json # package contract and locked toolchain (tracked)
286
561
  plugins/superpowers/
287
- .codex-plugin/plugin.template.json # fallback manifest template (tracked)
288
- .codex-plugin/plugin.json # generated manifest (gitignored)
289
- skills/ assets/ LICENSE ... # generated from upstream (gitignored)
290
- .superpowers-upstream.json # generated provenance (gitignored)
291
- scripts/
292
- adapters/codex/ # Codex adapter entrypoint + validator helpers
293
- core/ # shared lifecycle, selection, provenance, and status modules
294
- pin track-latest unpin # persistent-selection entrypoints
295
- prepare probe install update uninstall # lifecycle entrypoints
296
- tests/ # hermetic suite + manual Codex probe
297
- .cache/upstream/ # upstream clone cache (gitignored)
562
+ .codex-plugin/plugin.template.json # fallback manifest template (tracked)
563
+ generated plugin tree # prepared from upstream (gitignored)
564
+ src/ # in-process TypeScript runtime (tracked)
565
+ cli.ts # sole maintained CLI entry, parsing, preflight, dispatch
566
+ commands/ # lifecycle and selection command handlers
567
+ adapter.ts # Codex integration
568
+ tests/ # hermetic suite and manual Codex probe (tracked)
569
+ migration-inventory/ # frozen historical evidence
570
+ tools/pack.ts # external staging and validated package emission
298
571
  ```
299
572
 
300
573
  Everything under `plugins/superpowers/` except the fallback manifest template is
301
- generated by `prepare` and ignored by Git; re-run `prepare` to regenerate it.
574
+ generated by `npx superpowers-manager prepare` and ignored by Git; re-run that
575
+ command to regenerate it.