Mesh peer pubkeys (LoRa advert ed25519) differ from federation node
pubkeys (archipelago identity), so matching on pubkey always missed
and attachments >160B had no transport. Match on master DID instead;
also accept an explicit peer_onion override from the frontend, which
resolves the peer by display name against federation.list-nodes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tap a bubble to open an action menu with Reply + 6 quick reactions.
Reply stashes the target MessageKey and flips the Send button to
"Reply" mode, routing through mesh.send-reply. Reactions call
mesh.send-reaction immediately and render as chips under the target
bubble, collapsed per emoji with a count and self-highlight. Reaction
messages are filtered out of the main chat stream so they don't create
standalone bubbles. Reply bubbles show a "↳ quoted snippet" header
when the target is still in the local window.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Compose row gains a 📎 attach button that uploads the file via /api/blob
and calls mesh.send-content for the selected peer. Received content_ref
bubbles render as a caption+filename card with either an inline image
preview or a Download button that calls mesh.fetch-content and swaps in
the returned local_url.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds renderers for tx_relay, tx_relay_response, tx_confirmation,
lightning_relay, and lightning_relay_response message types so these
appear as rich cards in the chat stream. sendArchMessage now looks up
our own onion via getTorAddress and skips federation peers that match,
preventing the duplicate "echoed back to self" message we were seeing
on single-node test federations. Empty-federation error message is
also clearer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Videos and audio now stream directly via URL with auth token query
param instead of downloading entire file into a JS blob. Fixes
playback of large videos (170MB+ was timing out). Images still use
blob URLs. streamUrl() added to filebrowser client and cloud store.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All hardcoded references to the old IP-based registry replaced across
Rust backend, Vue frontend, shell scripts, Dockerfiles, CI, and docs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ISO build no longer copies netavark from build host (Debian 13/GLIBC 2.41)
which broke container networking on Debian 12 targets. Rootfs already
installs netavark from Debian 12 repos — just configure the backend.
Install RPC now adopts existing containers (from first-boot) instead of
erroring on duplicates. Container scanner extracts real versions from
image tags and detects available updates against pinned versions.
Frontend shows update button with version info when updates are available.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Install progress bar replaces action buttons (no overlay)
- Hide status badge during install/uninstall
- Uninstall keeps progress state until container disappears from WebSocket
- Uninstall RPC timeout increased to 660s (Bitcoin UTXO flush)
- Installing apps appear in My Apps immediately as placeholders
- Auto-configure Tor hidden service for every app on install
- Widen Tor module visibility for install hooks
- Only clear stale install entries on error status
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove ReadWritePaths sandbox (causes namespace error when /run/nostr-vpn
doesn't exist after reboot — /run is tmpfs)
- Detect both 'active' and 'activating' states in VPN status check
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add vpn.create-peer, vpn.list-peers, vpn.remove-peer RPC methods
- Generate WireGuard config + QR code (SVG) for mobile device connection
- Add "Add Device" modal on Network page with QR scanner support
- Remove old build-iso.yml (replaced by build-iso-dev.yml)
- Remove container-tests.yml (tests run in dev workflow)
- Remove container orchestration tests from dev workflow (redundant)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical flow fixes:
- Disable boot reconciliation that auto-created ALL containers on
unbundled installs (only FileBrowser should exist on first boot)
- Fix onboarding loop: RootRedirect no longer clears the
neode_onboarding_complete flag on boot screen completion
- Seed phrase persists when navigating back (no regeneration)
UI fixes:
- Boot screen: removed github and save icons from animation loop
- Seed screens: viewport height scaling with 100dvh
- Seed restore: removed outer card container from word input grid
- Seed screens use distinct background (bg-intro-1.jpg)
- Install progress simplified to "Installing" button style
- Uninstall state moved to global store (persists across navigation)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace fragmented random key generation with a single 24-word BIP-39
mnemonic that deterministically derives all node keys: Ed25519 (DID),
secp256k1 (Nostr/Bitcoin), BIP-84 xprv (Bitcoin Core), and LND aezeed
entropy. New onboarding flow: seed generate → word verification → identity
naming. Restore path enabled via 24-word entry. Includes seed RPC handlers,
mock backend support, LND/Bitcoin Core wallet-from-seed integration, and
UI polish across settings and discover views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every app in curatedApps.ts was hardcoded to docker.io/* instead of
our registry (80.71.235.15:3000/archipelago/*). This caused Bitcoin
Knots and all Discover tab installs to fail with pull errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fix: login disconnect — verify session before WebSocket connect
- fix: 403 on app install — distinguish CSRF vs RBAC errors, only retry CSRF
- fix: health monitor now watches ALL containers (removed skip list for
backend services like nbxplorer, databases, UI containers)
- fix: server.get-state added to CSRF-exempt list (read-only)
- fix: ISO build includes container-specs.sh and lib/common.sh in rootfs
so reconcile actually works on fresh installs
- fix: gamepad nav — improved Server tab zone nav, focus styles, autofocus
- chore: move L484 web-only apps to Services tab
- chore: install store for cross-view install tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move installingApps from local refs in Marketplace/Discover to the
global server store. Install progress now persists when navigating
between views. My Apps shows installing overlay with progress bar
for apps being installed from the Marketplace.
Changes:
- server.ts: add installingApps Map + helpers to store
- Marketplace.vue: use store's installingApps instead of local ref
- Discover.vue: same
- Apps.vue: pass isInstalling + installProgress to AppCard
- AppCard.vue: add amber installing overlay with progress bar
522 tests pass, vue-tsc clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- F4: Fetch fresh server state after WebSocket reconnect
- F5: Guard message polling timer with auth check, stop on logout
- F6: Remove NIP-07 listener in appLauncher close()
- F7: Initialize audio player once to prevent listener stacking
- S3: Pin all container images to specific versions, create image-versions.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- F1: Guard connectWebSocket against concurrent calls with isWsConnecting flag
- F2: Serialize mesh send operations with sendQueue to prevent fetchMessages races
- F3: Add global Vue error handler with toast notification
- S1: Replace sudo podman with podman across all scripts (rootless Podman)
- S2: Add health-cmd to all 40 container run commands in first-boot-containers.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major changes:
- Full Tor hidden service management via systemd path unit pattern
(tor-helper.sh + archipelago-tor-helper.path/service) — respects
NoNewPrivileges=yes, no sudo needed from backend
- Container doctor: prefer system Tor over container, remove archy-tor
- Deploy script: fix torrc generation (read correct services.json path),
web apps map port 80→local port, enable both tor and tor@default
- Federation: server rename pushes name to peers via background sync
- Server name: fix root-owned file, optimistic store update
- Mesh: local echo for sent messages, sendingArch loading state
- Web5: Message button → Mesh redirect, node name lookup in messages
- PeerFiles: show DID not onion in header
- Connected Nodes: flex-1 instead of fixed max-h
- Toast notifications route to Mesh
- Deploy script: fix single-quote syntax in SSH block
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New Discover.vue (app store redesign)
- Fleet.vue dashboard for .228
- MeshMap.vue component
- Fixed Discover.vue type errors (unused var, type predicate)
- Various UI updates (Apps, Dashboard, Marketplace, Mesh, Web5)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests expected router.push but panel mode (now default) uses panelAppId
store state instead. Updated assertions to check panelAppId. Fixed
BTCPay app ID from 'btcpay' to 'btcpay-server'. All 515 tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- BUG-33: CPU load alert threshold increased from 2x to 4x core count
(8→16 on 4-core machine) to reduce false alerts during container ops
- TASK-27: Launch buttons for new-tab apps now show external link icon
(BTCPay, Grafana, PhotoPrism, Portainer, OnlyOffice, etc.)
- TASK-36: Iframe error screen now distinguishes between X-Frame-Options
blocked vs container not reachable, with appropriate messaging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frontend store (mesh.ts):
- Add typed message interfaces: InvoiceData, AlertData, CoordinateData,
SessionStatus, AlertStatus, MeshMessageTypeLabel
- New actions: sendInvoice, sendCoordinate, sendAlert, getSessionStatus,
rotatePrekeys
Mesh.vue UI:
- Typed message rendering in chat bubbles:
- Invoice: orange card with sats amount, memo, bolt11 preview, paid badge
- Alert: red card (emergency/dead_man) or blue (status), signed badge,
GPS link to OpenStreetMap
- Coordinate: blue card with lat/lng, label, OSM map link
- Block header: purple inline with chain icon
- Session badge in chat header: green shield (Double Ratchet),
yellow (static encryption), gray (none)
- Session status fetched on peer selection via mesh.session-status RPC
Mock backend:
- Messages now include message_type and typed_payload fields
- Mix of text, invoice (paid + unpaid), alert (emergency + status),
coordinate, and block_header messages for testing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Updated appLauncher tests to match current session-based routing.
Fixed settings test to use h2 instead of h1. Fixed RPC client test
to expect 'Session expired' on 401.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Simplify DHT encoding: use JSON instead of DNS packets (drop simple-dns)
- Fix mainline crate API: SigningKey takes 32 bytes, get_mutable returns Result
- Add missing dht_did field to IdentityRecord constructor
- Store DID Document as JSON in DHT (DNS encoding deferred)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added node.nostr-sign RPC that uses the node-level Nostr key (matching
getPublicKey), fixing pubkey mismatch where identity.nostr-sign used a
different key. Updated appLauncher to call node.nostr-sign. Added
nostr_sign_hash() to nostr_discovery.rs. Created test-nip07.sh with
11 automated checks (INSTALL-02).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: identity.nostr-encrypt-nip04, identity.nostr-decrypt-nip04,
identity.nostr-encrypt-nip44, identity.nostr-decrypt-nip44 endpoints
with auto-resolve to default identity. Frontend: appLauncher routes
nip04.* and nip44.* postMessage calls to backend RPC.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added nostrudel.ninja as a web-only app in Marketplace (community category).
Configured nginx reverse proxy at /ext/nostrudel/ with NIP-07 provider
injection in both HTTP and HTTPS blocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added new dependencies: `adler2`, `crc32fast`, `flate2`, `miniz_oxide`, and `libredox`.
- Updated existing dependencies: `tokio-rustls` to version 0.26.4 and `filetime` to version 0.2.27.
- Removed the `backup.rs` file as it is no longer needed.
- Introduced tests for configuration and credential management.
- Enhanced the `identity` module to generate W3C compliant DID documents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
515 tests across 38 files. Branch coverage 88%, function coverage 83%
on testable logic (stores, composables, api, utils, services, router).
New test files: websocket, useLoginSounds, useMobileBackButton,
useControllerNav, routes. Extended: rpc-client (99.5%), container store
(100%). Fixed: useNavSounds AudioContext mock, type errors across tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every empty/comment-only catch block now logs a descriptive warning
in dev mode via `if (import.meta.env.DEV) console.warn(...)`. Covers
15 files across views, stores, components, and utils. Zero silent
catches remaining.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The My Apps page went blank after installing apps because pkg['static-files'].icon
was accessed without optional chaining on dynamically installed packages that lack
the static-files property.
- Make static-files optional in PackageDataEntry type
- Add defensive ?.icon access with fallback in Apps.vue and AppDetails.vue
- Add filebrowser to mock backend staticDevApps (enables Cloud page in demo)
- Expand portMappings and marketplaceMetadata for all marketplace apps
- installPackage now uses staticApp() format for consistent data shape
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>