Commit Graph
126 Commits
Author SHA1 Message Date
abkslmandnucleic a6da93d09e Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 04:19:02 -07:00
abkslmandnucleic e09d855cfe Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 04:18:34 -07:00
abkslmandnucleic 510e48e68a Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 04:07:08 -07:00
abkslmandnucleic 6aaba99c16 Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 04:06:55 -07:00
abkslmandnucleic 107abb1e1e Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 04:06:46 -07:00
abkslmandnucleic 98679d9fff Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 04:06:31 -07:00
abkslmandnucleic c4f6274435 Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 03:58:19 -07:00
abkslmandnucleic 7782fdd874 Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 03:58:03 -07:00
abkslmandnucleic cec914b13c Begin MACOS_VM_NATIVE_AGENT_Markdown
Nucleic-Session: 8BBA8B40-FA38-4556-8B3A-7A2DFD4C87B2
Co-authored-by: Nucleic <[email protected]>
2026-07-06 03:57:45 -07:00
abkslmandnucleic d6577c1d59 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:39:46 -07:00
abkslmandnucleic c790fab76e Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:39:25 -07:00
abkslmandnucleic ded575a22b Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:38:50 -07:00
abkslmandnucleic a052c32b02 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:38:21 -07:00
abkslmandnucleic 88f9564511 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:12:33 -07:00
abkslmandnucleic 82c83a1b6c Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:12:24 -07:00
abkslmandnucleic 4bbbdecc91 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:12:17 -07:00
abkslmandnucleic 1986142383 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:11:53 -07:00
abkslmandnucleic 9911c7542c Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:11:24 -07:00
abkslmandnucleic 2313830e89 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 02:01:33 -07:00
abkslmandnucleic 7ca898bd3f Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 01:55:41 -07:00
abkslmandnucleic 858568cf8c Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 01:55:21 -07:00
abkslmandnucleic a19a9e1a92 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 01:55:07 -07:00
abkslmandnucleic a1f410bbf2 Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 01:26:23 -07:00
abkslmandnucleic 9409b69bdf Add Virtualization Framework Support
Nucleic-Session: 4FCF4F8B-A7C3-42F6-BE13-1979080F61C7
Co-authored-by: Nucleic <[email protected]>
2026-07-06 00:59:46 -07:00
abkslmandnucleic 9dbb873449 App Intents Integration Report
Nucleic-Session: 93D678C7-1451-4F73-B3CE-67BF8B2EDE02
Co-authored-by: Nucleic <[email protected]>
2026-07-05 18:26:33 -07:00
abkslmandnucleic 0f710582bf nvrsion: Add: Reconnect Icon Update, fix mesh iPhone discovery for new Macs, fix session order adjustment to pin sidebar sessions for remote projects, fix session status synchronization for remote viewer Macs, fix session order adjustment for iOS app session list, fix session status synchronization for remote sessions, fix iOS app live activity height by removing the “<n> files changed” line, fix Tool Call Card Mesh so AI bash summaries transit the mesh layer to other Macs, replace “Resolved by mac-ui” in transcripts with device ID, fix Chat: Print Wait Message, fix Chat: Reconnect Icon Update, fix Chat: Activity Theme Adjustment for “attention needed” live activity theme.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-05 04:24:25 -07:00
abkslmandClaude Fable 5 f8fa5c51fe mesh: Unify local and remote projects/sessions into one sidebar representation
Peer Macs' projects and sessions now render and behave identically to local
ones across the Mac app, differentiated only by a globe badge — one
abstraction instead of a parallel mesh section.

Core: new ProjectSummary (project analogue of SessionSummary) with
hostID/hostLabel origin; SessionSummary gains hostID, init(wire:hostID:), and
an origin-qualified sidebarRowID; AppStore.sidebarProjects name-sorts the mesh
union; projectSummary(_:) is the origin-agnostic project(_:); origin-keyed
summaries(for: ProjectSummary) overloads keep same-ProjectID Macs (migrated
databases) from crossing session lists; openSessionID.didSet auto-routes
remote opens (local records shadow; live copies beat moved-tombstones);
origin-aware verbs dispatch the phone's wire verbs via PeerClient.sendCommand
with a listSessions pull as the convergence backstop and surfaced errors when
the peer is unreachable.

