From a989ac19a2e61c22c7354da0a1b2b66e945ee4b7 Mon Sep 17 00:00:00 2001 From: hideouts-io <83608068+hideouts-io@users.noreply.github.com> Date: Mon, 28 Sep 2026 02:16:11 -0700 Subject: [PATCH 1/4] Stop a Web Inspector retry test depending on runner speed The release run failed because a loaded runner completed only two refused sessions before the 600 ms deadline, where the test required more than two. Two sessions already prove a refusal was retried; the test now requires that and allows 1.5 s. hideouts.io --- Tests/DeviceKitTests/ServiceTests.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/DeviceKitTests/ServiceTests.swift b/Tests/DeviceKitTests/ServiceTests.swift index 1732d96..45260e5 100644 --- a/Tests/DeviceKitTests/ServiceTests.swift +++ b/Tests/DeviceKitTests/ServiceTests.swift @@ -163,14 +163,16 @@ struct ServiceTests { let inspector = FakeWebInspector(refusals: 100) try await runWithServer({ inspector.register(on: $0) }) { server in do { - _ = try await WebInspector.openPages(on: server.target, usbmux: server.client, handshakeDeadline: .milliseconds(600), retryInterval: .milliseconds(100)) + _ = try await WebInspector.openPages(on: server.target, usbmux: server.client, handshakeDeadline: .milliseconds(1500), retryInterval: .milliseconds(100)) Issue.record("expected a refusal") } catch let error as ToolkitError { #expect(error.message == "Safari Web Inspector did not answer.") #expect(error.recovery?.contains("Settings › Apps › Safari › Advanced › Web Inspector") == true) #expect(error.recovery?.contains("ten seconds") == true) } - #expect(inspector.sessions > 2, "refusals are retried until the deadline") + // At least one retry. Each attempt includes a TLS handshake, which a loaded CI runner can + // make slow, so the exact number of attempts before the deadline varies. + #expect(inspector.sessions >= 2, "refusals are retried until the deadline") } } From abe064d81ac1c8c1c7a14bfbfce5a19a0e96fbc8 Mon Sep 17 00:00:00 2001 From: hideouts-io <83608068+hideouts-io@users.noreply.github.com> Date: Mon, 28 Sep 2026 02:16:11 -0700 Subject: [PATCH 2/4] Point to the Python app (0.3.4) in the README hideouts.io --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index db9323e..2aa17fa 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,14 @@ Version 1.0 is a complete rewrite of the earlier Python/PySide6 app (0.3.x), whi profiles exported by 0.3.x can be imported in **Settings › Profiles**; the preview explains how each setting carries over. +### The Python app (0.3.x) + +The last Python/PySide6 version, **0.3.4**, is still available: download it from the +[v0.3.4 release](https://github.com/hideouts-io/iOS-Developer-Toolkit/releases/tag/v0.3.4) +(separate Apple silicon and Intel builds) or use the source on the +[`python-0.3`](https://github.com/hideouts-io/iOS-Developer-Toolkit/tree/python-0.3) branch. It depends +on `pymobiledevice3` and is no longer developed; new features and fixes go into 1.x. + - The native lockdown services (logs, packet capture, backup, diagnostics, app installation over USB, developer-image checking and mounting including Apple personalization) are tested end to end against a protocol-accurate simulated device and against macOS's real device service. Their From f0da9daf9b48582e914399492b31e149b21ca727 Mon Sep 17 00:00:00 2001 From: hideouts-io <83608068+hideouts-io@users.noreply.github.com> Date: Mon, 28 Sep 2026 02:21:58 -0700 Subject: [PATCH 3/4] Document the Python app as maintained; keep release tags apart The Python app continues as the 0.x line on the python branch. The README and MIGRATION.md say so, and the Swift release workflow builds only 1.x and later tags, so 0.x tags from the python branch never trigger it. hideouts.io --- .github/workflows/release.yml | 4 +++- MIGRATION.md | 3 +++ README.md | 12 ++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4727348..d1c6d47 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,11 @@ name: Release +# The Swift app is released as 1.x and later from main; v0.* tags belong to the Python app +# on the python branch. on: push: tags: - - "v*" + - "v[1-9]*" permissions: contents: read diff --git a/MIGRATION.md b/MIGRATION.md index d75195d..577a693 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -9,6 +9,9 @@ itself) · 🟡 migrated and tested against the protocol-accurate fake device or needs physical-device verification · 🔁 replaced by a different Apple-supported mechanism · ❌ not migrated (see §6) or removed +> The Python app is not discontinued: it continues as the 0.x line on the `python` branch (see +> the README). This document covers how its features map to the Swift app (1.x) on `main`. + ## 1. Audit of the Python application (v0.3.4) ### 1.1 Repository inventory diff --git a/README.md b/README.md index 2aa17fa..3e745fe 100644 --- a/README.md +++ b/README.md @@ -343,13 +343,13 @@ Version 1.0 is a complete rewrite of the earlier Python/PySide6 app (0.3.x), whi profiles exported by 0.3.x can be imported in **Settings › Profiles**; the preview explains how each setting carries over. -### The Python app (0.3.x) +### The Python app (0.x) -The last Python/PySide6 version, **0.3.4**, is still available: download it from the -[v0.3.4 release](https://github.com/hideouts-io/iOS-Developer-Toolkit/releases/tag/v0.3.4) -(separate Apple silicon and Intel builds) or use the source on the -[`python-0.3`](https://github.com/hideouts-io/iOS-Developer-Toolkit/tree/python-0.3) branch. It depends -on `pymobiledevice3` and is no longer developed; new features and fixes go into 1.x. +The Python/PySide6 app is still maintained, as a separate line: it is developed on the +[`python`](https://github.com/hideouts-io/iOS-Developer-Toolkit/tree/python) branch and released as +`v0.x` ([0.x releases](https://github.com/hideouts-io/iOS-Developer-Toolkit/releases?q=v0.&expanded=true), +with separate Apple silicon and Intel builds). It uses `pymobiledevice3` and Python; this app (1.x) +needs neither. Workspace profiles move between them: 1.x imports profiles exported by 0.x. - The native lockdown services (logs, packet capture, backup, diagnostics, app installation over USB, developer-image checking and mounting including Apple personalization) are tested end to From 65bef11e702f2434e55d88264926ad8b5ed482f1 Mon Sep 17 00:00:00 2001 From: hideouts-io <83608068+hideouts-io@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:11:11 -0700 Subject: [PATCH 4/4] Accept slow Xcode tools in the simulator end-to-end test On a runner where the simulator took about seven minutes to boot, devicectl did not answer within the readiness probe's 45 seconds, and the app correctly reported "Xcode's tools did not answer in time". The test now accepts that outcome, and still fails if Xcode is reported missing. hideouts.io --- Tests/ToolkitFeaturesTests/RealSimulatorTests.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Tests/ToolkitFeaturesTests/RealSimulatorTests.swift b/Tests/ToolkitFeaturesTests/RealSimulatorTests.swift index 5dec2c2..c31934c 100644 --- a/Tests/ToolkitFeaturesTests/RealSimulatorTests.swift +++ b/Tests/ToolkitFeaturesTests/RealSimulatorTests.swift @@ -77,7 +77,11 @@ struct RealSimulatorTests { let running = readiness.first { $0.id == "simulator-running" } let xcode = readiness.first { $0.id == "xcode-tools" } #expect(running?.state == .ready, "\(running?.summary ?? "") \(running?.evidence ?? "")") - #expect(xcode?.state == .ready, "\(xcode?.summary ?? "") \(xcode?.evidence ?? "")") + // On a heavily loaded runner (a simulator that took minutes to boot), Xcode's tools can take + // longer than the probe allows; the app then says so rather than claiming Xcode is missing. + let xcodeAnsweredOrWasSlow = xcode?.state == .ready + || (xcode?.state == .attention && xcode?.summary.contains("did not answer in time") == true) + #expect(xcodeAnsweredOrWasSlow, "\(xcode?.state.rawValue ?? "none"): \(xcode?.summary ?? "") \(xcode?.evidence ?? "")") // Install, list, launch, and remove a real (minimal) simulator app. step("building fixture app")