superpowers-manager 0.2.0 → 0.3.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 (64) hide show
  1. package/README.md +112 -47
  2. package/bin/superpowers-manager.js +9 -283
  3. package/dist/adapter-result.js +204 -0
  4. package/dist/adapter.js +649 -0
  5. package/dist/atomic.js +142 -0
  6. package/dist/cli-arguments.js +32 -0
  7. package/dist/cli.js +293 -0
  8. package/dist/codex-json.js +89 -0
  9. package/dist/codex-state.js +78 -0
  10. package/dist/commands/context.js +1 -0
  11. package/dist/commands/install.js +376 -0
  12. package/dist/commands/pin.js +79 -0
  13. package/dist/commands/prepare.js +527 -0
  14. package/dist/commands/probe.js +392 -0
  15. package/dist/commands/track-latest.js +44 -0
  16. package/dist/commands/uninstall.js +308 -0
  17. package/dist/commands/unpin.js +95 -0
  18. package/dist/commands/update.js +138 -0
  19. package/dist/domain/fingerprint.js +4 -0
  20. package/dist/domain/refs.js +37 -0
  21. package/dist/effective-selection.js +123 -0
  22. package/dist/generated-plugin.js +748 -0
  23. package/dist/git.js +38 -0
  24. package/dist/hooks.js +290 -0
  25. package/dist/lifecycle.js +220 -0
  26. package/dist/manifest-overlay.js +125 -0
  27. package/dist/provenance.js +111 -0
  28. package/dist/python-json-format.js +83 -0
  29. package/dist/python-json.js +29 -0
  30. package/dist/python-text.js +74 -0
  31. package/dist/safe-path.js +137 -0
  32. package/dist/safety-error.js +10 -0
  33. package/dist/selection-state-cli.js +85 -0
  34. package/dist/selection-store.js +172 -0
  35. package/dist/selection.js +200 -0
  36. package/dist/status.js +24 -0
  37. package/dist/strict-json.js +248 -0
  38. package/dist/upstream-cli.js +110 -0
  39. package/dist/upstream-version.js +40 -0
  40. package/dist/upstream.js +253 -0
  41. package/dist/validate-generated-plugin-cli.js +118 -0
  42. package/dist/validator.js +317 -0
  43. package/dist/workspace.js +139 -0
  44. package/package.json +25 -2
  45. package/scripts/adapters/codex/adapter +0 -603
  46. package/scripts/adapters/codex/lib.sh +0 -449
  47. package/scripts/adapters/codex/validate-generated-plugin.py +0 -314
  48. package/scripts/core/adapter.sh +0 -103
  49. package/scripts/core/common.sh +0 -59
  50. package/scripts/core/lifecycle.sh +0 -141
  51. package/scripts/core/provenance.sh +0 -135
  52. package/scripts/core/selection-state.py +0 -414
  53. package/scripts/core/selection.sh +0 -168
  54. package/scripts/core/status.sh +0 -27
  55. package/scripts/core/upstream.sh +0 -280
  56. package/scripts/core/validate-adapter-response.py +0 -284
  57. package/scripts/install +0 -59
  58. package/scripts/pin +0 -51
  59. package/scripts/prepare +0 -117
  60. package/scripts/probe +0 -82
  61. package/scripts/track-latest +0 -30
  62. package/scripts/uninstall +0 -35
  63. package/scripts/unpin +0 -41
  64. package/scripts/update +0 -34
