@deeeed/metamask-harness 0.92.7 → 0.92.9

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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.92.9 - 2026-10-16
6
+
7
+ ### Changed
8
+
9
+ - Use recipe-cli 0.20.0 for shared review commands while preserving MetaMask reference discovery, missing-reference diagnostics and parity rules through the existing resolver and checklist rule formatter.
10
+
11
+ ## 0.92.8 - 2026-10-16
12
+
13
+ ### Changed
14
+
15
+ - Declare existing task gates, learning closeout, review rules and opt-in recipe advice for Farmslot task, review and recipe quality commands. Pin runtime 0.25.1, recipe-cli 0.19.1 and adapter-rn 0.22.16 so task policy retains the installed provider and its dependencies.
16
+
5
17
  ## 0.92.7 - 2026-10-15
6
18
 
7
19
  ### Changed
package/README.md CHANGED
@@ -10,6 +10,15 @@ and runtime paths are detected automatically.
10
10
  The generic graph engine and evidence schemas live in [Farmslot](https://farmslot.io) packages.
11
11
  `mm-harness` owns MetaMask runtime control and domain capabilities.
12
12
 
13
+ ## Project task helpers
14
+
15
+ Registered projects can use `farmslot task init`, `mark`, `verify` and `closeout`,
16
+ `farmslot review checklist` and `domain`, and `farmslot recipe quality`.
17
+ The MetaMask provider supplies diff-check gates, learning destinations, review
18
+ rules, parity runtimes and opt-in advice. Select the registered project at task
19
+ initialization; its tooling and policy are retained with the task. See the
20
+ [Farmslot command reference](https://farmslot.io/docs/reference/recipe-cli).
21
+
13
22
  ## Daily and release QA
14
23
 
15
24
  The same recipes can validate yesterday's domain changes together or a release
@@ -402,14 +411,14 @@ into markdown, so fences cannot break.
402
411
 
403
412
  ```bash
404
413
  # Which team library owns the change (declared --domain wins, else owned-paths.json).
405
- mm-harness domain
414
+ farmslot review domain --project <project>
406
415
 
407
416
  # The review guide: base review + the library's anti-pattern families and parity rule.
408
- mm-harness help review --domain perps
417
+ farmslot review checklist --project <project> --domain perps
409
418
 
410
419
  # A checklist the mark shim can track: Setup, Base review, Domain patterns, Parity, Verdict.
411
- mm-harness review checklist --domain perps --out temp/tasks/review/TAT-1/CHECKLIST.md
412
- mm-harness review checklist --domain perps --since <last-reviewed-sha> # incremental re-review
420
+ farmslot review checklist --project <project> --domain perps --out temp/tasks/review/TAT-1/CHECKLIST.md
421
+ farmslot review checklist --project <project> --domain perps --since <last-reviewed-sha> # incremental re-review
413
422
 
414
423
  # Where this machine keeps libraries and the other platform's checkout (outside any repo).
415
424
  mm-harness config set references.extension ~/dev/metamask-extension
@@ -6,6 +6,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
6
6
  import { defineAdapter } from "@farmslot/adapter-sdk";
7
7
  import { indexArtifactManifest, isRecipeExecution, usageError, writeContainedArtifact } from "@farmslot/recipe-cli/harness";
8
8
  import { validatePackPortability } from "@farmslot/protocol/node/pack-portability";
9
+ import { helperCommandOptions } from "../../provider-helpers.js";
9
10
  async function createBackendProvider(context) {
10
11
  if (!context.project?.root || !path.isAbsolute(context.project.root)) {
11
12
  throw usageError("terminal-backend requires a registered project root.");
@@ -136,6 +137,7 @@ async function createBackendProvider(context) {
136
137
  if (executing) runtime.resolveSlotPorts();
137
138
  return {
138
139
  runtime,
140
+ commandOptions: helperCommandOptions,
139
141
  ...owner ? { cancel: cleanup, finalize } : {}
140
142
  };
141
143
  }
@@ -141,6 +141,9 @@ function checkDiffGateReady(taskDir, step, parentChecklist) {
141
141
  return true;
142
142
  }
143
143
  if (!checklistStepRequiresDiffPass(checklist, stepNumber)) return true;
144
+ return checkDiffSummaryReady(taskDir, step);
145
+ }
146
+ function checkDiffSummaryReady(taskDir, step) {
144
147
  const summaryPath = path.join(
145
148
  taskDir,
146
149
  "artifacts",
@@ -232,5 +235,8 @@ async function handleChecklist(argv) {
232
235
  return status;
233
236
  }
234
237
  export {
235
- handleChecklist
238
+ checkDiffSummaryReady,
239
+ handleChecklist,
240
+ runCloseout,
241
+ teachRecipeCompletion
236
242
  };
@@ -0,0 +1,53 @@
1
+ import { checkDiffSummaryReady, runCloseout, teachRecipeCompletion } from "./commands/checklist.js";
2
+ import {
3
+ BASE_REVIEW_STEPS,
4
+ REVIEW_ADAPTERS,
5
+ configPath,
6
+ parityAdapter,
7
+ parityReviewSteps,
8
+ readConfig,
9
+ referenceHint,
10
+ resolveReference
11
+ } from "./review/knowledge.js";
12
+ const task = {
13
+ stepGates: [{ label: /mm-harness check diff/u, ready: checkDiffSummaryReady }],
14
+ closeout: runCloseout,
15
+ beforeComplete: (taskDir) => teachRecipeCompletion(taskDir, "complete")
16
+ };
17
+ const review = {
18
+ baseRules: BASE_REVIEW_STEPS.join("\n"),
19
+ runtimeIds: [...REVIEW_ADAPTERS, "unscoped"],
20
+ parityRuntimeIds: { mobile: "extension", extension: "mobile" },
21
+ parity: ({ runtime, target, hasParityGuide }) => {
22
+ const adapter = REVIEW_ADAPTERS.find((id) => id === runtime) ?? "unscoped";
23
+ const parity = parityAdapter(adapter);
24
+ const reference = parity ? resolveReference(parity, { target, config: readConfig(configPath()) }) : void 0;
25
+ const referenceMissing = parity && !reference ? `no ${parity} checkout found (${referenceHint(parity)})` : void 0;
26
+ return {
27
+ ...reference ? { reference } : {},
28
+ ...referenceMissing ? { referenceMissing } : {},
29
+ steps: parityReviewSteps({ adapter, reference, referenceMissing, hasParityGuide })
30
+ };
31
+ }
32
+ };
33
+ async function recipeAdvice(options, mode) {
34
+ const { handleRecipeAdvice } = await import("./commands/recipe-advice.js");
35
+ return handleRecipeAdvice(options, mode);
36
+ }
37
+ const recipeQuality = {
38
+ subcommands: {
39
+ plan: (options) => recipeAdvice(options, "plan"),
40
+ advise: (options) => recipeAdvice(options, "review"),
41
+ "advisor-status": (options) => recipeAdvice(options, "status")
42
+ },
43
+ subcommandOptions: {
44
+ names: ["advisor", "advisorModel", "advisorStages", "recipe", "task", "evidence", "adapter", "library", "params"],
45
+ message: "Advice options require the advise subcommand.",
46
+ userAction: "farmslot recipe quality advise --recipe <recipe.json> --task <TASK.md> --advisor <provider>"
47
+ },
48
+ missingAction: "Use build, plan, advise or advisor-status."
49
+ };
50
+ const helperCommandOptions = { task, review, recipeQuality };
51
+ export {
52
+ helperCommandOptions
53
+ };
package/dist/provider.js CHANGED
@@ -21,6 +21,7 @@ import { providerHost } from "./host.js";
21
21
  import { configureProviderReadiness, doctorOptions } from "./provider-doctor.js";
22
22
  import { statusOptions, stopOptions } from "./provider-lifecycle.js";
23
23
  import { createLogsOptions } from "./provider-logs.js";
24
+ import { helperCommandOptions } from "./provider-helpers.js";
24
25
  import { createBackendProvider } from "./adapters/terminal-backend/provider.js";
25
26
  import { providerHost as providerHost2 } from "./host.js";
26
27
  import { PUBLIC_COMMANDS } from "./command-contract.js";
@@ -69,7 +70,7 @@ async function createProvider(context) {
69
70
  return {
70
71
  runtime,
71
72
  engine: metaMaskEngine,
72
- commandOptions: { status: statusOptions, stop: stopOptions, doctor: doctorOptions, logs: createLogsOptions(runtime) },
73
+ commandOptions: { ...helperCommandOptions, status: statusOptions, stop: stopOptions, doctor: doctorOptions, logs: createLogsOptions(runtime) },
73
74
  ...executes ? {
74
75
  async cancel() {
75
76
  await abortRunMainnetOrders(context.target.value);
@@ -445,6 +445,18 @@ function parityAdapter(adapter) {
445
445
  if (adapter === "extension") return "mobile";
446
446
  return void 0;
447
447
  }
448
+ function parityReviewSteps(input) {
449
+ const parity = parityAdapter(input.adapter);
450
+ if (input.reference && parity) {
451
+ return [
452
+ `For each touched screen, hook, or formatter, compare it with its ${parity} counterpart at ${input.reference.root}` + (input.hasParityGuide ? " using review/parity.md" : "") + `; record every divergence, and apply the library's parity rule to decide which platform must change (the reference platform is never changed to match the other).`
453
+ ];
454
+ }
455
+ if (parity) {
456
+ return [`Parity with ${parity}: not checked \u2014 ${input.referenceMissing ?? "no reference checkout"}. Record this in the verdict.`];
457
+ }
458
+ return ["Parity: core changes are consumed by both mobile and extension; confirm both consumers still compile against the public surface."];
459
+ }
448
460
  function renderReviewChecklist(input) {
449
461
  const diffRange = input.since ? `${input.since}..HEAD` : `${input.base}...HEAD`;
450
462
  const lines = [];
@@ -484,16 +496,7 @@ function renderReviewChecklist(input) {
484
496
  }
485
497
  }