Owner-side broadcast fixes so viewers' mirrors converge: mutateSession(+
ForRemote) and createSession broadcast sessionUpdated; a new
HostBroadcast.sessionList is pushed on deleteSession / deleteProject /
setProjectArchived / transfer-restore (deletions previously broadcast
nothing); the wire startChat handler no longer reveals on the owner's screen.

UI: RootView renders one unified tree (MeshSessionRow / remoteProjectHeader /
meshHosts deleted); RemoteProjectView is the summary-driven overview;
NewChatComposer picks projects across the mesh and starts remote chats over
the wire (fails closed when a remembered project is unresolvable; attachments
never silently dropped); detail-view unarchive/discard/approvals/header
controls route to the owner — remote approvals previously no-oped silently,
and opening a remote Control chat fired a spurious setSessionAuto at its
owner.

Docs: SYNC_PROTOCOL sessionList push semantics; MESH_TRANSFER unified-
representation section. Tests: MeshUnifiedSidebarTests (9) — 821 green.
Reviewed by an adversarial multi-agent pass; all confirmed findings fixed.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-05 03:24:23 -07:00
abkslmandnucleic 7d7a7c457d nvrsion: Add: Global Icon For Remote Projects to display globe icon next to remote projects in sidebar, matching local projects in appearance, Fix: Chat: Remove Face ID Permission Text, Refactor: Chat: Live Activity Content Density to open app directly into waiting sessions when tapped, Refactor: Chat: Live Activity Content Density to refresh live activity info significantly faster, Refactor: Chat: Live Activity Content Density to refresh live activity info significantly faster, Fix: Chat: Live Activity Content Density to refresh live activity info significantly faster, Fix: Chat: Network Type Transition Optimization to reduce delay during network type switches, Feature Enhancement Planning: All devices in a mesh group should see and be aware of each other; “pair” reframed into “join”; scanning
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-05 00:28:21 -07:00
abkslmandClaude Fable 5 3ce0fb3778 feat(relay): wire the live Nucleic Private Relay into the desktop + iOS apps (mesh P2 complete)
The relay Worker (nucleic-edge at relay.nucleic.blakeslee.xyz) is deployed, so land the
formerly deploy-gated client side of the data path:

- NucleicProtocol/Sync/RelayTransport.swift: RelayAPI (one base URL for REST + WS,
  membership -> connection token trade), RelayWebSocket (ordered sends, ping keepalive,
  ping-confirmed connect), RelayFrameChannel (client leg, WireFraming inside WS binary,
  presence fail-fast when the room has no host), RelayPresence.
- NucleicCore/Sync/RelayAccess.swift: X25519 PoP enrollment (RelayEnrollment), room
  credential in the login Keychain (separate from the push credential), membership minting
  with re-enroll-on-401.
- NucleicCore/Sync/RelayListener.swift: host SyncListener demuxing the room socket into
  per-tag virtual FrameChannels via RelayEnvelope; presence-driven reaping; backoff redial;
  injectable RelayRoomSocket seam for tests.
- Wire: additive HostMsg.relayMembership(WireRelayMembership) pushed after every hello
  (SyncHost.register -> AppStore mint) so devices paired before the relay adopt it and the
  ~90-day token refreshes on each connect; the pairing QR also carries a bootstrap
  membership so first contact can ride the relay. Old clients ignore the unknown tag.
- AppStore: .relay joins the listener composite behind the Connection-methods checkbox
  (failure degrades to a status row), advertises relayRoomID in PeerAddresses, mints the
  QR bootstrap in beginPairing.
- Desktop UI: the Nucleic Private Relay toggle is enabled (was "coming soon"); the
  LAN-only banner offers it alongside Tailnet.
- iOS: relay is the last dial candidate in HostConnection pair + reconnect (10s handshake
  watchdog); PairedHost persists relayRoomID/relayMembershipToken/relayURL; the
  relayMembership push updates the registry in place; Settings shows Relay in Transports.

