Skip to content

Commit c11484d

Browse files
wangczclaude
andcommitted
fix: mark unimplemented HarmonyOS commands as unsupported and fix platform gaps
- capabilities: remove harmonyos support from logs and perf (not yet implemented) - dispatch-interactions: explicitly reject read command on HarmonyOS - client-shared: add harmonyos serial to device identifiers - session-open-surface: include serial for harmonyos open results - client-output: add harmonyos appstate output formatting - boot-diagnostics: add HDC_TRANSPORT_UNAVAILABLE for harmonyos and extend platform type - post-gesture-stabilization: include harmonyos in supported platforms - interaction-outcome-policy: include harmonyos in supported platforms - replay/script-utils: include harmonyos platform in script args - maestro/runtime-targets: correctly map harmonyos platform instead of falling back to ios - maestro/command-mapper: allow openLink on harmonyos with appId Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 54a3e48 commit c11484d

11 files changed

Lines changed: 42 additions & 13 deletions

src/client-shared.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ export function buildDeviceIdentifiers(
3636
return {
3737
deviceId: id,
3838
deviceName: name,
39-
...(platform === 'android' ? { serial: id } : platform === 'ios' ? { udid: id } : {}),
39+
...(platform === 'android' || platform === 'harmonyos'
40+
? { serial: id }
41+
: platform === 'ios'
42+
? { udid: id }
43+
: {}),
4044
};
4145
}
4246

@@ -56,9 +60,12 @@ function serializeSessionDevice(
5660
ios_simulator_device_set: device.ios?.simulatorSetPath ?? null,
5761
}
5862
: {}),
59-
...(device.platform === 'android' && includeAndroidSerial
63+
...((device.platform === 'android' || device.platform === 'harmonyos') && includeAndroidSerial
6064
? {
61-
serial: device.android?.serial ?? device.id,
65+
serial:
66+
device.platform === 'android'
67+
? device.android?.serial ?? device.id
68+
: device.harmonyos?.serial ?? device.id,
6269
}
6370
: {}),
6471
};

src/commands/client-output.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ function formatAppState(data: AppStateCommandResult): string | null {
249249
if (data.activity) lines.push(`Activity: ${data.activity}`);
250250
return lines.join('\n');
251251
}
252+
if (data.platform === 'harmonyos') {
253+
const lines = [`Foreground app: ${data.bundleId ?? 'unknown'}`];
254+
if (data.activity) lines.push(`Ability: ${data.activity}`);
255+
return lines.join('\n');
256+
}
252257
return null;
253258
}
254259

