Commit Graph
627 Commits
Author SHA1 Message Date
abkslm 8edd9734bd Merge claude/elastic-haibt-f29115 into dev (iPad remote port: adaptive sidebar+detail shell, Mac-style two-pane diff, structured commit/command transcript cards, keyboard/pointer affordances, camera-free manual pairing) 2026-07-04 00:54:14 -07:00
abkslmandClaude Opus 4.8 f8fdf98517 iPad: hardware keyboard, pointer, and a camera-free pairing path (Phase 3)
Make the remote feel native with a Magic Keyboard / trackpad, and give iPad a
pairing path that survives a blocked camera.

Keyboard shortcuts (mirroring the Mac's .commands):
- Cmd+Return sends in the session follow-up composer and the start-chat composer
  (plain Return stays a newline in the multiline fields).
- On the approval card, Return allows and Esc denies -- the approval bar replaces
  the composer, so Return is unclaimed there. Allow stays gated on the biometric.

Pointer:
- .hoverEffect on the diff file-list rows (native List rows already hover).

Camera-free pairing (ManualPairingView):
- "Enter code manually" in both the pairing intro and Settings opens a sheet to
  paste the Mac's nucleic://pair?d=... code, parsed with the same
  PairingPayload(qrString:) the scanner uses (+ a Paste-from-clipboard button).
  The iPad scanner can't run while mirrored to an external display or in some
  Stage Manager states; this always works.

Note: the Mac's RemoteAccessView currently shows only the QR, so a follow-up host
change is needed to surface a copyable pairing link for this to be end-to-end.

Builds clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 00:48:56 -07:00
abkslmandClaude Fable 5 25fb2eb8ad 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
abkslmandClaude Opus 4.8 15ea0f1dd2 iPad: render multi-step / destructive shell pipelines as a step list
The desktop CommandStepsCard breaks a shell pipeline (a rm/git chain) into a
step list with the destructive delete flagged, instead of a raw blob. Rather
than duplicate a parser, deliver that value by reusing the existing, tested
HostCommandSummary + HostCommandBreakdown (a general command parser whose
Invocation already carries a `destructive` flag for rm/rmdir) on the two paths
that still showed raw text:

- ToolCallCard.details: a shell tool whose command has >1 invocation or is
  destructive now renders the compact step breakdown (deletes glyphed/tinted in
  red) with the literal command under "Show command"; simple one-liners keep the
  plain input block.
- ApprovalCardView: the parsed breakdown (with its sudo/deletes risk banner) now
  covers any Bash pipeline / destructive approval, not just host_exec.

Demo transcript gains a destructive cleanup pipeline (rm -rf && git worktree
prune && git branch -D) so the step list is exercisable offline.

Verified in the iPad simulator: the pipeline expands to a step list with
`rm -rf` flagged in red.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 00:38:59 -07:00
abkslmandClaude Opus 4.8 149af312dc iPad: show the commit card for host-run and pending-approval commits too
Extend the git commit card beyond the Bash transcript path to the other two
surfaces a commit appears on, so all three read like the Mac:

- ApprovalCardView: a pending `git commit` approval (Bash or host_exec) renders
  the structured commit card (subject + Markdown body) with the literal command
  under "Show command", instead of a raw blob or the generic host breakdown --
  so you see exactly the message you're granting.
- HostExecToolCard: a host-run `git commit` surfaces the commit card in its
  expanded body (the `$ command` already sits in the header), rather than only
  the generic "Commit changes" purpose.

Both reuse GitCommitSummary.parse + GitCommitCard from the previous commit.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 00:27:20 -07:00
abkslmandClaude Opus 4.8 850ee0cd96 iPad: render git commits as a structured card in the transcript
Port the desktop GitBlockCard's commit rendering (+ CommandDisclosure) to the
remote transcript: a Bash `git commit` now shows the commit subject as a
headline and the message body as Markdown, with the raw command one tap away
under "Show command" -- instead of a raw `git commit -F - <<'EOF' ...` blob.

- GitCommitCard.swift: the card + the CommandDisclosure helper (portable
  SwiftUI, mirroring Sources/NucleicApp/{GitBlockCard,CommandDisclosure}).
- GitCommitSummary.parse (in HostCommandSummary.swift) extracts the message
  from -m/--message args or a `-F -` heredoc body, reusing the file-private
  shell Lexer already used for host-exec summaries; skips env prefixes and git
  global flags, and only fires for real `git commit` segments.
- Hooked into ToolCallCard.details, gated to shell tools so non-shell input is
  never misread as a commit.
- Demo transcript gains a git-commit call so the card is exercisable offline.

SummaryCard is intentionally not ported -- it's the host-only Apple-Intelligence
recap, which a remote has no way to generate.

Verified in the iPad simulator (demo mode); parser covered by a standalone test.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-04 00:21:32 -07:00
abkslmandClaude Opus 4.8 34aa01a724 iPad: adaptive sidebar+detail shell and Mac-style diff (remote Phases 1-2)
Grow the universal NucleicRemote app into a width-adaptive shell so a
regular-width iPad renders the macOS sidebar+detail IA while the iPhone
keeps its TabView -- both over the same RemoteStore projection (one host
authority, N renderers).

Phase 1 (adaptive shell):
- AdaptiveRootView branches on horizontalSizeClass: CompactRootView (the
  existing iPhone TabView, moved verbatim) vs SplitRootView
  (NavigationSplitView) on regular width.
- SplitSidebar: Home/Projects/To-dos/Settings destinations + sessions
  grouped under their projects (attention-sorted), connection chip footer.
- SplitDetail selects a destination or a session; a selected session reuses
  SessionDetailView keyed .id(sessionID) so switching drives open/close.
- RemoteStore.closeOpen(_:) is now id-guarded so a split-view A->B switch
  (onAppear(B) before onDisappear(A)) can't tear down B's fresh subscription.
- IdentityStore.deviceID idiom-tags the prefix (ipad-/iphone-) for new
  installs so the host lists a paired iPad correctly.

Phase 2 (width tuning + diff):
- readableColumn() caps+centers Home and the transcript on wide layouts;
  a no-op at phone/portrait width.
- SessionDiffView switches on available width (GeometryReader): a Mac-style
  two-pane diff (file list + selected file's patch) on wide/landscape, the
  phone stack otherwise. UnifiedPatch splits the combined patch per file.
  Read-only, same wire, no protocol change.
- Demo diff fixture now carries both files' patches.

iPhone layout and behavior unchanged. Builds clean; verified in the iPad
simulator (demo mode).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-03 23:59:29 -07:00
abkslm a641aed081 Merge branch 'dev' into nucleic/trunk 2026-07-03 18:57:19 -07:00
abkslmandNucleic 6a268abbb9 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 33f404555a Remove Permission Button
Nucleic-Session: E0927223-36BE-4F01-9E69-575442FC3E5A
Co-authored-by: Nucleic <[email protected]>
2026-07-03 18:54:41 -07:00
abkslm 3d9a5b5506 fixing version conflict 2026-07-03 17:54:16 -07:00
abkslmandNucleic b0284f1da1 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 f84ccd47de Review New Feature Proposal
Nucleic-Session: 8EFC43BE-BAE9-4E54-9D6D-2484C5F71F16
Co-authored-by: Nucleic <[email protected]>
2026-07-03 17:38:37 -07:00
abkslm d9319d0e65 Merge branch 'dev' into nucleic/trunk 2026-07-03 16:37:27 -07:00
abkslmandNucleic f39fd16800 Resolve Trunk Promotion Conflict
Nucleic-Session: 20A52F7E-A10D-4B59-B650-D3FD6BC3B46B
Co-authored-by: Nucleic <[email protected]>
2026-07-03 16:32:14 -07:00
abkslmandNucleic 23baade658 Resolve Trunk Promotion Conflict
Nucleic-Session: 20A52F7E-A10D-4B59-B650-D3FD6BC3B46B
Co-authored-by: Nucleic <[email protected]>
2026-07-03 16:32:01 -07:00
abkslmandClaude Fable 5 57d0ccc5f6 ios: surface the browser-login step on the pairing intro screen
A first tailnet pairing with no auth key detours through a Tailscale browser
login that can take minutes. The intro screen — the only UI an unpaired phone
has — showed just "Connecting to your Mac…" for that whole window, and if
the user closed Safari there was no way back to the login page (the Settings
tab with the login link only exists once paired). The intro's pairing status
now explains the approval step and links to the login page whenever the
embedded node is waiting on one.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 16:25:27 -07:00
abkslmandClaude Fable 5 e623247117 Merge branch 'claude/vigorous-nash-457773' into dev
Tailscale (Tailnet) sync transport: transport picker in Settings ▸ Remote,
interactive browser login, and LAN↔tailnet fallback.

Semantic merge fixes (both sides compiled alone but not together):
- handleTransportFailure (dev's friendly transport errors) now checks
  connectivity.isLive — .connected gained a transport payload on the branch —
  and stays silent while the branch's connect chain still has candidates to
  try, so a LAN probe failing over to the tailnet doesn't flash a red error.
- Chain-exhaustion paths keep a friendlier transport-level failure message
  when onFailed already surfaced one instead of clobbering it with the
  generic handshake error.

Verified on the merge: swift build + 37 sync/transport/store tests green
(incl. dev's FilePairedDeviceStore + the now-fixed contract tests), iOS
simulator build green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 16:22:13 -07:00
abkslmandClaude Fable 5 272039cca5 Tailnet: interactive browser login + LAN↔tailnet fallback
Browser login — the auth key is now optional on both platforms. When the
embedded node starts with no key, TailnetNode asks the backend (LocalAPI
backendStatus — IPN state, deliberately not filesystem heuristics: tsnet
writes logs and a machine key on every start, registered or not) whether a
login is needed, triggers login-interactive, surfaces the auth URL through a
new statusStream()/.needsLogin, and waits for Running (4-minute deadline,
generation-fenced against stop/restart). The Mac auto-opens the login page
from Settings ▸ Remote and shows a re-open button; the iPhone auto-opens only
during user-initiated pairing (a background reconnect that suddenly needs a
login must not eject the user to Safari — Settings ▸ Tailscale carries the
link). The remote-access toggle now reflects the in-flight start instead of
snapping off for the whole login window, and toggling off mid-start is
honored at both commit points (before and after host.start).

LAN↔tailnet fallback — picking Tailnet now keeps LAN on too: the host runs
both listeners under a new CompositeSyncListener (merged accept stream; one
child ending doesn't end the rest) and the pairing QR carries both hints.
The phone builds an ordered candidate chain — LAN first (QR hint or Bonjour),
tailnet second — and walks it on pair and reconnect, so a phone that leaves
the Mac's Wi‑Fi rolls over to the tailnet and rolls back when it returns.
A per-channel 4s connect guard (readiness-checking, bound to exactly its
channel) keeps a stale LAN hint from hanging the chain; a stale-client guard
in consume() keeps a replaced client's tail events from advancing it; chain
exhaustion during pairing lands in a terminal failure instead of spinning on
"Connecting…"; routine pre-fallback handshake errors no longer flash the red
error bubble. "Connected · LAN / Tailnet" shows whichever transport won.

Multi-agent review: 11 confirmed findings (incl. the login gate being dead
code via tsnet's eager state-dir writes, and two connect-timeout races), all
fixed and re-verified. Suite green (24 sync-related tests incl. 3 new
CompositeSyncListener tests); macOS + iOS builds clean.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 16:14:45 -07:00
abkslmandClaude Fable 5 94a962bd20 Add Tailscale (Tailnet) as a sync transport between Mac and iPhone
Settings ▸ Remote gains a "Connect via" picker — LAN (default), Tailscale
(tailnet), or Relay (disabled, coming soon). On Tailnet, both devices run an
embedded tsnet node via TailscaleKit (tailscale/libtailscale) and sync frames
flow over the user's tailnet, so the phone can connect from anywhere the
tailnet reaches; Noise E2EE runs above the transport unchanged.

- NucleicTailnet (new target, macOS + iOS): TailnetNode wraps TailscaleKit's
  node lifecycle (auth-key login, generation-fenced start/stop since up() is
  un-cancellable) and drops to the framework's public C API for the data path
  — tailscale_dial/listen/accept hand back full-duplex socketpair fds, wrapped
  by FDFrameChannel (DispatchIO) into the shared FrameChannel seam. The Swift
  wrapper's one-way connection actors can't carry a bidirectional stream.
- Host: TailnetListener adopts SyncListener; startSyncServer is single-flight
  and honors toggle-off/picker changes at the commit point; pairing QRs carry
  transport + tailnet IP/port hints (PairingPayload additive optional fields,
  forward/backward compatible over CBOR).
- iPhone: pair/reconnect dial over whichever transport the pairing recorded;
  Settings gains a Tailscale auth-key field (Keychain, committed on editing
  end); connectivity chip shows "Connected · Tailnet".
- TailscaleKit has no SwiftPM distribution: scripts/build-tailscalekit.sh
  builds a pinned libtailscale commit into an untracked local xcframework;
  Package.swift links it only when present (everything builds without it, the
  picker then reports Tailscale support as not built in), and the script
  clears SwiftPM's content-keyed manifest cache so the toggle is picked up.
- iOS floor 17.0 → 18.1 (TailscaleKit requires the iOS 18 Swift runtime);
  package-app.sh embeds the framework in the .app like Sparkle.

703-test suite: no new failures (the 7 fake-claude/fake-grok staging issues
reproduce identically on an untouched checkout — pre-existing, tracked
separately). New coverage: FDFrameChannel over socketpairs, pairing-payload
version-skew both directions, transport-setting resolution.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 03:50:45 -07:00
abkslmandNucleic 22d0752329 nvrsion: Add fix for QR Code Scan Failure in AppStore, Sync, and Tests; explore connection failures over local network; update Info.plist, Models, and SettingsView.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 01:42:40 -07:00
abkslmandNucleic 2c634e7db6 QR Code Scan Failure
Nucleic-Session: 80E30D7B-70A8-479A-A9A8-7E267486EAE1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 01:41:42 -07:00
abkslmandNucleic 308fc28448 QR Code Scan Failure
Nucleic-Session: 80E30D7B-70A8-479A-A9A8-7E267486EAE1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 01:41:04 -07:00
abkslmandNucleic 701bd6e6ab QR Code Scan Failure
Nucleic-Session: 80E30D7B-70A8-479A-A9A8-7E267486EAE1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 01:40:53 -07:00
abkslmandNucleic 16da64da3b QR Code Scan Failure
Nucleic-Session: 80E30D7B-70A8-479A-A9A8-7E267486EAE1
Co-authored-by: Nucleic <[email protected]>
2026-07-03 01:40:46 -07:00
abkslm 60eea6ece2 release(ios/canary): v0.2.0 (build 5) 2026-07-02 22:50:41 -07:00
abkslm cb6976baa4 release(ios/beta): v0.2.0 (build 4) 2026-07-02 22:32:37 -07:00
abkslm 48732940d3 Merge branch 'canary' into staging 2026-07-02 22:23:13 -07:00
abkslm 572262c224 Merge branch 'dev' into canary 2026-07-02 22:23:03 -07:00
abkslm bc006e4e40 Merge branch 'canary' into staging 2026-07-02 22:15:20 -07:00
abkslm 1a9eff585e Merge branch 'dev' into canary 2026-07-02 22:13:52 -07:00
abkslm cce6a0c4d9 Merge branch 'dev' into nucleic/trunk 2026-07-02 22:12:16 -07:00
abkslmandNucleic f668a204ab nvrsion: Add: Adjust iOS beta channel release targets to “Nucleic Remote (Beta)” in BUILD.md, Makefile, app-logo-beta.icon/icon.json, ios/NucleicRemote/NucleicRemote.xcodeproj/project.pbxproj, scripts/ios-release.sh, signing/README.md.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-02 22:12:15 -07:00
abkslmandNucleic 65a7897233 iOS Beta Target Adjustment
Nucleic-Session: B5F39681-AF29-4F9A-8666-16E1FD5009A3
Co-authored-by: Nucleic <[email protected]>
2026-07-02 22:04:54 -07:00
abkslmandNucleic 528f1b08db iOS Beta Target Adjustment
Nucleic-Session: B5F39681-AF29-4F9A-8666-16E1FD5009A3
Co-authored-by: Nucleic <[email protected]>
2026-07-02 22:04:47 -07:00
abkslmandNucleic 137ca12a4d iOS Beta Target Adjustment
Nucleic-Session: B5F39681-AF29-4F9A-8666-16E1FD5009A3
Co-authored-by: Nucleic <[email protected]>
2026-07-02 22:04:40 -07:00
abkslmandNucleic 962a6014d8 iOS Beta Target Adjustment
Nucleic-Session: B5F39681-AF29-4F9A-8666-16E1FD5009A3
Co-authored-by: Nucleic <[email protected]>
2026-07-02 22:04:34 -07:00
abkslmandNucleic b10b26ba37 nvrsion: Add: Align iOS remote banner cases (beta, canary, etc) to desktop version to fix divergence in build number hash.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:58:03 -07:00
abkslm 423a356fe2 Merge branch 'dev' into nucleic/trunk 2026-07-02 21:58:03 -07:00
abkslmandNucleic e960e6e4d5 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:57:48 -07:00
abkslmandNucleic 7b5bdc9d0b nvrsion: Add: Adjust Canary Build Auto-Update to run every hour, fix Keychain permission audit by updating files: ControlAuth.swift, GitHubCredentials.swift, HeartbeatReporter.swift, KeychainOwnedAccess.swift, HostIdentityStore.swift, PushRelayClient.swift, refactor Remote Build Icon to use “bell.and.waves.left.and.right.fill” in ios/NucleicRemote/NucleicRemote/Views/BuildBanner.swift, add a Remote Release Channel Check in AppStore.swift, Sync/ConnectionHandler.swift, Sync/SyncHostBridge.swift, Sync/ReleaseChannel.swift, Sync/SyncClient.swift, Sync/WireMessages.swift, tests/SyncHostTests.swift, tests/SyncTestSupport.swift, and align build number hash in ios/NucleicRemote/NucleicRemote.xcodeproj/project.pbxproj, ios/NucleicRemote/NucleicRemote/Info.plist, ios/NucleicRemote/NucleicRemote/Views/BuildBanner.swift.
Nucleic-Promote: 1
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:54:40 -07:00
abkslm 1f11f6f330 Merge branch 'dev' into nucleic/trunk 2026-07-02 21:54:40 -07:00
abkslmandNucleic 36083dc4e3 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:53:46 -07:00
abkslmandNucleic 7379bfba49 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:53:23 -07:00
abkslmandNucleic aa38f931e1 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:52:27 -07:00
abkslmandNucleic 41ee43aa75 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:52:14 -07:00
abkslmandNucleic 9bc685aa3f Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:52:07 -07:00
abkslmandNucleic 159d7636a2 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:52:00 -07:00
abkslmandNucleic 1ec8871536 Build Number Hash Alignment
Nucleic-Session: F8E9CC32-59CC-4022-B42C-0B0694C57F42
Co-authored-by: Nucleic <[email protected]>
2026-07-02 21:51:55 -07:00
abkslm 33e0459451 release(ios/beta): v0.1.0 (build 3) 2026-07-02 21:45:51 -07:00