Skip to content

Commit 6ebda34

Browse files
committed
fix(kernel): ground the wrong-flag hint in observed device identity only
The UDID-shape fallback reconstructed Apple identity syntax with a UUID-only regex: it missed modern physical-device UDIDs (00008150-001849640CF8401C), could misclassify a UUID-shaped device name, and justified itself with an inventory state (a shut-down device) the exact-candidate match already covers wherever inventory lists it. Only a listed candidate's actual id now earns the hint; an unlisted value keeps the generic device-not-found answer. Also corrects help physical-device, which claimed --device accepts a UDID (it never did): it now names --udid/--serial for name collisions. Addresses the P1 review on #2065.
1 parent be8200d commit 6ebda34

3 files changed

Lines changed: 20 additions & 34 deletions

File tree

‎packages/kernel/src/device-selector-flags.test.ts‎

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,22 +75,16 @@ test('a serial passed to --device names --serial, not --udid', async () => {
7575
assert.match(String(error.details?.hint ?? ''), /Did you mean --serial emulator-5580\?/);
7676
});
7777

78-
test('a UDID-shaped --device value names --udid even when no listed device has that id', async () => {
79-
const error = await resolveError([APPLE], {
80-
platform: 'ios',
81-
deviceName: '204BFFD9-9644-4830-B2C1-1B946597A07C',
82-
});
83-
assert.equal(error.code, 'DEVICE_NOT_FOUND');
84-
assert.match(
85-
String(error.details?.hint ?? ''),
86-
/--device takes a device name\. Did you mean --udid 204BFFD9-9644-4830-B2C1-1B946597A07C\?/,
87-
);
88-
});
89-
90-
test('an ordinary unknown --device name keeps the generic device-not-found hint', async () => {
91-
const error = await resolveError([APPLE], { platform: 'ios', deviceName: 'iPhone 99' });
92-
assert.equal(error.code, 'DEVICE_NOT_FOUND');
93-
assert.equal(error.details?.hint, undefined);
78+
test('an unknown --device value gets the generic hint, even when it looks like a UDID', async () => {
79+
// The hint is grounded in observed identity: only a candidate's actual id earns the
80+
// wrong-flag answer. A UDID-shaped value that no listed device carries stays a plain
81+
// unknown name — guessing from shape would misclassify UUID-named devices and miss
82+
// every identity syntax the shape guess does not cover.
83+
for (const deviceName of ['204BFFD9-9644-4830-B2C1-1B946597A07C', 'iPhone 99']) {
84+
const error = await resolveError([APPLE], { platform: 'ios', deviceName });
85+
assert.equal(error.code, 'DEVICE_NOT_FOUND');
86+
assert.equal(error.details?.hint, undefined);
87+
}
9488
});
9589

9690
async function resolveError(

‎packages/kernel/src/device.ts‎

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -353,35 +353,27 @@ function resolveDeviceByName(
353353
return match;
354354
}
355355

356-
// A simulator/device UDID: five hex groups, 8-4-4-4-12. Only used to recognize a UDID the
357-
// inventory does not currently list (a shut-down or unplugged one), so the answer is still
358-
// "wrong flag" rather than "no such device".
359-
const DEVICE_UDID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
360-
361356
/**
362357
* `--device` takes a device NAME, and `--udid`/`--serial` take a device IDENTITY. Passing an
363358
* identity to `--device` reached name resolution and answered "No device named
364359
* 204BFFD9-9644-4830-B2C1-1B946597A07C" (#2064) — literally true, and unactionable: it names
365360
* neither the flag that does take that value nor the fact that one exists. It is the same class of
366361
* mistake `assertSelectorFlagMatchesPlatform` already answers for a mismatched identity flag, so
367-
* answer it the same way: name the flag the value belongs to.
362+
* answer it the same way: name the flag the value belongs to. Only an observed identity earns the
363+
* hint — the candidates' own ids, with the flag derived from that device's platform; guessing from
364+
* the value's shape would have to reimplement every platform's identity syntax here.
368365
*/
369366
function deviceIdentityMistakenForNameHint(
370367
candidates: DeviceInfo[],
371368
deviceName: string,
372369
): string | undefined {
373370
const identityMatch = candidates.find((device) => device.id === deviceName);
374-
if (identityMatch) {
375-
const flag = isSerialAddressablePlatform(identityMatch.platform) ? '--serial' : '--udid';
376-
return (
377-
`${deviceName} is the id of ${JSON.stringify(identityMatch.name)}, not its name. ` +
378-
`Did you mean ${flag} ${deviceName}?`
379-
);
380-
}
381-
if (DEVICE_UDID_SHAPE.test(deviceName)) {
382-
return `--device takes a device name. Did you mean --udid ${deviceName}?`;
383-
}
384-
return undefined;
371+
if (!identityMatch) return undefined;
372+
const flag = isSerialAddressablePlatform(identityMatch.platform) ? '--serial' : '--udid';
373+
return (
374+
`${deviceName} is the id of ${JSON.stringify(identityMatch.name)}, not its name. ` +
375+
`Did you mean ${flag} ${deviceName}?`
376+
);
385377
}
386378

387379
/**

‎src/cli-schema/cli-help.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ For simulator/emulator flows, use help manual-qa for routine QA or help workflow
656656
Discovery:
657657
agent-device devices --platform ios
658658
agent-device devices --platform android
659-
Use --device <name-or-udid> only when multiple devices are present.
659+
With multiple devices present, select one: --device <name>, or --udid <udid> (iOS) / --serial <serial> (Android) when names collide.
660660
661661
iOS physical-device prerequisites:
662662
Xcode, xcrun xcdevice, and xcrun xctrace must be available from the selected Xcode.

0 commit comments

Comments
 (0)