swipium 1.0.0 → 1.1.0

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 (74) hide show
  1. package/README.md +17 -27
  2. package/dist/appMap/codeIndex.js +37 -5
  3. package/dist/appMap/codeIndex.js.map +1 -1
  4. package/dist/appMap/query.js +22 -4
  5. package/dist/appMap/query.js.map +1 -1
  6. package/dist/build/plan.js +2 -1
  7. package/dist/build/plan.js.map +1 -1
  8. package/dist/drivers/WdaDriver.js +42 -6
  9. package/dist/drivers/WdaDriver.js.map +1 -1
  10. package/dist/explore/candidates.js +17 -0
  11. package/dist/explore/candidates.js.map +1 -1
  12. package/dist/explore/runner.js +29 -2
  13. package/dist/explore/runner.js.map +1 -1
  14. package/dist/lib/wda.js +70 -2
  15. package/dist/lib/wda.js.map +1 -1
  16. package/dist/oracle/failures.js +1 -0
  17. package/dist/oracle/failures.js.map +1 -1
  18. package/dist/orchestration/envelope.js +1 -0
  19. package/dist/orchestration/envelope.js.map +1 -1
  20. package/dist/prompts/index.js +10 -0
  21. package/dist/prompts/index.js.map +1 -1
  22. package/dist/report/export.js +9 -0
  23. package/dist/report/export.js.map +1 -1
  24. package/dist/server.js +29 -2
  25. package/dist/server.js.map +1 -1
  26. package/dist/services/build.js +15 -2
  27. package/dist/services/build.js.map +1 -1
  28. package/dist/services/prepareIos.js +34 -4
  29. package/dist/services/prepareIos.js.map +1 -1
  30. package/dist/services/report.js +47 -5
  31. package/dist/services/report.js.map +1 -1
  32. package/dist/session/store.js.map +1 -1
  33. package/dist/suite/pom.js +24 -9
  34. package/dist/suite/pom.js.map +1 -1
  35. package/dist/tools/act.js +23 -2
  36. package/dist/tools/act.js.map +1 -1
  37. package/dist/tools/appControl.js +176 -0
  38. package/dist/tools/appControl.js.map +1 -0
  39. package/dist/tools/capabilities.js +29 -0
  40. package/dist/tools/capabilities.js.map +1 -1
  41. package/dist/tools/clearOverlay.js +56 -21
  42. package/dist/tools/clearOverlay.js.map +1 -1
  43. package/dist/tools/device.js +151 -0
  44. package/dist/tools/device.js.map +1 -0
  45. package/dist/tools/doctor.js +174 -52
  46. package/dist/tools/doctor.js.map +1 -1
  47. package/dist/tools/history.js +56 -0
  48. package/dist/tools/history.js.map +1 -0
  49. package/dist/tools/metro.js +260 -0
  50. package/dist/tools/metro.js.map +1 -0
  51. package/dist/tools/network.js +97 -5
  52. package/dist/tools/network.js.map +1 -1
  53. package/dist/tools/permissions.js +149 -0
  54. package/dist/tools/permissions.js.map +1 -0
  55. package/dist/tools/screenInfo.js +70 -0
  56. package/dist/tools/screenInfo.js.map +1 -0
  57. package/dist/tools/screenRecord.js +215 -6
  58. package/dist/tools/screenRecord.js.map +1 -1
  59. package/dist/tools/seed.js +101 -0
  60. package/dist/tools/seed.js.map +1 -0
  61. package/dist/tools/state.js +83 -0
  62. package/dist/tools/state.js.map +1 -1
  63. package/dist/tools/testThis.js +55 -6
  64. package/dist/tools/testThis.js.map +1 -1
  65. package/dist/tools/visual.js +139 -0
  66. package/dist/tools/visual.js.map +1 -0
  67. package/dist/tools/visualText.js +61 -0
  68. package/dist/tools/visualText.js.map +1 -0
  69. package/dist/version.js +25 -3
  70. package/dist/version.js.map +1 -1
  71. package/docs/README.md +4 -4
  72. package/docs/mcp-server.md +5 -3
  73. package/docs/tools.md +68 -4
  74. package/package.json +2 -2
@@ -8,6 +8,14 @@ import { parseSnapshot, boundsContain } from '../snapshot/parse.js';
8
8
  import { detectTreeOverlays, classifyForeground, obstructionAt } from '../snapshot/overlays.js';
9
9
  const STRATEGIES = ['auto', 'hide_keyboard', 'press_back', 'tap_outside', 'minimize_logbox', 'dismiss_logbox', 'allow_permission', 'deny_permission', 'dismiss_toast_if_possible'];