@@ -0,0 +1,123 @@
1
+ // `selectionError` already exists at
2
+ // `src/selection.ts:41::export function selectionError` and tags errors with
3
+ // module "selection". Import it rather than defining a second one.
4
+ import { normalizeSaved, selectionError, validateSource, } from "./selection.js";
5
+ import { readSelectionState } from "./selection-store.js";
6
+ import { readConfigRef, resolveRef } from "./upstream.js";
7
+ import { COMMIT_RE } from "./domain/refs.js";
8
+ function requireAbsolute(value, variable) {
9
+ if (!value.startsWith("/")) {
10
+ throw selectionError(`${variable} must be absolute`);
11
+ }
12
+ return value;
13
+ }
14
+ // Precedence mirrors
15
+ // `git show ad56569a4c161e7b122967442e2b026eeb6395f6:scripts/core/selection.sh:4-29::spw_selection_config_dir(`.
16
+ // SUPERPOWERS_CONFIG_DIR is selected on *presence*, matching the shell's
17
+ // ${SUPERPOWERS_CONFIG_DIR+x}: an empty value takes this branch and then fails
18
+ // the absolute check, rather than falling through to XDG.
19
+ export function selectionConfigDir(env) {
20
+ const explicit = env.SUPERPOWERS_CONFIG_DIR;
21
+ if (explicit !== undefined) {
22
+ return requireAbsolute(explicit, "SUPERPOWERS_CONFIG_DIR");
23
+ }
24
+ const xdg = env.XDG_CONFIG_HOME;
25
+ if (xdg !== undefined && xdg.length > 0) {
26
+ return `${requireAbsolute(xdg, "XDG_CONFIG_HOME")}/superpowers-manager`;
27
+ }
28
+ const home = env.HOME;
29
+ if (home === undefined || home.length === 0) {
30
+ throw selectionError("HOME is required to locate selection state");
31
+ }
32
+ return `${requireAbsolute(home, "HOME")}/.config/superpowers-manager`;
33
+ }
34
+ export function selectionStatePath(env) {
35
+ return `${selectionConfigDir(env)}/selection.json`;
36
+ }
37
+ // Composes exactly what `src/selection-state-cli.ts:39::const normalized`
38
+ // composes. The shell wrote a normalized document to a mktemp file and read
39
+ // five fields back with five python3 invocations; in-process this is one call.
40
+ export async function loadSavedSelection(env) {
41
+ return normalizeSaved(await readSelectionState(selectionStatePath(env)));
42
+ }
43
+ export const UPSTREAM_URL_DEFAULT = "https://github.com/obra/superpowers";
44
+ // Ports the env > saved > package-default precedence ladder from
45
+ // `git show ad56569a4c161e7b122967442e2b026eeb6395f6:scripts/core/selection.sh:88-162::spw_compute_effective_selection`.
46
+ // validateSource runs before any ref resolution -- pinned by
47
+ // tests/unit/effective-selection.test.js's "source validation precedes ref
48
+ // resolution": a credential-bearing source must fail before Git is ever
49
+ // invoked.
50
+ export async function computeEffectiveSelection(root, env) {
51
+ const saved = await loadSavedSelection(env);
52
+ let upstreamSourceOrigin;
53
+ let effectiveSource;
54
+ if (env.SUPERPOWERS_UPSTREAM_URL) {
55
+ upstreamSourceOrigin = "environment";
56
+ effectiveSource = env.SUPERPOWERS_UPSTREAM_URL;
57
+ }
58
+ else if (saved.saved_mode !== "none") {
59
+ upstreamSourceOrigin = "user-config";
60
+ effectiveSource = saved.saved_source;
61
+ }
62
+ else {
63
+ upstreamSourceOrigin = "package-default";
64
+ effectiveSource = UPSTREAM_URL_DEFAULT;
65
+ }
66
+ // Before any Git access. Pinned by tests/unit/effective-selection.test.js's
67
+ // "source validation precedes ref resolution".
68
+ validateSource(effectiveSource);
69
+ let selectionOrigin;
70
+ let selectionMode;
71
+ let requestedRef;
72
+ let usesSavedPin = false;
73
+ if (env.SUPERPOWERS_REF) {
74
+ selectionOrigin = "environment";
75
+ selectionMode = "override";
76
+ requestedRef = env.SUPERPOWERS_REF;
77
+ }
78
+ else if (saved.saved_mode === "pinned") {
79
+ selectionOrigin = "user-config";
80
+ selectionMode = "pinned";
81
+ requestedRef = saved.saved_requested_ref;
82
+ usesSavedPin = true;
83
+ }
84
+ else if (saved.saved_mode === "track-latest") {
85
+ selectionOrigin = "user-config";
86
+ selectionMode = "track-latest";
87
+ requestedRef = "latest-release";
88
+ }
89
+ else {
90
+ selectionOrigin = "package-default";
91
+ selectionMode = "default";
92
+ requestedRef = await readConfigRef(root, env);
93
+ }
94
+ if (usesSavedPin) {
95
+ return {
96
+ selectionOrigin,
97
+ selectionMode,
98
+ upstreamSourceOrigin,
99
+ effectiveSource,
100
+ requestedRef,
101
+ resolvedRef: saved.saved_resolved_ref,
102
+ desiredCommit: saved.saved_commit,
103
+ resolutionKind: COMMIT_RE.test(saved.saved_requested_ref)
104
+ ? "raw-commit"
105
+ : "tag",
106
+ saved,
107
+ };
108
+ }
109
+ const resolution = await resolveRef(effectiveSource, requestedRef);
110
+ // `Resolution` (src/upstream.ts) is { kind, ref, commit } — the
111
+ // resolved ref field is named `ref`, not `resolvedRef`.
112
+ return {
113
+ selectionOrigin,
114
+ selectionMode,
115
+ upstreamSourceOrigin,
116
+ effectiveSource,
117
+ requestedRef,
118
+ resolvedRef: resolution.ref,
119
+ desiredCommit: resolution.commit,
120
+ resolutionKind: resolution.kind,
121
+ saved,
122
+ };
123
+ }