superpowers-manager 0.3.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.
- package/README.md +240 -31
- package/dist/adapter.js +85 -44
- package/dist/cli.js +51 -31
- package/dist/codex-harness.js +271 -0
- package/dist/codex-prepare.js +199 -0
- package/dist/codex-presentation.js +259 -0
- package/dist/commands/install.js +88 -173
- package/dist/commands/prepare.js +74 -181
- package/dist/commands/probe.js +41 -176
- package/dist/commands/uninstall.js +48 -139
- package/dist/commands/update.js +29 -88
- package/dist/harness.js +1 -0
- package/dist/lifecycle.js +1 -86
- package/dist/manifest-overlay.js +2 -2
- package/dist/strict-json.js +1 -1
- package/dist/validator.js +1 -1
- package/package.json +14 -16
- package/bin/superpowers-manager.js +0 -16
package/README.md
CHANGED
|
@@ -16,16 +16,21 @@ npx superpowers-manager probe
|
|
|
16
16
|
npx superpowers-manager update
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Use
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
|
28
|
-
|
|
|
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,10 +44,11 @@ It never removes the legacy provider automatically.
|
|
|
39
44
|
|
|
40
45
|
## Requirements and platforms
|
|
41
46
|
|
|
42
|
-
Superpowers Manager requires Node 24
|
|
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
|
|
43
49
|
integration today. Every other requirement is per command, enforced by
|
|
44
50
|
preflight before any dispatch. This table is checked against production by
|
|
45
|
-
`tests/bin/readme-requirements.test.
|
|
51
|
+
`tests/bin/readme-requirements.test.ts`; edit it when a command's requirements
|
|
46
52
|
change, in the same pull request.
|
|
47
53
|
|
|
48
54
|
<!-- requirements:begin -->
|
|
@@ -73,6 +79,78 @@ of a saved exact pin can reuse its recorded identity without upstream access.
|
|
|
73
79
|
Updates remain user-triggered; the manager does not run automatic or background
|
|
74
80
|
updates.
|
|
75
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
|
+
|
|
76
154
|
## What it does
|
|
77
155
|
|
|
78
156
|
- Resolves an upstream ref, defaulting to the latest stable `vX.Y.Z` release
|
|
@@ -111,6 +189,8 @@ eliminates latent hook-policy drift.
|
|
|
111
189
|
- The in-process TypeScript runtime under `src/` owns lifecycle dispatch,
|
|
112
190
|
status, and adapter-result handling;
|
|
113
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).
|
|
114
194
|
- `src/adapter.ts` owns build, inspection, reconciliation, and Codex mutation.
|
|
115
195
|
- Codex is the only supported adapter today; no public harness selector ships
|
|
116
196
|
yet.
|
|
@@ -306,46 +386,175 @@ updates the official provider or any other provider automatically.
|
|
|
306
386
|
SUPERPOWERS_INSTALL_REFRESH_MODE=remove-add npx superpowers-manager update
|
|
307
387
|
```
|
|
308
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
|
+
|
|
309
404
|
## Tests
|
|
310
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
|
+
|
|
311
487
|
```sh
|
|
312
488
|
pnpm install --frozen-lockfile
|
|
313
|
-
pnpm run
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
489
|
+
pnpm run check:static
|
|
490
|
+
pnpm run test:acceptance
|
|
491
|
+
```
|
|
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
|
|
317
509
|
```
|
|
318
510
|
|
|
319
|
-
|
|
320
|
-
|
|
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.
|
|
321
518
|
|
|
322
519
|
Layers 1-3 stay offline and hermetic: they use a fake local upstream repo plus
|
|
323
520
|
host-side fixtures, and they perform no mutation of the developer's or runner's
|
|
324
521
|
real Codex state.
|
|
325
522
|
|
|
326
|
-
Layer 4 is the Docker acceptance path.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
+
```
|
|
333
536
|
|
|
334
537
|
The container probe uses Codex's `hooks/list` only as compatibility evidence
|
|
335
538
|
for the tested Codex build. It is not a stable Superpowers Manager API.
|
|
336
539
|
|
|
337
|
-
|
|
540
|
+
`sh tests/manual/codex-behavior-probe.sh` remains opt-in and covers native-only compatibility residue such as
|
|
338
541
|
path/cache and version-precedence behavior against an intentionally real local
|
|
339
|
-
Codex install. It is not part of acceptance. GitHub Actions runs
|
|
340
|
-
toolchain
|
|
341
|
-
and pushes to `main`.
|
|
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.
|
|
342
552
|
|
|
343
553
|
## Repository layout
|
|
344
554
|
|
|
345
555
|
```
|
|
346
556
|
.agents/plugins/marketplace.json # local marketplace definition (tracked)
|
|
347
557
|
.github/ # CI, security, dependency, and release workflows (tracked)
|
|
348
|
-
bin/superpowers-manager.js # public thin loader for dist/cli.js
|
|
349
558
|
config/upstream-ref # packaged upstream fallback policy (tracked)
|
|
350
559
|
docs/ # adapter result contract and baseline evidence (tracked)
|
|
351
560
|
package.json pnpm-lock.yaml tsconfig.json # package contract and locked toolchain (tracked)
|
|
@@ -353,12 +562,12 @@ plugins/superpowers/
|
|
|
353
562
|
.codex-plugin/plugin.template.json # fallback manifest template (tracked)
|
|
354
563
|
generated plugin tree # prepared from upstream (gitignored)
|
|
355
564
|
src/ # in-process TypeScript runtime (tracked)
|
|
356
|
-
cli.ts # CLI parsing, preflight,
|
|
565
|
+
cli.ts # sole maintained CLI entry, parsing, preflight, dispatch
|
|
357
566
|
commands/ # lifecycle and selection command handlers
|
|
358
567
|
adapter.ts # Codex integration
|
|
359
568
|
tests/ # hermetic suite and manual Codex probe (tracked)
|
|
360
569
|
migration-inventory/ # frozen historical evidence
|
|
361
|
-
|
|
570
|
+
tools/pack.ts # external staging and validated package emission
|
|
362
571
|
```
|
|
363
572
|
|
|
364
573
|
Everything under `plugins/superpowers/` except the fallback manifest template is
|
package/dist/adapter.js
CHANGED
|
@@ -197,11 +197,8 @@ async function fileExists(path) {
|
|
|
197
197
|
return false;
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
async function runBuild(
|
|
201
|
-
const
|
|
202
|
-
const upstreamRoot = flags["--upstream-root"];
|
|
203
|
-
const candidateRoot = flags["--candidate-root"];
|
|
204
|
-
const fallbackManifest = flags["--fallback-manifest"];
|
|
200
|
+
async function runBuild(input, env, log) {
|
|
201
|
+
const { upstreamRoot, candidateRoot, fallbackManifest } = input;
|
|
205
202
|
if (!isAbsolute(upstreamRoot)) {
|
|
206
203
|
fail("invalid-arguments", "--upstream-root must be an absolute path");
|
|
207
204
|
}
|
|
@@ -276,7 +273,7 @@ async function runBuild(argv, root, env, log) {
|
|
|
276
273
|
}
|
|
277
274
|
let overlaid;
|
|
278
275
|
try {
|
|
279
|
-
overlaid = applyManifestOverlay(source,
|
|
276
|
+
overlaid = applyManifestOverlay(source, input.managerVersion, candidateManifest);
|
|
280
277
|
}
|
|
281
278
|
catch (cause) {
|
|
282
279
|
// applyManifestOverlay's own messages already name the manifest
|
|
@@ -321,13 +318,13 @@ async function runBuild(argv, root, env, log) {
|
|
|
321
318
|
// on the adapter's surface.
|
|
322
319
|
const splitValues = [
|
|
323
320
|
{ value: candidateRoot, name: "--plugin-root" },
|
|
324
|
-
{ value:
|
|
325
|
-
{ value:
|
|
326
|
-
{ value:
|
|
327
|
-
{ value:
|
|
321
|
+
{ value: input.requestedRef, name: "--requested-ref" },
|
|
322
|
+
{ value: input.resolvedRef, name: "--resolved-ref" },
|
|
323
|
+
{ value: input.commit, name: "--commit" },
|
|
324
|
+
{ value: input.managerVersion, name: "--manager-version" },
|
|
328
325
|
{ value: manifestSource, name: "--manifest-source" },
|
|
329
326
|
{
|
|
330
|
-
value:
|
|
327
|
+
value: input.upstreamManifestVersion,
|
|
331
328
|
name: "--upstream-manifest-version",
|
|
332
329
|
},
|
|
333
330
|
];
|
|
@@ -347,12 +344,12 @@ async function runBuild(argv, root, env, log) {
|
|
|
347
344
|
errors = await validateGeneratedPlugin({
|
|
348
345
|
pluginRoot: candidateRoot,
|
|
349
346
|
source: upstreamSource,
|
|
350
|
-
requestedRef:
|
|
351
|
-
resolvedRef:
|
|
352
|
-
commit:
|
|
353
|
-
manifestVersion:
|
|
347
|
+
requestedRef: input.requestedRef,
|
|
348
|
+
resolvedRef: input.resolvedRef,
|
|
349
|
+
commit: input.commit,
|
|
350
|
+
manifestVersion: input.managerVersion,
|
|
354
351
|
manifestSource,
|
|
355
|
-
upstreamManifestVersion:
|
|
352
|
+
upstreamManifestVersion: input.upstreamManifestVersion,
|
|
356
353
|
});
|
|
357
354
|
}
|
|
358
355
|
catch {
|
|
@@ -377,9 +374,7 @@ async function runBuild(argv, root, env, log) {
|
|
|
377
374
|
throw cause;
|
|
378
375
|
}
|
|
379
376
|
}
|
|
380
|
-
async function runInstall(
|
|
381
|
-
const flags = parseFlags(argv, ["--package-root"]);
|
|
382
|
-
const packageRoot = flags["--package-root"];
|
|
377
|
+
async function runInstall(packageRoot, env, log) {
|
|
383
378
|
if (!isAbsolute(packageRoot)) {
|
|
384
379
|
fail("invalid-arguments", "--package-root must be an absolute path");
|
|
385
380
|
}
|
|
@@ -453,23 +448,15 @@ async function runInstall(argv, env, log) {
|
|
|
453
448
|
throw cause;
|
|
454
449
|
}
|
|
455
450
|
}
|
|
456
|
-
async function runUninstall(
|
|
457
|
-
const
|
|
458
|
-
const pluginPresent = flags["--plugin-present"];
|
|
459
|
-
const marketplacePresent = flags["--marketplace-present"];
|
|
460
|
-
if (pluginPresent !== "true" && pluginPresent !== "false") {
|
|
461
|
-
fail("invalid-arguments", "--plugin-present must be true or false");
|
|
462
|
-
}
|
|
463
|
-
if (marketplacePresent !== "true" && marketplacePresent !== "false") {
|
|
464
|
-
fail("invalid-arguments", "--marketplace-present must be true or false");
|
|
465
|
-
}
|
|
451
|
+
async function runUninstall(input, env, log) {
|
|
452
|
+
const { pluginPresent, marketplacePresent } = input;
|
|
466
453
|
const codexBin = env.SUPERPOWERS_CODEX || "codex";
|
|
467
454
|
await requireCodex(codexBin, env);
|
|
468
455
|
let entered = false;
|
|
469
456
|
try {
|
|
470
457
|
return await withWorkspace(tmpdir(), "superpowers-manager.adapter-uninstall.", async () => {
|
|
471
458
|
entered = true;
|
|
472
|
-
if (pluginPresent
|
|
459
|
+
if (pluginPresent) {
|
|
473
460
|
const result = await mutationCommand(log, codexBin, ["plugin", "remove", PLUGIN_ID], env);
|
|
474
461
|
if (commandFailed(result)) {
|
|
475
462
|
fail("uninstall-failed", `codex plugin remove failed for ${PLUGIN_ID}`);
|
|
@@ -479,7 +466,7 @@ async function runUninstall(argv, env, log) {
|
|
|
479
466
|
else {
|
|
480
467
|
log.appendText("stdout", "plugin not installed; skipping");
|
|
481
468
|
}
|
|
482
|
-
if (marketplacePresent
|
|
469
|
+
if (marketplacePresent) {
|
|
483
470
|
const result = await mutationCommand(log, codexBin, ["plugin", "marketplace", "remove", MARKETPLACE_NAME], env);
|
|
484
471
|
if (commandFailed(result)) {
|
|
485
472
|
fail("uninstall-failed", `codex plugin marketplace remove failed for ${MARKETPLACE_NAME}`);
|
|
@@ -499,9 +486,7 @@ async function runUninstall(argv, env, log) {
|
|
|
499
486
|
throw cause;
|
|
500
487
|
}
|
|
501
488
|
}
|
|
502
|
-
async function runInspect(
|
|
503
|
-
const flags = parseFlags(argv, ["--view"]);
|
|
504
|
-
const view = flags["--view"];
|
|
489
|
+
async function runInspect(view, env, log) {
|
|
505
490
|
if (view === "update-control") {
|
|
506
491
|
return { view: "update-control", update_control: "managed" };
|
|
507
492
|
}
|
|
@@ -610,39 +595,95 @@ async function runInspect(argv, env, log) {
|
|
|
610
595
|
throw cause;
|
|
611
596
|
}
|
|
612
597
|
}
|
|
613
|
-
|
|
598
|
+
const unsupportedView = view;
|
|
599
|
+
fail("invalid-arguments", `unsupported inspect view: ${unsupportedView}`);
|
|
600
|
+
}
|
|
601
|
+
async function runCodexOperation(operation, context, execute) {
|
|
602
|
+
const env = { ...process.env, ...context.env };
|
|
603
|
+
const log = new AdapterMessageLog();
|
|
604
|
+
try {
|
|
605
|
+
const result = await execute(env, log);
|
|
606
|
+
return successResult(operation, result, log.snapshot());
|
|
607
|
+
}
|
|
608
|
+
catch (cause) {
|
|
609
|
+
if (cause instanceof AdapterFailure) {
|
|
610
|
+
return failureResult(operation, cause.code, cause.message, cause.hints, log.snapshot());
|
|
611
|
+
}
|
|
612
|
+
throw cause;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
export function codexBuild(input, context) {
|
|
616
|
+
return runCodexOperation("build", context, (env, log) => runBuild(input, env, log));
|
|
617
|
+
}
|
|
618
|
+
export function codexInstall(packageRoot, context) {
|
|
619
|
+
return runCodexOperation("install", context, (env, log) => runInstall(packageRoot, env, log));
|
|
620
|
+
}
|
|
621
|
+
export function codexRemove(input, context) {
|
|
622
|
+
return runCodexOperation("uninstall", context, (env, log) => runUninstall(input, env, log));
|
|
623
|
+
}
|
|
624
|
+
export function codexInspect(view, context) {
|
|
625
|
+
return runCodexOperation("inspect", context, (env, log) => runInspect(view, env, log));
|
|
614
626
|
}
|
|
615
627
|
export async function runAdapter(argv, context) {
|
|
616
628
|
const rawOperation = argv[0];
|
|
617
629
|
const operation = rawOperation || "adapter";
|
|
618
630
|
const args = argv.slice(1);
|
|
619
|
-
const env = { ...process.env, ...context.env };
|
|
620
|
-
const log = new AdapterMessageLog();
|
|
621
631
|
try {
|
|
622
|
-
let result;
|
|
623
632
|
if (rawOperation === undefined || rawOperation.length === 0) {
|
|
624
633
|
fail("invalid-arguments", "missing adapter operation");
|
|
625
634
|
}
|
|
626
635
|
else if (operation === "build") {
|
|
627
|
-
|
|
636
|
+
const flags = parseFlags(args, BUILD_FLAGS);
|
|
637
|
+
return codexBuild({
|
|
638
|
+
upstreamRoot: flags["--upstream-root"],
|
|
639
|
+
candidateRoot: flags["--candidate-root"],
|
|
640
|
+
requestedRef: flags["--requested-ref"],
|
|
641
|
+
resolvedRef: flags["--resolved-ref"],
|
|
642
|
+
commit: flags["--commit"],
|
|
643
|
+
managerVersion: flags["--manager-version"],
|
|
644
|
+
upstreamManifestVersion: flags["--upstream-manifest-version"],
|
|
645
|
+
fallbackManifest: flags["--fallback-manifest"],
|
|
646
|
+
}, context);
|
|
628
647
|
}
|
|
629
648
|
else if (operation === "install") {
|
|
630
|
-
|
|
649
|
+
const flags = parseFlags(args, ["--package-root"]);
|
|
650
|
+
return codexInstall(flags["--package-root"], context);
|
|
631
651
|
}
|
|
632
652
|
else if (operation === "uninstall") {
|
|
633
|
-
|
|
653
|
+
const flags = parseFlags(args, [
|
|
654
|
+
"--plugin-present",
|
|
655
|
+
"--marketplace-present",
|
|
656
|
+
]);
|
|
657
|
+
const pluginPresent = flags["--plugin-present"];
|
|
658
|
+
const marketplacePresent = flags["--marketplace-present"];
|
|
659
|
+
if (pluginPresent !== "true" && pluginPresent !== "false") {
|
|
660
|
+
fail("invalid-arguments", "--plugin-present must be true or false");
|
|
661
|
+
}
|
|
662
|
+
if (marketplacePresent !== "true" && marketplacePresent !== "false") {
|
|
663
|
+
fail("invalid-arguments", "--marketplace-present must be true or false");
|
|
664
|
+
}
|
|
665
|
+
return codexRemove({
|
|
666
|
+
pluginPresent: pluginPresent === "true",
|
|
667
|
+
marketplacePresent: marketplacePresent === "true",
|
|
668
|
+
}, context);
|
|
634
669
|
}
|
|
635
670
|
else if (operation === "inspect") {
|
|
636
|
-
|
|
671
|
+
const flags = parseFlags(args, ["--view"]);
|
|
672
|
+
const view = flags["--view"];
|
|
673
|
+
if (view !== "ownership" &&
|
|
674
|
+
view !== "update-control" &&
|
|
675
|
+
view !== "fingerprint") {
|
|
676
|
+
fail("invalid-arguments", `unsupported inspect view: ${view}`);
|
|
677
|
+
}
|
|
678
|
+
return codexInspect(view, context);
|
|
637
679
|
}
|
|
638
680
|
else {
|
|
639
681
|
fail("unsupported-operation", `unsupported adapter operation: ${operation}`);
|
|
640
682
|
}
|
|
641
|
-
return successResult(operation, result, log.snapshot());
|
|
642
683
|
}
|
|
643
684
|
catch (cause) {
|
|
644
685
|
if (cause instanceof AdapterFailure) {
|
|
645
|
-
return failureResult(operation, cause.code, cause.message, cause.hints,
|
|
686
|
+
return failureResult(operation, cause.code, cause.message, cause.hints, []);
|
|
646
687
|
}
|
|
647
688
|
throw cause;
|
|
648
689
|
}
|