- Add syncServers setting (default false) to extension and native host state
- Add "Sync Servers" toggle under Settings → Sync; when disabled, server
tunnels stay local and are not synced across linked devices
- On push: omit servers from snapshot when syncServers is false
- On apply: keep local servers and nextServerId when syncServers is false
(incremental and full restore)
- Stop calling closeSyncForBackup() during backup create so sync and
autopass keep running; backup already excludes autopass/ from the
archive.
- Restore still quiesces sync and removes autopass/ so storage can be
replaced safely; sync reconnects on next use.
- Clarify setSyncManager comment (restore-only). Update BACKUP.md,
SYNC.md, and ARCHITECTURE.md accordingly.
When a device pairs with the master, the master's autopass can emit an update
and applyRemoteUpdate would sometimes apply an empty or weaker snapshot from the
merged view, overwriting the master's state. Skip applying remote state when
we're the master and the incoming snapshot has less content (servers + vhosts +
serviceTunnels) than current state.
- Delink: any peer can leave; removeWriter notifies others, local state reset to defaults.
- Disband: master only; push syncGroupDisbanded so peers reset; master exports state to
state.json, then reloads (cleanup + restorePersistedState + restorePersistedTunnels).
- Skip handleDisbandFromMaster when receiver is master so master state is not reset.
- Store syncMasterDeviceId in synced state so MASTER badge shows on all devices.
- UI: show Delink for peers, Disband for master only; confirm modals for both.
When reopening with existing identity, do not pass discovery key to
Autopass. That makes Autobase bootstrap from this device's local core
(name: 'local') instead of bootstrap.getUserData('autobase/local'),
which can point at another device's writer and open it read-only.
- Device that creates sync group is the Master; MASTER label in Linked devices table
- Create invite when already linked generates invite for same sync group (no wipe)
- Any peer can create invites so devices can be added when Master is offline
- Identity file stores isMaster; same sync group reused across native host restarts
- Update SYNC.md, NATIVE-HOST.md, ARCHITECTURE.md, CHANGELOG.md
- Add getStateSnapshot, applySnapshotData, setStateSaveSuppressed to holesail-manager
- Sync diffs snapshot vs current state and only removes/adds/updates changed tunnels
- Suppress saves during apply and write state.json once at the end
- Fall back to full cleanup + restore when incremental APIs are unavailable
- Backup: do not include autopass/ (may be in use); always include
autopass-identity.json so sync identity is never lost
- Restore: remove autopass/ after extract so autopass can recreate from
restored identity
- Docs: BACKUP.md, SYNC.md, ARCHITECTURE.md updated
- pairWithInvite: await store.ready() before pair; await pass.ready()
after pair.finished(); on error call pair.close() then closePass()
- createSyncInvite: on error await closePass() instead of nulling refs
- Remove autopass dir before createSyncInvite/pairWithInvite so Corestore
gets a fresh device-file (device-file throws when inode/mtime changes)
- Await sync/rdp/holesail cleanup on host shutdown so corestore closes
before process exit
- Reset initPromise on init failure so Create invite can retry after
removing corrupt autopass dir
- getSyncStatus: fire-and-forget push device hostname when missing so
linked peers see names after opening Sync page
- Backup/restore: close sync (corestore) before copy/extract so autopass
data is consistent; backup includes autopass/ and autopass-identity.json
- Installer: preserve sync data on re-run (comments and messages)
- Docs: BACKUP.md sync-in-backup and pause behaviour; SYNC.md backups
include sync data
- Sync: use OS hostname for each device in Linked devices table; persist
deviceNames in state and merge on save/apply so peers see each other's names
- Docs: expand SYNC.md (linked devices table, replace-state modal, multi-device,
offline); NATIVE-HOST getSyncStatus (deviceId, syncGroupId, linkedDevices,
deviceName/name); ARCHITECTURE sync-manager and autopass paths; README
features/dashboard/file locations/doc link; BACKUP and SECURITY cross-refs
- getSyncStatus() now iterates pass.base.activeWriters and returns
linkedDevices: [{ id, isCurrent }] for each writer in the sync group
- Dashboard Linked devices table shows every device: "This device" plus
"Device 2", "Device 3", etc. with their IDs; rows sorted by id
- Fallback to single "This device" row when activeWriters is missing
- Await restorePersistedTunnels so applyingSync stays true for full restore,
preventing saveState() during tunnel startup from pushing back and looping
- Debounce onRemoteUpdate (600ms) and skip apply when state unchanged
(canonical fingerprint) to avoid redundant restarts
- Add confirm modal before "Link device": warns that current state will be
replaced and suggests creating a backup first
- Add Linked devices table when linked: show This device ID (writerKey) and
Sync group ID (discoveryKey); getSyncStatus returns deviceId and syncGroupId
- Await restorePersistedTunnels in applySyncedState so applyingSync stays
true for the full restore. Prevents saveState() during tunnel startup
from pushing back to autopass and causing a feedback loop.
- Debounce onRemoteUpdate (600ms) so bursts of autopass 'update' events
trigger a single apply.
- Skip apply when remote state matches current state (canonical fingerprint)
to avoid redundant restarts and re-pushes.
- Clear remoteUpdateDebounceTimer in cleanup().
- Replace sudo with pkexec so PolicyKit shows a graphical auth dialog
when the native host is launched by the browser (no terminal).
- Pass DISPLAY and XAUTHORITY into the pkexec env so the polkit
agent can display the dialog in the current session.
- Keep copy + update-ca-certificates in a single pkexec sh -c for
one password prompt.
- Update SECURITY.md and JSDoc to describe pkexec / PolicyKit.
- Move connect-proxy and https-proxy into proxy/
- Move certificate-authority, backup-manager, ssh-manager, rdp-manager into managers/
- Move messenger.js into host/
- Move test-dirname.cjs into test/
- Update imports, CI lint paths, and ARCHITECTURE.md