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 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@0.1.4 install
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 or fetches that exact upstream commit and assembles a Codex plugin tree
59
- under `plugins/superpowers/`.
60
- - Preserves the upstream manifest when available, while applying the
61
- manager-owned plugin contract.
62
- - Records `source`, `requested_ref`, `resolved_ref`, `commit`, and the upstream
63
- manifest version in `.superpowers-upstream.json`.
64
- - Validates the candidate tree before replacing a previous generated tree or
65
- mutating Codex state.
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
- ## Choosing the upstream version
77
+ ## Runtime architecture
77
78
 
78
- `SUPERPOWERS_REF` selects a stable release tag, full commit SHA, branch, or
79
- other resolvable upstream ref for that invocation. The stateless npx package
80
- records the requested ref, resolved ref, and exact commit, but does not persist
81
- the selection for a later invocation that omits `SUPERPOWERS_REF`.
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
- Without `SUPERPOWERS_REF`, the manager reads `config/upstream-ref`, which ships
84
- as `latest-release`. Accepted values include:
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
- - `latest-release` — the highest stable `vX.Y.Z` tag; prereleases are excluded.
87
- - A specific tag, such as `v6.0.3`.
88
- - A full 40-character commit SHA.
89
- - Any other ref upstream resolves, such as `main` or a branch name.
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
- `SUPERPOWERS_CACHE_DIR` may point to a persistent upstream clone cache to avoid
99
- re-cloning between package materializations. It caches Git objects; it does not
100
- persist ref selection or trigger updates.
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 prepare and validate before changing Codex state.
134
- Uninstall inspects and removes only manager-owned Codex state. Those mutating
135
- commands fail closed when required state cannot be inspected and refuse to
136
- report success when the resulting state cannot be verified.
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
- ### Refresh modes
137
+ ## Choosing the upstream version
139
138
 
140
- `install` and `update` accept `SUPERPOWERS_INSTALL_REFRESH_MODE`:
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
- - `add-only` (default) asks Codex to add the plugin from the current local
143
- marketplace source.
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
- Use `remove-add` only when an add-only refresh fails to take:
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
- SUPERPOWERS_INSTALL_REFRESH_MODE=remove-add npx superpowers-manager update
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
- ## How generated versions work
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
- - If upstream provides `.codex-plugin/plugin.json`, the manager uses it as the
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
- The generated version is for readable Codex package identity. The exact commit
165
- in `.superpowers-upstream.json` is the authoritative value compared by `probe`
166
- and `update`.
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
- `SUPERPOWERS_VALIDATOR=/path/to/validator.py` adds an optional Python validator
169
- after the built-in generated-tree validation. It receives the candidate plugin
170
- root as its only argument. It cannot bypass the built-in validator, and either
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 # Layers 1-3: hermetic, no network or real Codex state
177
- sh tests/container.sh # Layer 4: blocking isolated real-Codex CLI check
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
- The container suite runs with networking disabled and a throwaway home, so it
181
- may mutate only isolated container state. The optional
182
- `tests/manual/codex-behavior-probe.sh` is reserved for intentional native-only
183
- compatibility residue and is not part of acceptance.
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
- ```text
188
- .agents/plugins/marketplace.json # local manager marketplace definition
189
- bin/superpowers-manager.js # npm CLI launcher
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 # tracked fallback manifest
193
- .codex-plugin/plugin.json # generated manifest (ignored)
194
- skills/ assets/ LICENSE ... # generated from upstream (ignored)
195
- .superpowers-upstream.json # generated provenance (ignored)
196
- scripts/ # prepare/probe/install/update/uninstall
197
- tests/ # hermetic and isolated-container suites
198
- .cache/upstream/ # optional upstream clone cache (ignored)
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
- is generated by `prepare` and ignored by Git. Do not edit generated plugin
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
- 'use strict';
2
+ // @ts-check
3
3
 
4
- const fs = require('fs');
5
- const path = require('path');
6
- const { spawnSync } = require('child_process');
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 subcommands
121
- // whose scripts read or mutate Codex state.
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
- return errors.length
152
- ? { ok: false, errors }
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(__filename);
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
- module.exports = { resolvePackageRoot, parseArgs, findTool, discoverShell, preflight, buildSpawn, usage };
242
+ export { resolvePackageRoot, isMain, parseArgs, findTool, discoverShell, preflight, buildSpawn, usage };
234
243
 
235
- if (require.main === module) main();
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.4",
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"