Tests: RelayTransportTests, RelayListenerTests, SyncHostTests relay push + QR bootstrap.
Full suite green (783 core + 113 protocol + 2 new); iOS simulator build succeeds. Live
smoke test against the deployed Worker passed end-to-end (PoP enroll, both token tiers,
two-socket frame round-trip through the Room DO with correct envelope tags).

Known limits: host revoke-on-unpair not wired (endpoint is admin-only); PeerClient
(Mac<->Mac) doesn't dial the relay yet.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-04 21:05:01 -07:00
abkslmandClaude Opus 4.8 0901295996 docs(mesh): multiplexer rewire complete (compile + demo verified; live path needs 2 Macs)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 18:23:19 -07:00
abkslmandClaude Opus 4.8 f75d0a099a docs(mesh): record multiplexer start (HostConnection engine extracted)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 17:56:57 -07:00
abkslmandClaude Opus 4.8 6f5cf6f110 docs(mesh): record P3 host switcher + defer simultaneous multiplexer
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 17:41:01 -07:00
abkslmandClaude Opus 4.8 d38b5b78a1 docs(mesh): record iOS-build fix + Phase 3 foundation (paired-host registry)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 17:15:10 -07:00
abkslmandClaude Opus 4.8 1786fba01f Mesh P5: finish transfer feature set — moved/arrived visibility, recovery, bulk hand-off
Completes Phase 5 of the multi-device mesh / session-transfer program (docs/MESH_TRANSFER.md)
except the two-Mac memory-carry spike. All additive + capability-gated; SyncProtocol stays v1.

- Moved-session visibility: additive SessionSummary.movedTo (MovedDestination), decode-defaulted.
  A moved session no longer silently vanishes — the source keeps a read-only "Moved to <Mac>"
  tombstone under Archived (name resolved live from paired Macs), surfaced on relaunch without
  rebuilding a runnable controller, and sent on the wire so phones see it too.

- Relaunch recovery driven from launch (+ on every peer reconnect, single-flight):
  AppStore.recoverInterruptedTransfers clears abandoned pre-tombstone locks, discards orphaned
  inbound staging, and re-drives a tombstoned commit via SessionTransferCoordinator.recoverTombstoned
  (bounded, idempotent; a dest that lost staging leaves the lock, never revives the source).

- Bulk "Hand off active sessions…": transferableSessions + moveSessionsToPeer (sequential, rollup
  error) behind a "Hand off…" button → HandoffSheet checklist in RemoteAccessView.

- Arrived-from provenance (mirror of moved-to): GRDB v24 arrived_from_device_id/arrived_at; the
  importer stamps them at staging; additive SessionSummary.arrivedFrom (ArrivedFrom); a subtle
  "Arrived from <Mac>" marker on the sidebar (live name) + iOS row (host-baked name).

- Stranded-arrival "Activate anyway": the importer persists the staged Session to the staging dir
  at .ready, so a destination that relaunches before commit can recoverableInboundTransfers() and
  activateRecoveredTransfer()/clearInboundStaging(). AppStore surfaces pendingArrivedTransfers with
  activate/discard, shown in a new "Interrupted arrivals" section. (A .ready lock with no manifest
  is now cleared as unrecoverable.)

Tests: +6 core, +2 protocol across WireMessageTests, SessionTransferTests, AppStoreTests,
AppStoreSyncBridgeTests. Full package builds; Swift suites green. iOS NucleicRemote edits reviewed
but not compiled here (separate Xcode target).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 17:02:15 -07:00
abkslmandClaude Fable 5 73144fb24d Mesh P5: adversarial-review fixes (never-runs-in-two-places, path traversal, +)
A 4-dimension × 2-refuter review of the P5 surface confirmed a critical invariant
violation and several majors; all fixed:

- CRITICAL "never runs in two places": a DB tombstone alone didn't make the source
  session inert — sendInput/sessionSummaries/snapshot never checked archived/moved and
  the live controller stayed addressable, so during the post-tombstone commit round-trip
  a connected peer could run the session while the destination also ran it (permanent in
  the committedButUnconfirmed case). Fix: a `transferringSessions` set holds the session
  inert (hidden from the sync list + snapshot, refuses sendInput) for the whole transfer;
  loadSessions never rebuilds a controller for a movedToDeviceID session (relaunch
  safety); any post-tombstone commit failure now surfaces as committedButUnconfirmed,
  which tears the source down (inert, worktree preserved) and keeps the lock at
  .tombstoned for recovery — never reviving or double-running it.
- MAJOR path traversal: the importer built filesystem paths from attacker-supplied
  transferID / record.sessionID / branch. Now validated as safe path components (no
  `..`/separators; branch must be `nucleic/<safe-slug>`) before any fs work or lock claim.
- MAJOR missing capability gate: moveSession now checks peerClient.canTransfer(to:)
  (connected + advertised canReceiveSessionTransfer) before sending any verb.
- MAJOR controller leak: tearDownMovedSession now shuts the controller down + reaps its
  sandbox container (like the archive/delete paths), not just dropping the reference.
- MINOR: resolveTransferProject's UUID fast-path no longer matches an archived project.

Tests: committedButUnconfirmed keeps source moved + lock held + worktree preserved;
path-traversal identifiers rejected before fs work; isSafePathComponent/Branch rules.
770 core + 105 protocol green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-04 03:49:32 -07:00
abkslmandClaude Fable 5 3215aae003 Mesh P5 (destination integration): AppStore importer wiring + capability
Wires the tested transfer engine into the live app on the receiving side:

- AppStore owns a SessionTransferImporter via a StandardTransferImportEnvironment
  (project resolution by UUID then repo identity; native-transcript destination
  computed from the sandbox/claude-home convention; activateTransferredSession
  reconstructs the controller + broadcasts sessionUpdated so the sidebar and any
  connected phones see the arrival).
- SyncHostBridge receiveTransfer{Offer,Chunk,Commit,Cancel} on AppStore forward to
  the importer; capabilities advertises canReceiveSessionTransfer = true.
- The archived-worktree sweep skips a session with an active transfer lock, so a
  mid-transfer worktree is never reclaimed/committed-WIP under the importer.

Tested through the real AppStore bridge: capability advertised, unknown-project
reject (projectNotFound), known-project accept with shared-base haveSHAs.

Remaining for a functionally-complete P5 (documented in docs/MESH_TRANSFER.md): the
outbound source driver (a TransferChannel over PeerClient's SyncClient +
AppStore.moveSession with transferability classification + quiesce) and the SwiftUI
(Move-to picker, hand-off flow, moved-row rendering). The engine's loopback test
already exercises the exact coordinator<->importer protocol the production source
path drives.

766 core + 105 protocol tests green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-04 03:16:29 -07:00
abkslmandClaude Fable 5 8776c9f333 Mesh P4 remainder: PeerClient, Mac↔Mac pairing, addresses, dedup
Completes Phase 4 of the multi-device mesh program (docs/MESH_TRANSFER.md):
a Mac now dials paired sibling Macs with the same platform-neutral SyncClient
the iPhone uses, so it is both a host to its phones and a .control-scope client
of its peers — the dependency session transfer (P5) was waiting on.

Wire (NucleicProtocol, version stays 1, additive + capability-gated):
- PeerAddresses {lanHint, tailnet, relayRoomID, updatedAt}; optional
  Hello.addresses / Welcome.addresses; ClientMsg.addressUpdate gated on new
  WireCapabilities.canUpdateAddresses; PairedDevice.addresses — all
  decode-defaulted so shipped iPhones and pre-mesh stores load unchanged.

Core (NucleicCore):
- PeerClient: serial LAN→tailnet dial over an injectable PeerDialer, capped
  backoff, live presence stream, listPeers only when advertised. MacPeerDialer
  + LANDialChannel add the outbound dial-side FrameChannel that didn't exist.
