superpowers-manager 0.8.0 → 0.9.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 +36 -16
- package/dist/atomic.js +1 -3
- package/dist/cli-arguments.js +4 -1
- package/dist/cli.js +14 -43
- package/dist/commands/adapter-call.js +24 -0
- package/dist/commands/install.js +16 -63
- package/dist/commands/mutation.js +5 -5
- package/dist/commands/pin.js +10 -5
- package/dist/commands/prepare.js +42 -108
- package/dist/commands/probe.js +33 -19
- package/dist/commands/uninstall.js +18 -46
- package/dist/commands/unpin.js +2 -1
- package/dist/commands/update.js +8 -29
- package/dist/domain/refs.js +0 -3
- package/dist/effective-selection.js +11 -15
- package/dist/git-tree.js +4 -6
- package/dist/harness-command-result.js +33 -3
- package/dist/harnesses/claude-code/harness.js +39 -0
- package/dist/harnesses/claude-code/install.js +380 -0
- package/dist/harnesses/claude-code/native.js +79 -0
- package/dist/harnesses/claude-code/paths.js +35 -0
- package/dist/harnesses/claude-code/prepare.js +117 -0
- package/dist/harnesses/claude-code/presentation.js +25 -0
- package/dist/harnesses/claude-code/state.js +253 -0
- package/dist/harnesses/codex/adapter.js +27 -68
- package/dist/harnesses/codex/conflicts.js +3 -8
- package/dist/harnesses/codex/generated-plugin.js +4 -11
- package/dist/harnesses/codex/harness.js +4 -26
- package/dist/harnesses/codex/hooks.js +11 -27
- package/dist/harnesses/codex/lifecycle.js +22 -107
- package/dist/harnesses/codex/manifest-overlay.js +9 -27
- package/dist/harnesses/codex/paths.js +29 -0
- package/dist/harnesses/codex/prepare.js +9 -43
- package/dist/harnesses/codex/presentation.js +1 -1
- package/dist/harnesses/codex/publication.js +5 -40
- package/dist/harnesses/codex/state.js +1 -6
- package/dist/harnesses/codex/stored-state.js +1 -6
- package/dist/harnesses/opencode/config.js +2 -4
- package/dist/harnesses/opencode/discovery.js +1 -5
- package/dist/harnesses/opencode/install.js +12 -93
- package/dist/harnesses/opencode/native.js +28 -49
- package/dist/harnesses/opencode/package.js +11 -55
- package/dist/harnesses/opencode/prepare.js +2 -7
- package/dist/harnesses/opencode/presentation.js +2 -7
- package/dist/harnesses/pi/install.js +31 -120
- package/dist/harnesses/pi/native.js +9 -34
- package/dist/harnesses/pi/package.js +9 -50
- package/dist/harnesses/pi/prepare.js +3 -8
- package/dist/harnesses/pi/presentation.js +2 -7
- package/dist/harnesses/pi/settings.js +5 -9
- package/dist/harnesses/pi/shared-skills.js +23 -53
- package/dist/harnesses/pi/state.js +3 -10
- package/dist/provenance.js +3 -19
- package/dist/resource-lock.js +11 -16
- package/dist/safe-path.js +28 -1
- package/dist/selection.js +15 -19
- package/dist/snapshot-journal.js +101 -0
- package/dist/snapshot-package.js +62 -1
- package/dist/snapshot-prepare.js +9 -2
- package/dist/snapshot-presentation.js +9 -0
- package/dist/upstream.js +8 -12
- package/dist/validator.js +26 -23
- package/dist/workspace.js +29 -35
- package/package.json +10 -9
- package/dist/python-json.js +0 -4
- package/dist/upstream-workspace.js +0 -8
package/dist/workspace.js
CHANGED
|
@@ -3,17 +3,11 @@ import { mkdtemp, rm } from "node:fs/promises";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { SafetyError } from "./safety-error.js";
|
|
5
5
|
const MANAGED_SIGNALS = ["SIGHUP", "SIGINT", "SIGTERM"];
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
// diagnostic straight to process.stderr, unconditionally; that raw write is
|
|
12
|
-
// the only thing actually visible to a caller. Previously the signal path
|
|
13
|
-
// called the module-private cleanup and swallowed the rejection in
|
|
14
|
-
// Promise.allSettled, so a signal-time failure was silent entirely — this is
|
|
15
|
-
// the state PR 11.4 removed from the normal path.
|
|
16
|
-
const active = new Map();
|
|
6
|
+
// Workspaces the signal path must remove. A signal death never builds a
|
|
7
|
+
// result outcome (see src/adapter-result.ts), so the signal path writes its
|
|
8
|
+
// hand-written diagnostic straight to process.stderr; that write is the only
|
|
9
|
+
// report a caller can observe.
|
|
10
|
+
const active = new Set();
|
|
17
11
|
let exiting = false;
|
|
18
12
|
const handlers = new Map();
|
|
19
13
|
// One phrasing for one condition. The adapter re-emits this for a suppressed
|
|
@@ -40,29 +34,18 @@ function cleanupForSignal(signal) {
|
|
|
40
34
|
if (exiting)
|
|
41
35
|
return;
|
|
42
36
|
exiting = true;
|
|
43
|
-
for (const
|
|
37
|
+
for (const path of active) {
|
|
44
38
|
try {
|
|
45
39
|
rmSync(path, { recursive: true, force: true });
|
|
46
40
|
}
|
|
47
41
|
catch {
|
|
48
|
-
// The reporter is invoked for parity with the normal path, but nothing
|
|
49
|
-
// ever reads it back here — no outcome is built before the process
|
|
50
|
-
// dies — so the diagnostic is also written straight to stderr,
|
|
51
|
-
// unconditionally; that write is the only thing actually observable.
|
|
52
42
|
// The diagnostic is hand-written and names the workspace; the caught
|
|
53
|
-
// cause is not interpolated.
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// workspaces' cleanup, deregistration, and the re-raise below never run.
|
|
43
|
+
// cause is not interpolated. Guarded: if the write throws — plausibly
|
|
44
|
+
// EPIPE after SIGHUP — the remaining workspaces' cleanup,
|
|
45
|
+
// deregistration, and the re-raise below must still run. Node documents
|
|
46
|
+
// pipe writes as asynchronous on some platforms (notably macOS); small
|
|
47
|
+
// buffers like this one are written inline.
|
|
59
48
|
try {
|
|
60
|
-
if (report)
|
|
61
|
-
report(path);
|
|
62
|
-
// Node documents pipe writes as asynchronous on some platforms
|
|
63
|
-
// (notably macOS); a saturated pipe could drop this write. Small
|
|
64
|
-
// buffers like this one are written inline, which is why the
|
|
65
|
-
// covering test observes it reliably.
|
|
66
49
|
process.stderr.write(`${workspaceRemovalFailure(path)}\n`);
|
|
67
50
|
}
|
|
68
51
|
catch {
|
|
@@ -96,7 +79,7 @@ function deregisterCoordinator() {
|
|
|
96
79
|
process.off(signal, handler);
|
|
97
80
|
handlers.clear();
|
|
98
81
|
}
|
|
99
|
-
|
|
82
|
+
async function runInWorkspace(parent, prefix, fn, options, reportCleanupFailure) {
|
|
100
83
|
const remove = options.cleanup ?? cleanup;
|
|
101
84
|
let workspace;
|
|
102
85
|
try {
|
|
@@ -105,35 +88,46 @@ export async function withWorkspace(parent, prefix, fn, options = {}) {
|
|
|
105
88
|
catch (cause) {
|
|
106
89
|
throw new SafetyError("workspace", "cannot create workspace", { cause });
|
|
107
90
|
}
|
|
108
|
-
active.
|
|
91
|
+
active.add(workspace);
|
|
109
92
|
registerCoordinator();
|
|
110
93
|
try {
|
|
111
|
-
let
|
|
94
|
+
let value;
|
|
112
95
|
let failed = false;
|
|
113
96
|
let callbackError;
|
|
114
97
|
try {
|
|
115
|
-
|
|
98
|
+
value = await fn(workspace);
|
|
116
99
|
}
|
|
117
100
|
catch (error) {
|
|
118
101
|
failed = true;
|
|
119
102
|
callbackError = error;
|
|
120
103
|
}
|
|
104
|
+
let cleanupWarning = null;
|
|
121
105
|
try {
|
|
122
106
|
await remove(workspace);
|
|
123
107
|
}
|
|
124
108
|
catch (cleanupError) {
|
|
125
109
|
if (failed)
|
|
126
110
|
throw callbackError;
|
|
127
|
-
if (
|
|
111
|
+
if (!reportCleanupFailure)
|
|
128
112
|
throw cleanupError;
|
|
129
|
-
|
|
113
|
+
cleanupWarning = workspaceRemovalFailure(workspace);
|
|
130
114
|
}
|
|
131
115
|
if (failed)
|
|
132
116
|
throw callbackError;
|
|
133
|
-
return
|
|
117
|
+
return { value, cleanupWarning };
|
|
134
118
|
}
|
|
135
119
|
finally {
|
|
136
120
|
active.delete(workspace);
|
|
137
121
|
deregisterCoordinator();
|
|
138
122
|
}
|
|
139
123
|
}
|
|
124
|
+
export async function withWorkspace(parent, prefix, fn, options = {}) {
|
|
125
|
+
return (await runInWorkspace(parent, prefix, fn, options, false)).value;
|
|
126
|
+
}
|
|
127
|
+
// Like withWorkspace, except a cleanup failure after a SUCCESSFUL callback is
|
|
128
|
+
// returned as `cleanupWarning` instead of thrown, so the caller keeps the value
|
|
129
|
+
// it already computed and reports the leak itself. A callback throw still
|
|
130
|
+
// propagates, and a cleanup failure never masks it.
|
|
131
|
+
export function withWorkspaceReporting(parent, prefix, fn, options = {}) {
|
|
132
|
+
return runInWorkspace(parent, prefix, fn, options, true);
|
|
133
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superpowers-manager",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Install obra/superpowers directly from upstream for Codex, Pi, and
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Install obra/superpowers directly from upstream for Codex, Pi, OpenCode, and Claude Code. Stay on a known-good release or commit, try a branch, and upgrade when you choose.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"superpowers",
|
|
7
7
|
"obra-superpowers",
|
|
@@ -18,21 +18,22 @@
|
|
|
18
18
|
"pi",
|
|
19
19
|
"pi-coding-agent",
|
|
20
20
|
"opencode",
|
|
21
|
+
"claude-code",
|
|
22
|
+
"claude-code-plugin",
|
|
21
23
|
"version-pinning"
|
|
22
24
|
],
|
|
23
25
|
"license": "MIT",
|
|
24
26
|
"type": "module",
|
|
25
|
-
"packageManager": "pnpm@12.4.
|
|
27
|
+
"packageManager": "pnpm@12.4.2",
|
|
26
28
|
"scripts": {
|
|
27
|
-
"lint": "oxlint src/ tests/
|
|
28
|
-
"format": "prettier --write src/ tests/
|
|
29
|
-
"format:check": "prettier --check src/ tests/
|
|
30
|
-
"test": "
|
|
31
|
-
"test:unit": "node tests/run-node-suites.ts --group unit",
|
|
32
|
-
"test:integration": "node tests/run-node-suites.ts --group integration",
|
|
29
|
+
"lint": "oxlint src/ tests/",
|
|
30
|
+
"format": "prettier --write src/ tests/",
|
|
31
|
+
"format:check": "prettier --check src/ tests/",
|
|
32
|
+
"test": "sh tests/run.sh",
|
|
33
33
|
"test:harness:codex": "sh tests/container.sh harness-codex",
|
|
34
34
|
"test:harness:pi": "sh tests/container.sh harness-pi",
|
|
35
35
|
"test:harness:opencode": "sh tests/container.sh harness-opencode",
|
|
36
|
+
"test:harness:claude-code": "sh tests/container.sh harness-claude-code",
|
|
36
37
|
"test:acceptance": "sh tests/acceptance.sh",
|
|
37
38
|
"check:static": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run knip",
|
|
38
39
|
"check": "pnpm run check:static && pnpm run test",
|
package/dist/python-json.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { isAbsolute, join, resolve } from "node:path";
|
|
2
|
-
export function upstreamCacheRoot(root, env, cwd) {
|
|
3
|
-
const configured = env.SUPERPOWERS_CACHE_DIR || join(root, ".cache", "upstream");
|
|
4
|
-
const cacheParent = isAbsolute(configured)
|
|
5
|
-
? configured
|
|
6
|
-
: resolve(cwd, configured);
|
|
7
|
-
return join(cacheParent, "superpowers");
|
|
8
|
-
}
|