@deeeed/metamask-harness 0.7.4 → 0.7.5

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 (51) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/adapters/core/cleanup.sh +0 -0
  3. package/adapters/core/inject.sh +0 -0
  4. package/adapters/extension/cleanup.mjs +0 -0
  5. package/adapters/extension/ensure-browser.sh +0 -0
  6. package/adapters/extension/inject.mjs +0 -0
  7. package/adapters/extension/launch-browser.cjs +0 -0
  8. package/adapters/extension/launch.sh +0 -0
  9. package/adapters/extension/live.sh +0 -0
  10. package/adapters/extension/readiness.mjs +0 -0
  11. package/adapters/extension/reattach.sh +0 -0
  12. package/adapters/extension/refresh-build.sh +0 -0
  13. package/adapters/extension/seed-fixture.sh +0 -0
  14. package/adapters/extension/sidepanel-toggle.sh +0 -0
  15. package/adapters/extension/snapshot-dist.sh +0 -0
  16. package/adapters/extension/start-watch.sh +0 -0
  17. package/adapters/extension/verify.sh +0 -0
  18. package/adapters/extension/wallet-fixture-state.cjs +0 -0
  19. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +0 -0
  20. package/adapters/mobile/bridge-runtime/setup-wallet.sh +0 -0
  21. package/adapters/mobile/cleanup.sh +0 -0
  22. package/adapters/mobile/inject.sh +0 -0
  23. package/adapters/mobile/lib/metro-listener.sh +0 -0
  24. package/adapters/mobile/lib/tmux-viewer.sh +0 -0
  25. package/adapters/mobile/open-device.sh +0 -0
  26. package/adapters/mobile/prewarm-bundle.sh +0 -0
  27. package/adapters/mobile/start-metro.sh +0 -0
  28. package/adapters/mobile/stop-metro.sh +0 -0
  29. package/adapters/mobile/verify.sh +0 -0
  30. package/adapters/mobile/wait-for-bridge.sh +0 -0
  31. package/adapters/mobile/yarn-setup.sh +0 -0
  32. package/adapters/shared/activate-repo-node.sh +0 -0
  33. package/adapters/shared/activate-repo-ruby.sh +0 -0
  34. package/adapters/shared/cli-ux.sh +0 -0
  35. package/adapters/shared/ensure-runner-deps.sh +0 -0
  36. package/adapters/shared/harness-path.sh +0 -0
  37. package/adapters/shared/hash-helpers.sh +0 -0
  38. package/adapters/shared/json-field.sh +0 -0
  39. package/adapters/shared/open-log-window.sh +0 -0
  40. package/adapters/shared/reap-checkout-metros.sh +0 -0
  41. package/adapters/shared/resolve-farmslot-ports.mjs +0 -0
  42. package/adapters/shared/resolve-farmslot-ports.sh +0 -0
  43. package/adapters/shared/resolve-slot-ports.mjs +0 -0
  44. package/adapters/shared/resolve-slot-ports.sh +0 -0
  45. package/adapters/shared/sync-wallet-fixture.sh +0 -0
  46. package/adapters/shared/tmux-session.sh +0 -0
  47. package/dist/adapters/extension/ensure-ready.js +38 -11
  48. package/dist/commands/launch/index.js +8 -0
  49. package/package.json +2 -2
  50. package/scripts/completions.sh +0 -0
  51. package/scripts/install-completions.sh +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.5 - 2026-07-07
4
+
5
+ ### Fixed
6
+ - **`launch --verify` converges duplicate extension home tabs instead of failing prepare forever.** A second bare `home.html` tab can appear beside the operator's slot-titled one outside the harness's control (the extension opens its own tab after the build-freeze reload), and the live verify health gate requires exactly one home tab — but nothing in launch/verify ever collapsed duplicates (`ensureExtensionReady` was only reachable via the retired `ensure-ready` verb), so every preflight retry recounted two tabs and failed. `launch --verify` (extension, with a CDP port) now runs the convergence before the live verify phase.
7
+ - **Convergence keeps the operator's tab.** With multiple home tabs, `ensureExtensionReady` now prunes the extras keeping the preferred tab — attached (another client is driving it) over custom slot title (`<slot-id> — MetaMask`, how operators tell which agent owns a browser) over first listed — instead of closing all and reopening fresh, which discarded the slot title. The deterministic close-all + fresh-open remains as a one-shot fallback when the kept tab fails the health check, and a failed re-listing during the fallback reports `cdp-unreachable` instead of a stale tab count.
8
+
9
+ ### Changed
10
+ - **`EnsureReadyAction` gains `pruned`** — extras were closed keeping the preferred tab; `reopened` now specifically means the pruned keeper failed the health check and one fresh tab was reopened.
11
+
3
12
  ## 0.7.4 - 2026-07-07
4
13
 
5
14
  ### Added
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -47,6 +47,12 @@ function homePages(targets, extensionId) {
47
47
  (t) => t.type === "page" && typeof t.url === "string" && t.url.startsWith(prefix) && t.url.includes("/home.html") && t.id
48
48
  );
