@deeeed/metamask-harness 0.79.0 → 0.81.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 (252) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +1 -1
  3. package/adapters/extension/ensure-browser.sh +2 -2
  4. package/adapters/extension/inject.mjs +0 -1
  5. package/adapters/extension/launch-browser.cjs +39 -613
  6. package/adapters/extension/readiness.mjs +2 -5
  7. package/adapters/extension/reattach.sh +2 -2
  8. package/adapters/extension/stamp-runtime-title.cjs +1 -1
  9. package/adapters/manifest.json +16 -64
  10. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +57 -1358
  11. package/adapters/mobile/bridge-runtime/teaching.cjs +20 -0
  12. package/adapters/mobile/inject.sh +16 -0
  13. package/adapters/mobile/launch-console-forwarder.cjs +1 -2
  14. package/adapters/mobile/open-device.sh +2 -2
  15. package/adapters/mobile/reload-app.mjs +4 -4
  16. package/adapters/mobile/reset-app-data.sh +1 -1
  17. package/adapters/mobile/start-console-forwarder.sh +3 -2
  18. package/adapters/mobile/start-metro.sh +17 -12
  19. package/adapters/mobile/wait-for-bridge.cjs +2 -2
  20. package/adapters/shared/harness-source-fingerprint.mjs +13 -8
  21. package/adapters/shared/open-debug.mjs +2 -2
  22. package/adapters/shared/sync-wallet-fixture.sh +8 -5
  23. package/adapters/terminal/cleanup.mjs +2 -1
  24. package/adapters/terminal/inject.mjs +2 -1
  25. package/adapters/terminal/launch.mjs +17 -13
  26. package/adapters/terminal/lib/mainnet-guard.mjs +9 -0
  27. package/adapters/terminal/lib/readiness.mjs +20 -12
  28. package/adapters/terminal/policy.mjs +35 -0
  29. package/adapters/terminal/verify.mjs +10 -3
  30. package/adapters/terminal/wallet-host.mjs +43 -225
  31. package/bin/mm-harness +9 -28
  32. package/dist/adapters/checkout-files.js +16 -0
  33. package/dist/adapters/console-capture.js +14 -1
  34. package/dist/adapters/core/actions.js +8 -4
  35. package/dist/adapters/core/overlay.js +1 -1
  36. package/dist/adapters/core/readiness.js +28 -1
  37. package/dist/adapters/core/run.js +2 -2
  38. package/dist/adapters/core/surface.js +16 -1
  39. package/dist/adapters/extension/actions.js +6 -2
  40. package/dist/adapters/extension/browser-pid.js +56 -0
  41. package/dist/adapters/extension/console-capture.js +1 -1
  42. package/dist/adapters/extension/doctor-checks.js +1 -1
  43. package/dist/adapters/extension/ensure-ready.js +5 -4
  44. package/dist/adapters/extension/extension-id.js +1 -1
  45. package/dist/adapters/extension/feature-flags.js +1 -1
  46. package/dist/adapters/extension/fixtures.js +1 -2
  47. package/dist/adapters/extension/launch.js +4 -5
  48. package/dist/adapters/extension/launched-browser.js +1 -2
  49. package/dist/adapters/extension/network-observer.js +14 -1
  50. package/dist/adapters/extension/overlay.js +1 -1
  51. package/dist/adapters/extension/product-config.js +1 -1
  52. package/dist/adapters/extension/readiness.js +1 -1
  53. package/dist/adapters/extension/reload.js +1 -1
  54. package/dist/adapters/extension/run.js +135 -14
  55. package/dist/adapters/extension/runtime-decision.js +2 -1
  56. package/dist/adapters/extension/runtime.js +9 -5
  57. package/dist/adapters/extension/surface.js +15 -2
  58. package/dist/adapters/extension/verify.js +2 -2
  59. package/dist/adapters/harness-freshness.js +2 -1
  60. package/dist/adapters/mobile/actions.js +4 -1
  61. package/dist/adapters/mobile/android-gfxinfo-performance.js +1 -3
  62. package/dist/adapters/mobile/app-identity.js +10 -0
  63. package/dist/adapters/mobile/doctor-checks.js +1 -1
  64. package/dist/adapters/mobile/fixtures.js +1 -1
  65. package/dist/adapters/mobile/launch.js +27 -28
  66. package/dist/adapters/mobile/lifecycle.js +1 -1
  67. package/dist/adapters/mobile/metro-env.js +9 -59
  68. package/dist/adapters/mobile/network-observer.js +68 -0
  69. package/dist/adapters/mobile/performance-observer.js +2 -4
  70. package/dist/adapters/mobile/prepare-target.js +1 -1
  71. package/dist/adapters/mobile/prepare.js +3 -4
  72. package/dist/adapters/mobile/provision.js +1 -1
  73. package/dist/adapters/mobile/readiness.js +1 -1
  74. package/dist/adapters/mobile/recording-target.js +15 -0
  75. package/dist/adapters/mobile/release-artifact-state.js +1 -1
  76. package/dist/adapters/mobile/reload.js +1 -1
  77. package/dist/adapters/mobile/run.js +39 -15
  78. package/dist/adapters/mobile/runtime-decision.js +2 -4
  79. package/dist/adapters/mobile/source-freshness.js +22 -126
  80. package/dist/adapters/mobile/surface.js +26 -3
  81. package/dist/adapters/mobile/ui.js +16 -5
  82. package/dist/adapters/mobile/verify.js +2 -3
  83. package/dist/adapters/performance/cdp-trace.js +1 -1
  84. package/dist/adapters/performance/device-platform.js +1 -1
  85. package/dist/adapters/perps-order-inputs.js +36 -0
  86. package/dist/adapters/proof-failure.js +11 -0
  87. package/dist/adapters/slot-ports.js +1 -1
  88. package/dist/adapters/surface.js +1 -0
  89. package/dist/adapters/terminal/actions.js +4 -1
  90. package/dist/adapters/terminal/console-capture.js +1 -1
  91. package/dist/adapters/terminal/doctor-checks.js +2 -0
  92. package/dist/adapters/terminal/launch.js +4 -1
  93. package/dist/adapters/terminal/overlay.js +8 -1
  94. package/dist/adapters/terminal/run.js +33 -5
  95. package/dist/adapters/terminal/surface.js +9 -1
  96. package/dist/adapters.js +27 -7
  97. package/dist/advisor-policy.js +1 -1
  98. package/dist/checkout-view.js +1 -2
  99. package/dist/cli.js +59 -21
  100. package/dist/command-contract.js +1 -26
  101. package/dist/commands/check.js +33 -10
  102. package/dist/commands/checklist.js +1 -1
  103. package/dist/commands/completion-candidates.js +6 -14
  104. package/dist/commands/config.js +2 -2
  105. package/dist/commands/core-readiness.js +12 -7
  106. package/dist/commands/debug.js +3 -3
  107. package/dist/commands/device-target.js +5 -5
  108. package/dist/commands/doctor.js +2 -14
  109. package/dist/commands/domain.js +2 -2
  110. package/dist/commands/ensure-ready.js +1 -7
  111. package/dist/commands/fixtures.js +5 -6
  112. package/dist/commands/help.js +3 -4
  113. package/dist/commands/launch/device.js +10 -17
  114. package/dist/commands/launch/extension.js +2 -8
  115. package/dist/commands/launch/mobile.js +1 -1
  116. package/dist/commands/logs.js +3 -3
  117. package/dist/commands/mobile-device-view.js +4 -2
  118. package/dist/commands/overlay.js +110 -0
  119. package/dist/commands/pin.js +1 -1
  120. package/dist/commands/pr-body.js +2 -2
  121. package/dist/commands/prepare.js +4 -9
  122. package/dist/commands/provision.js +3 -12
  123. package/dist/commands/recipe-advice.js +1 -2
  124. package/dist/commands/recipe-quality.js +2 -3
  125. package/dist/commands/resolve-extension.js +1 -7
  126. package/dist/commands/review.js +4 -4
  127. package/dist/commands/runtime-decision.js +1 -6
  128. package/dist/commands/runtime-health.js +1 -7
  129. package/dist/commands/runtime-launch.js +1 -13
  130. package/dist/commands/self-test.js +5 -8
  131. package/dist/commands/status-watch.js +1 -2
  132. package/dist/commands/status.js +2 -5
  133. package/dist/commands/task-init.js +2 -3
  134. package/dist/commands/tutorial.js +2 -2
  135. package/dist/commands/update.js +1 -1
  136. package/dist/completions-cache.js +1 -1
  137. package/dist/console-classifier.js +19 -0
  138. package/dist/doctor.js +2 -3
  139. package/dist/engine.js +57 -0
  140. package/dist/funding-execution-context.js +96 -1
  141. package/dist/host.js +32 -0
  142. package/dist/index.js +1 -6
  143. package/dist/live-tsx.js +49 -0
  144. package/dist/mm-harness-cli.js +4 -6
  145. package/dist/paths.js +34 -64
  146. package/dist/performance-observation.js +3 -5
  147. package/dist/progress.js +1 -1
  148. package/dist/recipe-assistance-context.js +6 -9
  149. package/dist/recipe-security.js +2 -59
  150. package/dist/review/knowledge.js +2 -2
  151. package/dist/runner.js +7 -4
  152. package/dist/runtime-context.js +1 -1
  153. package/dist/task-view.js +2 -3
  154. package/docs/CONTRIBUTING.md +5 -3
  155. package/docs/RECIPES.md +31 -3
  156. package/docs/cli-contract.md +2 -2
  157. package/docs/feature-guard.md +90 -0
  158. package/library/README.md +3 -1
  159. package/library/actions/core/perps/_controller.mjs +153 -134
  160. package/library/actions/core/perps/_rewards.mjs +186 -0
  161. package/library/actions/core/perps/close_positions.mjs +1 -1
  162. package/library/actions/core/perps/place_order.mjs +167 -45
  163. package/library/actions/core/perps/quote_fees.mjs +61 -0
  164. package/library/actions/core/wallet/list_accounts.mjs +14 -57
  165. package/library/actions/extension/feature_flags/state.mjs +1 -1
  166. package/library/actions/extension/perps/close_visible_position.mjs +5 -0
  167. package/library/actions/extension/perps/edit_margin.mjs +4 -0
  168. package/library/actions/extension/perps/mutation-receipt.mjs +95 -3
  169. package/library/actions/extension/perps/perps.mjs +320 -3
  170. package/library/actions/extension/perps/place_order.mjs +3 -1
  171. package/library/actions/extension/perps/update_position_tpsl.mjs +4 -0
  172. package/library/actions/extension/platform/cdp.mjs +73 -11
  173. package/library/actions/harness-exports.mjs +1 -6
  174. package/library/actions/mobile/app/network-control.mjs +6 -8
  175. package/library/actions/mobile/perps/perps.mjs +216 -11
  176. package/library/actions/mobile/perps/place_order.mjs +3 -1
  177. package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +1 -1
  178. package/library/actions/mobile/platform/bridge.mjs +8 -8
  179. package/library/actions/mobile/platform/native-session-name.mjs +21 -1
  180. package/library/actions/mobile/platform/native-session.mjs +3 -4
  181. package/library/actions/mobile/platform/observe-ui.mjs +12 -6
  182. package/library/actions/mobile/ui/native-navigation.mjs +4 -3
  183. package/library/actions/mobile/wallet/native-ui.mjs +3 -2
  184. package/library/actions/shared/analytics/_adapter.mjs +1 -1
  185. package/library/actions/shared/console-findings.mjs +1 -1
  186. package/library/actions/shared/perps/order-policy.mjs +177 -0
  187. package/library/actions/shared/wallet/fixture-accounts.mjs +84 -0
  188. package/library/actions/terminal/app/launch.mjs +3 -2
  189. package/library/actions/terminal/platform/hud.mjs +2 -1
  190. package/library/actions/terminal/platform/page.mjs +2 -1
  191. package/library/actions/terminal/platform/runtime.mjs +2 -1
  192. package/library/actions/terminal/wallet/_signature-log.mjs +40 -161
  193. package/library/actions/terminal/wallet/assert_signatures.mjs +6 -12
  194. package/library/actions/terminal/wallet/read_signatures.mjs +10 -9
  195. package/library/manifests/core.action-manifest.json +87 -13
  196. package/library/manifests/extension.action-manifest.json +4 -0
  197. package/library/manifests/mobile.action-manifest.json +12 -0
  198. package/package.json +8 -9
  199. package/site/assets/help-recipes.json +1 -0
  200. package/adapters/extension/lib/slot-title.cjs +0 -292
  201. package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
  202. package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
  203. package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
  204. package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
  205. package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
  206. package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
  207. package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
  208. package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
  209. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
  210. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
  211. package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
  212. package/adapters/mobile/coalesce-metro-log.cjs +0 -24
  213. package/adapters/mobile/launch-metro.cjs +0 -77
  214. package/adapters/mobile/metro-config.cjs +0 -98
  215. package/adapters/mobile/metro-log-generation.cjs +0 -106
  216. package/adapters/terminal/lib/origin.mjs +0 -30
  217. package/adapters/terminal/lib/page-script.mjs +0 -246
  218. package/adapters/terminal/lib/strict-wallet.mjs +0 -138
  219. package/dist/adapters/mobile/frame-metrics.js +0 -118
  220. package/dist/adapters/mobile/video-recorder.js +0 -289
  221. package/dist/artifact-files.js +0 -92
  222. package/dist/checkout-lock.js +0 -149
  223. package/dist/cli-color.js +0 -98
  224. package/dist/command-journal.js +0 -308
  225. package/dist/commands/call.js +0 -685
  226. package/dist/commands/last.js +0 -60
  227. package/dist/commands/launch/index.js +0 -109
  228. package/dist/commands/list-executables.js +0 -247
  229. package/dist/commands/manifest.js +0 -488
  230. package/dist/commands/parse-args.js +0 -279
  231. package/dist/commands/reload.js +0 -41
  232. package/dist/commands/run-engine.js +0 -1340
  233. package/dist/commands/run-report.js +0 -241
  234. package/dist/commands/run.js +0 -751
  235. package/dist/commands/shared.js +0 -323
  236. package/dist/commands/stop.js +0 -60
  237. package/dist/devices.js +0 -100
  238. package/dist/discovery.js +0 -15
  239. package/dist/execution-provenance.js +0 -332
  240. package/dist/harness.js +0 -451
  241. package/dist/heal-bounds.js +0 -137
  242. package/dist/json-stream.js +0 -60
  243. package/dist/leaf-invoke.js +0 -19
  244. package/dist/library-provenance.js +0 -33
  245. package/dist/live-adapter-contract.js +0 -380
  246. package/dist/metamask-action-validation.js +0 -68
  247. package/dist/network-observation.js +0 -290
  248. package/dist/recording-target.js +0 -120
  249. package/dist/run-diagnostics.js +0 -364
  250. package/dist/run-recording.js +0 -481
  251. package/dist/runtime-proof.js +0 -90
  252. package/library/actions/mobile/platform/tool-paths.mjs +0 -123
