@farmslot/adapter-rn 0.19.4 → 0.19.6

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
@@ -6,6 +6,15 @@ All notable changes to `@farmslot/adapter-rn` (published as `@farmslot/expo-reci
6
6
 
7
7
  - Active-development baseline; add user-facing changes here before release or package publication.
8
8
 
9
+ ## 0.19.6 - 2026-10-09
10
+
11
+ - `hasMatchingRoute` and `matchesBridgeTarget` accept the manufacturer-prefixed name a physical Android device reports in its bridge snapshot ("Google Pixel 6a" for the pin "Pixel 6a"). They accepted only the Metro form ("Pixel 6a - 17 - API 37"), so wait-for-bridge never saw the Pixel 6a as ready and launch failed after its full timeout. The model must be whole trailing words ("Pixel 6" does not match "Google Pixel 6a"), the serial must not be an `emulator-` serial, and two manufacturer-prefixed entries on one Metro (counting one that has not reported a platform yet) count as no match. `manufacturerNameMatches(deviceName, androidName, adbSerial)` is exported so mm-harness applies the same rule.
12
+ - Publish with protocol 0.35.1 and recipe-runner 0.28.2.
13
+
14
+ ## 0.19.5 - 2026-10-09
15
+
16
+ - Publish with protocol 0.35.1 and recipe-runner 0.28.2 so consumers share one protocol and one recipe-runner copy. No code change.
17
+
9
18
  ## 0.19.4 - 2026-10-09
10
19
 
11
20
  - Publish with protocol 0.35.0 and recipe-runner 0.28.1 so consumers share one recipe-runner copy. No code change.
@@ -11,6 +11,16 @@
11
11
  // the matcher would fall back to that ambient identity and confirm against the wrong
12
12
  // platform's target. Binding the platform up front closes that corner.
13
13
 
14
+ // Metro names a physical device by its model ("Pixel 6a - 17 - API 37"), but the
15
+ // in-app bridge snapshot can prefix the manufacturer ("Google Pixel 6a"). Accept that
16
+ // form only for a physical device (not an emulator- serial) and only with the model as
17
+ // whole trailing words, so "Pixel 6" never matches "Google Pixel 6a".
18
+ function manufacturerNameMatches(deviceName, androidName, adbSerial) {
19
+ if (!adbSerial || adbSerial.startsWith('emulator-')) return false;
20
+ if (deviceName === androidName || deviceName.startsWith(`${androidName} -`)) return false;
21
+ return deviceName.endsWith(` ${androidName}`) || deviceName.includes(` ${androidName} -`);
22
+ }
23
+
14
24
  function matchesBridgeTarget(target, env) {
15
25
  const e = env || process.env;
16
26
  if (!target || typeof target !== 'object') return false;
@@ -33,7 +43,8 @@ function matchesBridgeTarget(target, env) {
33
43
  if (target.platform !== 'android') return false;
34
44
  if (!androidName) return true;
35
45
  const deviceName = String(target.deviceName || '');
36
- return deviceName === androidName || deviceName.startsWith(`${androidName} -`);
46
+ if (deviceName === androidName || deviceName.startsWith(`${androidName} -`)) return true;
47
+ return manufacturerNameMatches(deviceName, androidName, adbSerial);
37
48
  }
38
49
 
39
50
  // iOS simulator pin applies only when iOS is requested (or nothing constrains the
@@ -48,10 +59,28 @@ function matchesBridgeTarget(target, env) {
48
59
 
49
60
  // True when at least one answering target matches the request AND carries a route
50
61
  // (an in-app agentic bridge is live), not merely a registered debug target.
62
+ // Two phones of the same model on one Metro both report "Google Pixel 6a"; the
63
+ // snapshot cannot tell which one is pinned, so a manufacturer-form match counts only
64
+ // when it is the sole one. The count includes entries that have not reported a
65
+ // platform yet: the pinned phone may still be starting while the other one answers.
51
66
  function hasMatchingRoute(value, env) {
52
- const targets = Array.isArray(value) ? value : [value];
53
- return targets.some(
54
- (t) => matchesBridgeTarget(t, env) && t && t.agenticPresent === true && Boolean(t.route),
67
+ const e = env || process.env;
68
+ const entries = (Array.isArray(value) ? value : [value]).filter(
69
+ (t) => t && typeof t === 'object',
70
+ );
71
+ const androidName = e.ANDROID_TARGET_DEVICE_NAME || e.ANDROID_DEVICE || '';
72
+ const adbSerial = e.ADB_SERIAL || e.ANDROID_SERIAL || '';
73
+ const manufacturerForm = (t) =>
74
+ Boolean(androidName) &&
75
+ (!t.platform || t.platform === 'android') &&
76
+ manufacturerNameMatches(String(t.deviceName || ''), androidName, adbSerial);
77
+ const ambiguous = entries.filter(manufacturerForm).length > 1;
78
+ return entries.some(
79
+ (t) =>
80
+ matchesBridgeTarget(t, e) &&
81
+ !(ambiguous && manufacturerForm(t)) &&
82
+ t.agenticPresent === true &&
83
+ Boolean(t.route),
55
84
  );
56
85
  }
57
86
 
@@ -86,4 +115,10 @@ function describeRequested(env) {
86
115
  return 'any platform';
87
116
  }
88
117
 
89
- module.exports = { matchesBridgeTarget, hasMatchingRoute, describeTargets, describeRequested };
118
+ module.exports = {
119
+ matchesBridgeTarget,
120
+ manufacturerNameMatches,
121
+ hasMatchingRoute,
122
+ describeTargets,
123
+ describeRequested,
124
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farmslot/adapter-rn",
3
- "version": "0.19.4",
3
+ "version": "0.19.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -42,8 +42,8 @@
42
42
  "prepublishOnly": "node ../../scripts/quality/check-farmslot-package-readiness.mjs --publish --packages @farmslot/adapter-rn"
43
43
  },
44
44
  "dependencies": {
45
- "@farmslot/protocol": "0.35.0",
46
- "@farmslot/recipe-runner": "0.28.1",
45
+ "@farmslot/protocol": "0.35.1",
46
+ "@farmslot/recipe-runner": "0.28.2",
47
47
  "pngjs": "^7.0.0",
48
48
  "ws": "^8.18.0"
49
49
  },