feat(apple): enable native dogfooding and session handoff - #87
Conversation
…t it The single-file t4-host is built with --external playwright-core (its dynamic deep requires defeat bundling), but the preview service imported it eagerly, crashing deployed binaries at startup with 'Cannot find package'. Now the import happens on first preview launch and fails closed with a clear 'unavailable' PreviewServiceError.
…tures Pair validation rejects unknown capability strings, and preview/search/watch commands are feature-gated; the app now sends DEVICE_CAPABILITIES-valid caps and requests the pane feature names.
…w/diff/agents/audit/config) Tickets minted by 't4-host pair' capped devices at 10 read/drive caps, so a freshly paired client got remote-policy denials on the usage pane, settings (config.read), browser preview, and diff search.
Official-mode hosts don't implement them, and an unauthorized command makes the host close the whole connection; the panes now fall back to their empty state instead of killing the session.
…wned file) OfficialOmpProfileAuthority now implements fork(), which unblocks the session.fork feature on official hosts (previously bridge-only). The copy rewrites just the header (new id/timestamp, optional cwd) and lands in -t4/ like create; the lazy loader requirement was already satisfied.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3bdc3cd916
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "session.delta", "files.list", "terminal.io", | ||
| "preview.control", "files.search", "transcript.search", | ||
| "session.watch", "host.watch", "project.reveal", | ||
| "session.observer", "session.unverified", "session.fork", |
There was a problem hiding this comment.
Request the session.transfer feature
session.release and session.reclaim are gated by session.transfer in both the host dispatcher and remote policy, but this negotiated list omits it. Native clients can therefore display Continue in Terminal, yet invoking it is denied and closes a paired connection with code 1008; released sessions are also downgraded, preventing reclaim. Add session.transfer here and to ProtocolFeature—whose strict Welcome decoder currently has no matching case—and gate the controls on the resulting grant.
Useful? React with 👍 / 👎.
| defer { connecting = false } | ||
| let transport = makeTransport(endpoint: endpoint) | ||
| let c = HostClient(transport: transport, config: HostClient.Config(identity: identity, authentication: authentication)) | ||
| let c = HostClient(transport: transport, config: HostClient.Config(identity: identity, authentication: authentication, requestedFeatures: Self.clientFeatures)) |
There was a problem hiding this comment.
Send the expanded capabilities in authenticated Hello frames
On each paired iOS/macOS reconnect, TailscaleRemotePolicy intersects the token's grants with HelloFrame.capabilities, but this constructor only overrides requestedFeatures and therefore retains HostClient's old default capability list. The newly added PairStart grants (files.diff, the preview capabilities, usage.read, agents.control, audit.read, and config.read) are absent from the authenticated Hello and are never granted, leaving usage/settings unavailable and causing commands such as files.diff to be denied. Pass the expanded native capability list into this HostClient.Config.
Useful? React with 👍 / 👎.
What changed
session.forkWhy
The native clients could discover historical OMP sessions, but they did not surface the ownership boundary or provide a safe continuation path. Writing directly to an unmarked CLI session could create competing writers. Pairing and same-machine Tailnet behavior also made local device dogfooding fragile.
This change makes the compatibility boundary explicit: historical sessions remain readable, a writable copy can be created without mutating the source, and sessions created under the ownership protocol can transfer between the app and terminal.
User impact
Maintainers can dogfood the native macOS and iOS apps against the local packaged OMP runtime, browse existing sessions, continue a legacy session in a safe copy, and transfer compatible app-owned sessions between native UI and terminal.
Validation
pnpm test:tooling— 143 passed, 1 Linux-only skipswift test --package-path apps/ios/HostWire— 11 passedNotes