superpowers-manager 0.9.1 → 0.10.1

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 (251) hide show
  1. package/README.md +35 -16
  2. package/dist/cli-arguments.js +2 -1
  3. package/dist/cli.js +12 -9
  4. package/dist/commands/adapter-call.js +0 -11
  5. package/dist/commands/install.js +153 -171
  6. package/dist/commands/prepare.js +1 -1
  7. package/dist/commands/uninstall.js +49 -64
  8. package/dist/harnesses/hermes/harness.js +36 -0
  9. package/dist/harnesses/hermes/install.js +235 -0
  10. package/dist/harnesses/hermes/native.js +40 -0
  11. package/dist/harnesses/hermes/observe.js +178 -0
  12. package/dist/harnesses/hermes/paths.js +48 -0
  13. package/dist/harnesses/hermes/prepare.js +78 -0
  14. package/dist/harnesses/hermes/presentation.js +23 -0
  15. package/dist/harnesses/hermes/state.js +144 -0
  16. package/dist/harnesses/opencode/paths.js +8 -14
  17. package/dist/snapshot-prepare.js +2 -0
  18. package/node_modules/yaml/LICENSE +13 -0
  19. package/node_modules/yaml/README.md +172 -0
  20. package/node_modules/yaml/bin.mjs +11 -0
  21. package/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
  22. package/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
  23. package/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
  24. package/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
  25. package/node_modules/yaml/browser/dist/compose/composer.js +219 -0
  26. package/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
  27. package/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
  28. package/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
  29. package/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
  30. package/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
  31. package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +225 -0
  32. package/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
  33. package/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
  34. package/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
  35. package/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
  36. package/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
  37. package/node_modules/yaml/browser/dist/doc/Document.js +335 -0
  38. package/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
  39. package/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
  40. package/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
  41. package/node_modules/yaml/browser/dist/doc/directives.js +176 -0
  42. package/node_modules/yaml/browser/dist/errors.js +57 -0
  43. package/node_modules/yaml/browser/dist/index.js +17 -0
  44. package/node_modules/yaml/browser/dist/log.js +11 -0
  45. package/node_modules/yaml/browser/dist/nodes/Alias.js +116 -0
  46. package/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
  47. package/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
  48. package/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
  49. package/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
  50. package/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
  51. package/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
  52. package/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
  53. package/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
  54. package/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
  55. package/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
  56. package/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
  57. package/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
  58. package/node_modules/yaml/browser/dist/parse/cst.js +98 -0
  59. package/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
  60. package/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
  61. package/node_modules/yaml/browser/dist/parse/parser.js +975 -0
  62. package/node_modules/yaml/browser/dist/public-api.js +102 -0
  63. package/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
  64. package/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
  65. package/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
  66. package/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
  67. package/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
  68. package/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
  69. package/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
  70. package/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
  71. package/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
  72. package/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
  73. package/node_modules/yaml/browser/dist/schema/tags.js +96 -0
  74. package/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
  75. package/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
  76. package/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
  77. package/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
  78. package/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
  79. package/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
  80. package/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
  81. package/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
  82. package/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
  83. package/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
  84. package/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
  85. package/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
  86. package/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
  87. package/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
  88. package/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
  89. package/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
  90. package/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
  91. package/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
  92. package/node_modules/yaml/browser/dist/util.js +11 -0
  93. package/node_modules/yaml/browser/dist/visit.js +233 -0
  94. package/node_modules/yaml/browser/index.js +5 -0
  95. package/node_modules/yaml/browser/package.json +3 -0
  96. package/node_modules/yaml/dist/cli.d.ts +8 -0
  97. package/node_modules/yaml/dist/cli.mjs +201 -0
  98. package/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
  99. package/node_modules/yaml/dist/compose/compose-collection.js +90 -0
  100. package/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
  101. package/node_modules/yaml/dist/compose/compose-doc.js +45 -0
  102. package/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
  103. package/node_modules/yaml/dist/compose/compose-node.js +112 -0
  104. package/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
  105. package/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
  106. package/node_modules/yaml/dist/compose/composer.d.ts +63 -0
  107. package/node_modules/yaml/dist/compose/composer.js +224 -0
  108. package/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
  109. package/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
  110. package/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
  111. package/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
  112. package/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
  113. package/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
  114. package/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
  115. package/node_modules/yaml/dist/compose/resolve-end.js +39 -0
  116. package/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
  117. package/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
  118. package/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
  119. package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +227 -0
  120. package/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
  121. package/node_modules/yaml/dist/compose/resolve-props.js +148 -0
  122. package/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
  123. package/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
  124. package/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
  125. package/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
  126. package/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
  127. package/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
  128. package/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
  129. package/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
  130. package/node_modules/yaml/dist/doc/Document.d.ts +141 -0
  131. package/node_modules/yaml/dist/doc/Document.js +337 -0
  132. package/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
  133. package/node_modules/yaml/dist/doc/anchors.js +76 -0
  134. package/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
  135. package/node_modules/yaml/dist/doc/applyReviver.js +57 -0
  136. package/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
  137. package/node_modules/yaml/dist/doc/createNode.js +90 -0
  138. package/node_modules/yaml/dist/doc/directives.d.ts +49 -0
  139. package/node_modules/yaml/dist/doc/directives.js +178 -0
  140. package/node_modules/yaml/dist/errors.d.ts +21 -0
  141. package/node_modules/yaml/dist/errors.js +62 -0
  142. package/node_modules/yaml/dist/index.d.ts +25 -0
  143. package/node_modules/yaml/dist/index.js +50 -0
  144. package/node_modules/yaml/dist/log.d.ts +3 -0
  145. package/node_modules/yaml/dist/log.js +19 -0
  146. package/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
  147. package/node_modules/yaml/dist/nodes/Alias.js +118 -0
  148. package/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
  149. package/node_modules/yaml/dist/nodes/Collection.js +151 -0
  150. package/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
  151. package/node_modules/yaml/dist/nodes/Node.js +40 -0
  152. package/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
  153. package/node_modules/yaml/dist/nodes/Pair.js +39 -0
  154. package/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
  155. package/node_modules/yaml/dist/nodes/Scalar.js +27 -0
  156. package/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
  157. package/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
  158. package/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
  159. package/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
  160. package/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
  161. package/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
  162. package/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
  163. package/node_modules/yaml/dist/nodes/identity.js +53 -0
  164. package/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
  165. package/node_modules/yaml/dist/nodes/toJS.js +39 -0
  166. package/node_modules/yaml/dist/options.d.ts +350 -0
  167. package/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
  168. package/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
  169. package/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
  170. package/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
  171. package/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
  172. package/node_modules/yaml/dist/parse/cst-visit.js +99 -0
  173. package/node_modules/yaml/dist/parse/cst.d.ts +109 -0
  174. package/node_modules/yaml/dist/parse/cst.js +112 -0
  175. package/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
  176. package/node_modules/yaml/dist/parse/lexer.js +723 -0
  177. package/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
  178. package/node_modules/yaml/dist/parse/line-counter.js +41 -0
  179. package/node_modules/yaml/dist/parse/parser.d.ts +84 -0
  180. package/node_modules/yaml/dist/parse/parser.js +980 -0
  181. package/node_modules/yaml/dist/public-api.d.ts +44 -0
  182. package/node_modules/yaml/dist/public-api.js +107 -0
  183. package/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
  184. package/node_modules/yaml/dist/schema/Schema.js +39 -0
  185. package/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
  186. package/node_modules/yaml/dist/schema/common/map.js +19 -0
  187. package/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
  188. package/node_modules/yaml/dist/schema/common/null.js +17 -0
  189. package/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
  190. package/node_modules/yaml/dist/schema/common/seq.js +19 -0
  191. package/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
  192. package/node_modules/yaml/dist/schema/common/string.js +16 -0
  193. package/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
  194. package/node_modules/yaml/dist/schema/core/bool.js +21 -0
  195. package/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
  196. package/node_modules/yaml/dist/schema/core/float.js +47 -0
  197. package/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
  198. package/node_modules/yaml/dist/schema/core/int.js +42 -0
  199. package/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
  200. package/node_modules/yaml/dist/schema/core/schema.js +25 -0
  201. package/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
  202. package/node_modules/yaml/dist/schema/json/schema.js +64 -0
  203. package/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
  204. package/node_modules/yaml/dist/schema/tags.d.ts +48 -0
  205. package/node_modules/yaml/dist/schema/tags.js +99 -0
  206. package/node_modules/yaml/dist/schema/types.d.ts +92 -0
  207. package/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
  208. package/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
  209. package/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
  210. package/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
  211. package/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
  212. package/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
  213. package/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
  214. package/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
  215. package/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
  216. package/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
  217. package/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
  218. package/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
  219. package/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
  220. package/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
  221. package/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
  222. package/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
  223. package/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
  224. package/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
  225. package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
  226. package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
  227. package/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
  228. package/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
  229. package/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
  230. package/node_modules/yaml/dist/stringify/stringify.js +132 -0
  231. package/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
  232. package/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
  233. package/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
  234. package/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
  235. package/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
  236. package/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
  237. package/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
  238. package/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
  239. package/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
  240. package/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
  241. package/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
  242. package/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
  243. package/node_modules/yaml/dist/test-events.d.ts +4 -0
  244. package/node_modules/yaml/dist/test-events.js +134 -0
  245. package/node_modules/yaml/dist/util.d.ts +16 -0
  246. package/node_modules/yaml/dist/util.js +28 -0
  247. package/node_modules/yaml/dist/visit.d.ts +102 -0
  248. package/node_modules/yaml/dist/visit.js +236 -0
  249. package/node_modules/yaml/package.json +97 -0
  250. package/node_modules/yaml/util.js +2 -0
  251. package/package.json +13 -7
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Superpowers Manager
2
2
 