49
49
  }
50
+ function pickHomeKeeper(homes) {
51
+ const attached = homes.filter((t) => typeof t.webSocketDebuggerUrl !== "string");
52
+ const pool = attached.length > 0 ? attached : homes;
53
+ const marked = pool.find((t) => typeof t.title === "string" && t.title.trim() !== "" && t.title.trim() !== "MetaMask");
54
+ return marked ?? pool[0];
55
+ }
50
56
  async function ensureExtensionReady(target, options) {
51
57
  const resolved = path.resolve(target);
52
58
  const { cdpPort } = options;
@@ -91,14 +97,14 @@ async function ensureExtensionReady(target, options) {
91
97
  opened = await openHome(cdpPort, extensionId) || opened;
92
98
  await sleep(1500);
93
99
  } else {
94
- action = "reopened";
100
+ action = "pruned";
101
+ const keeper = pickHomeKeeper(homes);
95
102
  for (const h of homes) {
103
+ if (h === keeper) continue;
96
104
  await closeTab(cdpPort, String(h.id));
97
105
  closed += 1;
98
106
  }
99
107
  await sleep(500);
100
- opened = await openHome(cdpPort, extensionId) || opened;
101
- await sleep(1500);
102
108
  }
103
109
  const next = await jsonList(cdpPort);
104
110
  if (!next.ok) {
@@ -125,14 +131,35 @@ async function ensureExtensionReady(target, options) {
125
131
  if (!finalListing.ok) {
126
132
  return base({ extensionId, opened, action, homeTabs: { before, closed, after: homesNow.length }, reasonCode: "cdp-unreachable" });
127
133
  }
128
- const after = homePages(finalListing.targets, extensionId).length;
129
- let health = { status: "unknown", findings: [] };
130
- try {
131
- const { checkExtensionRuntimeHealth } = await import("./runtime.js");
132
- const report = await checkExtensionRuntimeHealth(resolved, cdpPort);
133
- health = { status: report.status, findings: report.findings };
134
- } catch (error) {
135
- health = { status: "FAIL", findings: [error instanceof Error ? error.message : String(error)] };
134
+ let after = homePages(finalListing.targets, extensionId).length;
135
+ const checkHealth = async () => {
136
+ try {
137
+ const { checkExtensionRuntimeHealth } = await import("./runtime.js");
138
+ const report = await checkExtensionRuntimeHealth(resolved, cdpPort);
139
+ return { status: report.status, findings: report.findings };
140
+ } catch (error) {
141
+ return { status: "FAIL", findings: [error instanceof Error ? error.message : String(error)] };
142
+ }
143
+ };
144
+ let health = await checkHealth();
145
+ if (action === "pruned" && (health.status !== "PASS" || after !== 1)) {
146
+ const listing = await jsonList(cdpPort);
147
+ if (listing.ok) {
148
+ action = "reopened";
149
+ for (const h of homePages(listing.targets, extensionId)) {
150
+ await closeTab(cdpPort, String(h.id));
151
+ closed += 1;
152
+ }
153
+ await sleep(500);
154
+ opened = await openHome(cdpPort, extensionId) || opened;
155
+ await sleep(1500);
156
+ const relisted = await jsonList(cdpPort);
157
+ if (!relisted.ok) {
158
+ return base({ extensionId, opened, action, homeTabs: { before, closed, after }, reasonCode: "cdp-unreachable" });
159
+ }
160
+ after = homePages(relisted.targets, extensionId).length;
161
+ health = await checkHealth();
162
+ }
136
163
  }
137
164
  const ready = health.status === "PASS" && after === 1;
138
165
  return base({
@@ -104,6 +104,14 @@ async function handleLaunch(argv) {
104
104
  });
105
105
  }
106
106
  if (tier === "verify") {
107
+ const verifyCdpPort = Number(process.env.CDP_PORT ?? "");
108
+ if (adapter === "extension" && Number.isInteger(verifyCdpPort) && verifyCdpPort > 0) {
109
+ const { ensureExtensionReady } = await import("../../adapters/extension/ensure-ready.js");
110
+ const convergence = await ensureExtensionReady(target, { cdpPort: verifyCdpPort });
111
+ console.error(
112
+ `[launch] home-tab convergence: ${convergence.action} (${convergence.homeTabs.before}\u2192${convergence.homeTabs.after} tabs, closed ${convergence.homeTabs.closed})${convergence.ready ? "" : ` \u2014 ${convergence.reasonCode}`}`
113
+ );
114
+ }
107
115
  const liveArgs = ["live", "--adapter", adapter, "--target", target];
108
116
  if (adapter === "mobile" && mobileTarget) liveArgs.push("--platform", mobileTarget);
109
117
  if (json) liveArgs.push("--json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -69,4 +69,4 @@
69
69
  "url": "https://github.com/MetaMask/experimental-metamask-harness/issues"
70
70
  },
71
71
  "homepage": "https://github.com/MetaMask/experimental-metamask-harness#readme"
72
- }
72
+ }
File without changes
File without changes