534 Commits

Author SHA1 Message Date
archipelago
386d4bfc3f perf(ui): losslessly optimize background images; convert bg-mesh PNG→JPEG
- 16 JPEGs re-encoded lossless via jpegtran (optimized Huffman + progressive,
  EXIF stripped) — pixel-identical, ~4-11% smaller each.
- bg-mesh.jpg was a 5.8MB RGBA PNG mislabeled .jpg → real progressive JPEG
  (mozjpeg q92, opaque), 5.8MB → 0.76MB (-87%).
- Synced optimized assets into web/dist and per-app container UIs (lnd/bitcoin/
  fedimint/aiui) + app-icons. Source img dir 21.4MB → 16MB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 02:19:50 -04:00
archipelago
c0d41cf8cf fix(ui): faster bitcoin sync refresh + unstick ElectrumX loader (B15,B7)
B15: Home system stats (incl. bitcoin sync %) polled every 30s — too slow;
now 10s so sync progress tracks the actual block height more closely.

B7: the ElectrumX sync overlay was gated only on status!=='synced', so if
the status never flips to 'synced' (ElectrumX stale/disconnected) the loader
stuck on top forever. Now the overlay hides and the app iframe loads when
the sync status is stale (fail-open), while still showing during active
indexing. type-check EXIT 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 16:29:44 -04:00
archipelago
5c8707432b fix(cloud): Range-streaming proxy for peer media so it plays/seeks (B3)
Peer media (music/video) wouldn't play: the frontend downloaded the whole
file via RPC as base64 and made a non-seekable Blob URL, so <video>/large
<audio> stalled and big files hit the RPC timeout.

Add GET /api/peer-content/<onion>/<id> — a same-origin, session-gated proxy
that forwards the browser's Range header to the peer's /content/<id> (which
already returns 206 Partial Content) and passes status + Content-Range +
Content-Type back. PeerFiles.playMedia() now points <video>/<audio> at this
streaming URL for free content instead of buffering a base64 blob, so the
player can seek and start immediately. Onion/id validated to prevent
SSRF/path traversal. (Paid preview keeps its existing flow.)

Verified: cargo build --release EXIT 0; vue-tsc --noEmit EXIT 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:46:51 -04:00
archipelago
0801dd6632 feat(cloud): show Tor/FIPS transport pill on peer browse (B21)
content.browse-peer now returns the transport that actually reached the
peer (fips/tor/mesh/lan). PeerFiles shows it as a small coloured pill next
to the peer name (FIPS/Mesh green, LAN blue, Tor amber) and the loading
text no longer hardcodes "Connecting via Tor" (it was misleading when FIPS
was used). Pairs with B14 (transport recording).

Verified: cargo build --release EXIT 0; vue-tsc --noEmit EXIT 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:25:39 -04:00
archipelago
ed4931064b fix(federation,cloud): dedup trusted nodes + chat contacts by onion; guard cloud my-folders (B1,B2,B4)
B1/B2: the same physical node can linger in the federation list under two
dids (e.g. after a did/key change). An onion is a node's unique stable
identity, so two entries with the same onion are one node. This showed the
node twice in the trusted-node list (B1) and as two mesh chat contacts —
one by name+logo, one by raw did (B2).
- storage::load_nodes now collapses same-onion entries (keep first, merge
  fips_npub/name/last_state) so every consumer (list + chat seed + sync)
  sees one entry per node.
- federation::sync merge_transitive_peers also matches by onion (not just
  did) so new transitive hints don't re-add a known node under a new did.
- mesh::seed_federation_peers_into_mesh skips already-seeded onions (belt
  and suspenders).
- Unit tests for dedup_nodes_by_onion (collapse + onion-suffix handling).

B4: filebrowser-client.listDirectory only checked res.ok before res.json(),
so when File Browser is absent (nginx serves the SPA index.html, 200) or
down (502) the JSON parse threw the opaque "Unexpected token '<'". Now it
checks the content-type and throws a friendly "File Browser is not
available" the Cloud view already renders as an empty state.

