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