@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.
- package/CHANGELOG.md +43 -0
- package/adapters/manifest.json +48 -64
- package/adapters/{terminal → web-dapp}/cleanup.mjs +9 -9
- package/adapters/{terminal → web-dapp}/inject.mjs +14 -14
- package/adapters/{terminal → web-dapp}/launch.mjs +27 -24
- package/adapters/web-dapp/lib/blocked-hosts.mjs +24 -0
- package/adapters/{terminal → web-dapp}/lib/cdp-client.mjs +1 -1
- package/adapters/{terminal → web-dapp}/lib/display.mjs +1 -1
- package/adapters/{terminal → web-dapp}/lib/hud.mjs +1 -1
- package/adapters/web-dapp/lib/policy.mjs +79 -0
- package/adapters/{terminal → web-dapp}/lib/processes.mjs +8 -8
- package/adapters/{terminal → web-dapp}/lib/readiness.mjs +32 -34
- package/adapters/{terminal → web-dapp}/stop.mjs +5 -4
- package/adapters/{terminal → web-dapp}/verify.mjs +9 -6
- package/adapters/{terminal → web-dapp}/wallet-host.mjs +44 -227
- package/dist/adapters/core/actions.js +4 -1
- package/dist/adapters/extension/actions.js +6 -2
- package/dist/adapters/extension/network-observer.js +13 -0
- package/dist/adapters/extension/run.js +115 -31
- package/dist/adapters/mobile/actions.js +4 -1
- package/dist/adapters/mobile/network-observer.js +68 -0
- package/dist/adapters/mobile/performance-observer.js +1 -3
- package/dist/adapters/mobile/run.js +32 -9
- package/dist/adapters/perps-order-inputs.js +36 -0
- package/dist/adapters/plugin-surface.js +98 -0
- package/dist/adapters/proof-failure.js +11 -0
- package/dist/adapters/surface.js +1 -1
- package/dist/adapters/{terminal → web-dapp}/actions.js +11 -8
- package/dist/adapters/web-dapp/console-capture.js +63 -0
- package/dist/adapters/web-dapp/doctor-checks.js +33 -0
- package/dist/adapters/{terminal → web-dapp}/launch.js +21 -19
- package/dist/adapters/web-dapp/overlay.js +21 -0
- package/dist/adapters/web-dapp/readiness.js +10 -0
- package/dist/adapters/{terminal → web-dapp}/run.js +22 -17
- package/dist/adapters/{terminal → web-dapp}/stop.js +5 -4
- package/dist/adapters/web-dapp/surface.js +149 -0
- package/dist/adapters.js +20 -4
- package/dist/cli.js +34 -6
- package/dist/command-contract.js +29 -7
- package/dist/commands/check.js +32 -8
- package/dist/commands/completion-candidates.js +5 -5
- package/dist/commands/doctor.js +19 -2
- package/dist/commands/farmslot-ready.js +1 -0
- package/dist/commands/help.js +1 -1
- package/dist/commands/launch/device.js +5 -5
- package/dist/commands/self-test.js +10 -5
- package/dist/engine.js +47 -0
- package/dist/funding-execution-context.js +81 -0
- package/dist/manifest.js +48 -24
- package/dist/mm-harness-cli.js +20 -3
- package/dist/performance-observation.js +7 -15
- package/dist/recipe-assistance-context.js +6 -7
- package/dist/runner.js +28 -8
- package/docs/CONTRIBUTING.md +4 -2
- package/docs/RECIPES.md +31 -3
- package/docs/cli-contract.md +5 -3
- package/library/actions/core/perps/_controller.mjs +24 -28
- package/library/actions/core/perps/_rewards.mjs +186 -0
- package/library/actions/core/perps/close_positions.mjs +1 -1
- package/library/actions/core/perps/place_order.mjs +167 -45
- package/library/actions/core/perps/quote_fees.mjs +7 -4
- package/library/actions/core/wallet/list_accounts.mjs +1 -1
- package/library/actions/extension/perps/close_visible_position.mjs +5 -0
- package/library/actions/extension/perps/edit_margin.mjs +4 -0
- package/library/actions/extension/perps/mutation-receipt.mjs +95 -3
- package/library/actions/extension/perps/perps.mjs +320 -3
- package/library/actions/extension/perps/place_order.mjs +3 -1
- package/library/actions/extension/perps/update_position_tpsl.mjs +4 -0
- package/library/actions/extension/platform/cdp.mjs +71 -3
- package/library/actions/mobile/perps/perps.mjs +216 -11
- package/library/actions/mobile/perps/place_order.mjs +3 -1
- package/library/actions/shared/console-collector.mjs +1 -1
- package/library/actions/shared/perps/order-policy.mjs +177 -0
- package/library/actions/{core/wallet/_fixture-accounts.mjs → shared/wallet/fixture-accounts.mjs} +18 -3
- package/library/actions/{terminal → web-dapp}/app/assert_no_console_errors.mjs +4 -4
- package/library/actions/{terminal → web-dapp}/app/launch.mjs +8 -7
- package/library/actions/{terminal → web-dapp}/platform/hud.mjs +7 -6
- package/library/actions/{terminal → web-dapp}/platform/page.mjs +13 -12
- package/library/actions/{terminal → web-dapp}/platform/runtime.mjs +16 -12
- package/library/actions/web-dapp/ui/navigate.mjs +24 -0
- package/library/actions/web-dapp/wallet/_signature-log.mjs +32 -0
- package/library/actions/{terminal → web-dapp}/wallet/assert_signatures.mjs +8 -14
- package/library/actions/{terminal → web-dapp}/wallet/list_accounts.mjs +2 -2
- package/library/actions/web-dapp/wallet/read_signatures.mjs +38 -0
- package/library/manifests/core.action-manifest.json +6 -2
- package/library/manifests/extension.action-manifest.json +4 -0
- package/library/manifests/mobile.action-manifest.json +12 -0
- package/library/manifests/{terminal.action-manifest.json → web-dapp.action-manifest.json} +18 -702
- package/package.json +6 -6
- package/site/assets/help-recipes.json +1 -0
- package/adapters/terminal/lib/mainnet-guard.mjs +0 -177
- package/adapters/terminal/lib/origin.mjs +0 -30
- package/adapters/terminal/lib/page-script.mjs +0 -246
- package/adapters/terminal/lib/strict-wallet.mjs +0 -138
- package/dist/adapters/terminal/console-capture.js +0 -59
- package/dist/adapters/terminal/doctor-checks.js +0 -22
- package/dist/adapters/terminal/overlay.js +0 -18
- package/dist/adapters/terminal/readiness.js +0 -11
- package/dist/adapters/terminal/surface.js +0 -133
- package/dist/commands/call.js +0 -671
- package/dist/commands/list-executables.js +0 -245
- package/dist/commands/manifest.js +0 -477
- package/dist/commands/run-engine.js +0 -1301
- package/dist/commands/run.js +0 -730
- package/dist/discovery.js +0 -15
- package/dist/metamask-action-validation.js +0 -68
- package/dist/network-observation.js +0 -290
- package/library/actions/terminal/perps/_venue.mjs +0 -242
- package/library/actions/terminal/perps/assert_orders.mjs +0 -54
- package/library/actions/terminal/perps/assert_positions.mjs +0 -40
- package/library/actions/terminal/perps/read_orders.mjs +0 -26
- package/library/actions/terminal/perps/read_positions.mjs +0 -25
- package/library/actions/terminal/perps/read_snapshot.mjs +0 -40
- package/library/actions/terminal/perps/revoke_agent.mjs +0 -58
- package/library/actions/terminal/perps/teardown_state.mjs +0 -104
- package/library/actions/terminal/ui/navigate.mjs +0 -31
- package/library/actions/terminal/wallet/_signature-log.mjs +0 -177
- package/library/actions/terminal/wallet/read_signatures.mjs +0 -37
package/dist/commands/call.js
DELETED
|
@@ -1,671 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { randomUUID } from "node:crypto";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { resolveActionManifest } from "../manifest.js";
|
|
5
|
-
import { importRecipeProtocol } from "../paths.js";
|
|
6
|
-
import { color, acquireCheckoutLock, isSensitiveKey, recordCommandEvidence, redactStructuredValue, conciseFailureForHuman, recipeRunning, checkoutBusyOut, EXIT, usageOut, parseArgs, isRecord, optionFlag, optionString, optionStrings, resolveAdapter, shellQuote, usageError } from "@farmslot/recipe-cli/harness";
|
|
7
|
-
import {
|
|
8
|
-
actionLibraryContextArgs,
|
|
9
|
-
actionExampleCommand,
|
|
10
|
-
describeManifestActions,
|
|
11
|
-
resolveActionCapabilityMatrix
|
|
12
|
-
} from "./manifest.js";
|
|
13
|
-
import { fuzzyResolveActions, resolveActionCapabilityRefusal } from "@farmslot/recipe-cli";
|
|
14
|
-
import { getAdapterSurface } from "../adapters/surface.js";
|
|
15
|
-
import { handleListExecutables } from "./list-executables.js";
|
|
16
|
-
import { applyDeviceTargeting } from "./device-target.js";
|
|
17
|
-
import {
|
|
18
|
-
emitHealViolation,
|
|
19
|
-
executeWithHealBounds,
|
|
20
|
-
prepareHeal,
|
|
21
|
-
persistRunEffects,
|
|
22
|
-
resolveMetaMaskLibrarySources,
|
|
23
|
-
preflightRecipe,
|
|
24
|
-
runRecipe,
|
|
25
|
-
synthesizeOneNodeRecipe,
|
|
26
|
-
validateRecipeAdapterAware
|
|
27
|
-
} from "./run-engine.js";
|
|
28
|
-
import {
|
|
29
|
-
startRunNetworkObservation
|
|
30
|
-
} from "../network-observation.js";
|
|
31
|
-
import {
|
|
32
|
-
startRunPerformanceObservation
|
|
33
|
-
} from "../performance-observation.js";
|
|
34
|
-
import { closest, formatRunDiagnosticsForHuman, ProvenanceDriftError, readRunDiagnosticsDocument, recipeRunOptionsFromCli, recipeTrustFailure } from "@farmslot/recipe-cli/harness";
|
|
35
|
-
import { fundingOptionsFromCli } from "../funding-execution-context.js";
|
|
36
|
-
async function handleCall(argv) {
|
|
37
|
-
if (argv.includes("--list")) {
|
|
38
|
-
const { options: options2 } = parseArgs(argv);
|
|
39
|
-
return handleListExecutables("call", options2);
|
|
40
|
-
}
|
|
41
|
-
if (argv.length > 0 && argv[0].startsWith("--")) {
|
|
42
|
-
const message = "call requires <action> first: mm-harness call <action> [key=value ...] [--arg k=v ...] [flags]";
|
|
43
|
-
console.error(message);
|
|
44
|
-
return EXIT.usage;
|
|
45
|
-
}
|
|
46
|
-
const { action: shortName, args, rest } = parseCallArgs(argv);
|
|
47
|
-
const { options } = parseArgs(rest);
|
|
48
|
-
if (["domain", "source", "sort"].some((name) => optionString(options, name) !== void 0)) {
|
|
49
|
-
throw usageError("--domain, --source, and --sort require call --list.");
|
|
50
|
-
}
|
|
51
|
-
const json = optionFlag(options, "json");
|
|
52
|
-
if (!shortName) {
|
|
53
|
-
let example = "mm-harness call <action>";
|
|
54
|
-
let discovery = "mm-harness actions";
|
|
55
|
-
try {
|
|
56
|
-
const { adapter: adapter2 } = resolveAdapter(options);
|
|
57
|
-
const librarySources2 = await resolveMetaMaskLibrarySources(optionStrings(options, "library"));
|
|
58
|
-
const { manifest: manifest2 } = await resolveActionManifest(adapter2, optionString(options, "actionManifest"), librarySources2);
|
|
59
|
-
const { getRecipeActionManifestActionNames: getRecipeActionManifestActionNames2 } = await importRecipeProtocol();
|
|
60
|
-
const exampleAction = pickCallExampleAction(getRecipeActionManifestActionNames2(manifest2));
|
|
61
|
-
example = `mm-harness call ${exampleAction} --adapter ${adapter2}`;
|
|
62
|
-
discovery = `mm-harness actions --adapter ${adapter2}`;
|
|
63
|
-
} catch {
|
|
64
|
-
}
|
|
65
|
-
const message = `call requires <action>. Example: ${example}`;
|
|
66
|
-
const userAction = `${example} # see the vocabulary: ${discovery}`;
|
|
67
|
-
if (json) console.log(JSON.stringify({
|
|
68
|
-
schemaVersion: 1,
|
|
69
|
-
command: "call",
|
|
70
|
-
status: "fail",
|
|
71
|
-
error: { code: "CLI_MISSING_POSITIONAL", message, userAction },
|
|
72
|
-
exitCode: EXIT.usage
|
|
73
|
-
}, null, 2));
|
|
74
|
-
else console.error(`${message}
|
|
75
|
-
See the vocabulary: ${discovery}`);
|
|
76
|
-
return EXIT.usage;
|
|
77
|
-
}
|
|
78
|
-
const { adapter, target } = resolveAdapter(options);
|
|
79
|
-
if (!fs.existsSync(target)) {
|
|
80
|
-
return usageOut(
|
|
81
|
-
json,
|
|
82
|
-
"call",
|
|
83
|
-
`target does not exist: ${target}`,
|
|
84
|
-
"pass --target <metamask-checkout> pointing to an existing checkout"
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
getAdapterSurface(adapter).resolveSlotPorts(target);
|
|
88
|
-
const dtResult = applyDeviceTargeting("call", adapter, options, { gate: true, rerun: "" });
|
|
89
|
-
if ("code" in dtResult) {
|
|
90
|
-
if (json) console.log(JSON.stringify({ schemaVersion: 1, command: "call", adapter, error: { code: dtResult.code, message: dtResult.message, userAction: dtResult.userAction } }, null, 2));
|
|
91
|
-
else console.error(`\u2717 call: ${dtResult.message}
|
|
92
|
-
Next: ${dtResult.userAction}`);
|
|
93
|
-
return EXIT.usage;
|
|
94
|
-
}
|
|
95
|
-
if (recipeRunning(target)) {
|
|
96
|
-
const msg = "a recipe is currently running \u2014 refusing to start while another recipe executes.";
|
|
97
|
-
const userAction = `inspect the checkout state with: mm-harness status --target ${shellQuote(target)} --json; retry after the active recipe finishes`;
|
|
98
|
-
if (json) {
|
|
99
|
-
console.log(JSON.stringify({ schemaVersion: 1, command: "call", status: "fail", recoverable: false, error: { code: "RECIPE_RUNNING", message: msg, userAction } }, null, 2));
|
|
100
|
-
} else {
|
|
101
|
-
console.error(`\u2717 mm-harness call: ${msg}
|
|
102
|
-
Next: ${userAction}`);
|
|
103
|
-
}
|
|
104
|
-
return EXIT.bounded;
|
|
105
|
-
}
|
|
106
|
-
const actionManifestOverride = optionString(options, "actionManifest");
|
|
107
|
-
const librarySources = await resolveMetaMaskLibrarySources(optionStrings(options, "library"));
|
|
108
|
-
const { manifest, actionSources } = await resolveActionManifest(adapter, actionManifestOverride, librarySources);
|
|
109
|
-
const { getRecipeActionManifestActionNames } = await importRecipeProtocol();
|
|
110
|
-
const names = getRecipeActionManifestActionNames(manifest);
|
|
111
|
-
const resolution = resolveActionName(shortName, names);
|
|
112
|
-
if (resolution.status === "unknown") {
|
|
113
|
-
const refusal = actionManifestOverride ? void 0 : resolveActionCapabilityRefusal(
|
|
114
|
-
shortName,
|
|
115
|
-
adapter,
|
|
116
|
-
await resolveActionCapabilityMatrix(librarySources)
|
|
117
|
-
);
|
|
118
|
-
if (refusal) {
|
|
119
|
-
const satisfying = refusal.satisfyingAdapters.join(", ");
|
|
120
|
-
const message2 = `missing action capability "${refusal.capability}" for the ${adapter} adapter.`;
|
|
121
|
-
const userAction2 = `Satisfying adapters for "${refusal.capability}": ${satisfying}. Inspect: mm-harness actions --matrix --action ${shellQuote(refusal.capability)}${actionLibraryContextArgs(librarySources)} --json`;
|
|
122
|
-
const error = {
|
|
123
|
-
code: "ACTION_CAPABILITY_UNAVAILABLE",
|
|
124
|
-
message: message2,
|
|
125
|
-
capability: refusal.capability,
|
|
126
|
-
satisfyingAdapters: refusal.satisfyingAdapters,
|
|
127
|
-
userAction: userAction2
|
|
128
|
-
};
|
|
129
|
-
if (json) {
|
|
130
|
-
console.log(JSON.stringify({
|
|
131
|
-
schemaVersion: 1,
|
|
132
|
-
command: "call",
|
|
133
|
-
adapter,
|
|
134
|
-
action: shortName,
|
|
135
|
-
error
|
|
136
|
-
}, null, 2));
|
|
137
|
-
} else {
|
|
138
|
-
console.error(`\u2717 call: ${message2}
|
|
139
|
-
Next: ${userAction2}`);
|
|
140
|
-
}
|
|
141
|
-
return EXIT.usage;
|
|
142
|
-
}
|
|
143
|
-
const message = `unknown action "${shortName}" for the ${adapter} adapter.`;
|
|
144
|
-
const userAction = `mm-harness actions --adapter ${adapter} --json`;
|
|
145
|
-
if (json) console.log(JSON.stringify({ schemaVersion: 1, command: "call", adapter, action: shortName, error: { code: "ACTION_UNKNOWN", message, userAction } }, null, 2));
|
|
146
|
-
else console.error(`\u2717 call: ${message}
|
|
147
|
-
Next: ${userAction}`);
|
|
148
|
-
return EXIT.usage;
|
|
149
|
-
}
|
|
150
|
-
if (resolution.status === "ambiguous") {
|
|
151
|
-
const message = `"${shortName}" is ambiguous: ${resolution.candidates.join(", ")} \u2014 use the full name.`;
|
|
152
|
-
const userAction = `mm-harness actions --action ${resolution.candidates[0]} --adapter ${adapter} --json`;
|
|
153
|
-
if (json) console.log(JSON.stringify({ schemaVersion: 1, command: "call", adapter, action: shortName, error: { code: "ACTION_AMBIGUOUS", message, candidates: resolution.candidates, userAction } }, null, 2));
|
|
154
|
-
else console.error(`\u2717 call: ${message}
|
|
155
|
-
Next: ${userAction}`);
|
|
156
|
-
return EXIT.usage;
|
|
157
|
-
}
|
|
158
|
-
const resolvedAction = resolution.resolved;
|
|
159
|
-
const describedAction = describeManifestActions(manifest, actionSources).find((entry) => entry.name === resolvedAction);
|
|
160
|
-
const defaultsUsed = actionDefaultsUsed(describedAction, args);
|
|
161
|
-
const depsBlock = await getAdapterSurface(adapter).run?.dependencyBlock?.(target, { action: resolvedAction }) ?? null;
|
|
162
|
-
if (depsBlock) {
|
|
163
|
-
if (json) {
|
|
164
|
-
console.log(JSON.stringify({ schemaVersion: 1, command: "call", adapter, status: "fail", exitCode: EXIT.usage, error: depsBlock }, null, 2));
|
|
165
|
-
} else {
|
|
166
|
-
console.error(`\u2717 call: ${depsBlock.message}`);
|
|
167
|
-
console.error(` Next: ${depsBlock.userAction}`);
|
|
168
|
-
}
|
|
169
|
-
return EXIT.usage;
|
|
170
|
-
}
|
|
171
|
-
const recipe = synthesizeOneNodeRecipe(resolvedAction, args);
|
|
172
|
-
const validation = await validateRecipeAdapterAware(adapter, recipe, manifest, librarySources);
|
|
173
|
-
if (validation.status === "invalid") {
|
|
174
|
-
const message = `call ${resolvedAction}: recipe validation failed`;
|
|
175
|
-
const parameterHelp = parameterValidationHelp(describedAction, validation.findings, args);
|
|
176
|
-
const userAction = describedAction ? actionExampleCommand(
|
|
177
|
-
describedAction,
|
|
178
|
-
adapter,
|
|
179
|
-
target,
|
|
180
|
-
process.env.MM_HARNESS_INVOKED_AS ?? process.env.MM_HARNESS_EXECUTABLE ?? "mm-harness",
|
|
181
|
-
args
|
|
182
|
-
) ?? `mm-harness actions --action ${resolvedAction} --adapter ${adapter}` : `mm-harness actions --action ${resolvedAction} --adapter ${adapter}`;
|
|
183
|
-
if (json) console.log(JSON.stringify({ schemaVersion: 1, command: "call", adapter, action: shortName, resolvedAction, args: redactCallValue(args), findings: validation.findings, ...parameterHelp.length > 0 ? { parameterHelp } : {}, error: { code: "RECIPE_VALIDATION_FAILED", message, userAction } }, null, 2));
|
|
184
|
-
else {
|
|
185
|
-
console.error(`\u2717 ${message}`);
|
|
186
|
-
const taught = new Set(parameterHelp.map((entry) => `${entry.issue}:${entry.name}`));
|
|
187
|
-
for (const entry of parameterHelp) console.error(renderParameterValidationHelp(entry));
|
|
188
|
-
for (const finding of validation.findings) {
|
|
189
|
-
const name = finding.path.split(".").at(-1);
|
|
190
|
-
const issue = parameterIssue(finding.code);
|
|
191
|
-
if (issue && name && taught.has(`${issue}:${name}`)) continue;
|
|
192
|
-
console.error(` ${finding.code} ${finding.path} \u2014 ${finding.message}`);
|
|
193
|
-
}
|
|
194
|
-
console.error(` Next: ${userAction}`);
|
|
195
|
-
}
|
|
196
|
-
return EXIT.validation;
|
|
197
|
-
}
|
|
198
|
-
const artifactsDir = optionString(options, "artifactsDir") ?? defaultCallArtifactsDir(target, resolvedAction);
|
|
199
|
-
recordCommandEvidence(artifactsDir);
|
|
200
|
-
const requestedRuntimeOptions = {
|
|
201
|
-
...recipeRunOptionsFromCli(adapter, options),
|
|
202
|
-
...fundingOptionsFromCli(options)
|
|
203
|
-
};
|
|
204
|
-
const inheritedSource = process.env.FARMSLOT_RECIPE_SOURCE_TRUST || process.env.FARMSLOT_RECIPE_SOURCE_KIND || process.env.FARMSLOT_RECIPE_SOURCE_NAME || process.env.FARMSLOT_RECIPE_SOURCE_DIGEST;
|
|
205
|
-
let networkObservation;
|
|
206
|
-
let performanceObservation;
|
|
207
|
-
const callRuntimeOptions = {
|
|
208
|
-
...requestedRuntimeOptions,
|
|
209
|
-
...librarySources ? { librarySources } : {},
|
|
210
|
-
autoHud: false,
|
|
211
|
-
suppressLibraryResolutionLogs: true,
|
|
212
|
-
stdoutIsMachineContract: json,
|
|
213
|
-
onActionEvent: ({ nodeId, action, status }) => {
|
|
214
|
-
networkObservation?.onActionEvent({ nodeId, action, status });
|
|
215
|
-
performanceObservation?.onActionEvent({ nodeId, action, status });
|
|
216
|
-
},
|
|
217
|
-
...requestedRuntimeOptions.source ? { source: requestedRuntimeOptions.source } : inheritedSource ? {} : {
|
|
218
|
-
source: {
|
|
219
|
-
kind: "operator",
|
|
220
|
-
trust: "trusted",
|
|
221
|
-
name: "mm-harness call"
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
let preflightedExecution;
|
|
226
|
-
try {
|
|
227
|
-
preflightedExecution = await preflightRecipe(
|
|
228
|
-
adapter,
|
|
229
|
-
recipe,
|
|
230
|
-
artifactsDir,
|
|
231
|
-
target,
|
|
232
|
-
actionManifestOverride,
|
|
233
|
-
callRuntimeOptions
|
|
234
|
-
);
|
|
235
|
-
} catch (error) {
|
|
236
|
-
const trustFailure = recipeTrustFailure(error);
|
|
237
|
-
if (!trustFailure) throw error;
|
|
238
|
-
const planDigest = trustFailure.details?.recipeDigest;
|
|
239
|
-
if (planDigest) {
|
|
240
|
-
trustFailure.userAction = `review the plan, then rerun this call with --artifacts-dir ${shellQuote(artifactsDir)} --approve-plan ${shellQuote(planDigest)}; managed callers must keep the same artifact directory and execution environment, then set FARMSLOT_RECIPE_APPROVE_PLAN=${shellQuote(planDigest)}`;
|
|
241
|
-
}
|
|
242
|
-
if (json) {
|
|
243
|
-
console.log(JSON.stringify({
|
|
244
|
-
schemaVersion: 1,
|
|
245
|
-
command: "call",
|
|
246
|
-
status: "fail",
|
|
247
|
-
error: trustFailure,
|
|
248
|
-
exitCode: EXIT.validation
|
|
249
|
-
}, null, 2));
|
|
250
|
-
} else {
|
|
251
|
-
console.error(`\u2717 mm-harness call: ${trustFailure.message}`);
|
|
252
|
-
const blocked = trustFailure.details?.blocked;
|
|
253
|
-
if (blocked?.length) {
|
|
254
|
-
console.error(" Restricted plan nodes:");
|
|
255
|
-
for (const node of blocked.slice(0, 10)) {
|
|
256
|
-
const implementation = node.implementation?.digest ? ` implementation=${node.implementation.kind ?? "custom"}@${node.implementation.digest}` : "";
|
|
257
|
-
console.error(
|
|
258
|
-
` - ${node.nodeId}: ${node.action} [${node.capabilities.join(", ")}] source=${node.source}${implementation}`
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
if (blocked.length > 10) console.error(` - \u2026 ${blocked.length - 10} more (use --json)`);
|
|
262
|
-
}
|
|
263
|
-
console.error(` Next: ${trustFailure.userAction}`);
|
|
264
|
-
}
|
|
265
|
-
return EXIT.validation;
|
|
266
|
-
}
|
|
267
|
-
const lock = acquireCheckoutLock(target, "call");
|
|
268
|
-
if ("message" in lock) {
|
|
269
|
-
return checkoutBusyOut(json, "call", lock.message, lock.path);
|
|
270
|
-
}
|
|
271
|
-
try {
|
|
272
|
-
const prepared = await prepareHeal(adapter, target, options, json, {
|
|
273
|
-
appRestartAuthored: resolvedAction === "app.lifecycle" && args.command === "restart"
|
|
274
|
-
});
|
|
275
|
-
if (typeof prepared === "number") return prepared;
|
|
276
|
-
const { state } = prepared;
|
|
277
|
-
preflightedExecution = await preflightRecipe(
|
|
278
|
-
adapter,
|
|
279
|
-
recipe,
|
|
280
|
-
artifactsDir,
|
|
281
|
-
target,
|
|
282
|
-
actionManifestOverride,
|
|
283
|
-
callRuntimeOptions
|
|
284
|
-
);
|
|
285
|
-
networkObservation = await startRunNetworkObservation(
|
|
286
|
-
adapter,
|
|
287
|
-
target,
|
|
288
|
-
artifactsDir,
|
|
289
|
-
process.env,
|
|
290
|
-
{
|
|
291
|
-
cdpPort: callRuntimeOptions.cdpPort,
|
|
292
|
-
watcherPort: callRuntimeOptions.watcherPort
|
|
293
|
-
}
|
|
294
|
-
);
|
|
295
|
-
performanceObservation = startRunPerformanceObservation(
|
|
296
|
-
adapter,
|
|
297
|
-
target,
|
|
298
|
-
artifactsDir,
|
|
299
|
-
process.env,
|
|
300
|
-
{
|
|
301
|
-
cdpPort: callRuntimeOptions.cdpPort,
|
|
302
|
-
watcherPort: callRuntimeOptions.watcherPort
|
|
303
|
-
}
|
|
304
|
-
);
|
|
305
|
-
let executionResult;
|
|
306
|
-
try {
|
|
307
|
-
executionResult = await executeWithHealBounds(
|
|
308
|
-
() => {
|
|
309
|
-
const execution = preflightedExecution;
|
|
310
|
-
preflightedExecution = void 0;
|
|
311
|
-
return runRecipe(
|
|
312
|
-
adapter,
|
|
313
|
-
recipe,
|
|
314
|
-
artifactsDir,
|
|
315
|
-
target,
|
|
316
|
-
actionManifestOverride,
|
|
317
|
-
callRuntimeOptions,
|
|
318
|
-
execution,
|
|
319
|
-
state
|
|
320
|
-
);
|
|
321
|
-
},
|
|
322
|
-
target,
|
|
323
|
-
state
|
|
324
|
-
);
|
|
325
|
-
} catch (error) {
|
|
326
|
-
await networkObservation?.finalize().catch(() => void 0);
|
|
327
|
-
networkObservation = void 0;
|
|
328
|
-
await performanceObservation?.finalize().catch(() => void 0);
|
|
329
|
-
performanceObservation = void 0;
|
|
330
|
-
if (error instanceof ProvenanceDriftError) {
|
|
331
|
-
const failure = {
|
|
332
|
-
code: error.code,
|
|
333
|
-
message: error.message,
|
|
334
|
-
userAction: error.userAction,
|
|
335
|
-
provenancePath: error.provenancePath,
|
|
336
|
-
drift: error.drift
|
|
337
|
-
};
|
|
338
|
-
if (json) {
|
|
339
|
-
console.log(JSON.stringify({
|
|
340
|
-
schemaVersion: 1,
|
|
341
|
-
command: "call",
|
|
342
|
-
adapter,
|
|
343
|
-
action: shortName,
|
|
344
|
-
resolvedAction,
|
|
345
|
-
status: "fail",
|
|
346
|
-
error: failure,
|
|
347
|
-
exitCode: error.exitCode
|
|
348
|
-
}, null, 2));
|
|
349
|
-
} else {
|
|
350
|
-
console.error(`\u2717 mm-harness call: ${error.message}`);
|
|
351
|
-
console.error(` Next: ${error.userAction}`);
|
|
352
|
-
}
|
|
353
|
-
return error.exitCode;
|
|
354
|
-
}
|
|
355
|
-
throw error;
|
|
356
|
-
}
|
|
357
|
-
const { result, violation } = executionResult;
|
|
358
|
-
await networkObservation?.finalize(result.artifactManifestPath);
|
|
359
|
-
networkObservation = void 0;
|
|
360
|
-
await performanceObservation?.finalize(result.artifactManifestPath);
|
|
361
|
-
performanceObservation = void 0;
|
|
362
|
-
persistRunEffects(result.summaryPath, result.artifactManifestPath, state);
|
|
363
|
-
if (violation !== null) {
|
|
364
|
-
const conciseFailure = violation.originalError ? conciseFailureForHuman(violation.originalError) : "";
|
|
365
|
-
const taughtViolation = violation.code === "APP_LOGIC_FAILURE" && conciseFailure.includes(" requires ") && describedAction ? { ...violation, userAction: `mm-harness actions ${resolvedAction} --adapter ${adapter} --json` } : violation;
|
|
366
|
-
return emitHealViolation(json, "call", result, taughtViolation, state, adapter);
|
|
367
|
-
}
|
|
368
|
-
const callOutput = readCallOutput(result.tracePath);
|
|
369
|
-
const safeArgs = redactCallValue(args);
|
|
370
|
-
const safeCallOutput = redactCallValue(callOutput);
|
|
371
|
-
const failureUserAction = `mm-harness last --target ${shellQuote(target)} --json`;
|
|
372
|
-
if (json) {
|
|
373
|
-
console.log(
|
|
374
|
-
JSON.stringify(
|
|
375
|
-
{
|
|
376
|
-
schemaVersion: 1,
|
|
377
|
-
command: "call",
|
|
378
|
-
adapter,
|
|
379
|
-
action: shortName,
|
|
380
|
-
resolvedAction,
|
|
381
|
-
args: safeArgs,
|
|
382
|
-
...Object.keys(defaultsUsed).length > 0 ? { defaultsUsed } : {},
|
|
383
|
-
status: result.status,
|
|
384
|
-
summaryPath: result.summaryPath,
|
|
385
|
-
tracePath: result.tracePath,
|
|
386
|
-
artifactManifestPath: result.artifactManifestPath,
|
|
387
|
-
...result.diagnosticsPath ? { diagnosticsPath: result.diagnosticsPath } : {},
|
|
388
|
-
...result.sideFindings ? { sideFindings: result.sideFindings } : {},
|
|
389
|
-
...callOutput !== void 0 ? { output: safeCallOutput } : {},
|
|
390
|
-
recovered: state.recovered,
|
|
391
|
-
mutations: state.mutations,
|
|
392
|
-
exitCode: result.status === "pass" ? EXIT.ok : EXIT.runtime,
|
|
393
|
-
...result.status === "fail" ? { error: { code: "ACTION_EXECUTION_FAILED", message: `${resolvedAction} failed; inspect the persisted result and evidence paths`, userAction: failureUserAction } } : {}
|
|
394
|
-
},
|
|
395
|
-
null,
|
|
396
|
-
2
|
|
397
|
-
)
|
|
398
|
-
);
|
|
399
|
-
} else {
|
|
400
|
-
const renderedInputs = Object.keys(args).length > 0 ? formatCallOutput(safeArgs) : "";
|
|
401
|
-
const out = (style, text) => color(style, text, { stream: process.stdout });
|
|
402
|
-
const diagnostics = formatRunDiagnosticsForHuman(
|
|
403
|
-
readRunDiagnosticsDocument(result.diagnosticsPath),
|
|
404
|
-
adapter
|
|
405
|
-
);
|
|
406
|
-
const renderedDiagnostics = `${out("label", "Diagnostics:")}
|
|
407
|
-
${diagnostics.map((line) => ` ${line}`).join("\n")}
|
|
408
|
-
`;
|
|
409
|
-
console.log(
|
|
410
|
-
`${out("label", "call")} ${out("cmd", resolvedAction)}: ${out(result.status === "pass" ? "ok" : "err", result.status)}${renderedInputs ? `
|
|
411
|
-
${out("label", "Inputs:")}
|
|
412
|
-
${renderedInputs}` : ""}${Object.keys(defaultsUsed).length > 0 ? `
|
|
413
|
-
${renderDefaultsUsed(defaultsUsed, process.stdout)}` : ""}${callOutput !== void 0 ? `
|
|
414
|
-
${out("label", "Result:")}
|
|
415
|
-
${formatCallOutput(safeCallOutput)}` : ""}
|
|
416
|
-
` + renderedDiagnostics + `${out("label", "Artifacts:")} ${out("path", result.artifactManifestPath)}` + (result.status === "fail" ? `
|
|
417
|
-
Next: ${failureUserAction}` : "")
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
return result.status === "pass" ? EXIT.ok : EXIT.runtime;
|
|
421
|
-
} finally {
|
|
422
|
-
lock.release();
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
function parameterValidationHelp(action, findings, args) {
|
|
426
|
-
const schema = isRecord(action?.schema) ? action.schema : {};
|
|
427
|
-
const properties = isRecord(schema.properties) ? schema.properties : {};
|
|
428
|
-
return findings.flatMap((finding) => {
|
|
429
|
-
const issue = parameterIssue(finding.code);
|
|
430
|
-
if (!issue) return [];
|
|
431
|
-
const name = finding.path.split(".").at(-1);
|
|
432
|
-
const property = name && isRecord(properties[name]) ? properties[name] : void 0;
|
|
433
|
-
if (!name || !property) return [];
|
|
434
|
-
const validValues = Array.isArray(property.enum) ? property.enum : void 0;
|
|
435
|
-
const type = typeof property.type === "string" ? property.type : Array.isArray(property.type) ? property.type.filter((value) => typeof value === "string").join("|") : void 0;
|
|
436
|
-
const received = Object.hasOwn(args, name) ? args[name] : void 0;
|
|
437
|
-
const suggestion = issue === "invalid" && received !== void 0 && validValues ? closest(String(received), validValues.map(String)) : void 0;
|
|
438
|
-
return [{
|
|
439
|
-
issue,
|
|
440
|
-
name,
|
|
441
|
-
...type ? { type } : {},
|
|
442
|
-
...validValues ? { validValues } : {},
|
|
443
|
-
...typeof property.description === "string" ? { description: property.description } : {},
|
|
444
|
-
...issue === "invalid" && received !== void 0 ? { received } : {},
|
|
445
|
-
...suggestion ? { suggestion } : {}
|
|
446
|
-
}];
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
function parameterIssue(code) {
|
|
450
|
-
if (code === "recipe.missing_param") return "missing";
|
|
451
|
-
if (code === "recipe.invalid_param_value_enum") return "invalid";
|
|
452
|
-
return void 0;
|
|
453
|
-
}
|
|
454
|
-
function renderParameterValidationHelp(parameter) {
|
|
455
|
-
const out = (style, text) => color(style, text, { stream: process.stderr });
|
|
456
|
-
const heading = parameter.issue === "missing" ? `${out("cmd", parameter.name)}${parameter.type ? ` (${parameter.type}, required)` : " (required)"}` : `${out("cmd", parameter.name)} received ${out("err", JSON.stringify(parameter.received) ?? String(parameter.received))}`;
|
|
457
|
-
const values = parameter.validValues?.length ? ` Valid values: ${parameter.validValues.map((value) => out("accent", String(value))).join(", ")}.` : "";
|
|
458
|
-
const suggestion = parameter.suggestion ? ` Did you mean ${out("accent", JSON.stringify(parameter.suggestion))}?` : "";
|
|
459
|
-
const description = parameter.description ? ` ${parameter.description}` : "";
|
|
460
|
-
return ` ${heading}.${values}${suggestion}${description}`;
|
|
461
|
-
}
|
|
462
|
-
function actionDefaultsUsed(action, args) {
|
|
463
|
-
const schema = isRecord(action?.schema) ? action.schema : {};
|
|
464
|
-
const properties = isRecord(schema.properties) ? schema.properties : {};
|
|
465
|
-
return Object.fromEntries(
|
|
466
|
-
Object.entries(properties).filter(([name, entry]) => !Object.hasOwn(args, name) && isRecord(entry) && Object.hasOwn(entry, "default")).map(([name, entry]) => [name, entry.default])
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
function renderDefaultsUsed(defaults, stream) {
|
|
470
|
-
const out = (style, text) => color(style, text, { stream });
|
|
471
|
-
const values = Object.entries(defaults).map(([name, value]) => `${out("cmd", name)}=${out("accent", JSON.stringify(value) ?? String(value))}`).join(", ");
|
|
472
|
-
return `${out("label", "Defaults used:")} ${values}`;
|
|
473
|
-
}
|
|
474
|
-
function defaultCallArtifactsDir(target, action) {
|
|
475
|
-
const actionStem = action.replace(/[^a-zA-Z0-9._-]/gu, "_");
|
|
476
|
-
return path.join(target, "temp", "recipe", "calls", `${actionStem}-${randomUUID()}`);
|
|
477
|
-
}
|
|
478
|
-
function readCallOutput(tracePath) {
|
|
479
|
-
try {
|
|
480
|
-
const trace = JSON.parse(fs.readFileSync(tracePath, "utf8"));
|
|
481
|
-
const entries = Array.isArray(trace) ? trace : isRecord(trace) && Array.isArray(trace.entries) ? trace.entries : [];
|
|
482
|
-
const entry = entries.find((item) => isRecord(item) && item.nodeId === "call");
|
|
483
|
-
return isRecord(entry) && Object.prototype.hasOwnProperty.call(entry, "output") ? entry.output : void 0;
|
|
484
|
-
} catch {
|
|
485
|
-
return void 0;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
function formatCallOutput(value) {
|
|
489
|
-
if (typeof value === "string") return value;
|
|
490
|
-
if (typeof value === "number" || typeof value === "boolean" || value === null) return String(value);
|
|
491
|
-
return JSON.stringify(value, null, 2);
|
|
492
|
-
}
|
|
493
|
-
function redactCallValue(value, key = "") {
|
|
494
|
-
return key && isSensitiveKey(key) ? "<redacted>" : redactStructuredValue(value);
|
|
495
|
-
}
|
|
496
|
-
async function handleCallHelp(argv, genericHelp) {
|
|
497
|
-
const { action: shortName, rest } = parseCallArgs(argv.filter((arg) => arg !== "--help" && arg !== "-h"));
|
|
498
|
-
const { options } = parseArgs(rest);
|
|
499
|
-
let adapter;
|
|
500
|
-
let manifest;
|
|
501
|
-
let actionSources = /* @__PURE__ */ new Map();
|
|
502
|
-
try {
|
|
503
|
-
({ adapter } = resolveAdapter(options));
|
|
504
|
-
const librarySources = await resolveMetaMaskLibrarySources(optionStrings(options, "library"));
|
|
505
|
-
const resolution = await resolveActionManifest(adapter, optionString(options, "actionManifest"), librarySources);
|
|
506
|
-
manifest = resolution.manifest;
|
|
507
|
-
actionSources = resolution.actionSources;
|
|
508
|
-
} catch {
|
|
509
|
-
process.stdout.write(`${genericHelp}
|
|
510
|
-
`);
|
|
511
|
-
return EXIT.ok;
|
|
512
|
-
}
|
|
513
|
-
const matches = shortName ? fuzzyResolveActions(describeManifestActions(manifest, actionSources), shortName) : [];
|
|
514
|
-
if (matches.length === 0) {
|
|
515
|
-
process.stdout.write(`${genericHelp}
|
|
516
|
-
`);
|
|
517
|
-
if (shortName) {
|
|
518
|
-
process.stdout.write(
|
|
519
|
-
`
|
|
520
|
-
No action matches "${shortName}" for the ${adapter} adapter.
|
|
521
|
-
Next: mm-harness actions --adapter ${adapter} # list the action vocabulary
|
|
522
|
-
`
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
return EXIT.ok;
|
|
526
|
-
}
|
|
527
|
-
for (const entry of matches) process.stdout.write(renderCallActionHelp(entry));
|
|
528
|
-
process.stdout.write(`${genericHelp}
|
|
529
|
-
`);
|
|
530
|
-
return EXIT.ok;
|
|
531
|
-
}
|
|
532
|
-
function renderCallActionHelp(entry) {
|
|
533
|
-
const short = entry.name.split(".").pop() ?? entry.name;
|
|
534
|
-
const schema = isRecord(entry.schema) ? entry.schema : {};
|
|
535
|
-
const properties = isRecord(schema.properties) ? schema.properties : {};
|
|
536
|
-
const required = new Set(
|
|
537
|
-
Array.isArray(schema.required) ? schema.required.filter((r) => typeof r === "string") : []
|
|
538
|
-
);
|
|
539
|
-
const lines = [`mm-harness call ${entry.name} [key=value ...] [--arg k=v ...] [flags]`, ""];
|
|
540
|
-
if (entry.description) lines.push(` ${entry.description}`, "");
|
|
541
|
-
lines.push(` Source: ${entry.source}${entry.sourceManifest ? ` (${entry.sourceManifest})` : ""}`, "");
|
|
542
|
-
const names = Object.keys(properties).filter((name) => name !== "action" && name !== "next").sort();
|
|
543
|
-
if (names.length === 0) {
|
|
544
|
-
lines.push(" Fields: (none)");
|
|
545
|
-
} else {
|
|
546
|
-
lines.push(" Fields (pass as <name>=<value> or --arg <name>=<value>):");
|
|
547
|
-
const width = Math.max(...names.map((name) => name.length));
|
|
548
|
-
for (const name of names) {
|
|
549
|
-
const prop = isRecord(properties[name]) ? properties[name] : {};
|
|
550
|
-
const type = typeof prop.type === "string" ? prop.type : "any";
|
|
551
|
-
const req = required.has(name) ? " (required)" : "";
|
|
552
|
-
const desc = typeof prop.description === "string" ? ` \u2014 ${prop.description}` : "";
|
|
553
|
-
const enumVals = Array.isArray(prop.enum) ? ` [one of: ${prop.enum.join(", ")}]` : "";
|
|
554
|
-
const defaultValue = Object.hasOwn(prop, "default") ? ` [default: ${JSON.stringify(prop.default)}]` : "";
|
|
555
|
-
lines.push(` ${name.padEnd(width)} ${type}${req}${defaultValue}${desc}${enumVals}`);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
const examples = renderCallExamples(short, entry.examples);
|
|
559
|
-
if (examples.length > 0) {
|
|
560
|
-
lines.push("", " Examples:");
|
|
561
|
-
for (const example of examples) lines.push(` ${example}`);
|
|
562
|
-
}
|
|
563
|
-
return `${lines.join("\n")}
|
|
564
|
-
|
|
565
|
-
`;
|
|
566
|
-
}
|
|
567
|
-
function renderCallExamples(short, examples) {
|
|
568
|
-
if (!Array.isArray(examples)) return [];
|
|
569
|
-
const out = [];
|
|
570
|
-
for (const example of examples.slice(0, 2)) {
|
|
571
|
-
const node = isRecord(example) ? example : void 0;
|
|
572
|
-
if (!node) continue;
|
|
573
|
-
const tokens = Object.entries(node).filter(([key]) => key !== "action" && key !== "intent").map(([key, value]) => `${key}=${typeof value === "string" ? value : JSON.stringify(value)}`);
|
|
574
|
-
out.push(`mm-harness call ${short} ${tokens.join(" ")}`.trim());
|
|
575
|
-
}
|
|
576
|
-
return out;
|
|
577
|
-
}
|
|
578
|
-
function parseCallArgs(argv) {
|
|
579
|
-
const args = {};
|
|
580
|
-
const rest = [];
|
|
581
|
-
let action;
|
|
582
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
583
|
-
const arg = argv[i];
|
|
584
|
-
if (arg === "--arg" || arg.startsWith("--arg=")) {
|
|
585
|
-
const pair = arg === "--arg" ? argv[i += 1] : arg.slice("--arg=".length);
|
|
586
|
-
if (pair === void 0) throw usageError("--arg requires k=v.");
|
|
587
|
-
const eq = pair.indexOf("=");
|
|
588
|
-
if (eq === -1) throw usageError(`--arg must be k=v: ${pair}`);
|
|
589
|
-
args[pair.slice(0, eq)] = parseCallValue(pair.slice(eq + 1));
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
if (!arg.startsWith("--") && action === void 0) {
|
|
593
|
-
action = arg;
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
if (action !== void 0 && !isForwardedOptionValue(argv, i) && isArgPair(arg)) {
|
|
597
|
-
const eq = arg.indexOf("=");
|
|
598
|
-
args[arg.slice(0, eq)] = parseCallValue(arg.slice(eq + 1));
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
rest.push(arg);
|
|
602
|
-
}
|
|
603
|
-
return { action, args, rest };
|
|
604
|
-
}
|
|
605
|
-
function parseCallValue(value) {
|
|
606
|
-
if (value === "true") return true;
|
|
607
|
-
if (value === "false") return false;
|
|
608
|
-
if (value === "null") return null;
|
|
609
|
-
if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/u.test(value)) {
|
|
610
|
-
const number = Number(value);
|
|
611
|
-
if (Number.isFinite(number)) return number;
|
|
612
|
-
}
|
|
613
|
-
if (value.startsWith("[") && value.endsWith("]") || value.startsWith("{") && value.endsWith("}") || value.startsWith('"') && value.endsWith('"')) {
|
|
614
|
-
try {
|
|
615
|
-
return JSON.parse(value);
|
|
616
|
-
} catch {
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
return value;
|
|
620
|
-
}
|
|
621
|
-
function isArgPair(value) {
|
|
622
|
-
const eq = value.indexOf("=");
|
|
623
|
-
return eq > 0;
|
|
624
|
-
}
|
|
625
|
-
function isForwardedOptionValue(argv, index) {
|
|
626
|
-
if (index === 0) return false;
|
|
627
|
-
const previous = argv[index - 1];
|
|
628
|
-
if (!previous.startsWith("--") || previous.includes("=")) return false;
|
|
629
|
-
return VALUE_TAKING_CALL_FLAGS.has(normalizeFlagName(previous));
|
|
630
|
-
}
|
|
631
|
-
const VALUE_TAKING_CALL_FLAGS = /* @__PURE__ */ new Set([
|
|
632
|
-
"action-manifest",
|
|
633
|
-
"approve-plan",
|
|
634
|
-
"adapter",
|
|
635
|
-
"artifacts-dir",
|
|
636
|
-
"cdp-port",
|
|
637
|
-
"device",
|
|
638
|
-
"heal",
|
|
639
|
-
"library",
|
|
640
|
-
"metro-port",
|
|
641
|
-
"platform",
|
|
642
|
-
"slot",
|
|
643
|
-
"source-digest",
|
|
644
|
-
"source-kind",
|
|
645
|
-
"source-name",
|
|
646
|
-
"source-trust",
|
|
647
|
-
"target",
|
|
648
|
-
"validation-runtime-dir",
|
|
649
|
-
"watcher-port"
|
|
650
|
-
]);
|
|
651
|
-
function normalizeFlagName(flag) {
|
|
652
|
-
return flag.replace(/^--/u, "");
|
|
653
|
-
}
|
|
654
|
-
function resolveActionName(shortName, names) {
|
|
655
|
-
const tier = fuzzyResolveActions(names.map((name) => ({ name })), shortName).map(({ name }) => name);
|
|
656
|
-
if (tier.length === 1) return { status: "ok", resolved: tier[0], candidates: tier };
|
|
657
|
-
if (tier.length > 1) return { status: "ambiguous", resolved: "", candidates: tier };
|
|
658
|
-
return { status: "unknown", resolved: "", candidates: [] };
|
|
659
|
-
}
|
|
660
|
-
function pickCallExampleAction(names) {
|
|
661
|
-
const walletish = names.find((name) => /wallet|unlock/u.test(name));
|
|
662
|
-
if (walletish) return walletish;
|
|
663
|
-
if (names.includes("command")) return "command";
|
|
664
|
-
return names[0] ?? "command";
|
|
665
|
-
}
|
|
666
|
-
export {
|
|
667
|
-
defaultCallArtifactsDir,
|
|
668
|
-
handleCall,
|
|
669
|
-
handleCallHelp,
|
|
670
|
-
redactCallValue
|
|
671
|
-
};
|