3
- Install [`obra/superpowers`](https://github.com/obra/superpowers) directly from upstream for Codex, the Pi coding agent, OpenCode, and Claude Code. Stay on a known-good release or commit, try a branch, and upgrade when you choose—without waiting for a marketplace copy to catch up.
3
+ Install [`obra/superpowers`](https://github.com/obra/superpowers) directly from upstream for Codex, the Pi coding agent, OpenCode, Claude Code, and Hermes Agent. Stay on a known-good release or commit, try a branch, and upgrade when you choose—without waiting for a marketplace copy to catch up.
4
4
 
5
5
  > Unofficial community integration. Not affiliated with the `obra/superpowers` maintainers.
6
6
 
@@ -21,7 +21,7 @@ npx superpowers-manager pin v6.1.1
21
21
  npx superpowers-manager install --harness codex
22
22
  ```
23
23
 
24
- Use `--harness pi` for Pi, `--harness opencode` for OpenCode, or `--harness claude-code` for Claude Code. The pin is shared by all harnesses, but each installation changes only when you run its `install` or `update` command. A saved pin keeps subsequent installs and updates on that version unless you change or override the selection.
24
+ Use `--harness pi` for Pi, `--harness opencode` for OpenCode, `--harness claude-code` for Claude Code, or `--harness hermes` for Hermes Agent. The pin is shared by all harnesses, but each installation changes only when you run its `install` or `update` command. A saved pin keeps subsequent installs and updates on that version unless you change or override the selection.
25
25
 
26
26
  To try a branch, replace `feature/foo` with an existing upstream branch:
27
27
 
@@ -42,7 +42,7 @@ See [version selection](https://github.com/j7an/superpowers-manager/blob/main/do
42
42
 
43
43
  ## Start with your agent
44
44
 
45
- The four harnesses share upstream selection, while each has independent prepared and installed state. Omitting `--harness` selects Codex.
45
+ The five harnesses share upstream selection, while each has independent prepared and installed state. Omitting `--harness` selects Codex.
46
46
 
47
47
  ### Codex
48
48
 
@@ -97,6 +97,18 @@ Restart Claude Code or run `/reload-plugins` after an install, activating update
97
97
  or removal. See the [Claude Code reference](https://github.com/j7an/superpowers-manager/blob/main/docs/claude-code.md)
98
98
  for conflicts, hooks, and recovery.
99
99
 
100
+ ### Hermes Agent
101
+
102
+ ```sh
103
+ npx superpowers-manager install --harness hermes
104
+ npx superpowers-manager probe --harness hermes
105
+ npx superpowers-manager update --harness hermes
106
+ ```
107
+
108
+ Restart Hermes sessions after an install, activating update, or removal. See
109
+ the [Hermes Agent reference](https://github.com/j7an/superpowers-manager/blob/main/docs/hermes.md)
110
+ for plugin layout, compatibility, route switching, and recovery.
111
+
100
112
  To remove a Manager-owned installation, choose one harness explicitly:
101
113
 
102
114
  ### Uninstall Codex
@@ -123,24 +135,31 @@ npx superpowers-manager uninstall --harness opencode
123
135
  npx superpowers-manager uninstall --harness claude-code
124
136
  ```
125
137
 
138
+ ### Uninstall Hermes Agent
139
+
140
+ ```sh
141
+ npx superpowers-manager uninstall --harness hermes
142
+ ```
143
+
126
144
  The manager never removes another Superpowers provider. See the [ownership guidance](https://github.com/j7an/superpowers-manager/blob/main/docs/usage.md#provider-ownership) before switching providers.
127
145
 
128
146
  ## Shared selection and lifecycle
129
147
 
130
- The [selection commands above](#choose-what-you-run) save shared upstream intent. They do not activate Codex, Pi, OpenCode, or Claude Code; run the selected harness's `install` or `update` to apply that choice. `unpin` restores the packaged fallback policy.
148
+ The [selection commands above](#choose-what-you-run) save shared upstream intent. They do not activate Codex, Pi, OpenCode, Claude Code, or Hermes Agent; run the selected harness's `install` or `update` to apply that choice. `unpin` restores the packaged fallback policy.
131
149
 
132
150
  See [targeted lifecycle commands](https://github.com/j7an/superpowers-manager/blob/main/docs/usage.md#targeted-lifecycle) for preparation, inspection, installation, updates, and removal.
133
151
 
134
- Use `--harness codex`, `--harness pi`, `--harness opencode`, or `--harness claude-code` with each targeted lifecycle command.
152
+ Use `--harness codex`, `--harness pi`, `--harness opencode`, `--harness claude-code`, or `--harness hermes` with each targeted lifecycle command.
135
153
 
136
154
  ```text
137
155
  shared selection -> prepare / inspect / activate Codex
138
156
  -> prepare / inspect / activate Pi
139
157
  -> prepare / inspect / activate OpenCode
140
158
  -> prepare / inspect / activate Claude Code
159
+ -> prepare / inspect / activate Hermes Agent
141
160
  ```
142
161
 
143
- The [usage reference](https://github.com/j7an/superpowers-manager/blob/main/docs/usage.md) covers version selection, precedence, offline behavior, `prepare`, validators, and every lifecycle command. The harness references cover [Codex registration and hooks](https://github.com/j7an/superpowers-manager/blob/main/docs/codex.md), [Pi snapshots and recovery](https://github.com/j7an/superpowers-manager/blob/main/docs/pi.md), [OpenCode snapshots](https://github.com/j7an/superpowers-manager/blob/main/docs/opencode.md), and [Claude Code marketplace registration](https://github.com/j7an/superpowers-manager/blob/main/docs/claude-code.md).
162
+ The [usage reference](https://github.com/j7an/superpowers-manager/blob/main/docs/usage.md) covers version selection, precedence, offline behavior, `prepare`, validators, and every lifecycle command. The harness references cover [Codex registration and hooks](https://github.com/j7an/superpowers-manager/blob/main/docs/codex.md), [Pi snapshots and recovery](https://github.com/j7an/superpowers-manager/blob/main/docs/pi.md), [OpenCode snapshots](https://github.com/j7an/superpowers-manager/blob/main/docs/opencode.md), [Claude Code marketplace registration](https://github.com/j7an/superpowers-manager/blob/main/docs/claude-code.md), and [Hermes Agent plugin support](https://github.com/j7an/superpowers-manager/blob/main/docs/hermes.md).
144
163
 
145
164
  ## Requirements and platforms
146
165
 
@@ -148,16 +167,16 @@ The installed package requires Node >=24. Native source, tests, and packaging to
148
167
 
149
168
  <!-- requirements:begin -->
150
169
 
151
- | Command | git | Codex CLI (default) | Pi CLI (`--harness pi`) | OpenCode CLI (`--harness opencode`) | Claude Code CLI (`--harness claude-code`) |
152
- | -------------- | --- | ------------------- | ----------------------- | ----------------------------------- | ----------------------------------------- |
153
- | `pin` | yes | no | no | no | no |
154
- | `track-latest` | no | no | no | no | no |
155
- | `unpin` | no | no | no | no | no |
156
- | `prepare` | yes | no | no | no | no |
157
- | `probe` | yes | yes | no | no | yes |
158
- | `install` | yes | yes | yes | yes | yes |
159
- | `update` | yes | yes | yes | yes | yes |
160
- | `uninstall` | no | yes | yes | no | yes |
170
+ | Command | git | Codex CLI (default) | Pi CLI (`--harness pi`) | OpenCode CLI (`--harness opencode`) | Claude Code CLI (`--harness claude-code`) | Hermes Agent CLI (`--harness hermes`) |
171
+ | -------------- | --- | ------------------- | ----------------------- | ----------------------------------- | ----------------------------------------- | ------------------------------------- |
172
+ | `pin` | yes | no | no | no | no | no |
173
+ | `track-latest` | no | no | no | no | no | no |
174
+ | `unpin` | no | no | no | no | no | no |
175
+ | `prepare` | yes | no | no | no | no | no |
176
+ | `probe` | yes | yes | no | no | yes | no |
177
+ | `install` | yes | yes | yes | yes | yes | yes |
178
+ | `update` | yes | yes | yes | yes | yes | yes |
179
+ | `uninstall` | no | yes | yes | no | yes | yes |
161
180
 
162
181
  <!-- requirements:end -->
163
182
 
@@ -23,7 +23,8 @@ export function extractHarnessOptions(command, argv) {
23
23
  if (value !== "codex" &&
24
24
  value !== "pi" &&
25
25
  value !== "opencode" &&
26
- value !== "claude-code")
26
+ value !== "claude-code" &&
27
+ value !== "hermes")
27
28
  throw new UsageError(`unknown harness: ${value}`);
28
29
  harness = value;
29
30
  }
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@ import * as path from "node:path";
4
4
  import { extractHarnessOptions, oneLine, UsageError } from "./cli-arguments.js";
5
5
  import { codexHarness } from "./harnesses/codex/harness.js";
6
6
  import { claudeCodeHarness } from "./harnesses/claude-code/harness.js";
7
+ import { hermesHarness } from "./harnesses/hermes/harness.js";
7
8
  import { piHarness } from "./harnesses/pi/harness.js";
8
9
  import { openCodeHarness } from "./harnesses/opencode/harness.js";
9
10
  import { createResourceCoordinator } from "./resource-lock.js";
@@ -214,7 +215,7 @@ function usage() {
214
215
  " install --harness opencode [--allow-experimental]",
215
216
  " update --harness opencode [--allow-experimental]",
216
217
  " uninstall --harness opencode",
217
- " --harness=codex, --harness=pi, --harness=opencode, and --harness=claude-code are also accepted after the command.",
218
+ " --harness=codex, --harness=pi, --harness=opencode, --harness=claude-code, and --harness=hermes are also accepted after the command.",
218
219
  "",
219
220
  "Environment overrides (used by in-process commands): SUPERPOWERS_REF,",
220
221
  "SUPERPOWERS_UPSTREAM_URL, SUPERPOWERS_CODEX, SUPERPOWERS_CACHE_DIR,",
@@ -222,7 +223,7 @@ function usage() {
222
223
  "SUPERPOWERS_PLUGIN_ROOT, SUPERPOWERS_MANIFEST_TEMPLATE,",
223
224
  "SUPERPOWERS_VALIDATOR_EXECUTABLE,",
224
225
  "SUPERPOWERS_INSTALLED_SEARCH_ROOT, SUPERPOWERS_INSTALL_REFRESH_MODE,",
225
- "SUPERPOWERS_OPENCODE, SUPERPOWERS_CLAUDE_CODE, CLAUDE_CONFIG_DIR",
226
+ "SUPERPOWERS_OPENCODE, SUPERPOWERS_CLAUDE_CODE, CLAUDE_CONFIG_DIR, SUPERPOWERS_HERMES, HERMES_HOME",
226
227
  "",
227
228
  "SUPERPOWERS_VALIDATOR is removed; unset it and use",
228
229
  "SUPERPOWERS_VALIDATOR_EXECUTABLE with an executable validator.",
@@ -252,13 +253,15 @@ async function main() {
252
253
  console.error(usage());
253
254
  process.exit(2);
254
255
  }
255
- const status = parsed.options.harness === "claude-code"
256
- ? await dispatch(claudeCodeHarness, parsed, root)
257
- : parsed.options.harness === "opencode"
258
- ? await dispatch(openCodeHarness, parsed, root)
259
- : parsed.options.harness === "pi"
260
- ? await dispatch(piHarness, parsed, root)
261
- : await dispatch(codexHarness, parsed, root);
256
+ const status = parsed.options.harness === "hermes"
257
+ ? await dispatch(hermesHarness, parsed, root)
258
+ : parsed.options.harness === "claude-code"
259
+ ? await dispatch(claudeCodeHarness, parsed, root)
260
+ : parsed.options.harness === "opencode"
261
+ ? await dispatch(openCodeHarness, parsed, root)
262
+ : parsed.options.harness === "pi"
263
+ ? await dispatch(piHarness, parsed, root)
264
+ : await dispatch(codexHarness, parsed, root);
262
265
  process.exit(status);
263
266
  }
264
267
  async function dispatch(adapter, parsed, root) {
@@ -15,17 +15,6 @@ export async function callAdapter(call, failure) {
15
15
  };
16
16
  return { ok: true, result: { status: result.status, outcome } };
17
17
  }
18
- // Preserve outcomes collected before gathering throws so command catches can
19
- // replay them before reporting the underlying failure.
20
- export class GatherFailure extends Error {
21
- inner;
22
- outcomes;
23
- constructor(message, inner, outcomes) {
24
- super(message);
25
- this.inner = inner;
26
- this.outcomes = outcomes;
27
- }
28
- }
29
18
  export function writeOutput(output, ctx) {
30
19
  for (const line of output.stdout)
31
20
  ctx.stdout.write(`${line}\n`);
@@ -1,181 +1,162 @@
1
1
  import { tmpdir } from "node:os";
2
2
  import { oneLine } from "../cli-arguments.js";
3
3
  import { withWorkspaceReporting, } from "../workspace.js";
4
- import { GatherFailure, invoke, writeOutput } from "./adapter-call.js";
4
+ import { invoke, writeOutput } from "./adapter-call.js";
5
5
  import { probeFacts, replayOutcome } from "./probe.js";
6
6
  import { runPrepare } from "./prepare.js";
7
7
  import { runWithMutation } from "./mutation.js";
8
8
  import { activationBlock } from "../harness-compatibility.js";
9
- // Collect outcomes without writing so output failures cannot be classified as
10
- // inspection failures. Replay collected outcomes after gathering completes.
11
- // The callback never throws: invoke() catches every ctx.adapter failure and
12
- // every predicate here is pure, so a post-success cleanup failure is the only
13
- // case withWorkspaceReporting's cleanupWarning has to carry.
14
- async function gatherInstallStages(ctx, selection, artifact) {
9
+ // Collect outcomes into the caller's array without writing, so output failures
10
+ // cannot be classified as inspection failures. The caller replays them after
11
+ // gathering, including when gathering throws; a post-success cleanup failure
12
+ // comes back as withWorkspaceReporting's cleanupWarning instead.
13
+ async function gatherInstallStages(ctx, selection, artifact, outcomes) {
15
14
  const parent = ctx.env.TMPDIR ?? tmpdir();
16
- const outcomes = [];
17
- try {
18
- return await withWorkspaceReporting(parent, "superpowers-manager.install.", async (workspace) => {
19
- const env = { ...ctx.env, TMPDIR: workspace };
20
- const failed = (message) => ({
21
- kind: "failed",
22
- outcomes,
23
- message,
24
- });
25
- const adapterContext = { root: ctx.root, env };
26
- // Stage 1: inspect ownership, re-checked even though gatherProbe just
27
- // reported it. Mutation authority requires CURRENT, VALIDATED
28
- // evidence -- a probe's answer is neither by the time this runs.
29
- const ownershipFailure = ctx.adapter.presentation.callFailure("install-ownership", adapterContext);
30
- const ownership = await invoke(() => ctx.adapter.inspectOwnership(adapterContext), ownershipFailure, outcomes);
31
- if (!ownership.ok)
32
- return failed(ownership.message);
33
- const ownershipDecision = ownership.result.outcome.result.installEligibility;
34
- if (ownershipDecision.kind === "blocked") {
15
+ return await withWorkspaceReporting(parent, "superpowers-manager.install.", async (workspace) => {
16
+ const env = { ...ctx.env, TMPDIR: workspace };
17
+ const failed = (message) => ({
18
+ kind: "failed",
19
+ message,
20
+ });
21
+ const adapterContext = { root: ctx.root, env };
22
+ // Stage 1: inspect ownership, re-checked even though gatherProbe just
23
+ // reported it. Mutation authority requires CURRENT, VALIDATED
24
+ // evidence -- a probe's answer is neither by the time this runs.
25
+ const ownershipFailure = ctx.adapter.presentation.callFailure("install-ownership", adapterContext);
26
+ const ownership = await invoke(() => ctx.adapter.inspectOwnership(adapterContext), ownershipFailure, outcomes);
27
+ if (!ownership.ok)
28
+ return failed(ownership.message);
29
+ const ownershipDecision = ownership.result.outcome.result.installEligibility;
30
+ if (ownershipDecision.kind === "blocked") {
31
+ return {
32
+ kind: "blocked",
33
+ output: ownershipDecision.output,
34
+ };
35
+ }
36
+ // Stage 2: inspect update-control, re-checked for the same reason.
37
+ const controlFailure = ctx.adapter.presentation.callFailure("install-control", adapterContext);
38
+ const control = await invoke(() => ctx.adapter.inspectUpdateControl(adapterContext), controlFailure, outcomes);
39
+ if (!control.ok)
40
+ return failed(control.message);
41
+ const mutationDecision = control.result.outcome.result.mutationEligibility;
42
+ if (mutationDecision.kind === "blocked") {
43
+ return {
44
+ kind: "blocked",
45
+ output: mutationDecision.output,
46
+ };
47
+ }
48
+ // Stage 3: the mutation itself. Nothing above may have issued this --
49
+ // that is the whole point of stages 1 and 2 running first.
50
+ const activationFailure = activationBlock(artifact.compatibility, ctx.options.allowExperimental);
51
+ if (activationFailure !== null)
52
+ return failed(activationFailure);
53
+ const installFailure = ctx.adapter.presentation.callFailure("install", adapterContext);
54
+ const install = await invoke(() => ctx.adapter.install(artifact, adapterContext), installFailure, outcomes);
55
+ if (!install.ok)
56
+ return failed(install.message);
57
+ let transaction;
58
+ try {
59
+ const candidate = install.result.outcome.result.transaction;
60
+ if (candidate !== undefined) {
61
+ if (candidate === null || typeof candidate !== "object")
62
+ throw new Error("invalid transaction");
63
+ const finalize = candidate.finalize.bind(candidate);
64
+ const rollback = candidate.rollback.bind(candidate);
65
+ if (typeof finalize !== "function" || typeof rollback !== "function")
66
+ throw new Error("invalid transaction");
67
+ transaction = { finalize, rollback };
68
+ }
69
+ }
70
+ catch {
71
+ return failed("invalid installation transaction receipt; preserve recovery material for manual resolution");
72
+ }
73
+ // Stage 4: inspect fingerprint, to verify the mutation actually took.
74
+ //
75
+ // Deliberately NOT short-circuited on `!inspected.ok`, unlike stages
76
+ // 1-3. `git show ad56569a4c161e7b122967442e2b026eeb6395f6:scripts/install:57::spw_verify_installed_fingerprint` handed the inspect result to
77
+ // spw_verify_installed_fingerprint whatever it contained, and that
78
+ // function's first guard, from
79
+ // `git show ad56569a4c161e7b122967442e2b026eeb6395f6:scripts/core/lifecycle.sh:91-94::spw_inspect_fingerprint`,
80
+ // is what turns a failed inspection into "error: installed manager
81
+ // fingerprint inspection failed after install."
82
+ // renderInstallVerification's failed-inspection arm
83
+ // (`src/harnesses/codex/presentation.ts:280::if (inspection.status !== 0 || !inspection.outcome.ok) {`)
84
+ // exists for this result-bearing path. Returning
85
+ // failed() instead reported the adapter's own generic diagnostic and
86
+ // dropped the post-install verification claim -- a mutation had
87
+ // already been issued at stage 3,
88
+ // so "the install could not be verified" is the contract, not "an
89
+ // adapter call failed". A ctx.adapter THROW has no result to render.
90
+ // A pending transaction still rolls back before reporting that failure.
91
+ const inspectionFailure = ctx.adapter.presentation.callFailure("post-install", adapterContext);
92
+ const inspected = await invoke(() => ctx.adapter.inspectInstalled(selection, adapterContext), inspectionFailure, outcomes);
93
+ const inspection = inspected.result;
94
+ const verified = inspection !== null &&
95
+ inspection.status === 0 &&
96
+ inspection.outcome.ok &&
97
+ inspection.outcome.result.kind === "current";
98
+ if (transaction !== undefined) {
99
+ const operation = verified ? "finalize" : "rollback";
100
+ const settlement = await invoke(() => (verified ? transaction.finalize() : transaction.rollback()), {
101
+ unexpected: `installation ${operation} did not complete; preserve recovery material for manual resolution`,
102
+ invalidStatus: `installation ${operation} returned an invalid result; preserve recovery material for manual resolution`,
103
+ }, outcomes, (value) => value === null);
104
+ if (!verified) {
105
+ const restored = await invoke(() => ctx.adapter.inspectInstalled(selection, adapterContext), inspectionFailure, outcomes);
106
+ const restoration = restored.ok
107
+ ? `installed state after rollback: ${restored.result.outcome.result.kind}; identity=${restored.result.outcome.result.observedIdentity}`
108
+ : "installed state after rollback could not be inspected";
109
+ const verificationOutput = inspection === null
110
+ ? null
111
+ : ctx.adapter.presentation.renderInstallVerification(selection.desiredCommit, install.result, inspection);
112
+ const inspectionMessage = verificationOutput === null && !inspected.ok
113
+ ? inspected.message
114
+ : null;
115
+ const settlementMessage = !settlement.ok ? settlement.message : null;
35
116
  return {
36
- kind: "blocked",
37
- outcomes,
38
- output: ownershipDecision.output,
117
+ kind: "verified",
118
+ status: 1,
119
+ stdout: verificationOutput?.stdout ?? [],
120
+ stderr: [
121
+ ...(verificationOutput?.stderr ?? []),
122
+ ...(inspectionMessage === null
123
+ ? []
124
+ : [`error: ${inspectionMessage}`]),
125
+ ...(settlementMessage === null
126
+ ? []
127
+ : [`error: ${settlementMessage}`]),
128
+ restoration,
129
+ ],
39
130
  };
40
131
  }
41
- // Stage 2: inspect update-control, re-checked for the same reason.
42
- const controlFailure = ctx.adapter.presentation.callFailure("install-control", adapterContext);
43
- const control = await invoke(() => ctx.adapter.inspectUpdateControl(adapterContext), controlFailure, outcomes);
44
- if (!control.ok)
45
- return failed(control.message);
46
- const mutationDecision = control.result.outcome.result.mutationEligibility;
47
- if (mutationDecision.kind === "blocked") {
132
+ if (!settlement.ok) {
133
+ const actual = await invoke(() => ctx.adapter.inspectInstalled(selection, adapterContext), inspectionFailure, outcomes);
48
134
  return {
49
- kind: "blocked",
50
- outcomes,
51
- output: mutationDecision.output,
135
+ kind: "verified",
136
+ status: 1,
137
+ stdout: [],
138
+ stderr: [
139
+ "error: installation was verified, but transaction cleanup did not complete; preserve recovery material for manual resolution",
140
+ actual.ok
141
+ ? `installed state after failed finalization: ${actual.result.outcome.result.kind}; identity=${actual.result.outcome.result.observedIdentity}`
142
+ : "installed state after failed finalization could not be inspected",
143
+ ...(settlement.message === null
144
+ ? []
145
+ : [`error: ${settlement.message}`]),
146
+ ],
52
147
  };
53
148
  }
54
- // Stage 3: the mutation itself. Nothing above may have issued this --
55
- // that is the whole point of stages 1 and 2 running first.
56
- const activationFailure = activationBlock(artifact.compatibility, ctx.options.allowExperimental);
57
- if (activationFailure !== null)
58
- return failed(activationFailure);
59
- const installFailure = ctx.adapter.presentation.callFailure("install", adapterContext);
60
- const install = await invoke(() => ctx.adapter.install(artifact, adapterContext), installFailure, outcomes);
61
- if (!install.ok)
62
- return failed(install.message);
63
- let transaction;
64
- try {
65
- const candidate = install.result.outcome.result.transaction;
66
- if (candidate !== undefined) {
67
- if (candidate === null || typeof candidate !== "object")
68
- throw new Error("invalid transaction");
69
- const finalize = candidate.finalize.bind(candidate);
70
- const rollback = candidate.rollback.bind(candidate);
71
- if (typeof finalize !== "function" ||
72
- typeof rollback !== "function")
73
- throw new Error("invalid transaction");
74
- transaction = { finalize, rollback };
75
- }
76
- }
77
- catch {
78
- return failed("invalid installation transaction receipt; preserve recovery material for manual resolution");
79
- }
80
- // Stage 4: inspect fingerprint, to verify the mutation actually took.
81
- //
82
- // Deliberately NOT short-circuited on `!inspected.ok`, unlike stages
83
- // 1-3. `git show ad56569a4c161e7b122967442e2b026eeb6395f6:scripts/install:57::spw_verify_installed_fingerprint` handed the inspect result to
84
- // spw_verify_installed_fingerprint whatever it contained, and that
85
- // function's first guard, from
86
- // `git show ad56569a4c161e7b122967442e2b026eeb6395f6:scripts/core/lifecycle.sh:91-94::spw_inspect_fingerprint`,
87
- // is what turns a failed inspection into "error: installed manager
88
- // fingerprint inspection failed after install."
89
- // renderInstallVerification's failed-inspection arm
90
- // (`src/harnesses/codex/presentation.ts:280::if (inspection.status !== 0 || !inspection.outcome.ok) {`)
91
- // exists for this result-bearing path. Returning
92
- // failed() instead reported the adapter's own generic diagnostic and
93
- // dropped the post-install verification claim -- a mutation had
94
- // already been issued at stage 3,
95
- // so "the install could not be verified" is the contract, not "an
96
- // adapter call failed". A ctx.adapter THROW has no result to render.
97
- // A pending transaction still rolls back before reporting that failure.
98
- const inspectionFailure = ctx.adapter.presentation.callFailure("post-install", adapterContext);
99
- const inspected = await invoke(() => ctx.adapter.inspectInstalled(selection, adapterContext), inspectionFailure, outcomes);
100
- const inspection = inspected.result;
101
- const verified = inspection !== null &&
102
- inspection.status === 0 &&
103
- inspection.outcome.ok &&
104
- inspection.outcome.result.kind === "current";
105
- if (transaction !== undefined) {
106
- const operation = verified ? "finalize" : "rollback";
107
- const settlement = await invoke(() => (verified ? transaction.finalize() : transaction.rollback()), {
108
- unexpected: `installation ${operation} did not complete; preserve recovery material for manual resolution`,
109
- invalidStatus: `installation ${operation} returned an invalid result; preserve recovery material for manual resolution`,
110
- }, outcomes, (value) => value === null);
111
- if (!verified) {
112
- const restored = await invoke(() => ctx.adapter.inspectInstalled(selection, adapterContext), inspectionFailure, outcomes);
113
- const restoration = restored.ok
114
- ? `installed state after rollback: ${restored.result.outcome.result.kind}; identity=${restored.result.outcome.result.observedIdentity}`
115
- : "installed state after rollback could not be inspected";
116
- const verificationOutput = inspection === null
117
- ? null
118
- : ctx.adapter.presentation.renderInstallVerification(selection.desiredCommit, install.result, inspection);
119
- const inspectionMessage = verificationOutput === null && !inspected.ok
120
- ? inspected.message
121
- : null;
122
- const settlementMessage = !settlement.ok
123
- ? settlement.message
124
- : null;
125
- return {
126
- kind: "verified",
127
- outcomes,
128
- status: 1,
129
- stdout: verificationOutput?.stdout ?? [],
130
- stderr: [
131
- ...(verificationOutput?.stderr ?? []),
132
- ...(inspectionMessage === null
133
- ? []
134
- : [`error: ${inspectionMessage}`]),
135
- ...(settlementMessage === null
136
- ? []
137
- : [`error: ${settlementMessage}`]),
138
- restoration,
139
- ],
140
- };
141
- }
142
- if (!settlement.ok) {
143
- const actual = await invoke(() => ctx.adapter.inspectInstalled(selection, adapterContext), inspectionFailure, outcomes);
144
- return {
145
- kind: "verified",
146
- outcomes,
147
- status: 1,
148
- stdout: [],
149
- stderr: [
150
- "error: installation was verified, but transaction cleanup did not complete; preserve recovery material for manual resolution",
151
- actual.ok
152
- ? `installed state after failed finalization: ${actual.result.outcome.result.kind}; identity=${actual.result.outcome.result.observedIdentity}`
153
- : "installed state after failed finalization could not be inspected",
154
- ...(settlement.message === null
155
- ? []
156
- : [`error: ${settlement.message}`]),
157
- ],
158
- };
159
- }
160
- }
161
- if (inspection === null)
162
- return failed(inspected.ok ? null : inspected.message);
163
- const output = ctx.adapter.presentation.renderInstallVerification(selection.desiredCommit, install.result, inspection);
164
- return {
165
- kind: "verified",
166
- outcomes,
167
- status: verified ? 0 : 1,
168
- stdout: output.stdout,
169
- stderr: output.stderr,
170
- };
171
- });
172
- }
173
- catch (cause) {
174
- // Reachable only for mkdtemp failure (nothing collected yet): the
175
- // callback never throws, and a post-success cleanup failure comes back
176
- // as cleanupWarning.
177
- throw new GatherFailure("install gather failed", cause, outcomes);
178
- }
149
+ }
150
+ if (inspection === null)
151
+ return failed(inspected.ok ? null : inspected.message);
152
+ const output = ctx.adapter.presentation.renderInstallVerification(selection.desiredCommit, install.result, inspection);
153
+ return {
154
+ kind: "verified",
155
+ status: verified ? 0 : 1,
156
+ stdout: output.stdout,
157
+ stderr: output.stderr,
158
+ };
159
+ });
179
160
  }
180
161
  export async function runInstall(argv, ctx) {
181
162
  if (ctx.adapter.presentation.installNotice !== "")
@@ -223,20 +204,21 @@ async function performInstall(ctx) {
223
204
  ctx.stderr.write("error: adapter reported a failure status for prepared harness inspection\n");
224
205
  return 1;
225
206
  }
207
+ // Owned here, not in gatherInstallStages, so a gather throw still replays
208
+ // every outcome collected before it.
209
+ const outcomes = [];
226
210
  let stage;
227
211
  try {
228
- stage = await gatherInstallStages(ctx, facts.selection, prepared.outcome.result);
212
+ stage = await gatherInstallStages(ctx, facts.selection, prepared.outcome.result, outcomes);
229
213
  }
230
214
  catch (cause) {
231
- const outcomes = cause instanceof GatherFailure ? cause.outcomes : [];
232
- for (const outcome of outcomes)
233
- replayOutcome(outcome, ctx);
234
- const inner = cause instanceof GatherFailure ? cause.inner : cause;
235
- ctx.stderr.write(`error: ${oneLine(inner)}\n`);
215
+ for (const each of outcomes)
216
+ replayOutcome(each, ctx);
217
+ ctx.stderr.write(`error: ${oneLine(cause)}\n`);
236
218
  return 1;
237
219
  }
238
220
  const { value: outcome, cleanupWarning } = stage;
239
- for (const each of outcome.outcomes)
221
+ for (const each of outcomes)
240
222
  replayOutcome(each, ctx);
241
223
  let status;
242
224
  if (outcome.kind === "blocked") {
@@ -262,7 +262,7 @@ async function performPrepare(ctx, location) {
262
262
  // completed before cleanup ran, so it is not being reported as unverified
263
263
  // -- but something did still go wrong, and AGENTS.md's fail-closed rule
264
264
  // extends to it. Mirrors
265
- // `src/commands/install.ts:372::if (cleanupWarning`.
265
+ // `src/commands/install.ts:351::if (cleanupWarning`.
266
266
  ctx.stderr.write(`error: ${cleanupWarning}\n`);
267
267
  return 1;
268
268
  }