superpowers-manager 0.9.0 → 0.10.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 +35 -16
- package/dist/cli-arguments.js +2 -1
- package/dist/cli.js +12 -9
- package/dist/harnesses/codex/adapter.js +9 -1
- package/dist/harnesses/codex/hooks.js +17 -0
- package/dist/harnesses/hermes/harness.js +36 -0
- package/dist/harnesses/hermes/install.js +235 -0
- package/dist/harnesses/hermes/native.js +40 -0
- package/dist/harnesses/hermes/observe.js +178 -0
- package/dist/harnesses/hermes/paths.js +61 -0
- package/dist/harnesses/hermes/prepare.js +78 -0
- package/dist/harnesses/hermes/presentation.js +23 -0
- package/dist/harnesses/hermes/state.js +144 -0
- package/dist/snapshot-prepare.js +2 -0
- package/node_modules/yaml/LICENSE +13 -0
- package/node_modules/yaml/README.md +172 -0
- package/node_modules/yaml/bin.mjs +11 -0
- package/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
- package/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
- package/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
- package/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
- package/node_modules/yaml/browser/dist/compose/composer.js +219 -0
- package/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
- package/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
- package/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
- package/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
- package/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
- package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +225 -0
- package/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
- package/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
- package/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
- package/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
- package/node_modules/yaml/browser/dist/doc/Document.js +335 -0
- package/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
- package/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
- package/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
- package/node_modules/yaml/browser/dist/doc/directives.js +176 -0
- package/node_modules/yaml/browser/dist/errors.js +57 -0
- package/node_modules/yaml/browser/dist/index.js +17 -0
- package/node_modules/yaml/browser/dist/log.js +11 -0
- package/node_modules/yaml/browser/dist/nodes/Alias.js +116 -0
- package/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
- package/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
- package/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
- package/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
- package/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
- package/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
- package/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
- package/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
- package/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
- package/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
- package/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
- package/node_modules/yaml/browser/dist/parse/cst.js +98 -0
- package/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
- package/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
- package/node_modules/yaml/browser/dist/parse/parser.js +975 -0
- package/node_modules/yaml/browser/dist/public-api.js +102 -0
- package/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
- package/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
- package/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
- package/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
- package/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
- package/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
- package/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
- package/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
- package/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
- package/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
- package/node_modules/yaml/browser/dist/schema/tags.js +96 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
- package/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
- package/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
- package/node_modules/yaml/browser/dist/util.js +11 -0
- package/node_modules/yaml/browser/dist/visit.js +233 -0
- package/node_modules/yaml/browser/index.js +5 -0
- package/node_modules/yaml/browser/package.json +3 -0
- package/node_modules/yaml/dist/cli.d.ts +8 -0
- package/node_modules/yaml/dist/cli.mjs +201 -0
- package/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
- package/node_modules/yaml/dist/compose/compose-collection.js +90 -0
- package/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
- package/node_modules/yaml/dist/compose/compose-doc.js +45 -0
- package/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
- package/node_modules/yaml/dist/compose/compose-node.js +112 -0
- package/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
- package/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
- package/node_modules/yaml/dist/compose/composer.d.ts +63 -0
- package/node_modules/yaml/dist/compose/composer.js +224 -0
- package/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
- package/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
- package/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
- package/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
- package/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
- package/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
- package/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
- package/node_modules/yaml/dist/compose/resolve-end.js +39 -0
- package/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
- package/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +227 -0
- package/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
- package/node_modules/yaml/dist/compose/resolve-props.js +148 -0
- package/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
- package/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
- package/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
- package/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
- package/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
- package/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
- package/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
- package/node_modules/yaml/dist/doc/Document.d.ts +141 -0
- package/node_modules/yaml/dist/doc/Document.js +337 -0
- package/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
- package/node_modules/yaml/dist/doc/anchors.js +76 -0
- package/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
- package/node_modules/yaml/dist/doc/applyReviver.js +57 -0
- package/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
- package/node_modules/yaml/dist/doc/createNode.js +90 -0
- package/node_modules/yaml/dist/doc/directives.d.ts +49 -0
- package/node_modules/yaml/dist/doc/directives.js +178 -0
- package/node_modules/yaml/dist/errors.d.ts +21 -0
- package/node_modules/yaml/dist/errors.js +62 -0
- package/node_modules/yaml/dist/index.d.ts +25 -0
- package/node_modules/yaml/dist/index.js +50 -0
- package/node_modules/yaml/dist/log.d.ts +3 -0
- package/node_modules/yaml/dist/log.js +19 -0
- package/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
- package/node_modules/yaml/dist/nodes/Alias.js +118 -0
- package/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
- package/node_modules/yaml/dist/nodes/Collection.js +151 -0
- package/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
- package/node_modules/yaml/dist/nodes/Node.js +40 -0
- package/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
- package/node_modules/yaml/dist/nodes/Pair.js +39 -0
- package/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
- package/node_modules/yaml/dist/nodes/Scalar.js +27 -0
- package/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
- package/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
- package/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
- package/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
- package/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
- package/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
- package/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
- package/node_modules/yaml/dist/nodes/identity.js +53 -0
- package/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
- package/node_modules/yaml/dist/nodes/toJS.js +39 -0
- package/node_modules/yaml/dist/options.d.ts +350 -0
- package/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
- package/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
- package/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
- package/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
- package/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
- package/node_modules/yaml/dist/parse/cst-visit.js +99 -0
- package/node_modules/yaml/dist/parse/cst.d.ts +109 -0
- package/node_modules/yaml/dist/parse/cst.js +112 -0
- package/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
- package/node_modules/yaml/dist/parse/lexer.js +723 -0
- package/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
- package/node_modules/yaml/dist/parse/line-counter.js +41 -0
- package/node_modules/yaml/dist/parse/parser.d.ts +84 -0
- package/node_modules/yaml/dist/parse/parser.js +980 -0
- package/node_modules/yaml/dist/public-api.d.ts +44 -0
- package/node_modules/yaml/dist/public-api.js +107 -0
- package/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
- package/node_modules/yaml/dist/schema/Schema.js +39 -0
- package/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
- package/node_modules/yaml/dist/schema/common/map.js +19 -0
- package/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
- package/node_modules/yaml/dist/schema/common/null.js +17 -0
- package/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
- package/node_modules/yaml/dist/schema/common/seq.js +19 -0
- package/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
- package/node_modules/yaml/dist/schema/common/string.js +16 -0
- package/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
- package/node_modules/yaml/dist/schema/core/bool.js +21 -0
- package/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
- package/node_modules/yaml/dist/schema/core/float.js +47 -0
- package/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
- package/node_modules/yaml/dist/schema/core/int.js +42 -0
- package/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
- package/node_modules/yaml/dist/schema/core/schema.js +25 -0
- package/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
- package/node_modules/yaml/dist/schema/json/schema.js +64 -0
- package/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
- package/node_modules/yaml/dist/schema/tags.d.ts +48 -0
- package/node_modules/yaml/dist/schema/tags.js +99 -0
- package/node_modules/yaml/dist/schema/types.d.ts +92 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
- package/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
- package/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
- package/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
- package/node_modules/yaml/dist/stringify/stringify.js +132 -0
- package/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
- package/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
- package/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
- package/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
- package/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
- package/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
- package/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
- package/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
- package/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
- package/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
- package/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
- package/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
- package/node_modules/yaml/dist/test-events.d.ts +4 -0
- package/node_modules/yaml/dist/test-events.js +134 -0
- package/node_modules/yaml/dist/util.d.ts +16 -0
- package/node_modules/yaml/dist/util.js +28 -0
- package/node_modules/yaml/dist/visit.d.ts +102 -0
- package/node_modules/yaml/dist/visit.js +236 -0
- package/node_modules/yaml/package.json +97 -0
- package/node_modules/yaml/util.js +2 -0
- package/package.json +27 -11
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { readdir, realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
import { parseDocument } from "yaml";
|
|
4
|
+
import { readArtifactFile } from "../../artifact-tree.js";
|
|
5
|
+
import { compareByCodePoint } from "../../python-text.js";
|
|
6
|
+
import { assertNoFollowType, classifyPathNoFollow, isAbsenceError, } from "../../safe-path.js";
|
|
7
|
+
import { SafetyError } from "../../safety-error.js";
|
|
8
|
+
const DECODER = new TextDecoder("utf-8", { fatal: true });
|
|
9
|
+
function mapping(value) {
|
|
10
|
+
return (value !== null &&
|
|
11
|
+
typeof value === "object" &&
|
|
12
|
+
Object.getPrototypeOf(value) === Object.prototype);
|
|
13
|
+
}
|
|
14
|
+
function parseYaml(text, uniqueKeys = true) {
|
|
15
|
+
const document = parseDocument(text, { uniqueKeys, merge: true });
|
|
16
|
+
if (document.errors.length > 0 ||
|
|
17
|
+
document.warnings.some((warning) => warning.code === "TAG_RESOLVE_FAILED"))
|
|
18
|
+
throw new Error("YAML document");
|
|
19
|
+
return document.toJS();
|
|
20
|
+
}
|
|
21
|
+
async function configuration(root) {
|
|
22
|
+
await assertNoFollowType(root, ["directory", "missing"]);
|
|
23
|
+
const path = join(root, "config.yaml");
|
|
24
|
+
if ((await classifyPathNoFollow(path)) === "missing")
|
|
25
|
+
return null;
|
|
26
|
+
const value = parseYaml(DECODER.decode(await readArtifactFile(root, path))) ?? {};
|
|
27
|
+
if (!mapping(value))
|
|
28
|
+
throw new Error("configuration mapping");
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
async function managedDirectory(env, systemManagedDir) {
|
|
32
|
+
const configured = env.HERMES_MANAGED_DIR?.trim();
|
|
33
|
+
for (const path of configured
|
|
34
|
+
? [configured, systemManagedDir]
|
|
35
|
+
: [systemManagedDir]) {
|
|
36
|
+
const kind = await classifyPathNoFollow(path);
|
|
37
|
+
if (kind === "directory")
|
|
38
|
+
return path;
|
|
39
|
+
if (kind === "symlink")
|
|
40
|
+
throw new Error("managed directory symlink");
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function activationList(value) {
|
|
45
|
+
if (!Array.isArray(value))
|
|
46
|
+
return [];
|
|
47
|
+
if (value.some((item) => (item !== null && typeof item === "object") ||
|
|
48
|
+
(typeof item === "string" && item.includes("${"))))
|
|
49
|
+
throw new SafetyError("hermes-observe", "cannot determine Hermes plugin activation");
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
export async function readHermesStatus(paths, env, systemManagedDir = "/etc/hermes") {
|
|
53
|
+
let user;
|
|
54
|
+
try {
|
|
55
|
+
user = await configuration(paths.hermesHome);
|
|
56
|
+
}
|
|
57
|
+
catch (cause) {
|
|
58
|
+
throw new SafetyError("hermes-observe", "cannot inspect Hermes configuration", { cause });
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const directory = await managedDirectory(env, systemManagedDir);
|
|
62
|
+
const managed = directory === null ? null : await configuration(directory);
|
|
63
|
+
const plugins = managed?.plugins;
|
|
64
|
+
if (plugins !== undefined && plugins !== null && !mapping(plugins))
|
|
65
|
+
throw new Error("managed plugins shape");
|
|
66
|
+
if (mapping(plugins) &&
|
|
67
|
+
(Object.hasOwn(plugins, "enabled") || Object.hasOwn(plugins, "disabled")))
|
|
68
|
+
throw new Error("managed activation");
|
|
69
|
+
}
|
|
70
|
+
catch (cause) {
|
|
71
|
+
throw new SafetyError("hermes-observe", "cannot determine Hermes plugin activation", { cause });
|
|
72
|
+
}
|
|
73
|
+
const plugins = mapping(user?.plugins) ? user.plugins : {};
|
|
74
|
+
const enabled = activationList(plugins.enabled);
|
|
75
|
+
const disabled = activationList(plugins.disabled);
|
|
76
|
+
return disabled.includes("superpowers")
|
|
77
|
+
? "disabled"
|
|
78
|
+
: enabled.includes("superpowers")
|
|
79
|
+
? "enabled"
|
|
80
|
+
: "not enabled";
|
|
81
|
+
}
|
|
82
|
+
const FOREIGN_MANIFEST_DIRECTORIES = new Set([
|
|
83
|
+
".claude-plugin",
|
|
84
|
+
".codex-plugin",
|
|
85
|
+
".cursor-plugin",
|
|
86
|
+
".devin-plugin",
|
|
87
|
+
".kimi-plugin",
|
|
88
|
+
]);
|
|
89
|
+
export async function findSuperpowersManifests(paths) {
|
|
90
|
+
try {
|
|
91
|
+
if ((await classifyPathNoFollow(paths.pluginsRoot)) === "missing")
|
|
92
|
+
return [];
|
|
93
|
+
const found = [];
|
|
94
|
+
async function scan(root, physicalRoot, depth) {
|
|
95
|
+
await assertNoFollowType(physicalRoot, ["directory"]);
|
|
96
|
+
for (const name of (await readdir(physicalRoot)).sort(compareByCodePoint)) {
|
|
97
|
+
if ((name.startsWith("__") && name.endsWith("__")) ||
|
|
98
|
+
FOREIGN_MANIFEST_DIRECTORIES.has(name))
|
|
99
|
+
continue;
|
|
100
|
+
const child = join(root, name);
|
|
101
|
+
const physicalChild = join(physicalRoot, name);
|
|
102
|
+
const kind = await classifyPathNoFollow(physicalChild);
|
|
103
|
+
if (kind === "symlink") {
|
|
104
|
+
if (child === paths.pluginRoot)
|
|
105
|
+
throw new Error("owned plugin directory symlink");
|
|
106
|
+
try {
|
|
107
|
+
if (!(await stat(physicalChild)).isDirectory())
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
catch (cause) {
|
|
111
|
+
if (isAbsenceError(cause))
|
|
112
|
+
continue;
|
|
113
|
+
throw cause;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (kind !== "directory")
|
|
117
|
+
continue;
|
|
118
|
+
const directory = await realpath(physicalChild);
|
|
119
|
+
let manifest = null;
|
|
120
|
+
for (const file of ["plugin.yaml", "plugin.yml", "plugin.json"]) {
|
|
121
|
+
if ((await classifyPathNoFollow(join(directory, file))) !== "missing") {
|
|
122
|
+
manifest = file;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (manifest === null) {
|
|
127
|
+
if (depth === 0)
|
|
128
|
+
await scan(child, directory, 1);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const bytes = await readArtifactFile(directory, join(directory, manifest), 64 * 1024);
|
|
132
|
+
let value;
|
|
133
|
+
try {
|
|
134
|
+
const text = DECODER.decode(bytes);
|
|
135
|
+
if (manifest === "plugin.json")
|
|
136
|
+
value = JSON.parse(text);
|
|
137
|
+
else {
|
|
138
|
+
const parsed = parseYaml(text, false);
|
|
139
|
+
value =
|
|
140
|
+
parsed === null ||
|
|
141
|
+
parsed === undefined ||
|
|
142
|
+
parsed === false ||
|
|
143
|
+
parsed === 0 ||
|
|
144
|
+
parsed === "" ||
|
|
145
|
+
(Array.isArray(parsed) && parsed.length === 0) ||
|
|
146
|
+
(parsed instanceof Set && parsed.size === 0) ||
|
|
147
|
+
(parsed instanceof Map && parsed.size === 0) ||
|
|
148
|
+
(Buffer.isBuffer(parsed) && parsed.length === 0)
|
|
149
|
+
? {}
|
|
150
|
+
: parsed;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!mapping(value))
|
|
157
|
+
continue;
|
|
158
|
+
const pluginName = Object.hasOwn(value, "name")
|
|
159
|
+
? value.name
|
|
160
|
+
: manifest === "plugin.json"
|
|
161
|
+
? undefined
|
|
162
|
+
: basename(child);
|
|
163
|
+
if (pluginName === "superpowers")
|
|
164
|
+
found.push(child);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
await scan(paths.pluginsRoot, paths.pluginsRoot, 0);
|
|
168
|
+
return found.sort(compareByCodePoint);
|
|
169
|
+
}
|
|
170
|
+
catch (cause) {
|
|
171
|
+
throw new SafetyError("hermes-observe", "cannot inspect Hermes plugins", {
|
|
172
|
+
cause,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export function projectPluginsEnabled(env) {
|
|
177
|
+
return ["1", "true", "yes", "on"].includes((env.HERMES_ENABLE_PROJECT_PLUGINS ?? "").trim().toLowerCase());
|
|
178
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { assertNoFollowType } from "../../safe-path.js";
|
|
4
|
+
function trimHome(value) {
|
|
5
|
+
const whitespace = (index) => {
|
|
6
|
+
const code = value.charCodeAt(index);
|
|
7
|
+
return ((code >= 0x1c && code <= 0x1f) ||
|
|
8
|
+
/\p{White_Space}/u.test(value.charAt(index)));
|
|
9
|
+
};
|
|
10
|
+
let start = 0;
|
|
11
|
+
let end = value.length;
|
|
12
|
+
while (start < end && whitespace(start))
|
|
13
|
+
start++;
|
|
14
|
+
while (end > start && whitespace(end - 1))
|
|
15
|
+
end--;
|
|
16
|
+
return value.slice(start, end);
|
|
17
|
+
}
|
|
18
|
+
function expandHome(value, env, home) {
|
|
19
|
+
const expanded = trimHome(value).replace(/\$([A-Za-z0-9_]+|\{[^}]*\})/gu, (token, name) => {
|
|
20
|
+
const variable = name.startsWith("{") ? name.slice(1, -1) : name;
|
|
21
|
+
return Object.hasOwn(env, variable) ? (env[variable] ?? token) : token;
|
|
22
|
+
});
|
|
23
|
+
if (expanded === "~")
|
|
24
|
+
return home;
|
|
25
|
+
if (expanded.startsWith("~/"))
|
|
26
|
+
return join(home, expanded.slice(2));
|
|
27
|
+
if (expanded.startsWith("~"))
|
|
28
|
+
throw new Error("cannot resolve HERMES_HOME: named user homes are unsupported");
|
|
29
|
+
return expanded;
|
|
30
|
+
}
|
|
31
|
+
export function hermesPaths(env, cwd) {
|
|
32
|
+
const configured = trimHome(env.HERMES_HOME ?? "");
|
|
33
|
+
const home = env.HOME && env.HOME.length > 0 ? env.HOME : homedir();
|
|
34
|
+
const hermesHome = configured.length > 0
|
|
35
|
+
? resolve(cwd, expandHome(configured, env, home))
|
|
36
|
+
: join(resolve(cwd, home), ".hermes");
|
|
37
|
+
if (expandHome(hermesHome, env, home) !== hermesHome)
|
|
38
|
+
throw new Error("cannot resolve HERMES_HOME: home expansion is not stable");
|
|
39
|
+
const managerRoot = join(hermesHome, "superpowers-manager");
|
|
40
|
+
const pluginsRoot = join(hermesHome, "plugins");
|
|
41
|
+
return {
|
|
42
|
+
hermesHome,
|
|
43
|
+
managerRoot,
|
|
44
|
+
preparedRoot: join(managerRoot, "prepared"),
|
|
45
|
+
pluginsRoot,
|
|
46
|
+
pluginRoot: join(pluginsRoot, "superpowers"),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function assertHermesStorageAncestorsSafe(paths) {
|
|
50
|
+
for (const path of [
|
|
51
|
+
paths.hermesHome,
|
|
52
|
+
paths.managerRoot,
|
|
53
|
+
paths.preparedRoot,
|
|
54
|
+
paths.pluginsRoot,
|
|
55
|
+
])
|
|
56
|
+
await assertNoFollowType(path, ["directory", "missing"]);
|
|
57
|
+
}
|
|
58
|
+
export async function assertHermesStorageSafe(paths) {
|
|
59
|
+
await assertHermesStorageAncestorsSafe(paths);
|
|
60
|
+
await assertNoFollowType(paths.pluginRoot, ["directory", "missing"]);
|
|
61
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { failureResult, successResult, } from "../../adapter-result.js";
|
|
4
|
+
import { readArtifactFile, validateNativeSkill } from "../../artifact-tree.js";
|
|
5
|
+
import { assertNoFollowType, classifyPathNoFollow } from "../../safe-path.js";
|
|
6
|
+
import { SafetyError } from "../../safety-error.js";
|
|
7
|
+
import { validateSource } from "../../selection.js";
|
|
8
|
+
import { createSnapshotReceipts, } from "../../snapshot-package.js";
|
|
9
|
+
import { createSnapshotPreparation } from "../../snapshot-prepare.js";
|
|
10
|
+
import { assertHermesStorageSafe, hermesPaths } from "./paths.js";
|
|
11
|
+
async function flattenHermesPlugin(root) {
|
|
12
|
+
const nativeRoot = join(root, ".hermes-plugin");
|
|
13
|
+
if ((await classifyPathNoFollow(nativeRoot)) !== "directory")
|
|
14
|
+
return;
|
|
15
|
+
const entries = await readdir(nativeRoot);
|
|
16
|
+
if (entries.some((entry) => entry === "skills" || entry === "LICENSE"))
|
|
17
|
+
throw new SafetyError("hermes-package", `Hermes plugin layout collides with shared content: ${root}`);
|
|
18
|
+
for (const entry of await readdir(root))
|
|
19
|
+
if (entry !== ".hermes-plugin" && entry !== "skills" && entry !== "LICENSE")
|
|
20
|
+
await rm(join(root, entry), { recursive: true, force: true });
|
|
21
|
+
for (const entry of entries)
|
|
22
|
+
await rename(join(nativeRoot, entry), join(root, entry));
|
|
23
|
+
await rm(nativeRoot, { recursive: true });
|
|
24
|
+
await writeFile(join(root, "__pycache__"), "", { flag: "wx" });
|
|
25
|
+
}
|
|
26
|
+
async function assessHermesCompatibility(root, selection) {
|
|
27
|
+
try {
|
|
28
|
+
validateSource(selection.effectiveSource);
|
|
29
|
+
await readArtifactFile(root, join(root, "__pycache__"), 0);
|
|
30
|
+
for (const relative of [
|
|
31
|
+
"plugin.yaml",
|
|
32
|
+
"__init__.py",
|
|
33
|
+
"skills/using-superpowers/references/hermes-tools.md",
|
|
34
|
+
])
|
|
35
|
+
await assertNoFollowType(join(root, relative), ["regular-file"]);
|
|
36
|
+
await validateNativeSkill(root);
|
|
37
|
+
return {
|
|
38
|
+
kind: "supported",
|
|
39
|
+
generation: "hermes-flat-plugin-v1",
|
|
40
|
+
reason: "native Hermes plugin",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return {
|
|
45
|
+
kind: "unsupported",
|
|
46
|
+
reason: `Hermes package does not provide a native Hermes plugin: ${root}`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const receipts = createSnapshotReceipts({
|
|
51
|
+
harness: "hermes",
|
|
52
|
+
label: "Hermes",
|
|
53
|
+
strictGeneration: true,
|
|
54
|
+
assessCompatibility: assessHermesCompatibility,
|
|
55
|
+
});
|
|
56
|
+
export const readHermesReceipt = receipts.readReceipt;
|
|
57
|
+
export const readHermesPackageAssessment = receipts.readAssessment;
|
|
58
|
+
export async function validateHermesPreparationBeforeFetch(ctx) {
|
|
59
|
+
try {
|
|
60
|
+
await assertHermesStorageSafe(hermesPaths(ctx.env ?? {}, process.cwd()));
|
|
61
|
+
return successResult("prepare", null, []);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return failureResult("prepare", "invalid-package", "cannot validate Hermes artifact storage", [], []);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const preparation = createSnapshotPreparation({
|
|
68
|
+
harness: "hermes",
|
|
69
|
+
label: "Hermes",
|
|
70
|
+
paths: hermesPaths,
|
|
71
|
+
assessCompatibility: assessHermesCompatibility,
|
|
72
|
+
readAssessment: readHermesPackageAssessment,
|
|
73
|
+
layout: flattenHermesPlugin,
|
|
74
|
+
});
|
|
75
|
+
export const hermesPreparationLocation = preparation.preparationLocation;
|
|
76
|
+
export const prepareHermesCandidate = preparation.prepareCandidate;
|
|
77
|
+
export const inspectHermesPrepared = preparation.inspectPrepared;
|
|
78
|
+
export const readHermesPrepared = preparation.readPrepared;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { displaySource } from "../../selection.js";
|
|
2
|
+
import { createSnapshotPresentation, probeOutput, } from "../../snapshot-presentation.js";
|
|
3
|
+
import { displayPath } from "../../validator.js";
|
|
4
|
+
const renderProbe = (facts) => {
|
|
5
|
+
const fields = [
|
|
6
|
+
["harness", "hermes"],
|
|
7
|
+
["desired_commit", facts.selection.desiredCommit],
|
|
8
|
+
["upstream_source_origin", facts.selection.upstreamSourceOrigin],
|
|
9
|
+
["effective_source", displaySource(facts.selection.effectiveSource)],
|
|
10
|
+
["prepared_identity", facts.prepared.observedIdentity],
|
|
11
|
+
["installed_identity", facts.installed.observedIdentity],
|
|
12
|
+
["installation_state", facts.installed.kind],
|
|
13
|
+
["resource_state", facts.resourceState ?? "idle"],
|
|
14
|
+
["ownership", facts.ownership.presentationValue],
|
|
15
|
+
["conflicts", (facts.ownership.presentationConflicts ?? []).join("; ")],
|
|
16
|
+
["update_control", facts.control.presentationValue],
|
|
17
|
+
["compatibility", facts.compatibility.kind],
|
|
18
|
+
["compatibility_reason", facts.compatibility.reason],
|
|
19
|
+
["status", facts.status],
|
|
20
|
+
].map(([key, value]) => [key, displayPath(value)]);
|
|
21
|
+
return probeOutput(fields);
|
|
22
|
+
};
|
|
23
|
+
export const hermesPresentation = createSnapshotPresentation("Hermes", renderProbe, (input) => input.ownership === "absent");
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { inspectionFailure, successResult, } from "../../adapter-result.js";
|
|
4
|
+
import { classifyPathNoFollow } from "../../safe-path.js";
|
|
5
|
+
import { observeSnapshot, sameSnapshotSource } from "../../snapshot-package.js";
|
|
6
|
+
import { displayPath } from "../../validator.js";
|
|
7
|
+
import { findSuperpowersManifests, projectPluginsEnabled, readHermesStatus, } from "./observe.js";
|
|
8
|
+
import { assertHermesStorageAncestorsSafe, hermesPaths, } from "./paths.js";
|
|
9
|
+
import { readHermesPackageAssessment, readHermesReceipt, } from "./prepare.js";
|
|
10
|
+
export async function observeHermesOwnership(paths) {
|
|
11
|
+
await assertHermesStorageAncestorsSafe(paths);
|
|
12
|
+
const snapshot = await observeSnapshot(paths.pluginRoot, readHermesReceipt);
|
|
13
|
+
return snapshot.kind === "unverified" ? { kind: "foreign" } : snapshot;
|
|
14
|
+
}
|
|
15
|
+
export async function otherSuperpowersManifests(paths) {
|
|
16
|
+
await assertHermesStorageAncestorsSafe(paths);
|
|
17
|
+
return (await findSuperpowersManifests(paths)).filter((root) => root !== paths.pluginRoot);
|
|
18
|
+
}
|
|
19
|
+
async function observeFacts(ctx) {
|
|
20
|
+
const env = ctx.env ?? {};
|
|
21
|
+
const paths = hermesPaths(env, process.cwd());
|
|
22
|
+
const ownership = await observeHermesOwnership(paths);
|
|
23
|
+
const status = await readHermesStatus(paths, env);
|
|
24
|
+
// A foreign leaf is already a blocking decision. Do not scan its contents
|
|
25
|
+
// or pass a symlink to the manifest observer.
|
|
26
|
+
const manifests = ownership.kind === "foreign" ? [] : await findSuperpowersManifests(paths);
|
|
27
|
+
return {
|
|
28
|
+
paths,
|
|
29
|
+
ownership,
|
|
30
|
+
status,
|
|
31
|
+
manifests,
|
|
32
|
+
conflicts: manifests.filter((root) => root !== paths.pluginRoot),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function blocked(...stderr) {
|
|
36
|
+
return {
|
|
37
|
+
kind: "blocked",
|
|
38
|
+
output: { stdout: [], stderr: stderr.map(displayPath) },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function installDecision(facts, env) {
|
|
42
|
+
if (facts.ownership.kind === "foreign")
|
|
43
|
+
return blocked("error: another Superpowers copy is present in Hermes; remove it manually, then retry:", " hermes plugins remove superpowers");
|
|
44
|
+
if (facts.conflicts.length > 0)
|
|
45
|
+
return blocked("error: Hermes discovers another plugin named superpowers; remove it manually, then retry:", ...facts.conflicts.map((path) => ` ${path}`));
|
|
46
|
+
if (projectPluginsEnabled(env))
|
|
47
|
+
return blocked("error: HERMES_ENABLE_PROJECT_PLUGINS is set; a project-local Superpowers copy would override the managed one. Unset HERMES_ENABLE_PROJECT_PLUGINS, then retry.");
|
|
48
|
+
return { kind: "allowed" };
|
|
49
|
+
}
|
|
50
|
+
export async function inspectHermesOwnership(ctx) {
|
|
51
|
+
const operation = "inspect-hermes-ownership";
|
|
52
|
+
try {
|
|
53
|
+
const facts = await observeFacts(ctx);
|
|
54
|
+
const listed = facts.status !== "not enabled";
|
|
55
|
+
return successResult(operation, {
|
|
56
|
+
installEligibility: installDecision(facts, ctx.env ?? {}),
|
|
57
|
+
removalInput: { ownership: facts.ownership.kind, listed },
|
|
58
|
+
removalVerification: facts.ownership.kind !== "absent" || listed
|
|
59
|
+
? blocked("error: Hermes still lists Superpowers or its plugin directory is still present after removal")
|
|
60
|
+
: { kind: "allowed" },
|
|
61
|
+
postRemovalOutput: { stdout: [], stderr: [] },
|
|
62
|
+
presentationValue: facts.ownership.kind === "owned"
|
|
63
|
+
? `managed ${facts.ownership.digest}`
|
|
64
|
+
: facts.ownership.kind === "foreign"
|
|
65
|
+
? "foreign plugin directory"
|
|
66
|
+
: "absent",
|
|
67
|
+
presentationConflicts: facts.conflicts,
|
|
68
|
+
}, []);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return inspectionFailure(operation, "Hermes ownership");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export async function inspectHermesInstalled(selection, ctx) {
|
|
75
|
+
const operation = "inspect-hermes-installed";
|
|
76
|
+
let facts;
|
|
77
|
+
try {
|
|
78
|
+
facts = await observeFacts(ctx);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return inspectionFailure(operation, "Hermes installed state");
|
|
82
|
+
}
|
|
83
|
+
if (facts.ownership.kind === "absent" &&
|
|
84
|
+
facts.status === "not enabled" &&
|
|
85
|
+
facts.manifests.length === 0)
|
|
86
|
+
return successResult(operation, { kind: "absent", observedIdentity: "" }, []);
|
|
87
|
+
const observed = facts.ownership.kind === "owned"
|
|
88
|
+
? facts.ownership.digest
|
|
89
|
+
: facts.ownership.kind === "foreign"
|
|
90
|
+
? "foreign plugin directory"
|
|
91
|
+
: "listed without an installed snapshot";
|
|
92
|
+
const mismatch = () => successResult(operation, { kind: "mismatch", observedIdentity: observed }, []);
|
|
93
|
+
if (facts.ownership.kind !== "owned" ||
|
|
94
|
+
facts.status !== "enabled" ||
|
|
95
|
+
!facts.manifests.includes(facts.paths.pluginRoot) ||
|
|
96
|
+
facts.conflicts.length > 0)
|
|
97
|
+
return mismatch();
|
|
98
|
+
try {
|
|
99
|
+
const prepared = await readHermesPackageAssessment(facts.paths.preparedRoot);
|
|
100
|
+
if (prepared.compatibility.kind !== "supported" ||
|
|
101
|
+
prepared.receipt.commit !== selection.desiredCommit ||
|
|
102
|
+
!sameSnapshotSource(prepared.receipt.source, selection.effectiveSource) ||
|
|
103
|
+
facts.ownership.receipt.commit !== selection.desiredCommit ||
|
|
104
|
+
!sameSnapshotSource(facts.ownership.receipt.source, selection.effectiveSource) ||
|
|
105
|
+
facts.ownership.digest !== prepared.receipt.digest)
|
|
106
|
+
return mismatch();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return mismatch();
|
|
110
|
+
}
|
|
111
|
+
return successResult(operation, { kind: "current", observedIdentity: observed }, []);
|
|
112
|
+
}
|
|
113
|
+
export async function leftoverHermesPublication(paths) {
|
|
114
|
+
await assertHermesStorageAncestorsSafe(paths);
|
|
115
|
+
if ((await classifyPathNoFollow(paths.managerRoot)) === "missing")
|
|
116
|
+
return [];
|
|
117
|
+
return (await readdir(paths.managerRoot))
|
|
118
|
+
.filter((name) => name.startsWith("publish."))
|
|
119
|
+
.sort()
|
|
120
|
+
.map((name) => join(paths.managerRoot, name));
|
|
121
|
+
}
|
|
122
|
+
export async function inspectHermesControl(ctx) {
|
|
123
|
+
const operation = "inspect-hermes-control";
|
|
124
|
+
try {
|
|
125
|
+
const paths = hermesPaths(ctx.env ?? {}, process.cwd());
|
|
126
|
+
const leftovers = await leftoverHermesPublication(paths);
|
|
127
|
+
if (leftovers.length === 0)
|
|
128
|
+
return successResult(operation, {
|
|
129
|
+
probeEligibility: { kind: "allowed" },
|
|
130
|
+
mutationEligibility: { kind: "allowed" },
|
|
131
|
+
presentationValue: "clear",
|
|
132
|
+
}, []);
|
|
133
|
+
const decision = blocked("error: Hermes recovery required; inspect and remove leftover publication material manually:", ...leftovers.map((path) => ` ${path}`));
|
|
134
|
+
return successResult(operation, {
|
|
135
|
+
probeEligibility: decision,
|
|
136
|
+
mutationEligibility: decision,
|
|
137
|
+
presentationValue: displayPath(`recovery required at ${leftovers.join(", ")}`),
|
|
138
|
+
recoveryState: "required",
|
|
139
|
+
}, []);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return inspectionFailure(operation, "Hermes update control");
|
|
143
|
+
}
|
|
144
|
+
}
|
package/dist/snapshot-prepare.js
CHANGED
|
@@ -21,6 +21,8 @@ export function createSnapshotPreparation(b) {
|
|
|
21
21
|
async prepareCandidate(input) {
|
|
22
22
|
try {
|
|
23
23
|
await materializeGitTree(input.upstreamRoot, input.selection.desiredCommit, input.candidateRoot);
|
|
24
|
+
if (b.layout !== undefined)
|
|
25
|
+
await b.layout(input.candidateRoot);
|
|
24
26
|
const compatibility = await b.assessCompatibility(input.candidateRoot, input.selection);
|
|
25
27
|
if (compatibility.kind === "unsupported" ||
|
|
26
28
|
compatibility.kind === "unknown")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright Eemeli Aro <eemeli@gmail.com>
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
4
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
5
|
+
and this permission notice appear in all copies.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
8
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
9
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
10
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
11
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
12
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
13
|
+
THIS SOFTWARE.
|