10
10
  const center = (b) => ({ x: Math.round((b[0] + b[2]) / 2), y: Math.round((b[1] + b[3]) / 2) });
11
+ async function safe(fn, fallback) {
12
+ try {
13
+ return await fn();
14
+ }
15
+ catch {
16
+ return fallback;
17
+ }
18
+ }
11
19
  async function tapByText(d, nodes, re) {
12
20
  const n = nodes.find((x) => re.test(x.text) || re.test(x.desc));
13
21
  if (!n)
@@ -16,6 +24,18 @@ async function tapByText(d, nodes, re) {
16
24
  await d.pressXY(c.x, c.y, 100);
17
25
  return true;
18
26
  }
27
+ async function handleNativeAlert(d, action) {
28
+ const fn = action === 'accept' ? d.acceptAlert : d.dismissAlert;
29
+ if (!fn)
30
+ return false;
31
+ try {
32
+ await fn.call(d);
33
+ return true;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
19
39
  export function registerClearOverlay(server, sessions) {
20
40
  server.registerTool('qa_clear_overlay', {
21
41
  title: 'Clear an overlay',
@@ -53,25 +73,42 @@ export function registerClearOverlay(server, sessions) {
53
73
  const before = (await obstructionFor()).obstructed;
54
74
  const cleared = [];
55
75
  // gather context
56
- const ime = await d.imeShown();
57
- const fg = await d.foregroundOwner().catch(() => 'unknown');
58
- let xml = '';
59
- try {
60
- xml = await d.dumpXml();
61
- }
62
- catch { /* animated/idle-fail — proceed with what we know */ }
76
+ const ime = await safe(() => d.imeShown(), false);
77
+ const fg = await safe(() => d.foregroundOwner(), 'unknown');
78
+ const xml = await safe(() => d.dumpXml(), '');
63
79
  const parsedBefore = xml ? parseSnapshot(xml) : undefined;
64
80
  const nodes = parsedBefore?.allNodes ?? [];
65
81
  const treeOverlays = detectTreeOverlays(nodes, parsedBefore?.screen);
66
82
  const overlaysBefore = treeOverlays.map((o) => o.type);
67
83
  const fgOverlay = classifyForeground(session.appId, fg);
68
- const doHideKeyboard = async () => { if (await d.imeShown()) {
69
- await d.pressKey('back');
70
- cleared.push({ type: 'keyboard', action: 'hidden' });
71
- } };
72
- const doTapOutside = async () => { const sz = await d.screenSize(); const x = Math.round((sz?.width ?? 1080) * 0.5); const y = Math.round((sz?.height ?? 2000) * 0.08); await d.pressXY(x, y, 80); cleared.push({ type: 'unknown', action: 'tap_outside' }); };
84
+ const doHideKeyboard = async () => {
85
+ if (await safe(() => d.imeShown(), false)) {
86
+ await d.pressKey('back');
87
+ cleared.push({ type: 'keyboard', action: 'hidden' });
88
+ }
89
+ else {
90
+ cleared.push({ type: 'keyboard', action: 'not_visible_or_unsupported' });
91
+ }
92
+ };
93
+ const doTapOutside = async () => { const sz = await safe(() => d.screenSize(), null); const x = Math.round((sz?.width ?? 1080) * 0.5); const y = Math.round((sz?.height ?? 2000) * 0.08); await d.pressXY(x, y, 80); cleared.push({ type: 'unknown', action: 'tap_outside' }); };
73
94
  const doMinimizeLogbox = async () => { const ok = await tapByText(d, nodes, /minimize/i); cleared.push({ type: 'rn_logbox', action: ok ? 'minimized' : 'minimize_not_found' }); };
74
95
  const doDismissLogbox = async () => { const ok = await tapByText(d, nodes, /dismiss/i); cleared.push({ type: 'rn_logbox', action: ok ? 'dismissed' : 'dismiss_not_found' }); };
96
+ const doAllowPermission = async () => {
97
+ if (await handleNativeAlert(d, 'accept')) {
98
+ cleared.push({ type: 'permission_dialog', action: 'allowed_native_alert' });
99
+ return;
100
+ }
101
+ const ok = await tapByText(d, nodes, /allow|while using/i);
102
+ cleared.push({ type: 'permission_dialog', action: ok ? 'allowed' : 'allow_not_found' });
103
+ };
104
+ const doDenyPermission = async () => {
105
+ if (await handleNativeAlert(d, 'dismiss')) {
106
+ cleared.push({ type: 'permission_dialog', action: 'denied_native_alert' });
107
+ return;
108
+ }
109
+ const ok = await tapByText(d, nodes, /deny|don.?t allow/i);
110
+ cleared.push({ type: 'permission_dialog', action: ok ? 'denied' : 'deny_not_found' });
111
+ };
75
112
  try {
76
113
  switch (strategy) {
77
114
  case 'hide_keyboard':
@@ -90,16 +127,12 @@ export function registerClearOverlay(server, sessions) {
90
127
  case 'dismiss_logbox':
91
128
  await doDismissLogbox();
92
129
  break;
93
- case 'allow_permission': {
94
- const ok = await tapByText(d, nodes, /allow|while using/i);
95
- cleared.push({ type: 'permission_dialog', action: ok ? 'allowed' : 'allow_not_found' });
130
+ case 'allow_permission':
131
+ await doAllowPermission();
96
132
  break;
97
- }
98
- case 'deny_permission': {
99
- const ok = await tapByText(d, nodes, /deny|don.?t allow/i);
100
- cleared.push({ type: 'permission_dialog', action: ok ? 'denied' : 'deny_not_found' });
133
+ case 'deny_permission':
134
+ await doDenyPermission();
101
135
  break;
102
- }
103
136
  case 'dismiss_toast_if_possible':
104
137
  cleared.push({ type: 'toast', action: 'cannot_target (toasts are separate windows; wait it out)' });
105
138
  break;
@@ -125,7 +158,9 @@ export function registerClearOverlay(server, sessions) {
125
158
  const after = (await obstructionFor()).obstructed;
126
159
  let parsedAfter;
127
160
  try {
128
- parsedAfter = parseSnapshot(await d.dumpXml());
161
+ const afterXml = await safe(() => d.dumpXml(), '');
162
+ if (afterXml)
163
+ parsedAfter = parseSnapshot(afterXml);
129
164
  }
130
165
  catch { /* keep undefined */ }
131
166
  const afterOverlays = parsedAfter ? detectTreeOverlays(parsedAfter.allNodes, parsedAfter.screen) : [];
@@ -1 +1 @@
1
- {"version":3,"file":"clearOverlay.js","sourceRoot":"","sources":["../../src/tools/clearOverlay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clearOverlay.js","sourceRoot":"","sources":["../../src/tools/clearOverlay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ // qa_device_info + qa_orientation (PHASE3-PLAN §4.2) — device-parity introspection and rotation,
2
+ // without raw adb. Read-only info needs no consent; orientation is a logged, non-destructive
3
+ // environment change.
4
+ import { z } from 'zod';
5
+ import { qaOk, qaError } from '../lib/result.js';
6
+ import { requireConsent, consumeConsent } from '../consent/consent.js';
7
+ import { getDriver } from '../session/attach.js';
8
+ import { getDeviceProps, getOrientation, setOrientation, listPackages, setGeo } from '../lib/device.js';
9
+ function rotationLabel(rotation, auto) {
10
+ return auto ? 'auto' : rotation === 1 || rotation === 3 ? 'landscape' : 'portrait';
11
+ }
12
+ export function registerDevice(server, sessions) {
13
+ server.registerTool('qa_device_info', {
14
+ title: 'Device info',
15
+ description: 'Read-only device introspection (no consent needed): model/manufacturer/Android SDK+release, supported ABIs, locale, timezone, screen size/density, current orientation, and installed third-party app count. Pass listPackages:true (optionally packageFilter) to include package names.',
16
+ inputSchema: {
17
+ sessionId: z.string(),
18
+ listPackages: z.boolean().optional().describe('Include installed third-party package names.'),
19
+ packageFilter: z.string().optional().describe('Substring filter for the package list.'),
20
+ },
21
+ }, async ({ sessionId, listPackages: withPkgs, packageFilter }) => {
22
+ const session = sessions.get(sessionId);
23
+ const { driver } = session ? await getDriver(session) : { driver: undefined };
24
+ const serial = driver?.currentDevice();
25
+ if (!session || !driver || !serial) {
26
+ return qaError({ what: 'No device attached to this session', changedState: false, retrySafe: true, nextSteps: ['Call qa_prepare_target first.'] });
27
+ }
28
+ const [props, screen, density, orientation, pkgs] = await Promise.all([
29
+ getDeviceProps(serial),
30
+ driver.screenSize().catch(() => null),
31
+ driver.screenDensity().catch(() => null),
32
+ getOrientation(serial),
33
+ listPackages(serial, { thirdPartyOnly: true, filter: packageFilter }),
34
+ ]);
35
+ const orient = orientation ? rotationLabel(orientation.rotation, orientation.auto) : 'unknown';
36
+ const payload = {
37
+ device: serial,
38
+ props,
39
+ screen: screen ? { ...screen, density } : null,
40
+ orientation: orient,
41
+ rotation: orientation?.rotation ?? null,
42
+ autoRotate: orientation?.auto ?? null,
43
+ installedThirdPartyCount: pkgs.length,
44
+ ...(withPkgs ? { packages: pkgs } : {}),
45
+ };
46
+ const summary = `${props.manufacturer ?? '?'} ${props.model ?? '?'} · Android ${props.release ?? '?'} (SDK ${props.sdk ?? '?'}) · ${props.abis[0] ?? '?'}\n` +
47
+ `screen ${screen ? `${screen.width}x${screen.height}@${density ?? '?'}dpi` : '?'} · orientation ${orient} · locale ${props.locale ?? '?'} · tz ${props.timezone ?? '?'}\n` +
48
+ `${pkgs.length} third-party apps installed${withPkgs ? ':\n ' + pkgs.join('\n ') : ' (listPackages:true to list)'}`;
49
+ return qaOk(payload, summary);
50
+ });
51
+ server.registerTool('qa_orientation', {
52
+ title: 'Set orientation',
53
+ description: 'Set screen orientation: portrait | landscape | auto (re-enables auto-rotate). Non-destructive; logged as an environment change and surfaced in qa_report. Useful for testing rotation handling.',
54
+ inputSchema: {
55
+ sessionId: z.string(),
56
+ orientation: z.enum(['portrait', 'landscape', 'auto']),
57
+ },
58
+ }, async ({ sessionId, orientation }) => {
59
+ const session = sessions.get(sessionId);
60
+ const { driver } = session ? await getDriver(session) : { driver: undefined };
61
+ const serial = driver?.currentDevice();
62
+ if (!session || !driver || !serial) {
63
+ return qaError({ what: 'No device attached to this session', changedState: false, retrySafe: true, nextSteps: ['Call qa_prepare_target first.'] });
64
+ }
65
+ try {
66
+ await setOrientation(serial, orientation);
67
+ }
68
+ catch (e) {
69
+ return qaError({ what: `Could not set orientation: ${String(e)}`, changedState: false, retrySafe: true, nextSteps: ['Confirm the device is online.'] });
70
+ }
71
+ sessions.addEnvChange(session, `orientation → ${orientation}`);
72
+ const now = await getOrientation(serial);
73
+ sessions.recordMutation(session, {
74
+ tool: 'qa_orientation',
75
+ action: 'orientation_set',
76
+ risk: 'low',
77
+ target: { device: serial, orientation, rotation: now?.rotation ?? null, autoRotate: now?.auto ?? null },
78
+ consent: { required: false, approved: true },
79
+ status: 'executed',
80
+ });
81
+ return qaOk({ orientation, rotation: now?.rotation ?? null, autoRotate: now?.auto ?? null }, `orientation set to ${orientation}${now ? ` (rotation=${now.rotation}, auto=${now.auto})` : ''}`);
82
+ });
83
+ server.registerTool('qa_geolocation', {
84
+ title: 'Set location',
85
+ description: 'Spoof the device GPS location (emulator only). Consent-gated and logged as an environment change. Useful for testing location-dependent apps (maps, nearby, geofencing). Pass lat + lng (decimal degrees).',
86
+ inputSchema: {
87
+ sessionId: z.string(),
88
+ lat: z.number().describe('Latitude in decimal degrees.'),
89
+ lng: z.number().describe('Longitude in decimal degrees.'),
90
+ consentId: z.string().optional(),
91
+ approve: z.boolean().optional(),
92
+ },
93
+ }, async ({ sessionId, lat, lng, consentId, approve }) => {
94
+ const session = sessions.get(sessionId);
95
+ const { driver } = session ? await getDriver(session) : { driver: undefined };
96
+ const serial = driver?.currentDevice();
97
+ if (!session || !driver || !serial) {
98
+ return qaError({ what: 'No device attached to this session', changedState: false, retrySafe: true, nextSteps: ['Call qa_prepare_target first.'] });
99
+ }
100
+ if (driver.kind !== 'direct') {
101
+ return qaError({ what: 'Geolocation spoofing is only supported on the Android emulator backend', changedState: false, retrySafe: false, failureCode: 'BACKEND_UNSUPPORTED', nextSteps: ['On iOS, set a simulated location from the simulator UI; on real devices use a mock-location app.'] });
102
+ }
103
+ const gate = consumeConsent(consentId, approve, { action: 'geo_set', affects: { lat, lng } });
104
+ if (!gate.approved) {
105
+ sessions.recordMutation(session, {
106
+ tool: 'qa_geolocation',
107
+ action: 'geo_set',
108
+ risk: 'medium',
109
+ target: { device: serial, lat, lng },
110
+ consent: { required: true, approved: false },
111
+ status: 'requested',
112
+ });
113
+ return requireConsent({ action: 'geo_set', risk: 'medium', exactCommand: `adb -s ${serial} emu geo fix ${lng} ${lat}`, affects: { lat, lng }, explain: `Spoof the device location to (${lat}, ${lng})? Affects any location-aware app.` });
114
+ }
115
+ sessions.recordMutation(session, {
116
+ tool: 'qa_geolocation',
117
+ action: 'geo_set',
118
+ risk: 'medium',
119
+ target: { device: serial, lat, lng },
120
+ consent: { required: true, consentId, approved: true },
121
+ status: 'approved',
122
+ });
123
+ try {
124
+ await setGeo(serial, lat, lng);
125
+ }
126
+ catch (e) {
127
+ const emulatorHint = !serial.startsWith('emulator-') ? ' (this looks like a real device — `adb emu` only works on emulators)' : '';
128
+ sessions.recordMutation(session, {
129
+ tool: 'qa_geolocation',
130
+ action: 'geo_set',
131
+ risk: 'medium',
132
+ target: { device: serial, lat, lng },
133
+ consent: { required: true, consentId, approved: true },
134
+ status: 'blocked',
135
+ detail: String(e),
136
+ });
137
+ return qaError({ what: `Could not set location: ${String(e)}${emulatorHint}`, changedState: false, retrySafe: true, nextSteps: ['Use an emulator for location spoofing.'] });
138
+ }
139
+ sessions.addEnvChange(session, `geolocation → (${lat}, ${lng})`);
140
+ sessions.recordMutation(session, {
141
+ tool: 'qa_geolocation',
142
+ action: 'geo_set',
143
+ risk: 'medium',
144
+ target: { device: serial, lat, lng },
145
+ consent: { required: true, consentId, approved: true },
146
+ status: 'executed',
147
+ });
148
+ return qaOk({ lat, lng, set: true }, `location set to (${lat}, ${lng})`);
149
+ });
150
+ }
151
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/tools/device.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,65 @@
1
1
  // qa_doctor — proactive environment self-diagnosis (DESIGN §3, §7). Run first.
2
2
  import { z } from 'zod';
3
+ import { existsSync, readdirSync, statSync } from 'node:fs';
4
+ import { join } from 'node:path';
3
5
  import { qaOk } from '../lib/result.js';
4
6
  import { getSchemaHash } from '../lib/schemaHash.js';
5
7
  import { which, firstLine, adbDevices, listAvds, deviceFreeDataBytes, fmtBytes } from '../lib/android.js';
8
+ import { simctlAvailable, listSimulators } from '../lib/simctl.js';
9
+ import { checkWda, discoverWdaProjects, xcodeAvailable } from '../lib/wda.js';
10
+ import { loadWdaConfig } from '../lib/wdaConfig.js';
6
11
  import { SWIPIUM_VERSION, TOOL_NAMES, TOOL_COUNT, STALE_CLIENT_HINT } from '../version.js';
7
12
  const CLIENT_HINTS = {
8
13
  claude: 'Register with: claude mcp add swipium --scope project -- node <abs>/dist/index.js',
9
14
  gemini: 'Add to settings.json mcpServers; set an absolute "command" and a "cwd". stdio cwd is otherwise undefined.',
10
15
  codex: 'Codex has an open tool-injection regression (#19425) on builds after ~0.120.0. Set cwd explicitly, use an absolute node path, and verify tools actually appear after `init codex`.',
11
16
  };
17
+ function checkLine(c) {
18
+ const status = c.ok ? '[ok]' : c.optional ? '[warn]' : '[fail]';
19
+ return `${status} ${c.name}: ${c.detail}${c.fix && !c.ok ? ` -> ${c.fix}` : ''}`;
20
+ }
21
+ function wdaBuildProductStatus(derivedDataPath) {
22
+ if (!existsSync(derivedDataPath))
23
+ return { built: false, checkedPath: derivedDataPath };
24
+ const stack = [{ path: derivedDataPath, depth: 0 }];
25
+ while (stack.length) {
26
+ const cur = stack.pop();
27
+ if (cur.depth > 6)
28
+ continue;
29
+ let entries;
30
+ try {
31
+ entries = readdirSync(cur.path);
32
+ }
33
+ catch {
34
+ continue;
35
+ }
36
+ for (const name of entries) {
37
+ const p = join(cur.path, name);
38
+ let st;
39
+ try {
40
+ st = statSync(p);
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ if (!st.isDirectory())
46
+ continue;
47
+ if (/WebDriverAgentRunner.*\.app$/i.test(name))
48
+ return { built: true, productPath: p, checkedPath: derivedDataPath };
49
+ stack.push({ path: p, depth: cur.depth + 1 });
50
+ }
51
+ }
52
+ return { built: false, checkedPath: derivedDataPath };
53
+ }
12
54
  export function registerDoctor(server) {
13
55
  server.registerTool('qa_doctor', {
14
56
  title: 'QA environment doctor',
15
- description: 'Probe the local environment for Android mobile-app QA prerequisites (adb, emulator, online devices, AVDs, Java, Node) and report a structured diagnosis with actionable fixes. Run this BEFORE other tools. Pass `client` to tailor registration hints.',
57
+ description: 'Probe the local environment for simulator QA prerequisites. Use platform:"android" for Android Emulator, platform:"ios" for iOS Simulator + WDA status, or platform:"both". Pass client to tailor MCP registration hints.',
16
58
  inputSchema: {
59
+ platform: z
60
+ .enum(['android', 'ios', 'both'])
61
+ .optional()
62
+ .describe('Which simulator environment to evaluate. Defaults to android for backward compatibility.'),
17
63
  client: z
18
64
  .enum(['claude', 'gemini', 'codex'])
19
65
  .optional()
@@ -25,8 +71,13 @@ export function registerDoctor(server) {
25
71
  expectedVersion: z.string().optional().describe('Swipium version your docs expect; mismatch ⇒ stale client.'),
26
72
  expectedSchemaHash: z.string().optional().describe('Tool-surface hash your docs expect; mismatch ⇒ the client is on a build with a different surface (same tool count can still be stale).'),
27
73
  },
28
- }, async ({ client, expectedToolCount, expectedVersion, expectedSchemaHash }) => {
74
+ }, async ({ platform = 'android', client, expectedToolCount, expectedVersion, expectedSchemaHash }) => {
75
+ const requested = platform;
76
+ const wantsAndroid = requested === 'android' || requested === 'both';
77
+ const wantsIos = requested === 'ios' || requested === 'both';
29
78
  const checks = [];
79
+ const androidChecks = [];
80
+ const iosChecks = [];
30
81
  const schemaHash = getSchemaHash();
31
82
  // Stale-client detection (P1.8 + 3.3 A): the agent (via docs) tells us what it expects; we are
32
83
  // the source of truth. Version is for humans; the schema hash catches "same count, different
@@ -46,69 +97,140 @@ export function registerDoctor(server) {
46
97
  });
47
98
  }
48
99
  checks.push({ name: 'node', ok: true, detail: process.version });
49
- const hasAdb = await which('adb');
50
- checks.push({
51
- name: 'adb',
52
- ok: hasAdb,
53
- detail: hasAdb ? ((await firstLine('adb', ['version'])) ?? 'present') : 'not on PATH',
54
- fix: hasAdb ? undefined : 'Install Android platform-tools and add to PATH (ANDROID_HOME/platform-tools).',
55
- });
56
- const devices = hasAdb ? await adbDevices() : [];
57
- // Per-device free /data — surfaces the "APK too big for partition" class proactively.
58
- const deviceDetails = await Promise.all(devices.map(async (d) => {
59
- const free = await deviceFreeDataBytes(d);
60
- const low = free != null && free < 600 * 1024 * 1024; // <600MB is risky for RN APKs
61
- return `${d} (/data free: ${fmtBytes(free)}${low ? ' ⚠ low' : ''})`;
62
- }));
63
- const anyLowSpace = deviceDetails.some((d) => d.includes('⚠ low'));
64
- checks.push({
65
- name: 'device-online',
66
- ok: devices.length > 0,
67
- detail: devices.length ? deviceDetails.join(', ') : 'no device/emulator online',
68
- fix: devices.length
69
- ? anyLowSpace
70
- ? 'Low /data space — reboot the emulator with `-wipe-data -partition-size 8192` before installing large RN APKs.'
71
- : undefined
72
- : 'Boot an emulator (qa_prepare_target will offer to), then re-run.',
73
- });
74
- const hasEmulator = await which('emulator');
75
- const avds = hasEmulator ? await listAvds() : [];
76
- checks.push({
77
- name: 'emulator+avd',
78
- ok: hasEmulator && avds.length > 0,
79
- optional: devices.length > 0, // not needed if a device is already online
80
- detail: hasEmulator ? (avds.length ? `AVDs: ${avds.join(', ')}` : 'emulator present, no AVDs') : 'emulator not on PATH',
81
- fix: hasEmulator && avds.length === 0
82
- ? 'Create an AVD: sdkmanager "system-images;android-35;google_apis;arm64-v8a" && avdmanager create avd -n qa -k "system-images;android-35;google_apis;arm64-v8a"'
83
- : hasEmulator
84
- ? undefined
85
- : 'Install the Android Emulator package via sdkmanager.',
86
- });
87
- const java = await firstLine('java', ['-version']);
88
- checks.push({
89
- name: 'java',
90
- ok: java !== null,
91
- optional: true, // only needed for build-from-source / a native backend (later phases)
92
- detail: java ?? 'not found (only needed for build-from-source / a native backend)',
93
- });
94
- const requiredOk = checks.filter((c) => !c.optional).every((c) => c.ok);
100
+ let devices = [];
101
+ let avds = [];
102
+ let androidReady = true;
103
+ if (wantsAndroid) {
104
+ const hasAdb = await which('adb');
105
+ androidChecks.push({
106
+ name: 'adb',
107
+ ok: hasAdb,
108
+ detail: hasAdb ? ((await firstLine('adb', ['version'])) ?? 'present') : 'not on PATH',
109
+ fix: hasAdb ? undefined : 'Install Android platform-tools and add to PATH (ANDROID_HOME/platform-tools).',
110
+ });
111
+ devices = hasAdb ? await adbDevices() : [];
112
+ const deviceDetails = await Promise.all(devices.map(async (d) => {
113
+ const free = await deviceFreeDataBytes(d);
114
+ const low = free != null && free < 600 * 1024 * 1024;
115
+ return `${d} (/data free: ${fmtBytes(free)}${low ? ' low' : ''})`;
116
+ }));
117
+ const anyLowSpace = deviceDetails.some((d) => d.includes(' low'));
118
+ androidChecks.push({
119
+ name: 'device-online',
120
+ ok: devices.length > 0,
121
+ optional: true,
122
+ detail: devices.length ? deviceDetails.join(', ') : 'no device/emulator online',
123
+ fix: devices.length
124
+ ? anyLowSpace
125
+ ? 'Low /data space: reboot the emulator with `-wipe-data -partition-size 8192` before installing large RN APKs.'
126
+ : undefined
127
+ : 'Boot an emulator, or let qa_prepare_target boot an available AVD.',
128
+ });
129
+ const hasEmulator = await which('emulator');
130
+ avds = hasEmulator ? await listAvds() : [];
131
+ androidChecks.push({
132
+ name: 'emulator+avd',
133
+ ok: hasEmulator && avds.length > 0,
134
+ optional: devices.length > 0,
135
+ detail: hasEmulator ? (avds.length ? `AVDs: ${avds.join(', ')}` : 'emulator present, no AVDs') : 'emulator not on PATH',
136
+ fix: hasEmulator && avds.length === 0
137
+ ? 'Create an AVD with Android Studio or avdmanager.'
138
+ : hasEmulator
139
+ ? undefined
140
+ : 'Install the Android Emulator package via Android Studio or sdkmanager.',
141
+ });
142
+ androidChecks.push({
143
+ name: 'android-target',
144
+ ok: devices.length > 0 || (hasEmulator && avds.length > 0),
145
+ detail: devices.length > 0 ? 'online device/emulator available' : hasEmulator && avds.length > 0 ? 'bootable AVD available' : 'no online target or bootable AVD',
146
+ fix: devices.length > 0 || (hasEmulator && avds.length > 0) ? undefined : 'Create or boot an Android Emulator, then rerun qa_doctor.',
147
+ });
148
+ const java = await firstLine('java', ['-version']);
149
+ androidChecks.push({
150
+ name: 'java',
151
+ ok: java !== null,
152
+ optional: true,
153
+ detail: java ?? 'not found (only needed for build-from-source / native Android builds)',
154
+ });
155
+ checks.push(...androidChecks);
156
+ androidReady = androidChecks.filter((c) => !c.optional).every((c) => c.ok);
157
+ }
158
+ let simulators = [];
159
+ let iosReady = true;
160
+ let wdaSummary;
161
+ if (wantsIos) {
162
+ const xcode = await xcodeAvailable();
163
+ iosChecks.push({
164
+ name: 'xcodebuild',
165
+ ok: xcode.available,
166
+ detail: xcode.available ? (xcode.version ?? 'present') : (xcode.error ?? 'not available'),
167
+ fix: xcode.available ? undefined : 'Install Xcode and select it with `xcode-select`.',
168
+ });
169
+ const simctlOk = await simctlAvailable();
170
+ iosChecks.push({
171
+ name: 'simctl',
172
+ ok: simctlOk,
173
+ detail: simctlOk ? 'available' : 'xcrun simctl unavailable',
174
+ fix: simctlOk ? undefined : 'Install Xcode command line tools and an iOS simulator runtime.',
175
+ });
176
+ simulators = simctlOk ? await listSimulators() : [];
177
+ const booted = simulators.filter((s) => s.state === 'Booted');
178
+ iosChecks.push({
179
+ name: 'ios-simulator',
180
+ ok: simulators.length > 0,
181
+ detail: simulators.length ? `${booted.length} booted, ${simulators.length} available` : 'no iOS simulators available',
182
+ fix: simulators.length ? undefined : 'Install an iOS Simulator runtime in Xcode and create a simulator.',
183
+ });
184
+ const root = process.cwd();
185
+ const wdaConfig = loadWdaConfig(root);
186
+ const wda = await checkWda(wdaConfig.url, 1200);
187
+ const discovery = discoverWdaProjects(root);
188
+ const wdaProduct = wdaBuildProductStatus(wdaConfig.derivedDataPath);
189
+ iosChecks.push({
190
+ name: 'wda-server',
191
+ ok: wda.reachable && wda.ready,
192
+ optional: true,
193
+ detail: wda.reachable ? `${wda.ready ? 'ready' : 'reachable but not ready'} at ${wdaConfig.url}` : `not reachable at ${wdaConfig.url}`,
194
+ fix: wda.reachable && wda.ready ? undefined : 'For structured iOS flows, run qa_wda doctor/build/start or attach an external WDA URL.',
195
+ });
196
+ iosChecks.push({
197
+ name: 'wda-project-cache',
198
+ ok: discovery.candidates.length > 0 || wdaProduct.built,
199
+ optional: true,
200
+ detail: wdaProduct.built
201
+ ? `built product: ${wdaProduct.productPath}`
202
+ : discovery.candidates.length
203
+ ? `project candidates: ${discovery.candidates.slice(0, 3).join(', ')}`
204
+ : `no WDA project found; checked cache ${wdaProduct.checkedPath}`,
205
+ fix: discovery.candidates.length > 0 || wdaProduct.built ? undefined : 'Install appium-webdriveragent or configure ios.wda.derivedDataPath / wdaProjectPath.',
206
+ });
207
+ checks.push(...iosChecks);
208
+ iosReady = iosChecks.filter((c) => !c.optional).every((c) => c.ok);
209
+ wdaSummary = { config: { url: wdaConfig.url, mode: wdaConfig.mode, derivedDataPath: wdaConfig.derivedDataPath }, status: wda, projectDiscovery: discovery, buildProduct: wdaProduct };
210
+ }
211
+ const requiredOk = requested === 'android' ? androidReady :
212
+ requested === 'ios' ? iosReady :
213
+ androidReady && iosReady;
95
214
  const clientHint = client ? CLIENT_HINTS[client] : undefined;
96
- const table = checks
97
- .map((c) => `${c.ok ? '✅' : c.optional ? '⚠️ ' : '❌'} ${c.name}: ${c.detail}${c.fix && !c.ok ? ` → ${c.fix}` : ''}`)
98
- .join('\n');
215
+ const table = checks.map(checkLine).join('\n');
99
216
  const summary = `Swipium v${SWIPIUM_VERSION} · ${TOOL_COUNT} tools · schema ${schemaHash}\n${STALE_CLIENT_HINT}\n\n` +
100
- `${requiredOk ? 'Environment ready for Android QA.' : 'Environment NOT ready — see ❌ rows.'}\n${table}`;
217
+ `${requiredOk ? `Environment ready for ${requested} simulator QA.` : `Environment NOT ready for ${requested} simulator QA. See [fail] rows.`}\n${table}`;
101
218
  return qaOk({
102
219
  swipiumVersion: SWIPIUM_VERSION,
103
220
  schemaHash,
104
221
  toolSurface: { count: TOOL_COUNT, tools: TOOL_NAMES },
222
+ platform: requested,
105
223
  ready: requiredOk,
224
+ platformReady: { android: wantsAndroid ? androidReady : null, ios: wantsIos ? iosReady : null },
106
225
  clientFreshness: expectedToolCount != null || expectedVersion != null || expectedSchemaHash != null
107
226
  ? { stale: versionMismatch || toolCountMismatch || schemaHashMismatch, runningVersion: SWIPIUM_VERSION, runningToolCount: TOOL_COUNT, runningSchemaHash: schemaHash, expectedVersion: expectedVersion ?? null, expectedToolCount: expectedToolCount ?? null, expectedSchemaHash: expectedSchemaHash ?? null }
108
227
  : undefined,
109
228
  checks,
229
+ checksByPlatform: { android: androidChecks, ios: iosChecks },
110
230
  devicesOnline: devices,
111
231
  avds,
232
+ simulators: wantsIos ? simulators : undefined,
233
+ wda: wdaSummary,
112
234
  ...(clientHint ? { clientHint } : {}),
113
235
  }, summary);
114
236
  });