- Symmetric pairing into one PairedDeviceStore (one pasted link makes both Macs
  dialable); accepting-Mac confirm (locked decision #4); SyncHost per-deviceID
  connection dedup (keep-newest, 2s grace); AppStore lifecycle + meshPeers.

UI: "Paired Macs" section (presence/transport/revoke), paste-link pairing sheet,
QR sheet doubles as copy-link + confirm dialog.

Hardening (adversarial review, 11 defects fixed incl. two security holes):
- Mac-pairing confirm enforced on the reconnect promotion path (a phone can't
  reconnect claiming deviceKind=mac to skip the confirm).
- Existing-device hello branch requires the authenticated static key to match
  the pin (a pairing party can't claim another device's deviceID).
- startPeerClient guarded against a racing stopSyncServer; confirm timer stored
  and cancelled on resolve; pair() treats pre-welcome wireError as terminal and
  classifies decline vs unreachable; handshake deadlines; setPresence won't
  resurrect an unpaired peer; meshPeersChanged no-ops once the server is down;
  pairing UI cancels in-flight pair() on dismiss; LANDialChannel cancels on
  .failed + TCP keepalive.

Tests: 871 green (742 core + 98 protocol + 31 new) — wire codec/backcompat,
dedup, address exchange, addressUpdate, mac-confirm decline/phone-skip,
key-mismatch + promotion rejects, PeerClient pair-via-link/reconnect/listPeers
gating/unpair loopback.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-04 02:19:23 -07:00
abkslmandClaude Fable 5 7e80a45ddc Mesh + session transfer: P1 done, P2 core, P4 foundation
Multi-device mesh + session-transfer program (docs/MESH_TRANSFER.md).

P1 (multi-select connection methods, Mac): SyncTransportSet with legacy
migration; CompositeSyncListener partial-failure tolerant + per-method health;
AppStore listens on all enabled methods; HostInfo.hostID = DeviceIdentity.hostID
(key hash, not display name); Settings 3 method toggles + LAN-only recommendation
banner.

P2 core (relay hardening, security-critical, tested): nucleic-edge relayEnroll.ts
X25519 proof-of-possession enroll + server-side roomId derivation; room.ts
role-routed per-peer forwarding with deviceId-tag envelope + frame cap +
one-host-per-room eviction; host-bearer minting bound to the PoP room. Swift
cross-stack contracts pinned to test vectors: RelayEnrollment (PoP proof),
RelayEnvelope (routing tag), PairingPayload relay fields. Socket transport +
iOS un-gating remain deploy-gated.

P4 foundation (peer model + listPeers, tested): PeerTypes (PeerKind/
PeerCapabilities/PeerSummary); Hello.deviceKind+clientCaps;
WireCapabilities.canListPeers; ClientMsg.listPeers -> HostMsg.peerList;
PairedDevice.kind+capabilities (decode-defaulted); ConnectionHandler records
kind at pairing; SyncHost.connectedDeviceIDs(); AppStore.peerSummaries();
SyncClient .peerList event; iOS RemoteStore.meshPeers. PeerClient + Mac<->Mac
pairing UI remain.

All additive + capability-gated; SyncProtocol.version stays 1; pre-mesh stores
and clients unaffected. Swift 724 core + 91 protocol tests green; edge 50 green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-04 00:39:30 -07:00
abkslmandnucleic 92a3f277c8 nvrsion: Add re-sync from dev for VERSION and adjust Appcast releases; fix permission flow by removing the “allow always” button from approval views and docs; fix build script error by removing obsolete sh dependency from Makefile.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 18:57:19 -07:00
abkslmandnucleic 2c3535c3f9 nvrsion: Add: Adjust side padding on “Update available” card in sidebar to match session entries’ padding, fix internal tester invitation workflow for rapid Canary channel releases, and create a “trusted tester” system requiring approval to join internal testing groups.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 17:40:28 -07:00
abkslmandnucleic 8f03fc35a7 nvrsion: Add deprecation warnings and updates for Hdiutil mount command; fix BUILD.md, Makefile, and related files.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-02 20:24:53 -07:00
abkslmandnucleic c55f7a4248 nvrsion: Add review feature access for iOS remote: Enable reviewers to test all features in App Store (or TestFlight) reviews by updating BUILD.md, docs/APP_REVIEW_NOTES.md, RemoteStore.swift, RemoteApp.swift, BuildBanner.swift, and SettingsView.swift.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-02 19:26:43 -07:00
abkslm 55bf269334 Merge branch 'claude/competent-pasteur-a5bb90' into HEAD 2026-07-02 17:21:39 -07:00
abkslmandClaude Fable 5 e93fc14c9b relay: host self-enrollment — no admin secret in the app; push is one toggle
The admin bearer must not ship in a distributed build, so hosts no
longer use it at all. A Mac self-enrolls with the relay on first use
(POST /v1/host/enroll) and receives its own scoped credential (only
the SHA-256 is stored server-side; the credential lives in the login
Keychain). Register and notify are now authorized per host: a host
can wake only devices it registered itself (admin remains an
operator-only override); room-registered records are owner-tagged
with the DO id and refused out-of-band. Each device record's APNS
environment now wins over the global APNS_ENV secret, so mixed
sandbox/production fleets work.

Settings ▸ Remote's section is now just "Relay" with a single
"Push notifications" toggle that takes effect immediately; the relay
URL and APNS-environment overrides appear only in local dev builds.
PushRelayConfig reduces to enabled + baseURL (built-in production
default) + apnsEnv (production default). PUSH_SETUP.md §3/§4 updated;
stale dotted-bundle-id comments in env.ts/wrangler.jsonc fixed.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-02 17:21:38 -07:00
abkslmandClaude Fable 5 1fe9d8898d mac: remove the direct APNS sender — the provider key must stay server-side
An app can't hold a secret the machine's owner can't extract (root +
debugger defeats bundling, Keychain, and obfuscation; the Secure
Enclave can't import external keys), and a leaked .p8 can push to
every user of the topic. So the push path is relay-only again: the
key lives exclusively in the relay's Worker secrets and the Mac only
asks the relay to send. Settings and PUSH_SETUP.md revert to the
relay-only form, with the rationale recorded in §4.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-02 16:30:57 -07:00
abkslm 09fb4863ae Merge branch 'claude/competent-pasteur-a5bb90' into HEAD 2026-07-02 16:30:57 -07:00
abkslmandClaude Fable 5 add50fe074 mac: direct APNS sender — the host can wake phones without the relay
Answering "can push be local when on LAN": a backgrounded iOS app can
only be woken through Apple's push service, so a LAN-only wake path
doesn't exist — but the *sender* can be this Mac. DirectAPNSSender
holds the APNS .p8 (path + Key ID + Team ID, runtime-configured like
the relay: env vars first, then the Settings-written defaults keys)
and posts the same content-free approval.pending tickle straight to
api.push.apple.com (ES256 provider JWT via CryptoKit, 40-min cache,
per-device throttle) — no Cloudflare dependency for push.

ApprovalPushing unifies the two senders; SyncHost wakes non-connected
paired devices through whichever is configured (direct wins). The
Settings ▸ Remote push section gains a sender picker with the direct
fields (.p8 chooser, Key ID, Team ID). PUSH_SETUP.md §4 rewritten as
Option A (this Mac) / Option B (relay). JWT signing verified against
the public key in tests; payload asserted byte-compatible with the
worker's apns.ts tickle.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-02 16:18:53 -07:00
abkslm 4aa4aa16ae Merge branch 'claude/competent-pasteur-a5bb90' into HEAD 2026-07-02 16:18:53 -07:00
abkslm b54419aa02 Merge branch 'claude/competent-pasteur-a5bb90' into HEAD 2026-07-02 16:09:45 -07:00
abkslmandClaude Fable 5 8c28cc9132 mac: relay push settings UI (Settings ▸ Remote); clarify runtime config in PUSH_SETUP
The relay URL / admin secret / APNS environment are runtime host
settings (PushRelayConfig.resolve reads env then UserDefaults when
the sync server starts), not build settings — and a Finder-launched
app never sees shell env. Add an "Approval push (relay)" section to
Settings ▸ Remote writing the same defaults keys, with an Apply
button that restarts remote access so changes take effect. Update
PUSH_SETUP.md §4 to point at the UI and keep the env-var form for
scripted runs.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-02 16:09:32 -07:00