1.7.1 works around the Swift 6.4 defect that linked _swift_initBorrow
strongly (apple/swift-collections#739). A Release vphoned built with it
imports no _swift_initBorrow; StageBundle.sh keeps refusing one that does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Mac's CoreLocation fix has vertical accuracy -1 (no altitude). IcliKit
0.7.6 refused it with "vertical accuracy must be 0 or more metres", so
every location.set from Sync Host Location failed. 0.7.7 accepts -1 as an
unknown altitude.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IcliKit 0.7.5 counted AppleDouble sidecars as bundles: an IPA made with
Finder's Compress or ditto without --norsrc carries Payload/._Name.app,
and apps.install refused it with "IPA must contain exactly one
Payload/*.app". 0.7.6 skips __MACOSX and ._* files during extraction
and in the container bundle lookup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vphoned runs in the C locale launchd gives it, and icli's archive readers
converted entry names through that locale. An IPA whose ZIP entries carry
the UTF-8 flag, such as Payload/App.app/What’s New.html, failed apps.install
with "Pathname cannot be converted from UTF-8 to current locale", and a
deb with a PAX UTF-8 path failed the same way. icli 0.7.5 gives each
archive reader a thread-local UTF-8 LC_CTYPE, so vphoned needs no locale
handling of its own.
Reported with a vphoned-side fix and regression harness by Yanni Pang in
#530; the fix moved into icli, which carries the ported tests.
Co-Authored-By: Yanni Pang <2459177+yannip1234@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
icli before 0.7.4 leaked every launchd reply, and a load reply carries the
job's listening sockets. vphoned loads the bootstrap's daemons at boot and
lives until shutdown, so sshd's port stayed bound after an openssh
upgrade booted it out: the reload failed to bind port 22 (launchd logged
`assertion failed ... 0x30`) and the guest had no SSH until a reboot.
Killing vphoned freed the port, which is how the holder was found.
Tested on a RootHide guest with vphoned built against 0.7.4: two rounds
of dpkg -i, dpkg -r and dpkg -i of openssh-server and two rounds of
services.unload/services.load of sshd, with sshd answering after each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IcliKit found the frontmost app only by a FrontBoard focal assertion.
Setup Assistant drops its launch assertion once it is up and never takes
Workspace-ForegroundFocal, so apps.foreground reported "unavailable" and
every ui.* call failed with "frontmost application could not be
verified". 0.7.2 falls back to the one app whose RunningBoard role is
UserInteractiveFocal; 0.7.3 also removes screen describe/ocr temporary
JPEGs on every exit path.
Checked on research-01 (iOS 26.4) with the 0.7.2 build: once unlocked,
apps.foreground reports Setup and then Settings as verified, source
runningboard. A locked or dark screen still has no frontmost app.
The requirement is now upToNextMajor from 0.7.3, as for the other
packages, instead of an exact pin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IcliKit 0.7.0's listServices read launchd's full list with the keys of a
one-label lookup (PID, LastExitStatus). The full list names them pid and
status, so services.list reported all 696 services as stopped with PID 0,
vphoned included, while services.status was right. 0.7.1 reads both.
Checked on research-01: services.list now reports 299 of 696 running,
with vphoned and SpringBoard at the PIDs services.status gives. The
Program column stays empty in the list because launchd's full list has
no program path; the detail pane shows it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Post Darwin notifications from the Controls panel
vphoned gains notify.post {name, state?} and notify.state {name}, thin
calls into IcliKit 0.7.0's postDarwinNotification and
darwinNotificationState. The state is a full UInt64, so it is accepted
as a decimal string as well as a number.
The Controls panel gets a Darwin Notification section: a name field with
presets, an optional state, and Post and Read State buttons. This
replaces #248, which targeted the removed ObjC daemon and sources/ tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refuse a JSON boolean as a notification state
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The window now shows only the machines. Host Setup and Core Bundle are
form sheets opened from the toolbar or the app menu; the first stage
that is not ready opens by itself on launch, and a toolbar button marks
a stage that regresses later. The segmented section picker is gone.
Core Bundle lists GitHub Actions builds next to releases. Listing the
package workflow's vphone-release-<commit> artifacts needs no token;
downloading one does, so a token with Actions read access is kept in the
login keychain. The artifact is checked against GitHub's SHA-256 digest,
the token is dropped on the redirect to blob storage, and the bundle zip
inside is installed as <version>-ci.<commit>. The helper accepts that
suffix, so its build number moves to 7.
The install runs in a collapsible section at the top of the inspector.
It is written to Application Support on every change and survives a
relaunch; a step left running comes back failed. Retry reruns only the
checks once the bundle is in the store and starts over otherwise. A
failed policy exception or preflight can be skipped, which is remembered
per version and can be undone from the installed row's menu. Host Setup
can skip the macOS, physical Mac and APFS checks; Developer Tools access
and the helper stay required.
The inspector toggle sits at the trailing edge, the inspector column
sets its own width, and the window has no minimum size. New Machine
uses research-01 when the name is left empty and refuses it only when
that machine or folder already exists.
The string catalog gains the new strings, and ones that had gone
missing, in every locale.
Update libghostty-spm to 1.6.20260928.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The machine inspector drew the guest console as one SwiftUI Text per
line and updated it on the main actor for every line of serial output,
which made Launchpad unresponsive while a guest printed.
Consoles and the creation log now render in GhosttyTerminal
(Lakr233/libghostty-spm) and are read from their log files:
- The inspector's Console section is an Open Console button. It opens a
sheet with the terminal filling it and a Close button.
- The creation sheet's log is the same terminal over a new
<name>-create.log, written on a serial queue by
VPhoneLaunchpadLogWriter.
- The view replays the file's last 4 MiB and follows it from a
@concurrent task. Ghostty parses on its own queue.
- Command output callbacks run on the reader thread. The main actor
hears only panic lines.
- The terminal uses the project's light palette and a dark counterpart,
chosen by the system appearance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vphone-launchpad downloads and manages VPhone.bundle releases and drives
VMs through the active bundle's vphone-cli. It carries no entitlements.
Developer Tools access plus an EPExecutionPolicy exception per installed
bundle let the unnotarized bundle run, and one SMJobBless helper is the
only root surface.
The helper has fixed verbs, not a command runner. It installs a release
into the root-owned store after checking the published SHA-256 and a
strict signature check, recording cdhashes. It runs `cfw install` from
that store as root for the calling user, after rechecking the cdhash and
that the VM directory is theirs.
The UI is native SwiftUI in three stages: Host Setup, Core Bundle and
Machines. Each stage appears once the previous one passes. New Machine
runs the vm create stages one command at a time, so root is limited to
the CFW step. Guests log to files instead of pipes, so they outlive the
app.
Nothing is signed at build time. All settings live in layered xcconfigs,
and the signing team comes from a gitignored Developer.xcconfig.
Build/SignLaunchpad.sh signs afterwards.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0.6.9 takes minimum versions of its own dependencies instead of exact
pins; the API vphoned uses is unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
libarchive.xcframework 0.1.1 shipped a Swift module, LibArchive, that
differed from its C module, libarchive, only in case. Xcode 27 puts both
in one products directory, and on a case-insensitive volume the lookup
for libarchive found LibArchive.swiftmodule, so the nested
VPhoneArchiveKit build failed with "cannot load module 'LibArchive' as
'libarchive'" and the VPhone bundle could not be built. 1.0.0 renames
the module and products to ArchiveKit; icli 0.6.8 moves to it as well,
so the workspace resolves one version.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>