@deeeed/metamask-harness 0.21.0 → 0.22.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 +12 -0
- package/dist/adapters/extension/ensure-ready.js +44 -15
- package/dist/cli-commands.js +1 -0
- package/dist/cli.js +2 -0
- package/dist/command-contract.js +57 -0
- package/dist/commands/execution-template.js +28 -0
- package/dist/commands/run-engine.js +17 -8
- package/dist/library-provenance.js +33 -0
- package/dist/mm-harness-cli.js +35 -1
- package/library/actions/extension/ui/navigate.mjs +16 -6
- package/package.json +3 -3
- package/scripts/completions.sh +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.22.0 - 2026-07-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `execution-template` as the thin public boundary for shared checklist discovery and materialization.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `ui.navigate page=home` recognizes both the current bottom navigation and the selected legacy Tokens tab.
|
|
14
|
+
- Extension readiness recovers deterministically from transient target-list failures.
|
|
15
|
+
- Team-library calls retain their source provenance.
|
|
16
|
+
|
|
5
17
|
## 0.21.0 - 2026-07-24
|
|
6
18
|
|
|
7
19
|
### Changed
|
|
@@ -36,9 +36,11 @@ async function openHome(port, extensionId) {
|
|
|
36
36
|
try {
|
|
37
37
|
let res = await fetch(endpoint, { method: "PUT", signal: AbortSignal.timeout(8e3) });
|
|
38
38
|
if (res.status === 404 || res.status === 405) res = await fetch(endpoint, { signal: AbortSignal.timeout(8e3) });
|
|
39
|
-
|
|
39
|
+
if (!res.ok) return null;
|
|
40
|
+
const value = await res.json();
|
|
41
|
+
return value && typeof value === "object" ? value : {};
|
|
40
42
|
} catch {
|
|
41
|
-
return
|
|
43
|
+
return null;
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
function homePages(targets, extensionId) {
|
|
@@ -94,7 +96,7 @@ async function ensureExtensionReady(target, options) {
|
|
|
94
96
|
continue;
|
|
95
97
|
}
|
|
96
98
|
action = "opened";
|
|
97
|
-
opened = await openHome(cdpPort, extensionId) || opened;
|
|
99
|
+
opened = Boolean(await openHome(cdpPort, extensionId)) || opened;
|
|
98
100
|
await sleep(1500);
|
|
99
101
|
} else {
|
|
100
102
|
action = "pruned";
|
|
@@ -149,20 +151,47 @@ async function ensureExtensionReady(target, options) {
|
|
|
149
151
|
if (action === "pruned" && (health.status !== "PASS" || after !== 1)) {
|
|
150
152
|
const listing = await jsonList(cdpPort);
|
|
151
153
|
if (listing.ok) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
await sleep(500);
|
|
158
|
-
opened = await openHome(cdpPort, extensionId) || opened;
|
|
154
|
+
const existingHomeIds = new Set(
|
|
155
|
+
homePages(listing.targets, extensionId).map((home) => String(home.id))
|
|
156
|
+
);
|
|
157
|
+
const replacement = await openHome(cdpPort, extensionId);
|
|
158
|
+
opened = Boolean(replacement) || opened;
|
|
159
159
|
await sleep(1500);
|
|
160
|
-
const
|
|
161
|
-
if (!
|
|
162
|
-
return base({
|
|
160
|
+
const replacementListing = await jsonList(cdpPort);
|
|
161
|
+
if (!replacementListing.ok) {
|
|
162
|
+
return base({
|
|
163
|
+
extensionId,
|
|
164
|
+
opened,
|
|
165
|
+
action,
|
|
166
|
+
homeTabs: { before, closed, after },
|
|
167
|
+
reasonCode: "cdp-unreachable"
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const replacementHomes = homePages(replacementListing.targets, extensionId);
|
|
171
|
+
const replacementId = replacement?.id && replacementHomes.some((home) => home.id === replacement.id) ? String(replacement.id) : replacementHomes.find((home) => !existingHomeIds.has(String(home.id)))?.id;
|
|
172
|
+
if (replacementId) {
|
|
173
|
+
action = "reopened";
|
|
174
|
+
for (const home of replacementHomes) {
|
|
175
|
+
if (String(home.id) === replacementId) continue;
|
|
176
|
+
await closeTab(cdpPort, String(home.id));
|
|
177
|
+
closed += 1;
|
|
178
|
+
}
|
|
179
|
+
await sleep(500);
|
|
180
|
+
const relisted = await jsonList(cdpPort);
|
|
181
|
+
if (!relisted.ok) {
|
|
182
|
+
return base({
|
|
183
|
+
extensionId,
|
|
184
|
+
opened,
|
|
185
|
+
action,
|
|
186
|
+
homeTabs: { before, closed, after },
|
|
187
|
+
reasonCode: "cdp-unreachable"
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
after = homePages(relisted.targets, extensionId).length;
|
|
191
|
+
health = await checkHealth();
|
|
192
|
+
} else {
|
|
193
|
+
after = replacementHomes.length;
|
|
163
194
|
}
|
|
164
|
-
after = homePages(relisted.targets, extensionId).length;
|
|
165
|
-
health = await checkHealth();
|
|
166
195
|
}
|
|
167
196
|
}
|
|
168
197
|
let slotTitle;
|
package/dist/cli-commands.js
CHANGED
|
@@ -18,6 +18,7 @@ const SPEC = {
|
|
|
18
18
|
{ name: "actions", desc: "List runnable recipe actions", flags: ["--json", "--categories", "--category", "--action", "--library"] },
|
|
19
19
|
{ name: "doctor", desc: "Check harness/orchestration health", flags: ["--json", "--target", "--adapter", "--runtime-dir", "--expect-live", "--print-ready", "--cdp-port", "--device"] },
|
|
20
20
|
{ name: "run", desc: "Execute a proof recipe (path or library name, e.g. run perps.smoke)", args: ["recipe.json|name"], flags: ["--list", "--device"] },
|
|
21
|
+
{ name: "execution-template", desc: "Discover and materialize shared agent checklists", args: ["list", "materialize", "lint", "new"], flags: ["--dir", "--domain-dir", "--project-worker", "--project-name", "--package-templates", "--package-id", "--flow", "--run-mode", "--platform", "--domain", "--id", "--provenance", "--include-shadowed", "--no-include-shadowed", "--title", "--force", "--json"] },
|
|
21
22
|
{ name: "recipe-quality", desc: "Build the recipe-quality artifact from compact JSON", args: ["build"], flags: ["--input", "--output", "--json"] },
|
|
22
23
|
{ name: "interactive", aliases: ["menu"], desc: "Interactive command menu" },
|
|
23
24
|
{ name: "prepare", desc: "Install harness (+ optional validate)", flags: ["--target", "--runtime-dir", "--json"] },
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { handleRecipeQuality } from "./commands/recipe-quality.js";
|
|
|
20
20
|
import { handleStatus } from "./commands/status.js";
|
|
21
21
|
import { handleCheck } from "./commands/check.js";
|
|
22
22
|
import { handleChecklist } from "./commands/checklist.js";
|
|
23
|
+
import { handleExecutionTemplate } from "./commands/execution-template.js";
|
|
23
24
|
import { handleLast } from "./commands/last.js";
|
|
24
25
|
import { parseArgs, targetPath } from "./commands/parse-args.js";
|
|
25
26
|
const COMMANDS = {
|
|
@@ -121,6 +122,7 @@ async function main(argv) {
|
|
|
121
122
|
if (command === "recipe-quality") return handleRecipeQuality(argv.slice(1));
|
|
122
123
|
if (command === "check") return handleCheck(argv.slice(1));
|
|
123
124
|
if (command === "checklist") return handleChecklist(argv.slice(1));
|
|
125
|
+
if (command === "execution-template") return handleExecutionTemplate(argv.slice(1));
|
|
124
126
|
if (command === "last") return handleLast(parseArgs(argv.slice(1), command));
|
|
125
127
|
const handler = COMMANDS[command];
|
|
126
128
|
if (!handler) throw new Error(`Unknown command: ${command}`);
|
package/dist/command-contract.js
CHANGED
|
@@ -88,6 +88,32 @@ const PUBLIC_COMMAND_CONTRACTS = {
|
|
|
88
88
|
],
|
|
89
89
|
minimumPositionals: 2
|
|
90
90
|
},
|
|
91
|
+
"execution-template": {
|
|
92
|
+
usage: "mm-harness execution-template <list|materialize|lint|new> [target] [options]",
|
|
93
|
+
options: options(HELP, JSON, {
|
|
94
|
+
"--dir": value(),
|
|
95
|
+
"--domain-dir": value(),
|
|
96
|
+
"--project-worker": value(),
|
|
97
|
+
"--project-name": value(),
|
|
98
|
+
"--package-templates": value(),
|
|
99
|
+
"--package-id": value(),
|
|
100
|
+
"--flow": value(),
|
|
101
|
+
"--run-mode": value(["autonomous", "interactive", "validation"]),
|
|
102
|
+
"--platform": value(),
|
|
103
|
+
"--domain": value(),
|
|
104
|
+
"--id": value(),
|
|
105
|
+
"--provenance": value(),
|
|
106
|
+
"--include-shadowed": bool(),
|
|
107
|
+
"--no-include-shadowed": bool(),
|
|
108
|
+
"--title": value(),
|
|
109
|
+
"--force": bool()
|
|
110
|
+
}),
|
|
111
|
+
positionals: [
|
|
112
|
+
{ label: "action", choices: ["list", "materialize", "lint", "new"] }
|
|
113
|
+
],
|
|
114
|
+
minimumPositionals: 1,
|
|
115
|
+
variadic: { label: "target", validate: (value2) => value2.length > 0 }
|
|
116
|
+
},
|
|
91
117
|
actions: {
|
|
92
118
|
options: options(HELP, JSON, TARGET, ADAPTER, ADAPTER_OR_MOBILE_PLATFORM, {
|
|
93
119
|
"--action": value(),
|
|
@@ -360,6 +386,37 @@ function validatePublicInvocation(argv, examples = {}) {
|
|
|
360
386
|
);
|
|
361
387
|
}
|
|
362
388
|
}
|
|
389
|
+
if (name === "execution-template") {
|
|
390
|
+
const action = positionals[0];
|
|
391
|
+
const validAction = ["list", "materialize", "lint", "new"].includes(action ?? "");
|
|
392
|
+
const targetCount = Math.max(0, positionals.length - 1);
|
|
393
|
+
if (validAction && action === "list" && targetCount > 0) {
|
|
394
|
+
return usageFailure(
|
|
395
|
+
"CLI_EXCESS_POSITIONAL",
|
|
396
|
+
name,
|
|
397
|
+
`execution-template list does not accept positional '${positionals[1]}'.`,
|
|
398
|
+
contract,
|
|
399
|
+
examples
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
if (validAction && (action === "materialize" || action === "lint" || action === "new") && targetCount === 0) {
|
|
403
|
+
return missingPositionalFailure(
|
|
404
|
+
name,
|
|
405
|
+
`execution-template ${action} requires <target>.`,
|
|
406
|
+
contract,
|
|
407
|
+
examples
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
if (validAction && targetCount > 1) {
|
|
411
|
+
return usageFailure(
|
|
412
|
+
"CLI_EXCESS_POSITIONAL",
|
|
413
|
+
name,
|
|
414
|
+
`unexpected positional '${positionals[2]}'; execution-template ${action} accepts one <target>.`,
|
|
415
|
+
contract,
|
|
416
|
+
examples
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
363
420
|
if (contract.leadingPositionals && !contract.requiredUnless?.some((option) => seenOptions.has(option)) && tokens.slice(0, contract.leadingPositionals).some((argument) => !argument || argument.startsWith("-"))) {
|
|
364
421
|
const missing = contract.positionals?.[0]?.label ?? "argument";
|
|
365
422
|
return missingPositionalFailure(name, `${name} requires <${missing}> first.`, contract, examples);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
const require2 = createRequire(import.meta.url);
|
|
4
|
+
async function handleExecutionTemplate(argv) {
|
|
5
|
+
let entrypoint;
|
|
6
|
+
try {
|
|
7
|
+
entrypoint = require2.resolve(
|
|
8
|
+
"@farmslot/agent-runtime/scripts/execution-template-cli.mjs"
|
|
9
|
+
);
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error(
|
|
12
|
+
`mm-harness execution-template: installed @farmslot/agent-runtime does not expose the catalog command: ${error instanceof Error ? error.message : String(error)}`
|
|
13
|
+
);
|
|
14
|
+
return 1;
|
|
15
|
+
}
|
|
16
|
+
const result = spawnSync(process.execPath, [entrypoint, ...argv], {
|
|
17
|
+
env: process.env,
|
|
18
|
+
stdio: "inherit"
|
|
19
|
+
});
|
|
20
|
+
if (result.error) {
|
|
21
|
+
console.error(`mm-harness execution-template: ${result.error.message}`);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
return result.status ?? 1;
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
handleExecutionTemplate
|
|
28
|
+
};
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { captureHelperSupportsRecordSessionSnapshots } from "../recording-target.js";
|
|
22
22
|
import { startRecipeRecording, stopRecipeRecording } from "../run-recording.js";
|
|
23
23
|
import { validateMetaMaskActionInputs } from "../metamask-action-validation.js";
|
|
24
|
+
import { gitLibraryProvenance } from "../library-provenance.js";
|
|
24
25
|
import {
|
|
25
26
|
beginRunDiagnostics,
|
|
26
27
|
finishRunDiagnostics
|
|
@@ -655,14 +656,22 @@ async function resolveMetaMaskLibrarySources(libraryEntry, recipePath) {
|
|
|
655
656
|
if (!sources.some((source) => path.resolve(source.root) === canonicalRoot)) {
|
|
656
657
|
sources.push({ name: "metamask", root: canonicalRoot });
|
|
657
658
|
}
|
|
658
|
-
return
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
659
|
+
return Promise.all(
|
|
660
|
+
sources.map(async (source) => {
|
|
661
|
+
const isBundled = source.name === "metamask";
|
|
662
|
+
const detected = isBundled ? {} : await gitLibraryProvenance(source.root);
|
|
663
|
+
return {
|
|
664
|
+
...source,
|
|
665
|
+
provenance: {
|
|
666
|
+
kind: isBundled ? "bundled" : "library",
|
|
667
|
+
trust: isBundled ? "trusted" : "unknown",
|
|
668
|
+
name: source.name ?? path.basename(source.root),
|
|
669
|
+
...detected,
|
|
670
|
+
...source.provenance
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
})
|
|
674
|
+
);
|
|
666
675
|
}
|
|
667
676
|
function synthesizeOneNodeRecipe(action, args) {
|
|
668
677
|
return {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
async function gitLibraryProvenance(root) {
|
|
5
|
+
try {
|
|
6
|
+
const { stdout: tracked } = await execFileAsync("git", ["-C", root, "ls-files", "--", "."], {
|
|
7
|
+
encoding: "utf8",
|
|
8
|
+
timeout: 5e3
|
|
9
|
+
});
|
|
10
|
+
if (!tracked.trim()) return {};
|
|
11
|
+
const [{ stdout: revision }, { stdout: status }] = await Promise.all([
|
|
12
|
+
execFileAsync("git", ["-C", root, "rev-parse", "HEAD"], {
|
|
13
|
+
encoding: "utf8",
|
|
14
|
+
timeout: 5e3
|
|
15
|
+
}),
|
|
16
|
+
execFileAsync(
|
|
17
|
+
"git",
|
|
18
|
+
["-C", root, "status", "--porcelain=v1", "--untracked-files=normal", "--", "."],
|
|
19
|
+
{
|
|
20
|
+
encoding: "utf8",
|
|
21
|
+
timeout: 5e3
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
]);
|
|
25
|
+
const trimmedRevision = revision.trim();
|
|
26
|
+
return trimmedRevision ? { revision: trimmedRevision, dirty: status.trim().length > 0 } : {};
|
|
27
|
+
} catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
gitLibraryProvenance
|
|
33
|
+
};
|
package/dist/mm-harness-cli.js
CHANGED
|
@@ -77,6 +77,40 @@ Example:
|
|
|
77
77
|
mm-harness checklist mark temp/tasks/recipe-cook/<task> complete --mark-last
|
|
78
78
|
mm-harness checklist closeout temp/tasks/recipe-cook/<task> --share`
|
|
79
79
|
},
|
|
80
|
+
{
|
|
81
|
+
name: "execution-template",
|
|
82
|
+
summary: "Discover, validate, and materialize shared agent checklists.",
|
|
83
|
+
example: "mm-harness execution-template list --package-templates <path> --json",
|
|
84
|
+
helpText: `mm-harness execution-template <list|materialize|lint|new> [options]
|
|
85
|
+
|
|
86
|
+
Shared Markdown checklist catalog used by direct and orchestrated workflows.
|
|
87
|
+
Sources use the flow-tree shape <root>/<flow>/<variant>.md.
|
|
88
|
+
|
|
89
|
+
list List compatible templates and portable source provenance.
|
|
90
|
+
materialize Select one template, copy its immutable snapshot, and optionally
|
|
91
|
+
write a provenance record.
|
|
92
|
+
lint Validate one template file or flow-tree directory.
|
|
93
|
+
new Create a minimal starter template.
|
|
94
|
+
|
|
95
|
+
Common source/filter options:
|
|
96
|
+
--dir <path> Custom flow-tree source (repeatable)
|
|
97
|
+
--domain-dir <domain=path> Domain-scoped team source (repeatable)
|
|
98
|
+
--package-templates <path> Canonical package flow-tree root
|
|
99
|
+
--package-id <id> Source label for the package root
|
|
100
|
+
--project-worker <path> Project template directory
|
|
101
|
+
--project-name <name> Source label for project templates
|
|
102
|
+
--flow <flow> Exact flow
|
|
103
|
+
--platform <platform> Exact platform
|
|
104
|
+
--run-mode <mode> autonomous|interactive|validation
|
|
105
|
+
--domain <domain> Exact domain
|
|
106
|
+
--id <id> Exact template id
|
|
107
|
+
--json Machine-readable output
|
|
108
|
+
|
|
109
|
+
Materialize:
|
|
110
|
+
mm-harness execution-template materialize <output> --flow fix-bug \\
|
|
111
|
+
--platform mobile --run-mode autonomous --id fix-bug/autonomous.mobile \\
|
|
112
|
+
--package-templates <path> --provenance <path> --json`
|
|
113
|
+
},
|
|
80
114
|
{
|
|
81
115
|
name: "actions",
|
|
82
116
|
summary: "Discover typed single operations and their fields.",
|
|
@@ -552,7 +586,7 @@ const HELP_GROUPS = [
|
|
|
552
586
|
{
|
|
553
587
|
title: "DISCOVER",
|
|
554
588
|
blurb: "discover atomic actions and reusable recipes (--json is the agent-primary form)",
|
|
555
|
-
commands: ["actions", "call"]
|
|
589
|
+
commands: ["actions", "call", "execution-template"]
|
|
556
590
|
},
|
|
557
591
|
{
|
|
558
592
|
title: "PROVE",
|
|
@@ -69,12 +69,17 @@ async function activateSemanticControl(page, selector) {
|
|
|
69
69
|
export async function openHome(page, timeoutMs) {
|
|
70
70
|
const home = dataTestId('bottom-nav-home');
|
|
71
71
|
const selectedHome = `${home}[aria-current="page"]`;
|
|
72
|
+
const legacyHome = dataTestId('account-overview__asset-tab');
|
|
73
|
+
const selectedLegacyHome = `${legacyHome}[aria-selected="true"]`;
|
|
72
74
|
const deadline = Date.now() + timeoutMs;
|
|
73
75
|
const steps = [];
|
|
74
76
|
let pendingActivation;
|
|
75
77
|
|
|
76
78
|
while (Date.now() < deadline) {
|
|
77
|
-
if (
|
|
79
|
+
if (
|
|
80
|
+
(await hasVisibleSelector(page, selectedHome)) ||
|
|
81
|
+
(await hasVisibleSelector(page, selectedLegacyHome))
|
|
82
|
+
) {
|
|
78
83
|
return { method: 'visible-ui', href: await currentHref(page), steps };
|
|
79
84
|
}
|
|
80
85
|
const href = await currentHref(page);
|
|
@@ -83,12 +88,17 @@ export async function openHome(page, timeoutMs) {
|
|
|
83
88
|
await pauseForUi(page);
|
|
84
89
|
continue;
|
|
85
90
|
}
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const homeControl = (await hasVisibleSelector(page, home))
|
|
92
|
+
? home
|
|
93
|
+
: (await hasVisibleSelector(page, legacyHome))
|
|
94
|
+
? legacyHome
|
|
95
|
+
: undefined;
|
|
96
|
+
if (homeControl) {
|
|
97
|
+
if (pendingActivation?.selector !== homeControl) pendingActivation = undefined;
|
|
88
98
|
if (!pendingActivation) {
|
|
89
|
-
await activateSemanticControl(page,
|
|
90
|
-
steps.push(
|
|
91
|
-
pendingActivation = { selector:
|
|
99
|
+
await activateSemanticControl(page, homeControl);
|
|
100
|
+
steps.push(homeControl);
|
|
101
|
+
pendingActivation = { selector: homeControl, href };
|
|
92
102
|
}
|
|
93
103
|
await pauseForUi(page);
|
|
94
104
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@farmslot/agent-runtime": "^0.
|
|
22
|
+
"@farmslot/agent-runtime": "^0.4.0",
|
|
23
23
|
"@farmslot/handoff": "^0.3.1",
|
|
24
|
-
"@farmslot/protocol": "^0.
|
|
24
|
+
"@farmslot/protocol": "^0.13.0",
|
|
25
25
|
"@farmslot/recipe-harness": "^0.10.0",
|
|
26
26
|
"commander": "^12.0.0",
|
|
27
27
|
"es-module-lexer": "2.3.1",
|
package/scripts/completions.sh
CHANGED
|
@@ -29,7 +29,7 @@ _mmh_bin() {
|
|
|
29
29
|
return 1
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
_mmh_commands="launch stop logs debug fixtures actions call run doctor check checklist recipe-quality install verify cleanup completions"
|
|
32
|
+
_mmh_commands="launch stop logs debug fixtures actions call run doctor check checklist execution-template recipe-quality install verify cleanup completions"
|
|
33
33
|
|
|
34
34
|
# Per-command flags (static, from the mm-harness surface).
|
|
35
35
|
_mmh_flags_for() {
|
|
@@ -40,6 +40,7 @@ _mmh_flags_for() {
|
|
|
40
40
|
debug) printf '%s' "--worker --dev-menu --adapter --target --json" ;;
|
|
41
41
|
fixtures) printf '%s' "--from --dev --force --fixture --adapter --target --json" ;;
|
|
42
42
|
checklist) printf '%s' "" ;;
|
|
43
|
+
execution-template) printf '%s' "--dir --domain-dir --project-worker --project-name --package-templates --package-id --flow --run-mode --platform --domain --id --provenance --include-shadowed --no-include-shadowed --title --force --json" ;;
|
|
43
44
|
actions) printf '%s' "--adapter --action --kind --raw --action-manifest --target --json" ;;
|
|
44
45
|
call) printf '%s' "--list --arg --adapter --target --artifacts-dir --action-manifest --heal --json" ;;
|
|
45
46
|
run) printf '%s' "--list --describe --plan --adapter --artifacts-dir --target --library --cdp-port --heal --record-video --json" ;;
|