preflite 1.1.0 → 1.1.3
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/README.md +113 -62
- package/dist/infrastructure/midscene/MidsceneRuntimeReal.js +41 -3
- package/dist/mcp/agentHttpClient.js +19 -6
- package/dist/mcp/cli.js +27 -1
- package/dist/mcp/exploration/tools-intelligent.js +50 -7
- package/dist/mcp/exploration/tools-session.js +1 -0
- package/dist/mcp/network-mocks/NetworkMockServer.js +579 -0
- package/dist/mcp/network-mocks/NetworkMockService.js +156 -0
- package/dist/mcp/network-mocks/device-proxy.js +31 -0
- package/dist/mcp/network-mocks/index.js +3 -0
- package/dist/mcp/network-mocks/types.js +1 -0
- package/dist/mcp/runManager.js +4 -1
- package/dist/mcp/runtimeInstall.js +44 -10
- package/dist/mcp/server.js +229 -23
- package/dist/mcp/setup.js +9 -5
- package/dist/mcp/visual-flow/types.js +1 -1
- package/dist/mcp/visual-flow/validate.js +171 -0
- package/docs/visual-flow-ir-llm.md +221 -0
- package/package.json +3 -1
- package/scripts/hdc-bridge.sh +4 -0
- package/scripts/nvm-use-repo.sh +31 -0
- package/scripts/run-midscene-task.sh +43 -0
- package/scripts/start-ios-wda.sh +328 -0
- package/scripts/stop-ios-wda.sh +44 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
UDID="${1:-}"
|
|
5
|
+
WDA_PORT="${2:-}"
|
|
6
|
+
|
|
7
|
+
EXIT_MISSING_ARGS=1
|
|
8
|
+
EXIT_DEVICE_NOT_CONNECTED=2
|
|
9
|
+
EXIT_WDA_START_FAILED=3
|
|
10
|
+
EXIT_DEPENDENCY_MISSING=4
|
|
11
|
+
|
|
12
|
+
if [[ -z "${UDID}" || -z "${WDA_PORT}" ]]; then
|
|
13
|
+
echo "[start-ios-wda] usage: $0 <UDID> <WDA_PORT>"
|
|
14
|
+
exit "${EXIT_MISSING_ARGS}"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
if ! [[ "${WDA_PORT}" =~ ^[0-9]+$ ]]; then
|
|
18
|
+
echo "[start-ios-wda] invalid WDA_PORT: ${WDA_PORT}"
|
|
19
|
+
exit "${EXIT_MISSING_ARGS}"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Local MJPEG port: matches Agent / Midscene convention, default = WDA local port + 1000 → device:9100 (WDA video stream)
|
|
23
|
+
MJPEG_LOCAL_PORT=$((WDA_PORT + 1000))
|
|
24
|
+
if [[ "${MJPEG_LOCAL_PORT}" -gt 65535 ]]; then
|
|
25
|
+
echo "[start-ios-wda] WDA_PORT+1000 exceeds max port: ${WDA_PORT} -> ${MJPEG_LOCAL_PORT}"
|
|
26
|
+
exit "${EXIT_MISSING_ARGS}"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
30
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
31
|
+
AGENT_HOME="${AGENT_HOME:-${HOME}/.preflight}"
|
|
32
|
+
|
|
33
|
+
WDA_ROOT="${WDA_PROJECT_ROOT:-${REPO_ROOT}/third_party/WebDriverAgent}"
|
|
34
|
+
WDA_PROJECT="${WDA_PROJECT_PATH:-${WDA_ROOT}/WebDriverAgent.xcodeproj}"
|
|
35
|
+
WDA_SCHEME="${WDA_SCHEME:-WebDriverAgentRunner}"
|
|
36
|
+
WDA_DERIVED_DATA="${WDA_DERIVED_DATA:-${AGENT_HOME}/state/wda-derived-data/${UDID}}"
|
|
37
|
+
|
|
38
|
+
WDA_LOG_DIR="${WDA_LOG_DIR:-${AGENT_HOME}/logs/wda}"
|
|
39
|
+
WDA_LOG_FILE="${WDA_LOG_DIR}/wda-${UDID}-${WDA_PORT}.log"
|
|
40
|
+
IPROXY_LOG_FILE="${WDA_LOG_DIR}/iproxy-${UDID}-${WDA_PORT}.log"
|
|
41
|
+
|
|
42
|
+
WDA_STATUS_URL="http://127.0.0.1:${WDA_PORT}/status"
|
|
43
|
+
|
|
44
|
+
mkdir -p "${WDA_LOG_DIR}" "${WDA_DERIVED_DATA}"
|
|
45
|
+
|
|
46
|
+
# Lock file to prevent concurrent script instances (the watchdog polls every 5s,
|
|
47
|
+
# but build-for-testing can take minutes). Uses PID-based stale detection.
|
|
48
|
+
BUILD_LOCK_DIR="${AGENT_HOME}/state/wda-locks"
|
|
49
|
+
mkdir -p "${BUILD_LOCK_DIR}"
|
|
50
|
+
BUILD_LOCK="${BUILD_LOCK_DIR}/wda-start-${UDID}-${WDA_PORT}.pid"
|
|
51
|
+
|
|
52
|
+
try_acquire_lock() {
|
|
53
|
+
if [[ -f "${BUILD_LOCK}" ]]; then
|
|
54
|
+
local old_pid
|
|
55
|
+
old_pid=$(cat "${BUILD_LOCK}" 2>/dev/null)
|
|
56
|
+
if [[ -n "${old_pid}" ]] && kill -0 "${old_pid}" 2>/dev/null; then
|
|
57
|
+
echo "[start-ios-wda] another instance already running (pid=${old_pid}), skipping"
|
|
58
|
+
return 1
|
|
59
|
+
fi
|
|
60
|
+
echo "[start-ios-wda] removing stale lock from pid=${old_pid}"
|
|
61
|
+
rm -f "${BUILD_LOCK}"
|
|
62
|
+
fi
|
|
63
|
+
echo "$$" > "${BUILD_LOCK}"
|
|
64
|
+
trap 'rm -f "${BUILD_LOCK}"' EXIT
|
|
65
|
+
return 0
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if [[ ! -d "${WDA_PROJECT}" ]]; then
|
|
69
|
+
echo "[start-ios-wda] WDA project not found: ${WDA_PROJECT}"
|
|
70
|
+
echo "[start-ios-wda] run: npm run clone:wda"
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
for cmd in xcrun curl iproxy xcodebuild; do
|
|
75
|
+
if ! command -v "${cmd}" >/dev/null 2>&1; then
|
|
76
|
+
echo "[start-ios-wda] missing dependency: ${cmd}"
|
|
77
|
+
if [[ "${cmd}" == "iproxy" ]]; then
|
|
78
|
+
echo "[start-ios-wda] install it with: brew install libimobiledevice"
|
|
79
|
+
fi
|
|
80
|
+
exit "${EXIT_DEPENDENCY_MISSING}"
|
|
81
|
+
fi
|
|
82
|
+
done
|
|
83
|
+
|
|
84
|
+
device_is_online() {
|
|
85
|
+
# Check physical devices first (== Devices ==)
|
|
86
|
+
xcrun xctrace list devices 2>/dev/null | awk '
|
|
87
|
+
/^== Devices ==/ { in_devices=1; next }
|
|
88
|
+
/^== / { in_devices=0 }
|
|
89
|
+
in_devices { print }
|
|
90
|
+
' | grep -F "(${UDID})" >/dev/null 2>&1 && return 0
|
|
91
|
+
|
|
92
|
+
# Then check booted simulators
|
|
93
|
+
xcrun simctl list devices booted 2>/dev/null | grep -F "(${UDID})" >/dev/null 2>&1
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
device_is_simulator() {
|
|
97
|
+
xcrun simctl list devices booted 2>/dev/null | grep -F "(${UDID})" >/dev/null 2>&1
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
wda_is_healthy() {
|
|
101
|
+
curl -fsS --max-time 2 "${WDA_STATUS_URL}" >/dev/null 2>&1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
kill_iproxy_for_udid() {
|
|
105
|
+
pkill -f "iproxy.*-u[[:space:]]+${UDID}" >/dev/null 2>&1 || true
|
|
106
|
+
pkill -f "iproxy.*${UDID}" >/dev/null 2>&1 || true
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
kill_xcodebuild_for_udid() {
|
|
110
|
+
pkill -f "xcodebuild.*id=${UDID}" >/dev/null 2>&1 || true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
xcodebuild_is_running_for_udid() {
|
|
114
|
+
pgrep -f "xcodebuild.*id=${UDID}" >/dev/null 2>&1
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
start_iproxy() {
|
|
118
|
+
if device_is_simulator; then
|
|
119
|
+
echo "[start-ios-wda] simulator mode, WDA binds directly to port ${WDA_PORT} (USE_PORT) — no forwarding needed"
|
|
120
|
+
return 0
|
|
121
|
+
fi
|
|
122
|
+
echo "[start-ios-wda] starting iproxy: 127.0.0.1:${WDA_PORT}->device:8100, 127.0.0.1:${MJPEG_LOCAL_PORT}->device:9100 (MJPEG)"
|
|
123
|
+
nohup iproxy -u "${UDID}" "${WDA_PORT}:8100" "${MJPEG_LOCAL_PORT}:9100" >>"${IPROXY_LOG_FILE}" 2>&1 &
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Modify .xctestrun plist to inject environment variables into the test process.
|
|
127
|
+
# This is the only reliable way to set env vars (USE_PORT, MJPEG_SERVER_PORT)
|
|
128
|
+
# for simulator test runners, because testmanagerd does NOT forward macOS env vars
|
|
129
|
+
# into the simulator's iOS runtime.
|
|
130
|
+
# Find the test-bundle key (top-level key excluding __xctestrun_metadata__) in xctestrun.
|
|
131
|
+
# Recent Xcode uses flat <bundleName> as key instead of TestConfigurations array.
|
|
132
|
+
get_xctestrun_bundle_key() {
|
|
133
|
+
local xctestrun="$1"
|
|
134
|
+
plutil -p "${xctestrun}" 2>/dev/null | grep '^ "' | grep -v '__xctestrun_metadata__' | head -1 | sed 's/^ "\(.*\)" =>.*/\1/'
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
inject_env_vars_into_xctestrun() {
|
|
138
|
+
local xctestrun="$1"
|
|
139
|
+
local port="$2"
|
|
140
|
+
local mjpeg_port="$3"
|
|
141
|
+
local bundle_key
|
|
142
|
+
|
|
143
|
+
bundle_key=$(get_xctestrun_bundle_key "${xctestrun}")
|
|
144
|
+
if [[ -z "${bundle_key}" ]]; then
|
|
145
|
+
echo "[start-ios-wda] could not determine bundle key in xctestrun"
|
|
146
|
+
return 1
|
|
147
|
+
fi
|
|
148
|
+
echo "[start-ios-wda] xctestrun bundle key: ${bundle_key}"
|
|
149
|
+
|
|
150
|
+
# Method 1: Inject USE_PORT / MJPEG_SERVER_PORT into EnvironmentVariables dict
|
|
151
|
+
# This is consumed by FBConfiguration's NSProcessInfo.processInfo.environment check.
|
|
152
|
+
local env_path="${bundle_key}.EnvironmentVariables.USE_PORT"
|
|
153
|
+
echo "[start-ios-wda] injecting USE_PORT=${port} at ${env_path}"
|
|
154
|
+
if plutil -insert "${env_path}" -string "${port}" "${xctestrun}" 2>/dev/null; then
|
|
155
|
+
echo "[start-ios-wda] injected USE_PORT"
|
|
156
|
+
else
|
|
157
|
+
# Key may already exist — replace instead
|
|
158
|
+
plutil -replace "${env_path}" -string "${port}" "${xctestrun}" 2>/dev/null && \
|
|
159
|
+
echo "[start-ios-wda] replaced USE_PORT" || \
|
|
160
|
+
echo "[start-ios-wda] WARNING: could not set USE_PORT"
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
plutil -insert "${bundle_key}.EnvironmentVariables.MJPEG_SERVER_PORT" \
|
|
164
|
+
-string "${mjpeg_port}" "${xctestrun}" 2>/dev/null || \
|
|
165
|
+
plutil -replace "${bundle_key}.EnvironmentVariables.MJPEG_SERVER_PORT" \
|
|
166
|
+
-string "${mjpeg_port}" "${xctestrun}" 2>/dev/null || true
|
|
167
|
+
|
|
168
|
+
# Method 2: Inject --port into CommandLineArguments (HIGHEST priority in FBConfiguration:
|
|
169
|
+
# bindingPortRangeFromArguments reads NSProcessInfo.processInfo.arguments for "--port").
|
|
170
|
+
local cla_path="${bundle_key}.CommandLineArguments"
|
|
171
|
+
echo "[start-ios-wda] injecting --port ${port} into CommandLineArguments"
|
|
172
|
+
if plutil -replace "${cla_path}" \
|
|
173
|
+
-json "[\"--port\",\"${port}\",\"--mjpeg-server-port\",\"${mjpeg_port}\"]" \
|
|
174
|
+
"${xctestrun}" 2>/dev/null; then
|
|
175
|
+
echo "[start-ios-wda] injected --port via CommandLineArguments"
|
|
176
|
+
else
|
|
177
|
+
echo "[start-ios-wda] WARNING: could not set CommandLineArguments"
|
|
178
|
+
fi
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
start_xcodebuild() {
|
|
182
|
+
echo "[start-ios-wda] starting xcodebuild for WDA"
|
|
183
|
+
|
|
184
|
+
if device_is_simulator; then
|
|
185
|
+
echo "[start-ios-wda] simulator mode: using build-for-testing + xctestrun approach"
|
|
186
|
+
echo "[start-ios-wda] (macOS env vars do NOT propagate into simulator test processes)"
|
|
187
|
+
|
|
188
|
+
# Step 1: Build the test bundle and generate .xctestrun (blocking)
|
|
189
|
+
xcodebuild build-for-testing \
|
|
190
|
+
-project "${WDA_PROJECT}" \
|
|
191
|
+
-scheme "${WDA_SCHEME}" \
|
|
192
|
+
-destination "id=${UDID}" \
|
|
193
|
+
-derivedDataPath "${WDA_DERIVED_DATA}" \
|
|
194
|
+
>>"${WDA_LOG_FILE}" 2>&1
|
|
195
|
+
|
|
196
|
+
BUILD_RESULT=$?
|
|
197
|
+
if [[ "${BUILD_RESULT}" -ne 0 ]]; then
|
|
198
|
+
echo "[start-ios-wda] build-for-testing failed (exit=${BUILD_RESULT})"
|
|
199
|
+
echo "[start-ios-wda] check the log for details: ${WDA_LOG_FILE}"
|
|
200
|
+
return 1
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# Step 2: Find the .xctestrun file in derived data
|
|
204
|
+
XCTESTRUN=$(find "${WDA_DERIVED_DATA}" -name "*.xctestrun" -print -quit 2>/dev/null)
|
|
205
|
+
if [[ -z "${XCTESTRUN}" ]]; then
|
|
206
|
+
echo "[start-ios-wda] .xctestrun not found in ${WDA_DERIVED_DATA}"
|
|
207
|
+
echo "[start-ios-wda] falling back to env-var approach (may not work)"
|
|
208
|
+
USE_PORT="${WDA_PORT}" MJPEG_SERVER_PORT="${MJPEG_LOCAL_PORT}" \
|
|
209
|
+
nohup xcodebuild \
|
|
210
|
+
-project "${WDA_PROJECT}" \
|
|
211
|
+
-scheme "${WDA_SCHEME}" \
|
|
212
|
+
-destination "id=${UDID}" \
|
|
213
|
+
test >>"${WDA_LOG_FILE}" 2>&1 &
|
|
214
|
+
else
|
|
215
|
+
# Step 3: Inject environment variables into the xctestrun plist
|
|
216
|
+
inject_env_vars_into_xctestrun "${XCTESTRUN}" "${WDA_PORT}" "${MJPEG_LOCAL_PORT}"
|
|
217
|
+
|
|
218
|
+
echo "[start-ios-wda] modified xctestrun: ${XCTESTRUN}"
|
|
219
|
+
|
|
220
|
+
# Step 4: Run with modified xctestrun (skip rebuild, background)
|
|
221
|
+
nohup xcodebuild test-without-building \
|
|
222
|
+
-xctestrun "${XCTESTRUN}" \
|
|
223
|
+
-destination "id=${UDID}" \
|
|
224
|
+
-derivedDataPath "${WDA_DERIVED_DATA}" \
|
|
225
|
+
>>"${WDA_LOG_FILE}" 2>&1 &
|
|
226
|
+
fi
|
|
227
|
+
else
|
|
228
|
+
echo "[start-ios-wda] real-device mode: iproxy handles port forwarding, starting xcodebuild"
|
|
229
|
+
nohup xcodebuild \
|
|
230
|
+
-project "${WDA_PROJECT}" \
|
|
231
|
+
-scheme "${WDA_SCHEME}" \
|
|
232
|
+
-destination "id=${UDID}" \
|
|
233
|
+
test >>"${WDA_LOG_FILE}" 2>&1 &
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
XCODEBUILD_PID=$!
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
wait_for_wda() {
|
|
240
|
+
local timeout_seconds="${1:-90}"
|
|
241
|
+
|
|
242
|
+
echo "[start-ios-wda] waiting for WDA status: ${WDA_STATUS_URL}"
|
|
243
|
+
|
|
244
|
+
for _ in $(seq 1 "${timeout_seconds}"); do
|
|
245
|
+
if ! device_is_online; then
|
|
246
|
+
echo "[start-ios-wda] device disconnected while starting: ${UDID}"
|
|
247
|
+
exit "${EXIT_DEVICE_NOT_CONNECTED}"
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
if wda_is_healthy; then
|
|
251
|
+
echo "[start-ios-wda] wda ready: ${WDA_STATUS_URL}"
|
|
252
|
+
echo "[start-ios-wda] mjpeg_url=http://127.0.0.1:${MJPEG_LOCAL_PORT}/ (local -> device:9100)"
|
|
253
|
+
echo "[start-ios-wda] wda_log=${WDA_LOG_FILE}"
|
|
254
|
+
echo "[start-ios-wda] iproxy_log=${IPROXY_LOG_FILE}"
|
|
255
|
+
return 0
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
sleep 1
|
|
259
|
+
done
|
|
260
|
+
|
|
261
|
+
return 1
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
echo "[start-ios-wda] checking device online: ${UDID}"
|
|
265
|
+
|
|
266
|
+
if ! device_is_online; then
|
|
267
|
+
echo "[start-ios-wda] device not connected or not online: ${UDID}"
|
|
268
|
+
echo "[start-ios-wda] only devices under '== Devices ==' are considered online"
|
|
269
|
+
exit "${EXIT_DEVICE_NOT_CONNECTED}"
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
# Acquire exclusive lock to prevent concurrent watchdog instances from racing.
|
|
273
|
+
if ! try_acquire_lock; then
|
|
274
|
+
exit 0
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
# Case 1: requested local port is already healthy.
|
|
278
|
+
if wda_is_healthy; then
|
|
279
|
+
echo "[start-ios-wda] wda already healthy on requested port: ${WDA_STATUS_URL}"
|
|
280
|
+
exit 0
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# Case 2: status is unhealthy. Check whether xcodebuild is already running.
|
|
284
|
+
if xcodebuild_is_running_for_udid; then
|
|
285
|
+
echo "[start-ios-wda] xcodebuild already running for udid=${UDID}, waiting for WDA on port ${WDA_PORT}"
|
|
286
|
+
|
|
287
|
+
if wait_for_wda 60; then
|
|
288
|
+
echo "[start-ios-wda] WDA became healthy on port ${WDA_PORT}"
|
|
289
|
+
exit 0
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
# xcodebuild is running but WDA not healthy after waiting.
|
|
293
|
+
# Could be still building, or WDA is on a different port.
|
|
294
|
+
# Don't kill xcodebuild — let the next poll cycle retry.
|
|
295
|
+
echo "[start-ios-wda] xcodebuild running but WDA not healthy on ${WDA_PORT} after 60s, will retry"
|
|
296
|
+
exit 1
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
# Case 3: no running xcodebuild — start fresh.
|
|
300
|
+
echo "[start-ios-wda] no existing xcodebuild for udid, starting xcodebuild"
|
|
301
|
+
if ! start_xcodebuild; then
|
|
302
|
+
echo "[start-ios-wda] start_xcodebuild failed, aborting"
|
|
303
|
+
echo "[start-ios-wda] check the log: ${WDA_LOG_FILE}"
|
|
304
|
+
tail -n 40 "${WDA_LOG_FILE}" 2>/dev/null || true
|
|
305
|
+
exit "${EXIT_WDA_START_FAILED}"
|
|
306
|
+
fi
|
|
307
|
+
start_iproxy
|
|
308
|
+
|
|
309
|
+
if wait_for_wda 90; then
|
|
310
|
+
echo "[start-ios-wda] started udid=${UDID} wda_local=${WDA_PORT} mjpeg_local=${MJPEG_LOCAL_PORT}"
|
|
311
|
+
if [[ -n "${XCODEBUILD_PID:-}" ]]; then
|
|
312
|
+
echo "[start-ios-wda] xcodebuild_pid=${XCODEBUILD_PID}"
|
|
313
|
+
fi
|
|
314
|
+
exit 0
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
echo "[start-ios-wda] failed to start WDA within timeout"
|
|
318
|
+
echo "[start-ios-wda] status_url=${WDA_STATUS_URL}"
|
|
319
|
+
echo "[start-ios-wda] wda_log=${WDA_LOG_FILE}"
|
|
320
|
+
echo "[start-ios-wda] iproxy_log=${IPROXY_LOG_FILE}"
|
|
321
|
+
|
|
322
|
+
echo "[start-ios-wda] last WDA logs:"
|
|
323
|
+
tail -n 80 "${WDA_LOG_FILE}" 2>/dev/null || true
|
|
324
|
+
|
|
325
|
+
echo "[start-ios-wda] last iproxy logs:"
|
|
326
|
+
tail -n 40 "${IPROXY_LOG_FILE}" 2>/dev/null || true
|
|
327
|
+
|
|
328
|
+
exit "${EXIT_WDA_START_FAILED}"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
stop_all_by_name() {
|
|
5
|
+
local process_name="$1"
|
|
6
|
+
local -a pids=()
|
|
7
|
+
local -a remaining=()
|
|
8
|
+
|
|
9
|
+
# macOS built-in bash (3.2) has no mapfile; collect pids via read loop.
|
|
10
|
+
while IFS= read -r pid; do
|
|
11
|
+
if [[ -n "${pid}" ]]; then
|
|
12
|
+
pids+=("${pid}")
|
|
13
|
+
fi
|
|
14
|
+
done < <(pgrep -x "${process_name}" || true)
|
|
15
|
+
|
|
16
|
+
if [[ "${#pids[@]}" -eq 0 ]]; then
|
|
17
|
+
echo "[stop-ios-wda] no ${process_name} process found"
|
|
18
|
+
return 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "[stop-ios-wda] stopping ${process_name} pids: ${pids[*]}"
|
|
22
|
+
kill "${pids[@]}" 2>/dev/null || true
|
|
23
|
+
sleep 1
|
|
24
|
+
|
|
25
|
+
for pid in "${pids[@]}"; do
|
|
26
|
+
if kill -0 "${pid}" >/dev/null 2>&1; then
|
|
27
|
+
remaining+=("${pid}")
|
|
28
|
+
fi
|
|
29
|
+
done
|
|
30
|
+
|
|
31
|
+
if [[ "${#remaining[@]}" -gt 0 ]]; then
|
|
32
|
+
echo "[stop-ios-wda] force killing ${process_name} pids: ${remaining[*]}"
|
|
33
|
+
kill -9 "${remaining[@]}" 2>/dev/null || true
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
echo "[stop-ios-wda] ${process_name} cleaned"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
echo "[stop-ios-wda] cleanup started"
|
|
40
|
+
stop_all_by_name "iproxy"
|
|
41
|
+
stop_all_by_name "xcodebuild"
|
|
42
|
+
# Clean up simulator WDA Node.js TCP forwarding (pattern: connect(8100, '127.0.0.1'))
|
|
43
|
+
pkill -f "node.*connect.8100.*127.0.0.1" 2>/dev/null || true
|
|
44
|
+
echo "[stop-ios-wda] cleanup finished"
|