486
498
  lines.push("", "## Parity");
487
- const parity = parityAdapter(input.adapter);
488
- if (input.reference && parity) {
489
- item(
490
- `For each touched screen, hook, or formatter, compare it with its ${parity} counterpart at ${input.reference.root}` + (input.knowledge?.parity ? " using review/parity.md" : "") + `; record every divergence, and apply the library's parity rule to decide which platform must change (the reference platform is never changed to match the other).`
491
- );
492
- } else if (parity) {
493
- item(`Parity with ${parity}: not checked \u2014 ${input.referenceMissing ?? "no reference checkout"}. Record this in the verdict.`);
494
- } else {
495
- item("Parity: core changes are consumed by both mobile and extension; confirm both consumers still compile against the public surface.");
496
- }
499
+ for (const step2 of parityReviewSteps({ ...input, hasParityGuide: Boolean(input.knowledge?.parity) })) item(step2);
497
500
  lines.push("", "## Verdict");
498
501
  item(VERDICT_STEP);
499
502
  return `${lines.join("\n")}
@@ -555,6 +558,7 @@ export {
555
558
  loadOwnedPaths,
556
559
  matchOwnedFiles,
557
560
  parityAdapter,
561
+ parityReviewSteps,
558
562
  parseAdvisorSettings,
559
563
  parseLibraryPathEnv,
560
564
  parseSections,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.92.7",
3
+ "version": "0.92.9",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -21,15 +21,15 @@
21
21
  "check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
22
22
  },
23
23
  "dependencies": {
24
- "@farmslot/adapter-node": "0.1.26",
25
- "@farmslot/adapter-rn": "0.22.13",
26
- "@farmslot/adapter-sdk": "0.15.0",
27
- "@farmslot/adapter-web": "0.10.5",
28
- "@farmslot/agent-runtime": "0.23.3",
24
+ "@farmslot/adapter-node": "0.1.27",
25
+ "@farmslot/adapter-rn": "0.22.16",
26
+ "@farmslot/adapter-sdk": "0.15.1",
27
+ "@farmslot/adapter-web": "0.10.6",
28
+ "@farmslot/agent-runtime": "0.25.1",
29
29
  "@farmslot/handoff": "^0.3.1",
30
- "@farmslot/protocol": "0.47.0",
31
- "@farmslot/recipe-cli": "0.18.4",
32
- "@farmslot/recipe-runner": "0.37.0",
30
+ "@farmslot/protocol": "0.48.0",
31
+ "@farmslot/recipe-cli": "0.20.0",
32
+ "@farmslot/recipe-runner": "0.37.1",
33
33
  "agent-device": "0.19.3",
34
34
  "commander": "^12.0.0",
35
35
  "esbuild": "0.28.1",