Verified: dedup unit tests 2/2; live .198 (15 entries→13 distinct onions)
restarted healthy on new binary; B4 guard present in built bundle + deployed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:29:12 -04:00
archipelago
7aa1ca013f chore: release v1.7.96-alpha 2026-06-15 10:14:05 -04:00
archipelago
5af9a22b98 feat(fips): selectable TCP/UDP transport when adding a seed anchor
The add-anchor form previously hardcoded transport=udp. Expose a
TCP/UDP selector (default tcp) so public internet anchors and
local-network anchors can both be added. Includes changelog + What's
New entry for v1.7.96-alpha.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:12:23 -04:00
archipelago
786498a57a fix(kiosk): remove kiosk launcher grid, show normal app on the display
The kiosk attached-display showed a separate app-tile launcher grid
(Kiosk.vue at /kiosk) instead of the normal onboarding/login/dashboard.
The grid is auth-gated, so it only surfaced once the kiosk browser held a
persisted session; otherwise it bounced to login — masking the issue.

Remove the grid entirely. /kiosk now just persists kiosk mode + safe-area
insets and redirects to the root app. The launcher keeps pointing at
/kiosk (not directly at /) so the 'kiosk' localStorage flag is still set —
App.vue uses it to skip the remote relay, which would otherwise double
xdotool input on the kiosk display. Route made public so the auth guard
doesn't bounce it before the redirect runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:03:07 -04:00
archipelago
e2c2f942c2 chore: release v1.7.95-alpha 2026-06-15 08:48:22 -04:00
archipelago
e056c2477b fix(fips,federation,ui): mesh content browse, removed-node tombstones, modal sizing
FIPS peer content browse over the mesh was failing with "Peer returned
error: 404 Not Found" and never falling back to Tor. `is_peer_allowed_path`
only allowed `/content/<id>` (item fetches) — the catalog endpoint is
exactly `/content` (no trailing slash), so it 404'd over the FIPS peer
listener. A FIPS 404 was also treated as a successful response, so the dial
never retried Tor. Fixes: allow `/content` over the mesh; add
`fips_should_fall_back()` so a FIPS 404/5xx in Auto mode falls back to Tor
(handles version-skew peers reaching a different route). Also correct the
reconnect hint text — the public anchor is TCP/8443, not UDP/8668.