@@ -1,488 +0,0 @@
1
- import { resolveActionManifest } from "../manifest.js";
2
- import { color } from "../cli-color.js";
3
- import { EXIT } from "./shared.js";
4
- import {
5
- isRecord,
6
- optionFlag,
7
- optionString,
8
- optionStrings,
9
- resolveAdapter,
10
- shellQuoteArg
11
- } from "./parse-args.js";
12
- import { resolveMetaMaskLibrarySources } from "./run-engine.js";
13
- import { isSensitiveKey, redactStructuredValue } from "../command-journal.js";
14
- import {
15
- OFFICIAL_RECIPE_ACTIONS,
16
- officialRecipeActionCapabilities
17
- } from "@farmslot/protocol";
18
- import { metaMaskActionExecutionCapabilities } from "../recipe-security.js";
19
- import { closest } from "../command-contract.js";
20
- import {
21
- actionCapabilityMatrix,
22
- actionCategory,
23
- findRelatedActions,
24
- fuzzyResolveActions,
25
- resolveActionCapabilityRefusal,
26
- searchActions,
27
- summarizeActionCategories
28
- } from "@farmslot/recipe-cli";
29
- const OFFICIAL_ACTIONS = new Set(OFFICIAL_RECIPE_ACTIONS);
30
- const ACTION_MATRIX_ADAPTERS = ["mobile", "extension", "core", "terminal"];
31
- function actionLibraryContextArgs(librarySources) {
32
- return (librarySources ?? []).filter((source) => source.name !== "metamask").map((source) => {
33
- const entry = source.name ? `${source.name}=${source.root}` : source.root;
34
- return ` --library ${shellQuoteArg(entry)}`;
35
- }).join("");
36
- }
37
- async function handleActions({ options, positional }) {
38
- const librarySources = await resolveMetaMaskLibrarySources(optionStrings(options, "library"));
39
- const json = optionFlag(options, "json");
40
- const action = optionString(options, "action");
41
- const query = positional[0]?.trim();
42
- const category = optionString(options, "category")?.toLowerCase();
43
- if (optionFlag(options, "matrix")) {
44
- return handleActionMatrix(options, { json, action, query, category, librarySources });
45
- }
46
- const { adapter, target } = resolveAdapter(options);
47
- const actionManifestOverride = optionString(options, "actionManifest");
48
- const { manifest, actionSources } = await resolveActionManifest(
49
- adapter,
50
- actionManifestOverride,
51
- librarySources
52
- );
53
- if (optionFlag(options, "raw")) {
54
- console.log(JSON.stringify(manifest, null, 2));
55
- return EXIT.ok;
56
- }
57
- const categoriesOnly = optionFlag(options, "categories");
58
- const all = describeManifestActions(manifest, actionSources);
59
- const categories = summarizeActionCategories(all);
60
- if (categoriesOnly && (action || category)) {
61
- const message = "--categories cannot be combined with --action or --category.";
62
- const userAction = `mm-harness actions --adapter ${adapter} --categories`;
63
- if (json) {
64
- console.log(JSON.stringify({ schemaVersion: 1, command: "actions", adapter, error: { code: "ACTION_FILTER_CONFLICT", message, userAction } }, null, 2));
65
- } else {
66
- console.error(`\u2717 mm-harness actions: ${message}
67
- Next: ${userAction}`);
68
- }
69
- return EXIT.usage;
70
- }
71
- if (categoriesOnly) {
72
- if (json) console.log(JSON.stringify({ schemaVersion: 1, command: "actions", adapter, categories }, null, 2));
73
- else for (const entry of categories) console.log(`${entry.name} (${entry.count})`);
74
- return EXIT.ok;
75
- }
76
- const categoryActions = category ? all.filter((entry) => entry.category === category) : all;
77
- if (category && categoryActions.length === 0) {
78
- const message = `no action category matches "${category}" for the ${adapter} adapter.`;
79
- const userAction = `mm-harness actions --adapter ${adapter} --categories`;
80
- if (json) {
81
- console.log(JSON.stringify({ schemaVersion: 1, command: "actions", adapter, category, availableCategories: categories, error: { code: "ACTION_CATEGORY_UNKNOWN", message, userAction } }, null, 2));
82
- } else {
83
- console.error(`\u2717 mm-harness actions: ${message}
84
- Next: ${userAction}`);
85
- }
86
- return EXIT.usage;
87
- }
88
- const actions = action ? fuzzyResolveActions(categoryActions, action) : query ? searchActions(categoryActions, query) : categoryActions;
89
- if (action && actions.length === 0) {
90
- const refusal = actionManifestOverride ? void 0 : resolveActionCapabilityRefusal(
91
- action,
92
- adapter,
93
- await resolveActionCapabilityMatrix(librarySources)
94
- );
95
- if (refusal) {
96
- const satisfying = refusal.satisfyingAdapters.join(", ");
97
- const message2 = `missing action capability "${refusal.capability}" for the ${adapter} adapter.`;
98
- const userAction2 = `Satisfying adapters for "${refusal.capability}": ${satisfying}. Inspect: mm-harness actions --matrix --action ${shellQuoteArg(refusal.capability)}${actionLibraryContextArgs(librarySources)} --json`;
99
- if (json) {
100
- console.log(JSON.stringify({
101
- schemaVersion: 1,
102
- command: "actions",
103
- adapter,
104
- action,
105
- category,
106
- error: {
107
- code: "ACTION_CAPABILITY_UNAVAILABLE",
108
- message: message2,
109
- capability: refusal.capability,
110
- satisfyingAdapters: refusal.satisfyingAdapters,
111
- userAction: userAction2
112
- }
113
- }, null, 2));
114
- } else {
115
- console.error(`\u2717 mm-harness actions: ${message2}
116
- Next: ${userAction2}`);
117
- }
118
- return EXIT.usage;
119
- }
120
- const message = `no action matches "${action}" for the ${adapter} adapter.`;
121
- const userAction = `mm-harness actions --adapter ${adapter}`;
122
- if (json) {
123
- console.log(JSON.stringify({ schemaVersion: 1, command: "actions", adapter, action, category, error: { code: "ACTION_UNKNOWN", message, userAction } }, null, 2));
124
- } else {
125
- console.error(`\u2717 mm-harness actions: ${message}
126
- Next: ${userAction}`);
127
- }
128
- return EXIT.usage;
129
- }
130
- if (query && actions.length === 0) {
131
- const message = `no action matches search "${query}" for the ${adapter} adapter.`;
132
- const userAction = `mm-harness actions --adapter ${adapter} --categories`;
133
- if (json) {
134
- console.log(JSON.stringify({
135
- schemaVersion: 1,
136
- command: "actions",
137
- adapter,
138
- query,
139
- category,
140
- error: { code: "ACTION_SEARCH_EMPTY", message, userAction }
141
- }, null, 2));
142
- } else {
143
- console.error(`\u2717 mm-harness actions: ${message}
144
- Next: ${userAction}`);
145
- }
146
- return EXIT.usage;
147
- }
148
- const relatedActions = action && actions.length === 1 ? findRelatedActions(all, actions[0]) : void 0;
149
- if (json) {
150
- const detailed = Boolean(action && actions.length === 1);
151
- console.log(JSON.stringify({
152
- schemaVersion: 1,
153
- command: "actions",
154
- adapter,
155
- ...query ? { query } : {},
156
- category,
157
- detail: detailed ? "full" : "summary",
158
- actions: detailed ? actions : actions.map(summarizeDescribedAction),
159
- ...relatedActions?.length ? { relatedActions } : {}
160
- }, null, 2));
161
- } else {
162
- console.log(renderHumanActionCatalog(actions, {
163
- title: `actions (${adapter})`,
164
- guidance: "Inspect: mm-harness actions --action <name> \xB7 Run: mm-harness call <name>"
165
- }));
166
- const example = action && actions.length === 1 ? renderHumanActionExample(
167
- actions[0],
168
- adapter,
169
- target,
170
- process.env.MM_HARNESS_INVOKED_AS ?? process.env.MM_HARNESS_EXECUTABLE ?? "mm-harness"
171
- ) : void 0;
172
- if (example) console.log(`
173
- ${example}`);
174
- if (relatedActions?.length) console.log(`
175
- ${color("label", "Related:", { stream: process.stdout })} ${relatedActions.join(", ")}`);
176
- }
177
- return 0;
178
- }
179
- async function resolveActionCapabilityMatrix(librarySources) {
180
- const catalogs = await Promise.all(
181
- ACTION_MATRIX_ADAPTERS.map(async (adapter) => {
182
- const { manifest, actionSources } = await resolveActionManifest(
183
- adapter,
184
- void 0,
185
- librarySources
186
- );
187
- return { adapter, actions: describeManifestActions(manifest, actionSources) };
188
- })
189
- );
190
- return actionCapabilityMatrix(catalogs);
191
- }
192
- function handleActionMatrixError(json, code, message, userAction, details = {}) {
193
- if (json) {
194
- console.log(JSON.stringify({
195
- schemaVersion: 1,
196
- command: "actions",
197
- view: "matrix",
198
- ...details,
199
- error: { code, message, userAction }
200
- }, null, 2));
201
- } else {
202
- console.error(`\u2717 mm-harness actions: ${message}
203
- Next: ${userAction}`);
204
- }
205
- return EXIT.usage;
206
- }
207
- async function handleActionMatrix(options, input) {
208
- const inspectCommand = `mm-harness actions --matrix${actionLibraryContextArgs(input.librarySources)} --json`;
209
- const conflicts = [
210
- optionFlag(options, "raw") ? "--raw" : void 0,
211
- optionFlag(options, "categories") ? "--categories" : void 0,
212
- optionString(options, "adapter") ? "--adapter" : void 0,
213
- optionString(options, "platform") ? "--platform" : void 0,
214
- optionString(options, "actionManifest") ? "--action-manifest" : void 0
215
- ].filter((value) => Boolean(value));
216
- if (conflicts.length > 0) {
217
- return handleActionMatrixError(
218
- input.json,
219
- "ACTION_MATRIX_CONFLICT",
220
- `--matrix cannot be combined with ${conflicts.join(", ")}.`,
221
- inspectCommand
222
- );
223
- }
224
- const matrix = await resolveActionCapabilityMatrix(input.librarySources);
225
- const categories = summarizeActionCategories(matrix);
226
- const categoryActions = input.category ? matrix.filter((entry) => entry.category === input.category) : matrix;
227
- if (input.category && categoryActions.length === 0) {
228
- return handleActionMatrixError(
229
- input.json,
230
- "ACTION_CATEGORY_UNKNOWN",
231
- `no action category matches "${input.category}" across the adapter matrix.`,
232
- inspectCommand,
233
- { category: input.category, availableCategories: categories }
234
- );
235
- }
236
- const actions = input.action ? fuzzyResolveActions(categoryActions, input.action) : input.query ? searchActions(categoryActions, input.query) : categoryActions;
237
- if (input.action && actions.length === 0) {
238
- return handleActionMatrixError(
239
- input.json,
240
- "ACTION_UNKNOWN",
241
- `no action capability matches "${input.action}" across Mobile, Extension, or Core.`,
242
- inspectCommand,
243
- { action: input.action, category: input.category }
244
- );
245
- }
246
- if (input.query && actions.length === 0) {
247
- return handleActionMatrixError(
248
- input.json,
249
- "ACTION_SEARCH_EMPTY",
250
- `no action capability matches search "${input.query}" across Mobile, Extension, or Core.`,
251
- inspectCommand,
252
- { query: input.query, category: input.category }
253
- );
254
- }
255
- if (input.json) {
256
- console.log(JSON.stringify({
257
- schemaVersion: 1,
258
- command: "actions",
259
- view: "matrix",
260
- adapters: ACTION_MATRIX_ADAPTERS,
261
- ...input.query ? { query: input.query } : {},
262
- ...input.category ? { category: input.category } : {},
263
- actions
264
- }, null, 2));
265
- } else {
266
- console.log(renderHumanActionMatrix(actions));
267
- }
268
- return EXIT.ok;
269
- }
270
- function renderHumanActionMatrix(actions) {
271
- const out = (style, text) => color(style, text, { stream: process.stdout });
272
- const width = Math.max("action capability".length, ...actions.map((action) => action.name.length));
273
- const cell = (status, width2) => status === "available" ? out("accent", "yes".padEnd(width2)) : out("dim", "\u2014".padEnd(width2));
274
- return [
275
- out("bold", "action capability matrix"),
276
- out("comment", "Inspect one: mm-harness actions --matrix --action <name> --json"),
277
- `${"action capability".padEnd(width)} mobile extension core terminal`,
278
- ...actions.map(
279
- (action) => `${action.name.padEnd(width)} ${cell(action.support.mobile, 6)} ${cell(action.support.extension, 9)} ${cell(action.support.core, 4)} ${cell(action.support.terminal, 8)}`
280
- )
281
- ].join("\n");
282
- }
283
- function summarizeDescribedAction(entry) {
284
- const { schema: _schema, examples: _examples, ...summary } = entry;
285
- return summary;
286
- }
287
- function actionDomain(entry) {
288
- return entry.category.replaceAll("_", "-");
289
- }
290
- function renderHumanActionCatalog(actions, options) {
291
- const out = (style, text) => color(style, text, { stream: process.stdout });
292
- const groups = /* @__PURE__ */ new Map();
293
- for (const entry of actions) {
294
- const group = options.sort === "name" ? "" : options.sort === "library" ? `Library: ${entry.source}` : options.sort === "domain" ? actionDomain(entry) : actionDomainGroup(entry);
295
- groups.set(group, [...groups.get(group) ?? [], entry]);
296
- }
297
- const lines = [out("bold", options.title), ...options.contextLines ?? [], out("comment", options.guidance)];
298
- if (actions.length === 0) lines.push("No callable actions match.");
299
- for (const [group, entries] of groups) {
300
- const groupStyle = options.sort === "domain" ? options.domainStyles?.get(group) ?? "accent" : group === "official" ? "label" : "accent";
301
- if (group) lines.push("", `${out(groupStyle, group)} ${out("dim", `(${entries.length})`)}`);
302
- for (const entry of entries) {
303
- const fieldNames = humanFieldNames(entry);
304
- const fields = fieldNames.length ? ` ${out("dim", `fields=${fieldNames.join(",")}`)}` : "";
305
- const cases = entry.result_cases?.length ? ` ${out("dim", `cases=${entry.result_cases.join(",")}`)}` : "";
306
- const description = entry.description ? ` ${out("comment", `\u2014 ${entry.description}`)}` : "";
307
- const source = ` ${out("dim", `[${entry.source}]`)}`;
308
- const risk = entry.capabilities.length ? ` ${out("dim", `risk=${entry.capabilities.join(",")}`)}` : "";
309
- const nameStyle = options.domainStyles?.get(actionDomain(entry)) ?? "cmd";
310
- lines.push(` ${out(nameStyle, options.displayName?.(entry) ?? entry.name)}${source}${fields}${cases}${risk}${description}`);
311
- }
312
- }
313
- return lines.join("\n");
314
- }
315
- function renderHumanActionExample(entry, adapter, target, executable) {
316
- const node = authoredExampleNode(entry.examples, void 0, entry.schema);
317
- if (!node) return void 0;
318
- const out = (style, text) => color(style, text, { stream: process.stdout });
319
- const command = actionExampleCommand(entry, adapter, target, executable);
320
- if (!command) return void 0;
321
- const lines = [
322
- out("label", "Example call:"),
323
- ` ${out("cmd", command)}`,
324
- out("label", "Recipe node:"),
325
- ...JSON.stringify(node, null, 2).split("\n").map((line) => ` ${line}`)
326
- ];
327
- return lines.join("\n");
328
- }
329
- function actionExampleCommand(entry, adapter, target, executable, preferredValues) {
330
- const node = authoredExampleNode(entry.examples, preferredValues, entry.schema);
331
- if (!node) return void 0;
332
- const commandName = executable.endsWith("/mm-harness") ? "mm-harness" : executable;
333
- const args = entry.fields.flatMap(
334
- (field) => Object.hasOwn(node, field) ? [shellQuoteArg(`${field}=${safeActionCallValue(field, node[field])}`)] : []
335
- );
336
- return [
337
- shellQuoteArg(commandName),
338
- "call",
339
- shellQuoteArg(entry.name),
340
- ...args,
341
- "--adapter",
342
- adapter,
343
- "--target",
344
- shellQuoteArg(target)
345
- ].join(" ");
346
- }
347
- function authoredExampleNode(examples, preferredValues, schema) {
348
- if (!Array.isArray(examples)) return void 0;
349
- if (preferredValues && Object.keys(preferredValues).length > 0) {
350
- const normalizedValues = normalizePreferredValues(preferredValues, schema);
351
- const nodes = examples.filter(isRecord);
352
- if (nodes.length === 0) return void 0;
353
- const ranked = nodes.map((node) => ({
354
- node,
355
- completeness: Object.keys(node).filter((name) => !["action", "intent", "next"].includes(name)).length,
356
- score: Object.entries(normalizedValues).reduce((score, [name, value]) => {
357
- if (!Object.hasOwn(node, name)) return score;
358
- return score + (sameActionValue(name, node[name], value) ? 3 : -1);
359
- }, 0)
360
- })).sort(
361
- (left, right) => right.score - left.score || right.completeness - left.completeness
362
- );
363
- return { ...ranked[0].node, ...normalizedValues };
364
- }
365
- for (const example of examples) {
366
- if (isRecord(example)) return example;
367
- }
368
- return void 0;
369
- }
370
- function normalizePreferredValues(preferredValues, schema) {
371
- const properties = isRecord(schema) && isRecord(schema.properties) ? schema.properties : {};
372
- return Object.fromEntries(
373
- Object.entries(preferredValues).flatMap(([name, value]) => {
374
- const property = isRecord(properties[name]) ? properties[name] : void 0;
375
- if (property && !matchesSchemaType(property.type, value)) return [];
376
- const values = property && Array.isArray(property.enum) ? property.enum : void 0;
377
- if (!values) {
378
- return [[name, value]];
379
- }
380
- const compatibleValue = values.find(
381
- (candidate) => sameActionValue(name, candidate, value)
382
- );
383
- if (compatibleValue !== void 0) return [[name, compatibleValue]];
384
- const strings = values.filter((candidate) => typeof candidate === "string");
385
- const suggestion = typeof value === "string" ? closest(value, strings) : void 0;
386
- return suggestion === void 0 ? [] : [[name, suggestion]];
387
- })
388
- );
389
- }
390
- function matchesSchemaType(type, value) {
391
- const types = Array.isArray(type) ? type : [type];
392
- if (types.every((candidate) => typeof candidate !== "string")) return true;
393
- return types.some((candidate) => {
394
- if (candidate === "null") return value === null;
395
- if (candidate === "array") return Array.isArray(value);
396
- if (candidate === "object") return isRecord(value);
397
- if (candidate === "integer") return typeof value === "number" && Number.isInteger(value);
398
- return typeof value === candidate;
399
- });
400
- }
401
- function sameActionValue(name, left, right) {
402
- if (name === "state") {
403
- const canonicalState = (value) => {
404
- if (value === "present") return "open";
405
- if (value === "absent") return "none";
406
- return value;
407
- };
408
- left = canonicalState(left);
409
- right = canonicalState(right);
410
- }
411
- const scalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
412
- if (scalar(left) && scalar(right)) return String(left) === String(right);
413
- return JSON.stringify(left) === JSON.stringify(right);
414
- }
415
- function actionCallValue(value) {
416
- return typeof value === "string" ? value : JSON.stringify(value);
417
- }
418
- function safeActionCallValue(field, value) {
419
- if (isSensitiveKey(field)) return `<${field}>`;
420
- return actionCallValue(redactStructuredValue(value));
421
- }
422
- function humanFieldNames(entry) {
423
- const schema = isRecord(entry.schema) ? entry.schema : void 0;
424
- const properties = schema && isRecord(schema.properties) ? schema.properties : void 0;
425
- if (!properties) return entry.fields;
426
- return entry.fields.map((field) => {
427
- const property = properties[field];
428
- if (!isRecord(property) || !Array.isArray(property.enum)) return field;
429
- const values = property.enum.filter((value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean");
430
- return values.length > 0 ? `${field}=${values.join("|")}` : field;
431
- });
432
- }
433
- function actionDomainGroup(entry) {
434
- if (entry.kind === "official") return "official";
435
- const match = /^metamask[.]([^.]+)[.]/u.exec(entry.name);
436
- return match ? `metamask \xB7 ${match[1]}` : "custom";
437
- }
438
- function describeManifestActions(manifest, actionSources = /* @__PURE__ */ new Map()) {
439
- const manifestRecord = isRecord(manifest) ? manifest : {};
440
- const actions = isRecord(manifestRecord.actions) ? manifestRecord.actions : {};
441
- return Object.entries(actions).map(
442
- ([name, metadata]) => describeManifestAction(
443
- name,
444
- OFFICIAL_ACTIONS.has(name) ? "official" : "custom",
445
- metadata,
446
- actionSources.get(name)
447
- )
448
- );
449
- }
450
- function describeManifestAction(name, kind, metadata, source) {
451
- const record = isRecord(metadata) ? metadata : {};
452
- const schema = record.schema;
453
- const schemaRecord = isRecord(schema) ? schema : {};
454
- const properties = isRecord(schemaRecord.properties) ? Object.keys(schemaRecord.properties).filter((field) => field !== "action" && field !== "next").sort() : [];
455
- return {
456
- name,
457
- kind,
458
- category: actionCategory(name, ["metamask"]),
459
- description: typeof record.description === "string" ? record.description : "",
460
- fields: properties,
461
- schema,
462
- examples: record.examples,
463
- ...Array.isArray(record.result_cases) ? { result_cases: record.result_cases.filter((value) => typeof value === "string") } : {},
464
- source: source?.name ?? (kind === "official" ? "official" : "metamask"),
465
- sourceTier: source?.tier ?? (kind === "official" ? "official" : "canonical"),
466
- sourceManifest: source?.manifestPath ?? "",
467
- shadows: source?.shadows ?? [],
468
- capabilities: [.../* @__PURE__ */ new Set([
469
- ...Array.isArray(record.execution_capabilities) ? record.execution_capabilities.filter(
470
- (value) => typeof value === "string"
471
- ) : [],
472
- ...kind === "official" ? officialRecipeActionCapabilities(name) : metaMaskActionExecutionCapabilities(name)
473
- ])]
474
- };
475
- }
476
- export {
477
- ACTION_MATRIX_ADAPTERS,
478
- actionDomain,
479
- actionExampleCommand,
480
- actionLibraryContextArgs,
481
- describeManifestActions,
482
- handleActions,
483
- renderHumanActionCatalog,
484
- renderHumanActionExample,
485
- renderHumanActionMatrix,
486
- resolveActionCapabilityMatrix,
487
- summarizeDescribedAction
488
- };