Commit Graph

71 Commits

Author SHA1 Message Date
Fredrik Johansson
1bd719fa58 ci: downgrade artifact actions to v3 for Gitea GHES compatibility
upload-artifact@v4 and download-artifact@v4 are not supported on GHES.
Also drop merge-multiple (v4-only) and adjust release glob to artifacts/*/*.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 21:53:07 +02:00
Fredrik Johansson
be297d3a49 docs: add QUICKSTART.md for non-technical users
Three paths: browser-only, desktop app download, headless daemon.
Covers invites, anchor server basics, and mobile install.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 21:46:37 +02:00
Fredrik Johansson
c426fa8c08 chore: gitignore root-level app and waste binaries
Some checks failed
Build / Server binaries (amd64, linux) (push) Has been cancelled
Build / Server binaries (amd64, windows) (push) Has been cancelled
Build / Server binaries (arm64, darwin) (push) Has been cancelled
Build / Server binaries (arm64, linux) (push) Has been cancelled
Build / Desktop app (Linux amd64) (push) Has been cancelled
Build / Publish release (push) Has been cancelled
Build / Server binaries (amd64, darwin) (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.1.0
2026-06-28 21:38:50 +02:00
Fredrik Johansson
0789cf8840 feat: download dirs, file transfer resume, Wails desktop app, PWA, CI
Daemon:
- Per-network download directories (-download-dir flag, set_download_dir IPC)
- File transfer resume after disconnection: .tmp.meta sidecars survive
  interruption; resume_offset in file-accept lets sender seek and continue
- set_download_dir IPC command; download_dir reported in state_snapshot

Protocol:
- PeerMessage.ResumeOffset (EXT-006) for file transfer resume
- IpcMessage.ShareNetworks json tag changed from "networks" to "network_ids"
  to fix duplicate json tag collision with Networks []NetworkInfo

Desktop app (cmd/app):
- Wails v2 shell embedding daemon logic directly (no subprocess)
- System tray on Linux/Windows via getlantern/systray; macOS hides to Dock
- OS notifications for message_received and file_complete via Wails events
- notray build tag for headless/CI builds without GTK tray headers
- build-app.sh: builds web frontend, copies dist, runs wails build

Web / PWA:
- manifest.json + Apple touch icon meta tags for mobile "Add to Home Screen"
- PNG icons (192px, 512px, 180px) generated from SVG
- Wails EventsOn("notify") hook in App.tsx for native OS notifications

CI:
- .gitea/workflows/build.yml: server binaries cross-compiled for 5 platforms,
  desktop app for Linux amd64, release artifacts published on v* tags

Docs:
- README: download dir, file transfer resume, desktop app, PWA, CI sections
- EXTENSIONS.md: EXT-004 daemon mode marked shipped; EXT-006 resume added
- FUTURE.md: roadmap updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 21:38:28 +02:00
Fredrik Johansson
d233f4d79e docs: update README and FUTURE for TURN daemon, room creation, unread indicators
Mark TURN daemon mode, TUI room creation + SQLite persistence, and unread
room indicators as shipped. Update IPC reference with create_room/room_created.
Add TUI slash commands section. Remove now-stale "not yet done" notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:36:13 +02:00
Fredrik Johansson
95fd29ae8d feat: unread indicator (*) for rooms with new messages
Rooms that receive a message while not active show a * prefix in the
sidebar. The marker clears when you tab to that room.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:30:10 +02:00
Fredrik Johansson
340735f992 feat: TUI room creation + daemon-side room persistence
/room <name> in the TUI sends create_room to the daemon, which persists
it in the rooms SQLite table and echoes room_created back. state_snapshot
now includes persisted rooms so they survive reconnects. Tab navigation
and room rendering pick them up automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:26:12 +02:00
Fredrik Johansson
1308082c7b Add TURN relay support for daemon mode
-turn-url and -turn-secret flags on the daemon; credentials generated
using coturn use-auth-secret HMAC-SHA1 scheme (same as browser mode).
ICEServers field on mesh.Mesh threads extra ICE servers through to
every PeerConnection created by the anchor client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:16:18 +02:00
Fredrik Johansson
31e13fd509 Add signed invites, hang links, multi-share, and EXTENSIONS.md
- Signed invites: waste: URI gains inviter+sig fields (Ed25519); hello
  carries the invite so receiving peers can verify against known keys
- RequireInvite per-network flag: rejects peers without valid signed invite
- Hash-based hang links: #waste:base64 fragment pre-fills join form without
  server-side leakage of network name
- Multi-share: shares.json (daemon) + waste_shares localStorage (browser);
  IPC add_share/remove_share/list_shares commands
- EXTENSIONS.md: addendum documenting all waste-go protocol deviations from
  YAW/2; all extensions are additive and backward compatible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:05:56 +02:00
Fredrik Johansson
0e8ddbf4f4 docs: update README and FUTURE for multi-share, file browser, session persistence
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 21:18:56 +02:00
Fredrik Johansson
f326ff2605 fix: remove unused useEffect import in ShareManager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:49:17 +02:00
Fredrik Johansson
e0704f210c feat: persistent multi-share configuration (shares.json + localStorage)
Daemon side:
- internal/shares: new package reads/writes shares.json next to identity
- proto: add ShareEntry type, add_share/remove_share/list_shares IPC commands,
  shares_list event, path field on FileEntry
- netmgr: load shares.json on startup; ScanAllShares combines legacy ShareDir
  with shares.json entries (recursive walk with relative paths)
- mesh: ScanFiles callback lets manager inject multi-share scanning without
  mesh knowing about shares.json
- ipc: handle add_share, remove_share, list_shares commands

Browser side:
- ShareManager component replaces FolderPicker: shows list of named shares
  with remove/re-pick buttons; persists share records to waste_shares in
  localStorage (name, global flag, networkId)
- FolderPicker retained for internal use; Sidebar now uses ShareManager

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:47:11 +02:00
Fredrik Johansson
0f54f3bbad feat: subfolder support in file sharing + directory browser UI
- FolderPicker: uses webkitRelativePath so paths like docs/report.pdf
  are preserved; adds "include subfolders" checkbox (default on)
- FileBrowser: virtual directory tree with breadcrumb navigation,
  sort by name/size, search filter, folders shown before files
- Protocol: browse sends path alongside name; get uses path as key
- FileEntry type gains optional path field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:29:00 +02:00
Fredrik Johansson
80e05b81ac docs: clarify browser folder-picker upload prompt is a browser warning
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:18:34 +02:00
Fredrik Johansson
2c71d9c5c6 feat: session persistence, logout button, TURN HMAC fix; update docs
- Browser mode auto-rejoins saved network on reload (waste_last_network)
- Logout button (⏻) in sidebar clears session; optionally clears identity keypair
- TURN credentials now use HMAC-SHA1 of username (coturn use-auth-secret compatible)
- README: deploy scripts documented, session persistence section, serve-web.sh noted
- FUTURE.md: mark shipped items, add remaining work for daemon TURN + TUI rooms

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:16:18 +02:00
Fredrik Johansson
dfbdd34aaa fix(turn): generate HMAC-SHA1 credentials for coturn use-auth-secret
coturn's use-auth-secret mode requires the TURN password to be
HMAC-SHA1(secret, username), not the raw secret. Pass ice servers
as a constructor argument so the async credential generation happens
before RTCPeerConnection is created.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:07:53 +02:00
Fredrik Johansson
295851f966 docs: replace example TURN secret with placeholder
Committed a generated hex string that looked like a real secret.
Replaced with YOUR_SECRET_HERE to make it obviously an example.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:52:50 +02:00
Fredrik Johansson
02eb83b63a docs: use a real generated secret in coturn example
Replace placeholder YOUR_RANDOM_SECRET with an actual openssl rand -hex 32
output, with a note to generate a fresh one. Keeps the example copy-pasteable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:16:48 +02:00
Fredrik Johansson
ea1eb767f1 Add TURN relay support and document coturn setup
Browser adapter reads turnURL + turnSecret from WASTE_CONFIG and adds a
TURN ICEServer entry automatically. Uses time-limited credentials
compatible with coturn's use-auth-secret mode.

README: new section under Hosting with coturn install, turnserver.conf,
firewall note (UDP 3478, no NPM needed), and config.js snippet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:12:03 +02:00
Fredrik Johansson
c4032417ae Show peers immediately on discovery, before DataChannel opens
Emit peer_connected + peer_status(connecting) as soon as a PeerConn is
created, so peers appear in the sidebar even if ICE is still negotiating
or ultimately fails. The alias updates in-place once the DataChannel hello
arrives with the real nick.

Fixes: mobile/CGNAT peers being completely invisible when STUN hole
punching fails — they now show with a connecting/failed dot instead of
not appearing at all.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 20:54:47 +02:00
Fredrik Johansson
fb14ca82af Add rooms, per-network file sharing, and file transfer UX
Additional rooms:
- Store tracks customRooms per networkId; createRoom action slugifies and
  deduplicates, switches active room on creation
- Sidebar: + button next to Rooms label opens an inline input; Escape
  dismisses; Enter creates the room

Per-network share directories:
- Store tracks sharedFilesByNetwork keyed by networkId instead of a single
  global map; setSharedFiles(files, networkId?) defaults to activeNetworkId
- FolderPicker reads per-network map to display accurate file count label

File transfer UX:
- Incoming file-offer now emits pending_offer instead of auto-accepting;
  user sees Accept / Reject buttons in the sidebar Transfers section
- Progress events emitted per chunk during receive; Transfers panel shows
  a live progress bar with received/total sizes
- file-cancel protocol message: sender or receiver can cancel an in-flight
  transfer; DataChannel is closed and buffers discarded
- PeerConn: acceptOffer(), rejectOffer(), cancelRecv(), cancelSend()
- BrowserAdapter: acceptOffer(), rejectOffer(), cancelTransfer()
- Store: pendingOffers, fileProgress, acceptOffer, rejectOffer, cancelTransfer
- Transfers component renders in sidebar; auto-hides when no activity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 20:49:15 +02:00
Fredrik Johansson
5421352e62 docs: update FUTURE.md to reflect current shipped state
Mark web UI, peer gossip, and identity backup as shipped. Expand TURN
section with concrete implementation notes (one-liner ICEServers change +
3 daemon flags). Add per-network share directories and additional
channels/rooms as next items. Remove stale "not implemented" notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 20:40:33 +02:00
Fredrik Johansson
068e7e6566 docs: update README with file sharing and browser mode clarifications
Document the folder sharing, peer file browsing, and direct push (📎)
workflows added in the previous commit. Clarify that browser mode also
activates locally when config.js sets signalURL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 20:31:54 +02:00
Fredrik Johansson
91b7406d01 Add peer-to-peer file transfer in browser mode
Implements both pull (browse & download from a shared folder) and push
(send a file directly to a peer) using the yaw2 file protocol over WebRTC
DataChannels.

- PeerConn: handle browse/files/get/file-offer/file-accept/file-done
  control messages; stream files in 64KB chunks over f:xid binary
  DataChannels; auto-accept incoming offers (push and pull)
- PeerConn.sendFilePush(): initiate an outbound file transfer without
  requiring the peer to browse first
- BrowserAdapter: sharedFiles map, setSharedFiles(), requestBrowse(),
  requestGet(), sendFileTo() — propagates share map to all active peers
- Store: activeFilePeer, setActiveFilePeer, setSharedFiles, browseFiles,
  sendFileTo; file_complete handler triggers browser download automatically
- FileBrowser component: third-column panel listing a peer's shared files
  with name, size, and a download button
- FolderPicker component: webkitdirectory input in the sidebar (browser
  mode only) for selecting a local folder to share
- Sidebar: 📎 send-file button on peer rows (hover) with inline file picker
- App.tsx: use browser mode when WASTE_CONFIG.signalURL is set, even on
  localhost — allows testing browser mode via npm run dev with config.js
- deploy-daemon.sh: kill existing daemon before scp to avoid upload failure
  when the binary is locked; remove duplicate kill block in restart step

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 20:29:54 +02:00
Fredrik Johansson
ea66e2eb58 ui: fix peer row spacing — alias no longer flex:1
ID takes flex:1 now, sitting right after the alias. Actions push right via margin-left:auto.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:51:27 +02:00
Fredrik Johansson
076f9641c2 ui: clean up self entry in peer list
Replace bold duplicate-looking self row with dimmed name + small accent
"you" badge. Removes the ID (already shown in identity section at top).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:48:28 +02:00
Fredrik Johansson
1d38766006 ui: fix message layout — no-wrap timestamp, tighter alias column
Switch back to flex, set explicit widths: 52px timestamp (nowrap, 24h),
90px alias (right-aligned). Eliminates wrapping and the large gap.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:47:19 +02:00
Fredrik Johansson
f5a11cb22b ui: fix message alignment, show self in peer list
Messages now use a fixed grid (44px ts · 120px alias right-aligned · 1fr text)
instead of flex, so text always starts at the same column regardless of alias length.

Self shown at top of peer list with accent dot and bold name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:45:08 +02:00
Fredrik Johansson
478a0a32af chore: gitignore serve-web.sh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:37:48 +02:00
Fredrik Johansson
4e5e41b733 chore: gitignore deploy-web.sh and deploy-daemon.sh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:33:56 +02:00
Fredrik Johansson
27874cd721 chore: gitignore build-web.sh and build-daemon.sh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:30:21 +02:00
Fredrik Johansson
6e8c8180b5 feat: emit peer_status (ICE state + candidate type) from daemon
Hooks pc.OnConnectionStateChange in WireDataChannel to emit peer_status
events. On connected, calls pc.GetStats() to find the nominated candidate
pair and report candidateType (host/srflx/relay) and remote address.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 19:28:27 +02:00
Fredrik Johansson
bb53357bc8 redesign: 2-col layout, peers in sidebar, IRC-style messages, NAT dot
- Peers moved from right panel into sidebar below Rooms
- Messages left-aligned IRC style: time · alias · text
- Per-peer colored dot: green=direct/NAT-punched, amber=relay/connecting, red=failed
- Hover title on peer row shows full ID, connection type, remote address, last seen
- Removed right PeerList panel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 13:28:40 +02:00
Fredrik Johansson
cb80040ddb chore: gitignore web/public/config.js; fix netHash to use WebCrypto
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 13:21:12 +02:00
Fredrik Johansson
f7047b7bfe fix: align offer/answer tiebreak with yaw2/browser (lower ID offers)
The Go daemon was using higher-ID-offers while the browser adapter and
yaw2 use lower-ID-offers. This meant daemon↔browser pairs where the
daemon had the lower ID would never connect — neither side would offer.

All three comparison sites in anchor/client.go flipped: > 0 → < 0,
<= 0 → >= 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 11:47:13 +02:00
Fredrik Johansson
d529f58ddc Update README: hosting guide, browser vs daemon mode, NPM setup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:57:44 +02:00
Fredrik Johansson
bbd78ac4de Remove hardcoded anchor URL fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 08:52:21 +02:00
Fredrik Johansson
de8d3ff70d Remove unsolicited deploy/ and config.example.js
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 08:52:00 +02:00
Fredrik Johansson
739c63f6b3 Add deploy/ with nginx config and web deploy script
nginx-waste.conf: serve web/dist/ at root, proxy /ws to anchor (port
8080), SPA fallback for clean invite URLs, immutable cache for assets.

deploy-web.sh: build + rsync to anchor host, skip config.js so the
host's runtime config is not clobbered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 08:44:46 +02:00
Fredrik Johansson
5bc16daae1 Add standalone browser mode: no daemon required
BrowserAdapter speaks yaw/2.1 signaling + WebRTC protocol entirely in
the browser (libsodium-wrappers for Ed25519/X25519). Identity stored in
localStorage; peers connect via any waste/yaw2 anchor.

When served from a non-localhost origin the app defaults to browser
mode. On localhost the daemon adapter is tried first with a one-click
switch to browser mode. config.js (gitignored, served by anchor) lets
the host pre-inject signalURL and other defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 00:06:41 +02:00
Fredrik Johansson
add7c5fea8 Add yaw2 invite interoperability
Protocol:
- invite.go: include full 64-char `net` hash in waste: invite blob
  (matches yaw2's `net` field — any client parsing the base64 JSON can
  join without knowing the plaintext name). Expose NetHash() helper.
- netmgr: add JoinByHash() — join via full 64-char hex hash alone,
  storing the short ID as display name. Enables joining yaw2 networks
  from a URL that only carries the hash.
- anchor: expose RunByHash() so netmgr can pass a pre-computed hash
  directly without a name→hash roundtrip.
- ipc/proto: add network_hash field to join_network — routes to
  JoinByHash when present and network_name is absent.

Web UI:
- Parse ?net=<64hex> (yaw2 URL param) and ?a=<anchor> in addition to
  existing ?n= / ?invite= params. Hash-only joins send network_hash.
- Sidebar shows yaw: contact card (yaw:<masterID>?n=<alias>) using the
  master identity — compatible with yaw2 contact card format. Click to
  copy to clipboard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:29:45 +02:00
Fredrik Johansson
7fe02e9463 Fix web UI messaging, alias resolution, and onboarding
Messaging:
- Append \n to WS IPC sends so bufio.Scanner fires (messages from web
  were silently dropped — the line scanner never saw a newline)
- Handle session_ready in web store to update peer aliases after hello

Alias resolution:
- Seed AddPeer alias from SQLite cache so returning peers resolve
  immediately, before hello exchange completes
- Remove stale SavePeer call from AddPeer (was writing placeholder IDs)
- Add PeerAlias() point-lookup to store

Onboarding redesign:
- Three-state UI: disconnected (daemon instructions), connecting,
  connected-no-network (join form)
- Read ?n= / ?network= / ?anchor= / ?invite=waste:... URL params to
  pre-fill the join form for invite links
- Show daemon alias + peer ID before any network is joined
  (master_alias + master_id now included in state_snapshot)
- Identity backup: export (passphrase-protected yaw-key-backup-1 JSON,
  download button) and restore (paste + passphrase verify)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:22:32 +02:00
Fredrik Johansson
2bc1dbbedf fix: run TCP and WS IPC concurrently, fail only if either dies
Previously --ws-port started WS in a goroutine then called Run() which
blocked; if TCP IPC failed it took the whole process down even though WS
was up. Now both run in goroutines and the first error from either kills
the daemon.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 22:11:20 +02:00
Fredrik Johansson
06f9359da8 fix: allow any origin on WS IPC (127.0.0.1-only bind is the guard)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 22:08:44 +02:00
Fredrik Johansson
ff14e955ea feat: standalone web UI (React + Vite)
React + TypeScript UI on port 5274. Connects to local daemon via
WebSocket IPC (DaemonAdapter). Full chat layout with sidebar, message
pane, and peer list. Mirrors the TUI feature set.

- src/types.ts        — IPC types mirroring proto.go
- src/adapter/daemon  — WebSocket IPC adapter with auto-reconnect
- src/store/index.ts  — Zustand store; handles all daemon events
- src/pages/          — Onboarding (connect + join) and Chat
- src/components/     — Sidebar, MessagePane, PeerList

Dev: cd web && npm run dev  (port 5274)
Build: cd web && npm run build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:57:32 +02:00
Fredrik Johansson
77830a3b3f feat: WebSocket IPC endpoint for web UI
Add --ws-port flag to waste-daemon; when set, starts a WebSocket IPC
server alongside the existing TCP one. The web UI connects to this from
the browser. Uses nhooyr.io/websocket with localhost-only origin policy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:57:10 +02:00
Fredrik Johansson
c1dea1d19d chore: gitignore setup-anchor.sh and launch-tui.sh
Local-only scripts for deploying the anchor and launching the TUI —
not intended for the repository.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:45:37 +02:00
Fredrik Johansson
b47f659b7d feat: identity export/import (yaw-key-backup-1)
Portable encrypted identity backup compatible with the sister project's
format — argon2id KDF + nacl secretbox, peer ID visible in plaintext for
pre-import verification.

- crypto: ExportIdentity, ImportIdentity, SaveIdentity
- proto: export_identity / import_identity IPC commands + events
- ipc: export_identity returns encrypted blob; import_identity validates
  and decrypts (read-only — on-disk write requires daemon restart)
- netmgr: MasterIdentity() accessor
- daemon: --import-identity / --import-passphrase flags write identity.json
  and exit, enabling scripted account migration
- tests: roundtrip and wrong-passphrase rejection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 21:44:48 +02:00
Fredrik Johansson
f1498697b6 feat: live mesh peer gossip
When a peer's hello is verified, send a gossip burst of currently
connected peers so the new peer can discover and connect to nodes it
hasn't met yet — without relying on the anchor for a full peer-join
notification for each one.

- mesh: add PendingConnect chan for gossip-discovered peer IDs
- peer: send gossip burst after hello; push unknown peers from incoming
  gossip onto PendingConnect (skip self + already-connected)
- anchor: drain PendingConnect per runOnce, initiate startOffer for
  unknown peers using the same lexicographic tiebreak as anchor join;
  drain goroutine is scoped to the runOnce lifetime to avoid using stale
  sessions after a reconnect

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 16:02:11 +02:00
Fredrik Johansson
d02e18e212 feat: per-network share directories + isolation test
Each network now carries its own share dir, set at join_network time via
optional share_dir field or updated live with set_share_dir. The global
-share-dir daemon flag becomes a fallback default.

- proto: add ShareDir/DownloadDir to NetworkInfo and IpcMessage
- netmgr: Join accepts shareDir override; SetShareDir updates live
- ipc: wire join_network share_dir and set_share_dir command
- daemon: remove -share-dir from auto-join path (pass "" for default)
- test-network.sh: per-network join with share_dir; isolation verification
  section confirms alice/friends and alice/work share dirs are independent
- test-tui.sh: join_network with share_dir; peer IDs resolved after join

All tests pass: YAW/2.1 FS, share isolation, file transfer, persistence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 15:13:26 +02:00