Federation: deleted nodes reappeared because transitive discovery
(`merge` of a peer's advertised trusted peers) re-added any unknown DID.
Add a tombstone store (`removed-nodes.json`): remove_node tombstones the
DID, transitive merge skips tombstoned DIDs, and a remote-triggered
peer-joined is ignored for a removed DID. Explicit local re-add (add_node)
clears the tombstone.

UI: the app credentials modal panel stretched edge-to-edge (height:100%,
max-width:none, items-stretch overlay). Constrain it to a centered card
(max-width 34rem, rounded, dimmed full-screen backdrop) matching the
AppIconGrid / wallet-receive modal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 08:09:26 -04:00
archipelago
7bd22f1f80 chore: release v1.7.94-alpha 2026-06-15 07:09:58 -04:00
archipelago
cfb0e4735a chore: sync What's New modal for v1.7.94-alpha
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 06:43:20 -04:00
archipelago
327a4e34dd chore: release v1.7.93-alpha 2026-06-14 15:18:34 -04:00
archipelago
bf2793be7b chore: sync What's New modal for v1.7.93-alpha
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:45:56 -04:00
archipelago
d462e44453 chore: release v1.7.92-alpha 2026-06-14 09:09:57 -04:00
archipelago
1af583e1ab docs: add third v1.7.92 changelog bullet (What's New backfill) + sync modal
create-release staging requires >=3 curated release-note bullets. The What's
New restoration is itself user-facing, so it's an honest third note; mirror it
into the modal's v1.7.92 block via sync-whats-new.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 09:03:18 -04:00
archipelago
2fac63e58c feat(release): gate that Settings 'What's New' modal stays in sync with CHANGELOG
The What's New modal (AccountInfoSection.vue) hardcodes one block per release
and had silently drifted: it sat at v1.7.84 while the fleet shipped through
v1.7.92, so eight releases of notes never reached users in Settings.

- scripts/sync-whats-new.py: renders a modal block from each CHANGELOG version
  that's missing one (curated bullets, dev-process 'Validation…' lines dropped),
  inserts newest-first; never touches older hand-written pre-CHANGELOG history.
  --check mode lists anything missing and exits non-zero.
- tests/release/run.sh: new 'whats-new-sync' static gate runs --check, so a
  release with an un-surfaced CHANGELOG entry fails before shipping.
- Backfilled the eight missing blocks (v1.7.85 … v1.7.92) into the modal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:31:43 -04:00
archipelago
4232424b23 fix(ui): suppress app-unreachable overlay while ElectrumX sync screen shows
When ElectrumX is still building its index (or waiting on the Bitcoin node),
AppSessionFrame shows a sync 'pre UI'. The iframe-blocked fallback ('App not
reachable / retrying') was not gated on electrsSync, so it painted over the
sync screen and read as a hard connection error. Gate it on !electrsSync,
mirroring the iframe's own guard.

Also harden the lifecycle health probe: container_health used jq '// "unknown"',
which only catches null/false — an empty-string health (a brief window under
load) rendered as a blank 'bad health: X is '. Map empty to 'unknown' so the
retry loop keeps waiting instead of failing on a transient.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 07:58:24 -04:00
archipelago
9b9fa9cdee chore: release v1.7.91-alpha 2026-06-14 05:32:38 -04:00
archipelago
21aaacc8b4 fix(ui): guard receive-code index access — unblocks v1.7.91 frontend build
codeMatch[1] is string|undefined under noUncheckedIndexedAccess; using it
directly as an index into RECEIVE_CODE_MESSAGES failed vue-tsc (TS2538) and
aborted create-release.sh at the frontend build step. Bind to a const and
narrow before indexing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 04:35:21 -04:00
archipelago
0ed892a412 fix: wallet receive reliability, bitcoin install self-heal, ElectrumX app tile
Fixes three Bitcoin/wallet failures observed across the fleet on v1.7.90-alpha
(all nodes were already on the latest build — these were live bugs, not stale
builds), plus the missing ElectrumX tile, and adds automated coverage so each
can't regress silently.

Receive address (".116 receive fails", ".228 false 'wallet is locked'"):
- LND publishes its REST API on a host port that can drift from the manifest
  (a container created when the mapping was 8080 kept publishing 8080 after the
  manifest moved to 18080). The in-process client connects to the manifest port,
  gets connection-refused, and wallet init fails forever while the container
  looks "Up". Add published-port drift detection to the reconciler
  (container_ports_drifted / host_port_bindings_drifted) that recreates a
  drifted backend even for restart-sensitive apps — a drifted container is
  already broken, so leaving it "untouched" only perpetuates the failure.
- Receive errors now carry a stable [CODE] token (REST_UNREACHABLE, WALLET_LOCKED,
  WALLET_UNINITIALIZED, SYNCING) and always start with "Bitcoin address" so they
  survive the RPC error sanitizer instead of collapsing to the generic
  "Operation failed". The UI maps the code instead of guessing wallet state from
  substrings — so an unreachable REST endpoint is no longer mislabelled "locked".

Bitcoin install (".198 bitcoin gone / reinstall just stops"):
- bitcoin-knots requires the secret bitcoin-rpc-txrelay-rpcauth, which was only
  generated by the tx-relay flow. Nodes that never used tx-relay lacked it, so
  secret resolution hard-failed and the whole Bitcoin stack cascaded. Generate
  it idempotently before bitcoin starts (ensure_app_secrets, reusing
  ensure_txrelay_credentials), and name the missing secret in the error so a
  genuine gap is actionable instead of a bare "IO error".

ElectrumX app tile missing on every node with it installed:
- The catalog generator dropped electrumx because the manifest had no
  interfaces.main block, so the tile had no launch URL and was hidden. Declare
  the companion UI port (50002) in the manifest, regenerate the catalog, and let
  an app with a known launch URL stay launchable while its backend is still
  "starting" (ElectrumX indexes for 10m+).

Test harness:
- New lifecycle bats suites: bitcoin-receive, port-drift, secret-completeness
  (validated live; port-drift catches the real .116 drift).
- Rust unit tests for drift detection, the receive reason-code classifier, and
  the named-missing-secret error; vitest for the UI code mapping.
- create-release.sh now runs tests/release/run.sh and aborts the release on
  failure — previously it ran no tests at all.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 03:12:56 -04:00
archipelago
bb808df89a chore: release v1.7.90-alpha 2026-06-13 05:05:14 -04:00
archipelago
c800293f1f fix: bitcoin receive, AIUI pointer input, electrs self-heal, OTA timeout
- LND wallet: request correct address type so receive-address generation
  no longer 400s
- AIUI/app session: on-screen pointer can click + type into app content
  (incl. app store search); "open in new tab" opens the phone browser;
  mobile credential modal centered instead of full-height
  (remote-relay.ts, AppSession.vue, AppSessionFrame.vue, AppIconGrid.vue,
  openExternal.ts, WebViewScreen.kt) + remote-relay tests
- health_monitor: electrs auto-recovers from a corrupt index and shows a
  percent/block-height progress screen while reindexing (useElectrsSync.ts)
- update.rs: drop retired tx1138 secondary mirror (one-time migration);
  longer download timeout for slow connections
- CHANGELOG: v1.7.90-alpha notes
- tests/release/run.sh: harness tweaks

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 04:49:32 -04:00
archipelago
c49e8fcacd fix: harden OTA updates, AIUI desktop gap, LND no-proxy
- update.rs: post-OTA probe falls back to http://127.0.0.1/ on connect
  error (nginx binds :80, not :443) so good updates are no longer rolled
  back; recover stuck update_in_progress; avoid ETXTBSY on running binary
- LND: REST client bypasses proxy, GET newaddress p2wkh, wallet
  readiness/unlock after restart
- Dashboard.vue: chat route back to plain h-full (desktop bottom-gap fix)
- vite.config.ts: dev-only /aiui proxy
- tests/release/run.sh: release gate harness (static+frontend+backend)
- CHANGELOG: v1.7.89-alpha notes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 01:23:32 -04:00
archipelago
495b90782a fix: restore AIUI mobile layout 2026-06-12 06:01:24 -04:00
archipelago
b8ac68d844 fix: restore aiui and bitcoin receive before release 2026-06-12 05:10:03 -04:00
archipelago
eaf13effd5 fix: restore fast AIUI launch 2026-06-12 05:04:42 -04:00
archipelago
6fd1cf9ba7 chore: release v1.7.87-alpha 2026-06-12 04:49:58 -04:00
archipelago
8d4b309753 fix: patch bitcoin receive and full-screen launch overlays 2026-06-12 04:42:23 -04:00
archipelago
b11c6c17d1 chore: release v1.7.86-alpha 2026-06-12 04:21:18 -04:00
archipelago
e474a2b4c9 chore: sync generated release artifacts 2026-06-12 03:15:24 -04:00
archipelago
00c32688f8 chore: release v1.7.85-alpha 2026-06-12 03:14:59 -04:00
archipelago
d6f108d818 chore: snapshot release workspace 2026-06-12 03:00:15 -04:00
archipelago
6a30ff11bd chore: release v1.7.84-alpha 2026-06-11 04:44:58 -04:00
archipelago
22df3f8f5f chore: release v1.7.83-alpha 2026-06-11 03:03:32 -04:00
archipelago
87853fc29c frontend: keep mobile app tabs singular 2026-06-11 02:54:34 -04:00
archipelago
b7c2fd081f settings: update whats new for v1.7.83 2026-06-11 02:49:07 -04:00
archipelago
760796f650 frontend: polish mesh release layout 2026-06-11 02:39:24 -04:00
archipelago
10e4f218a6 deploy: bound indeedhub fixups and polish bitcoin ui 2026-06-11 02:32:10 -04:00
archipelago
8f2e03df2a deploy: exclude codex scratch artifacts 2026-06-11 01:46:38 -04:00
archipelago
c79afa9541 frontend: fix strict production build typing 2026-06-11 01:30:49 -04:00
archipelago
f818f1dcc1 app-platform: remove unsupported saleor release surface 2026-06-11 01:16:21 -04:00
archipelago
de60f7e21e app-platform: remove revoked onlyoffice app 2026-06-11 01:03:45 -04:00
archipelago
881478a873 app-platform: type manifest launch interfaces 2026-06-11 00:52:16 -04:00
archipelago
1a3d726eac frontend: polish app launch and release experience 2026-06-11 00:24:40 -04:00
archipelago
09ec64932f app-platform: generate catalog from app manifests 2026-06-11 00:24:20 -04:00
archipelago
136eda16c9 chore: release v1.7.82-alpha 2026-05-22 17:19:45 -04:00
archipelago
853d51ae14 chore: release v1.7.81-alpha 2026-05-21 21:44:14 -04:00
archipelago
bdd5a2c43e chore: release v1.7.80-alpha 2026-05-21 00:38:57 -04:00
archipelago
7be7420c4f chore: release v1.7.79-alpha 2026-05-20 23:11:54 -04:00