src/compat/maestro/command-mapper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ function convertOpenLink(
154154
): SessionAction {
155155
const rawLink = readOpenLink(value, name);
156156
const url = resolveMaestroString(rawLink, context);
157-
if ((context.platform === 'ios' || context.platform === 'android') && config.appId) {
157+
if ((context.platform === 'ios' || context.platform === 'android' || context.platform === 'harmonyos') && config.appId) {
158158
return action(
159159
'open',
160160
[resolveMaestroString(requireAppId(config, name), context), url],

src/compat/maestro/runtime-targets.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ function filterReactNativeOverlayBlockedMatches(
256256
}
257257

258258
export function readMaestroSelectorPlatform(flags: DaemonRequest['flags']): Platform {
259-
return flags?.platform === 'android' ? 'android' : 'ios';
259+
if (flags?.platform === 'android') return 'android';
260+
if (flags?.platform === 'harmonyos') return 'harmonyos';
261+
return 'ios';
260262
}
261263

262264
export function extractMaestroVisibleTextQuery(selectorExpression: string): string | null {

src/core/capabilities.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,9 @@ const COMMAND_CAPABILITY_MATRIX: Record<string, CommandCapability> = {
180180
logs: {
181181
apple: { simulator: true, device: true },
182182
android: { emulator: true, device: true, unknown: true },
183-
harmonyos: HARMONYOS_DEVICE,
183+
harmonyos: {},
184184
linux: LINUX_NONE,
185+
supports: (device) => device.platform !== 'harmonyos',
185186
},
186187
network: {
187188
apple: { simulator: true, device: true },
@@ -199,8 +200,9 @@ const COMMAND_CAPABILITY_MATRIX: Record<string, CommandCapability> = {
199200
perf: {
200201
apple: { simulator: true, device: true },
201202
android: { emulator: true, device: true, unknown: true },
202-
harmonyos: HARMONYOS_DEVICE,
203+
harmonyos: {},
203204
linux: LINUX_NONE,
205+
supports: (device) => device.platform !== 'harmonyos',
204206
},
205207
pan: {
206208
apple: { simulator: true, device: true },

src/core/dispatch-interactions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,9 @@ export async function handleReadCommand(
879879
context: DispatchContext | undefined,
880880
): Promise<Record<string, unknown>> {
881881
const { x, y } = readPoint(positionals, 'read requires x y');
882+
if (device.platform === 'harmonyos') {
883+
throw new AppError('UNSUPPORTED_OPERATION', 'read is not yet supported on HarmonyOS');
884+
}
882885
if (device.platform === 'android') {
883886
const { readAndroidTextAtPoint } = await import('../platforms/android/input-actions.ts');
884887
const text = await readAndroidTextAtPoint(device, x, y);

src/daemon/handlers/session-open-surface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function buildOpenResult(params: {
4545
result.device = device.name;
4646
result.id = device.id;
4747
result.kind = device.kind;
48-
if (device.platform === 'android') {
48+
if (device.platform === 'android' || device.platform === 'harmonyos') {
4949
result.serial = device.id;
5050
}
5151
}

src/daemon/interaction-outcome-policy.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,11 @@ export function areInteractionSurfaceSignaturesStable(
187187
}
188188

189189
function supportsInteractionOutcomePolicy(session: SessionState): boolean {
190-
return session.device.platform === 'ios' || session.device.platform === 'android';
190+
return (
191+
session.device.platform === 'ios' ||
192+
session.device.platform === 'android' ||
193+
session.device.platform === 'harmonyos'
194+
);
191195
}
192196

193197
function retryCommandForTap(command: string): string | undefined {

src/daemon/post-gesture-stabilization.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,5 @@ function isPostGestureStabilizingAction(action: string): boolean {
7979
}
8080

8181
function supportsPostGestureStabilization(platform: SessionState['device']['platform']): boolean {
82-
return platform === 'ios' || platform === 'android';
82+
return platform === 'ios' || platform === 'android' || platform === 'harmonyos';
8383
}

src/platforms/boot-diagnostics.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export type BootFailureReason =
66
| 'IOS_TOOL_MISSING'
77
| 'ANDROID_BOOT_TIMEOUT'
88
| 'ADB_TRANSPORT_UNAVAILABLE'
9+
| 'HDC_TRANSPORT_UNAVAILABLE'
910
| 'CI_RESOURCE_STARVATION_SUSPECTED'
1011
| 'BOOT_COMMAND_FAILED'
1112
| 'UNKNOWN';
@@ -16,11 +17,12 @@ const INFRASTRUCTURE_BOOT_FAILURE_REASONS = new Set<BootFailureReason>([
1617
'IOS_TOOL_MISSING',
1718
'ANDROID_BOOT_TIMEOUT',
1819
'ADB_TRANSPORT_UNAVAILABLE',
20+
'HDC_TRANSPORT_UNAVAILABLE',
1921
'CI_RESOURCE_STARVATION_SUSPECTED',
2022
]);
2123

2224
type BootDiagnosticContext = {
23-
platform?: 'ios' | 'android';
25+
platform?: 'ios' | 'android' | 'harmonyos';
2426
phase?: 'boot' | 'connect' | 'transport';
2527
};
2628

@@ -39,7 +41,11 @@ export function classifyBootFailure(input: {
3941
const platform = input.context?.platform;
4042
const phase = input.context?.phase;
4143
if (appErr?.code === 'TOOL_MISSING') {
42-
return platform === 'android' ? 'ADB_TRANSPORT_UNAVAILABLE' : 'IOS_TOOL_MISSING';
44+
return platform === 'android'
45+
? 'ADB_TRANSPORT_UNAVAILABLE'
46+
: platform === 'harmonyos'
47+
? 'HDC_TRANSPORT_UNAVAILABLE'
48+
: 'IOS_TOOL_MISSING';
4349
}
4450
const details = (appErr?.details ?? {}) as Record<string, unknown>;
4551
const detailMessage = typeof details.message === 'string' ? details.message : undefined;

0 commit comments

Comments
 (0)