App layer, four sequential slices (a shared .xcodeproj means adding files
regenerates it, so these could not run in parallel):
- token UX end to end: pairing prompts for a token when a host 401s, POST /auth
validates it, and 204-without-Set-Cookie is correctly read as "this server has
auth disabled" rather than "authenticated". A host paired before the token was
turned on recovers by re-pairing in place. Remove-host now exists and finally
gives PushRegistrar.handleHostRemoved a caller.
- project git panel + worktree lifecycle (T-iOS-32) + claude --resume history —
the parity gap with Android and the web front end.
- terminal search (T-iOS-33) and voice PTT (T-iOS-31) with an epoch guard so a
session switch between dictation and confirm cannot inject into the wrong
session.
- theme + Dynamic Type (T-iOS-34) and web ?join= interop (T-iOS-35). RootView no
longer hard-locks .preferredColorScheme(.dark).
Also unpins SwiftTerm to 1.15.0 by dropping the local hasActiveSelection that
collided with the upstream one, verified green from a fresh derivedDataPath.
Includes the two HIGH fixes the security review found:
- iOS resolved the WS token host-independently, so a token-gated host sitting
next to an open one could never open a terminal and no on-screen remedy could
fix it. Now one transport per host; cross-host leakage is structurally
impossible since both read paths return only that host's own value.
- Android reported the host's own git-credential 401 (git-ops.ts:108, "Push
authentication required on the host.") as "your access token is wrong", because
a blanket 401 mapping ran ahead of the per-route one. Git-write routes are now
ROUTE_DEFINED and keep the server's message.
And the doc sync: README/ios README no longer claim the client is unmerged on
feat/ios-client, the Clients section finally lists Android, and the plan
checkboxes reflect what is actually built.
iOS 534 app tests + 452 package tests; Android 687 tests.
Android could not connect at all once the server set WEBTERM_TOKEN. Hand-written
Cookie header on every request and on the WS upgrade (no CookieJar, matching the
frozen decision), POST /auth pairing probe, Keystore-backed storage, and a 401
upgrade as a terminal state with no reconnect loop.
Android SDK installed on this machine (cmdline-tools via brew;
platform-tools + platforms;android-35 + build-tools;35.0.0), local.properties
points Gradle at it (gitignored). Wired AGP 9.2.1 into the version catalog +
google() repos; proved the full chain by building a throwaway android-library
module against SDK 35 (AAR produced), then removed the probe.
Groundwork for AW2+: AGP plugins in the catalog, google() in settings, and the
working recipe in README (incl. the AGP-9-has-built-in-Kotlin gotcha — Android
modules apply ONLY the android plugin, never kotlin.android). Pure JVM modules
still green (218 tests). Framework module stubs stay gated until implemented.