673 Commits

Author SHA1 Message Date
Dorian
5c43e12782 chore(android): publish companion as raw APK instead of zip
Serve the companion download as a plain .apk so a phone installs it
straight from the link/QR with no unzip step. Repoint the in-app
download URL, the ship + publish scripts, and the pre-push hook at
archipelago-companion.apk, and drop the legacy .apk.zip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:41:10 +01:00
archipelago
a7c7c44843 feat(neode-ui): mobile app-launch UX — store-driven panel, loader, ElectrumX icon
- Mobile launches use the store-driven panel (no route push) so the background
  tab no longer changes and closing returns to where you launched from.
- Tab-only apps open directly (in-app WebView on companion / new tab on PWA) —
  no "this app opens in a tab" interstitial.
- Shared AppLoadingScreen (app icon + progress bar) on the app session and the
  legacy iframe overlay instead of a black screen.
- Pin the dashboard to 100dvh on mobile so the mesh chat/tools panes stop sliding
  under the bottom tab bar in mobile browsers (no-op in the companion WebView).
- ElectrumX/electrs/electrs-ui ids now resolve to the real ElectrumX icon in My Apps.
- isMobile made reactive so overlay/footer/teleport decisions track the viewport.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 03:48:57 -04:00
archipelago
0f05f73a23 fix(mempool): self-healing nginx backend proxy (v3.0.1) + gate timeout
The frontend nginx used a literal proxy_pass host with no resolver, so it
pinned mempool-api's IP at worker startup. When the backend restarts (gate,
OTA, crash, reboot re-IPAM) podman reassigns its IP and nginx keeps proxying
to the dead one -> /api hangs, websocket 502s, UI shows 'offline' until a
manual nginx reload. Same stale-upstream-IP class as the netbird 502.

Fix: mempool-frontend:v3.0.1 rewrites the generated nginx-mempool.conf to
re-resolve the backend per-request via 'resolver' + a variable proxy_pass.
Resolver address is read from /etc/resolv.conf (podman aardvark-dns answers
on the network gateway, not Docker's 127.0.0.11). Per-location path mapping
preserved (ws -> '/', /api/v1 identity via no-URI, /api/ -> /api/v1/ rewrite).
Proven on .228: backend IP change now auto-recovers with no reload; the
literal-host control still 502s. Migrated the manifest off the retired
tx1138 registry to vps2.

Also: mempool.bats #74 waited only 180s post-restart (the slow path) and
called an undefined 'fail' helper (status 127). Bumped to 300s to match the
passing parity probes and emit a real failure instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:07:07 -04:00
archipelago
7efebb4a8c feat(demo): per-folder media merge + AIUI seed-chats bootstrap
- Curated files loader now MERGES per top-level folder: dropping real files into
  demo/files/Music/ swaps only Music and keeps the sample Documents/Photos/Videos
  (verified). Media plays with the Range support already in place.
- AIUI index.html: a ?seed bootstrap pre-loads the example "Content Showcase"
  conversation into AIUI's IndexedDB by calling the bundle's own
  seedPromptsToConversation() (identical to its /seed command), so the chat
  history isn't empty when the demo points users to "previous chats". Guarded by
  try/catch + an existence check; no-op without ?seed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:45:26 -04:00
archipelago
445f08a5c1 feat(demo): iframe asset-rewrite proxy, AIUI mockArchy, QR 2s, dummy mints
- IndeeHub + Mempool: nginx reverse-proxy + strip X-Frame-Options/CSP + sub_filter
  rewrite of absolute asset paths so the frame-busting SPAs load in the iframe
  (mempool.space remains best-effort — third-party CSP/ws may still limit it).
- AIUI iframe gets ?mockArchy in demo → its built-in mock node data loads.
- Pay-with-mobile QR: invoice settles after ~2s (backend gate keyed by
  payment_hash) and the poll tightened to 1s, so the QR is visible before auto-pay.
- Wallet settings: dummy Cashu mints (4) + Fedimint federations (2, 222,500 sats),
  interactive per session (streaming.list/configure-mints, wallet.fedimint-list/
  join/balance).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:34:12 -04:00
archipelago
1b7335f4ac fix(demo): nostr-rs-relay icon (nostr.svg missing → nostrudel.svg)
The catalog pointed at a non-existent nostr.svg (handleImageError only falls
back .png→.svg, so an .svg miss stays broken). Point it at the existing nostr
icon. fedimint icon already uses fedimint.png (exists); the stale fedimint.jpg
request is resolved by /api/app-catalog now serving the local catalog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:23:25 -04:00
archipelago
c991e61a8f feat(demo): network/wallet dummy data — profits, federation, VPN, nostr, visibility
- wallet.networking-profits = 5,231,978 sats (content 3,180,000 / routing
  1,281,978 / relay 770,000); 6 labelled profit transactions added to the wallet
  history (1-2 per type: content sale, routing fee, file/mesh relay) — labels are
  production-ready.
- federation.list (the Web5 Federation container's method) now returns the 12
  demo nodes (was unhandled → empty).
- vpn.status: connected WireGuard with peers + traffic.
- nostr.list-relays / nostr.get-stats: 5 relays (3 connected).
- network.get/set-visibility: interactive, persisted per demo session.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:18:29 -04:00
archipelago
b99c4a604f fix(demo): iframe mempool+indeehub directly, serve real UIs statically, AIUI canned
- Mempool and IndeeHub load their real site directly in the iframe (reverted the
  proxy/new-tab — per request "use https://indee.tx1138.com/").
- Real app UIs now served as whole static dirs under /app/<id>/ (express.static)
  so their bundled assets (qrcode.js, css, bg images) resolve; /app/<id>/assets/*
  redirect to the frontend's shared assets. Fixes the console 404 cascade.
- Bitcoin Core/Knots: register rpc/v1 + bitcoin-rpc on their paths (relay-status
  no longer 404s); per-impl bitcoin-status preserved.
- AIUI chat returns a fixed line in demo ("Not available in demo, check out the
  previous chats to experience AIUI") instead of calling Claude — no key spend.
- Add /api/app-catalog (serves the baked catalog) to stop that 404.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:45:04 -04:00
archipelago
cf5f6d021a feat(demo): real registry UIs, IndeeHub iframe proxy, mempool tab, media Range
- App UIs now use the real registry shells with dummy data: bitcoin-ui for
  Bitcoin Core (Satoshi subversion) and Bitcoin Knots (Knots subversion) via
  per-path /app/bitcoin-{core,knots}/bitcoin-status; the real lnd-ui (mock
  /proxy/lnd/v1/getinfo+channels, /lnd-connect-info, /api/container/logs); the
  static fedimint-ui. ElectrumX already on the real electrs-ui. Custom mock UIs
  dropped — accurate UX.
- IndeeHub loads in the iframe: nginx reverse-proxies /app/indeedhub/ →
  indee.tx1138.com and strips X-Frame-Options/CSP (it blocked framing before).
- Mempool opens in a new tab (mempool.space can't be iframed).
- Cloud media playback: HTTP Range support in the curated-file server so audio/
  video can stream and seek (needs real files dropped into demo/files/).
- Dockerfile/.dockerignore copy docker/lnd-ui + docker/fedimint-ui.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:19:38 -04:00
archipelago
a0f70b3949 feat(demo): black-theme app UIs w/ icons, real ElectrumX UI, Core/Knots split
- Mock app UIs (ElectrumX, LND, Fedimint, Bitcoin Core) + the "Not available"
  notice now use the Archipelago black theme and show the app's My-Apps icon.
- Bitcoin Core gets its own UI (/app/bitcoin-core/) so it no longer shows Bitcoin
  Knots branding; the Knots-branded bitcoin-ui shell is reserved for Bitcoin Knots.
- ElectrumX now serves the real electrs-ui shell (+ qrcode.js + a dummy
  /electrs-status) with the correct ElectrumX icon; "Electrs" renamed to ElectrumX.
- My Apps: pre-install Bitcoin Knots again, drop ThunderHub, rename Electrs→ElectrumX.
- App store no longer shows "Checking…" forever in demo — non-demoable apps show
  "No demo" immediately (skip the container-scan state).
- Relay endpoint no longer reveals a real domain (randomised host).
- Dockerfile/.dockerignore copy docker/electrs-ui into the backend image.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 13:55:50 -04:00
archipelago
4cc808c73e fix(demo): /app proxy (fixes 404s), mempool iframe, LND UI, icons
- nginx-demo.conf + vite proxy now route every /app/<id>/ to the mock backend, so
  the per-app mock UIs and the generic "Not available in the demo" notice render
  (previously only /app/filebrowser was proxied → most apps 404'd).
- Mempool and IndeeHub now load in the in-app iframe (not a new tab).
- Add an LND Lightning mock UI (channels, balances, routing) with dummy data;
  lnd/thunderhub are demoable. Notice page reworded to "Not available in the demo".
- Fix missing icons: Bitcoin Core → bitcoin-core.png, Mempool → mempool.webp.
- Pre-install only Bitcoin Core (drop duplicate Bitcoin Knots; still installable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:39:33 -04:00
archipelago
79c3769542 feat(demo): curated cloud files drop-in + fix backend asset copies
- demo/files/<Folder>/<file> becomes the cloud's content for every visitor
  (read-only; "private login" = git/repo access). Text inlined, binaries streamed
  from disk; empty folder falls back to the built-in seeded set.
- Dockerfile.backend now copies docker/bitcoin-ui and demo/files into the image
  (they live outside neode-ui/) — this also fixes the Bitcoin UI mock, which the
  backend reads from /docker/bitcoin-ui and was previously absent in the container.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:11:40 -04:00
archipelago
df2ae3d7d8 feat(demo): ground AIUI chat in the node's mock state
The Claude proxy injects a system-prompt describing this node (version, signet
chain + height, wallet balances, installed apps, 5 FIPS peers / 12 trusted nodes)
into every demo chat request. The assistant answers local-node and Bitcoin
questions with the node's real-looking data automatically — no /seed needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:58:58 -04:00
archipelago
3f411c1d10 feat(demo): mock FIPS as active (status, seed anchors, reconnect, install)
fips.status reports installed+active with 5 authenticated peers and an anchor
connection; list/add/remove/apply seed-anchors and reconnect/install all resolve
to working states so the FIPS Mesh + Seed Anchors cards light green in the demo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:55:13 -04:00
archipelago
4d0c2d6717 feat(demo): real testnet tx links + interactive buy-files flow
- Tx/explorer links open mempool.space/testnet/tx/<id>; the backend hydrates the
  wallet's transactions with REAL recent testnet txids at startup (best-effort,
  falls back to mock hashes offline). Mempool app + demo-external apps open in a
  new tab; deep-link paths are carried through.
- Add the content.* paid-download handlers the buy flow needs (owned-list,
  preview-peer, download-peer-{paid,invoice,onchain}, request-invoice,
  invoice-status, request-onchain, onchain-status) — every path resolves to a
  success state with testnet receive addresses / bolt11 invoices so visitors can
  walk the full buy → unlock journey.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:53:05 -04:00
archipelago
2cffa79d9d feat(demo): app launch UIs, "No demo" gating, onboarding skip, 12 nodes
App launching (DEMO):
- resolveAppUrl routes every app to its demo target: mock UIs for Bitcoin Core,
  ElectrumX, Fedimint (served by the backend), IndeeHub → iframe indee.tx1138.com,
  Mempool → mempool.space/testnet (new tab); all others → a generic "Demo preview"
  notice page.
- Non-demoable apps show a disabled "No demo" install button (marketplace details,
  app grid, featured apps).

Onboarding:
- Demo treats the visitor as fully set up so the onboarding WIZARD (seed/identity)
  is never forced; the welcome intro still replays per day. Intro CTA goes straight
  to login; wizard entry points + login restart-onboarding link hidden in demo.

Network:
- federation.list-nodes now returns 12 trusted/federated nodes (9 trusted, 3
  observer); transport.peers already at 5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:26:35 -04:00
archipelago
2715f2d847 feat(demo): public multi-visitor demo sandbox for Portainer
Turn the mock backend + UI into a public, click-to-play demo deployable as a
Portainer stack, gated behind DEMO=1 (classic single-user mock unchanged when off).

Backend (neode-ui/mock-backend.js):
- Per-session state isolation via AsyncLocalStorage + Proxy: every visitor gets
  an isolated, deep-cloned copy of mockData/walletState/userState/etc., keyed by
  a demo_sid cookie. Per-session WebSocket fan-out, idle reaper, session cap.
- Real per-session file storage (upload/folder/rename/delete) with a 50MB quota,
  replacing the no-op filebrowser handlers; adds the missing app.filebrowser-token RPC.
- Force simulation mode (never touch a host Docker/Podman socket).
- Testnet (signet) flavor; shared login password "entertoexit".
- Report the real app version suffixed with -demo.

Frontend:
- VITE_DEMO build flag (useDemoIntro.ts): replay the intro once per calendar day
  per browser; prefill + show the "entertoexit" login hint.

Deploy:
- docker-compose.demo.yml wired for DEMO, UI on :2100 (build-from-repo).
- demo-deploy/ thin stack (prebuilt :demo image refs + .env.example + README).
- .github/workflows/demo-images.yml builds/pushes archy-demo-{web,backend} images.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:28:05 -04:00
archipelago
0860dfacc7 feat(ui): Services tab — backend classification, parent icons, categories sub-nav
- Classify databases/APIs/backends into Services (#10): add immich-postgres/redis
  to SERVICE_NAMES; isServiceContainer matches -postgres/-redis/-valkey/-cache/-db
  suffixes; isWebsitePackage final fallback now routes any no-UI, non-known package
  to Services ("anything that isn't the frontend UI launcher").
- Services show their parent app's icon (#14): backends reuse the app logo
  (immich-* → immich, archy-btcpay-db → btcpay, indeedhub-* → indeedhub, etc.)
  via explicit APP_ICON_FALLBACKS + prefix map, instead of 404 → 📦.
- Categories sub-nav for Services (#12): getServiceCategory + buildServiceCategories
  + useServiceCategories; Services tab gets the same desktop/mobile category strips
  (Databases/Caches/APIs/Backends), shown only for categories with items. Shared
  selectedCategory resets to 'all' on tab switch.
- Mobile swipe (#11): the tab-swipe gesture is suppressed over .mobile-category-strip
  so swiping the category chips scrolls them instead of changing tabs (covers both
  My Apps and the new Services strip).

vue-tsc build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 07:42:48 -04:00
archipelago
03a4ee1b30 feat(container): manifest-declared generated secrets + companion/quadlet hardening
Generated-secrets system: apps declare `generated_secrets` in their manifest
(kinds hex16/hex32/bcrypt); `container::secrets::ensure_generated_secrets`
materialises them 0600/rootless in resolve_dynamic_env — idempotent and
self-healing (recovers wrongly root-owned secrets with no privilege). Replaces
per-app Rust (deletes ensure_fmcd_password). fedimint-clientd/gateway manifests
now declare fmcd-password / fedimint-gateway-hash.

companion.rs: rebuild the auto-built :latest image when its build context changes
(staleness check) so baked-in fixes (e.g. guardian-UI CSS) actually reach nodes.

quadlet.rs: skip PublishPort under Network=host (podman rejects the combo, exit
125) + regression tests.

UI: "Fedimint Guardian" rename, fedimint-clientd/nostr-rs-relay/meshtastic tagged
as Services (headless backends), gateway icon fallback.

Deployed + verified on .228 (generated-secrets fixed fedimint-gateway start;
grafana/strfry orphan crash-loop units removed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 05:11:07 -04:00
archipelago
db7d424bff feat(content): owned-content persistence + Fedimint paid downloads, fmcd caps fix, FIPS warm-path perf
Buyer-side paid downloads now persist: purchases are cached on disk
(content_owned.rs) keyed by (seller onion, content_id), the gallery shows
an "Owned" badge unblurred, and items view/play in-app from the local
cache with no re-payment or reliance on a browser download (which
silently failed on the mobile companion). New RPCs content.owned-list /
content.owned-get. Validated e2e .116<-.198 (paid 100 sats via Fedimint,
166KB jpeg returns, survives restart).

fedimint-clientd manifest: restore the standard container capability set
(CHOWN/DAC_OVERRIDE/FOWNER/SETUID/SETGID) so fmcd's startup chown of an
existing-federation /data succeeds instead of dying EPERM (#7). Confirmed
the orchestrator applies these to the running container.

FIPS perf: tighten the supervisor warm-path keepalive 45s -> 25s so peer
paths stay inside the ~30-60s NAT cold window. Dials now reliably land on
FIPS instead of re-punching and falling back to Tor. Measured to the same
peer: cloud browse 18-22s -> 0.4s; full Fedimint paid download 29s -> 11s
(residual is the seller-side guardian reissue round-trip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 18:58:52 -04:00
archipelago
12f54e390d feat(wallet): ecash pay confirmation screen + auto-refund on failed sale (#3)
- PeerFiles: new confirmation step after "pay from ecash" — shows the amount and
  which wallet will be spent (Cashu/Fedimint) with balances, lets the user switch
  backends, and a styled Confirm button. The chosen backend is passed to the
  payment so it spends exactly what was confirmed.
- content.download-peer-paid: accept `method` (cashu|fedimint) to honor the
  confirmed choice; log the backend + outcome; backend-specific rejection errors
  ("not in the same Fedimint federation" / "doesn't accept your Cashu mint").
- AUTO-REFUND: a minted token whose sale fails (peer unreachable, rejected, or
  error) is now reclaimed (fedimint reissue / cashu receive) so the buyer no
  longer loses the spent ecash — fixes the stuck-Fedimint-notes report.
- wallet.ecash-balance already reports cashu_sats/fedimint_sats/total_sats which
  the confirm screen uses to pick/show the covering wallet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 12:16:02 -04:00
archipelago
242baf5deb fix(ui): on-screen error overlay so companion crashes are visible without a console
chrome://inspect isn't always reachable on the Android companion WebView, so the
real error stayed invisible. Add a plain-DOM, screenshot-able overlay (built
without Vue so it survives a crash in Vue itself) that shows the captured error
message + stack and a Copy button for the full window.__archyErrors buffer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 10:23:59 -04:00
archipelago
a8c668ee0a fix(ui): stop mobile tab bar covering last row of content (#2)
On Cloud/files (and any scrolling view), the bottom of the list could sit behind
the fixed mobile tab bar. Cause: DashboardMobileNav measured the bar's
offsetHeight and wrote it to --mobile-tab-bar-height, but when the bar was hidden
or not yet laid out the measurement was 0 — and writing "0px" defeats the
", 88px" fallback in the .mobile-scroll-pad clearance calc (an explicit 0 is
still a set value), so the clearance collapsed and the ~88px bar overlapped the
last row.

- never write 0px: only set a real measured height, else remove the var so the
  88px fallback applies.
- re-measure after first paint (rAF) and after the WebView safe-area injection,
  so the clearance reflects the bar's final laid-out height.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:50:44 -04:00
archipelago
8f06d88fbf feat(wallet): pay for peer files from BOTH Cashu and Fedimint ecash (#3)
Paying for a peer file minted a Cashu-only token, so a node whose ecash balance
lived in Fedimint couldn't pay even with funds. Now both backends are tried:

- payer (content.download-peer-paid): mint a Cashu token first; on failure fall
  back to spending Fedimint notes. Only error if BOTH backends can't cover it.
- seller (verify_and_receive_payment): accept Fedimint notes as well as Cashu —
  anything not starting with "cashu" is redeemed via reissue_into_any.
- new fedimint_client::spend_from_any() — spend from whichever joined federation
  has the balance, returning the notes + federation id (mirrors reissue_into_any).
- wallet.ecash-balance now also reports fedimint_sats + combined total_sats; the
  pay-for-file pre-check uses the combined total so a Fedimint-funded node isn't
  wrongly blocked.

Compiles (cargo check + vue-tsc). Live cross-node federation validation pending
(dual-ecash phase 6) — needs two nodes sharing a federation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:13:23 -04:00
archipelago
b3633ec525 fix(ui): surface real error instead of generic toast + catch async errors
The global Vue errorHandler swallowed every crash into "Something went wrong.
Please refresh the page." — which hides exactly what we need to diagnose the
companion-app (Android WebView) post-login crash. Now:
- the toast shows the real (truncated) error message;
- a 25-entry ring buffer is kept on window.__archyErrors for retrieval where
  there's no console (companion WebView via chrome://inspect, or a debug view);
- window 'error' and 'unhandledrejection' listeners catch async/non-Vue errors
  that Vue's errorHandler misses (e.g. a JS API absent in an older WebView).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:05:51 -04:00
archipelago
f92e442bfc fix(mesh): collapse cross-transport twin contacts into one conversation (#12)
A node reachable both over LoRa and federation has two MeshPeer rows (radio
twin: low contact_id + firmware key; federation twin: high contact_id +
archipelago key), and messages key by peer_contact_id split across the two ids
— so opening one twin shows an empty thread (the .120->.89 symptom).

- backend: new group_peer_twins() helper groups peers by arch_pubkey_hex (set on
  BOTH twins by bind_federation_twins), keeps the radio id as the mesh-first
  send target, and unions messages across all twin ids. Wired into
  conversations.list / conversations.messages / mesh.contacts-list. +3 unit tests.
- frontend: the live chat list merges client-side (mergedPeers) and matched twins
  by the "Archy-z6Mk..." advert prefix, which the Meshtastic device rename broke
  (radio now advertises the server name). Merge by arch_pubkey_hex instead, which
  the backend reliably sets on both twins. Expose arch_pubkey_hex on MeshPeer.
- fix unrelated stale test: EcashTransaction test missing the new `kind` field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:01:14 -04:00
Dorian
b00c5247f5 chore(android): update companion apk download 2026-06-20 10:34:49 +01:00
Dorian
3b9eb35a37 chore(android): update companion apk download 2026-06-19 22:22:59 +01:00
Dorian
011f6559e1 fix(android): icon ring matching logo.svg gradient at visible edge (v0.4.5)
Ring uses logo.svg's #000->#666 gradient (stroke 22.8834) pushed to scale 0.53
so it sits at the launcher's visible crop edge (calibrated from a device
screenshot). Grid at 0.55. versionCode 9 so launcher3 refreshes its icon cache.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 22:21:58 +01:00
archipelago
af816c61a5 fix(ui): reliable federation-join feedback (90s timeout + re-check + success)
Joining a Fedimint federation is heavy and routinely outlasts the default 15s
client timeout while still succeeding server-side, so the UI wrongly showed
failure. Bump the join timeout to 90s, and on any error re-check the list: if a
new federation appeared the join worked — show 'Federation joined.' instead of
a misleading error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 16:43:30 -04:00
Dorian
0f2e6f6aaf chore(android): update companion apk download 2026-06-19 21:28:29 +01:00
Dorian
857dc66240 chore(android): update companion apk download 2026-06-19 19:22:00 +01:00
Dorian
75666cdc31 chore(android): update companion apk download 2026-06-19 19:20:21 +01:00
Dorian
ca38f5d8f4 chore(android): update companion apk download 2026-06-19 19:05:57 +01:00
Dorian
dc2cdca549 chore(android): update companion apk download 2026-06-19 19:00:35 +01:00
archipelago
cebbde7bde fix(ui): square mobile file tiles, files scroll clearance, apps-tab swipe guard
- Apps tab: a horizontal swipe that starts on an app icon no longer flips the
  top tab — it lets the app-page scroll / icon tap win (swipe empty space to
  change tab). Fixes the swipe conflict with two pages of apps.
- Files: file cover tiles are forced square on mobile (aspect driven by CSS,
  not a Tailwind arbitrary class) so the grid is uniform and tappable.
- Files: scroll container gets bottom safe-area + tab-bar padding so the last
  row clears the mobile back button / bottom nav.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:57:51 -04:00
Dorian
839da80e0b chore(android): update companion apk download 2026-06-19 18:50:39 +01:00
Dorian
bf6d98195e chore(android): update companion apk download 2026-06-19 18:40:39 +01:00
Dorian
6df776b25a chore(android): update companion apk download 2026-06-19 18:32:00 +01:00
Dorian
726cc132af chore(android): update companion apk download 2026-06-19 18:26:59 +01:00
Dorian
b83e2c2f37 chore(android): update companion apk download 2026-06-19 18:26:34 +01:00
Dorian
64937df8a2 chore(android): update companion apk download 2026-06-19 18:12:41 +01:00
Dorian
07b611d07d chore(android): add companion APK auto-publish hook + script
scripts/publish-companion-apk.sh builds the debug APK and refreshes the served
download neode-ui/public/packages/archipelago-companion.apk.zip; .githooks/pre-push
runs it on every push to main that touches Android. Enable per clone with
  git config core.hooksPath .githooks

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 17:53:38 +01:00
Dorian
dcedf9582a chore(android): update companion apk download 2026-06-19 17:46:44 +01:00
Dorian
993f30456f feat(neode-ui): instant press feedback + launching spinner on app icons
Tapping a dashboard app icon now scales it down immediately (CSS :active)
and shows a per-icon spinner until the app overlay opens, so the tap is
acknowledged even while the app session spins up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 16:21:48 +01:00
archipelago
0ac67f5092 fix(ui): companion QR absolute 146 URL + Dashboard swipe type guard
- Companion app QR encoded a relative path (/packages/...apk.zip) which
  can't resolve when scanned by a phone. Point it at the absolute 146
  release-server URL so the download works from any device.
- Dashboard tab-swipe: guard tabs[next] (noUncheckedIndexedAccess) so the
  frontend type-checks/builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 09:52:26 -04:00
archipelago
1bce694ebb feat(ui): mobile mesh tabs, AIUI-style audio player, cloud grid + map fixes
UI (this session):
- Global audio player now scales the whole interface into the space above it
  on desktop (sidebar + main) and docks directly above the tab bar on mobile;
  it stays visible while navigating.
- Mesh mobile redesign: floating Chat / BTC / Dead Man / AI / Map tab strip
  with a single fixed, internally-scrolling pane (page no longer scrolls);
  tabs hide while a conversation is open; floating back button; collapsible
  Device panel (starts collapsed); keyboard-aware conversation sizing via
  VisualViewport so the chat sits just above the keyboard.
- Cloud file grid: uniform 4/3 card heights (folders + images match).
- Swipe left/right switches tabs on the Apps and Web5 screens.
- Map tool fills its pane (no bottom gap); fix skewed Share Location toggle
  on mobile (global min-height rule was deforming the switch).
- Trim redundant helper copy from the mesh AI tab.

Also bundles pre-existing in-progress work that was already in the tree:
mesh listener/session + wallet + container + bitcoin-status backend changes,
docker UI updates, and assorted other UI tweaks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 09:52:26 -04:00
archipelago
c4855526fe feat(wallet): wire fmcd as core app + dual-ecash receive
Fedimint never appeared in Wallet > Settings > Fedimint because the
fmcd (fedimint-clientd) sidecar was never installed: ensure_default_
federation() needs the fmcd password to reach the daemon, found none,
and silently no-oped, leaving the registry empty.

- prod_orchestrator: add fedimint-clientd to the baseline auto-install
  set so it self-heals onto every node and auto-joins the default
  federation; generate the fmcd-password secret before secret_env
  resolves.
- fedimint_client: ensure_fmcd_password (random hex, 0600) shared with
  the container's secret_env; from_node reads the same secret (legacy
  fmcd/password kept as fallback); reissue_into_any redeems received
  notes into the first joined federation that accepts them.
- wallet.ecash-receive: dual-token — cashu* tokens redeem at the mint,
  anything else is reissued via fmcd; returns the kind + federation_id.
- UI: receive box advertises "Cashu or Fedimint" and reports which kind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 09:52:26 -04:00
Dorian
f636c5d505 fix(neode-ui): float connection banners as overlay
The offline/reconnecting banners were in-flow (mx-6 mt-6) and pushed the whole
dashboard down when shown. Teleport them to <body> as a fixed, top-centered
overlay with a fade/slide transition and safe-area inset, so they no longer
shift layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 14:40:50 +01:00
Dorian
d1fbcd9b0a feat(neode-ui): route "open in browser" through native bridge in companion app
When ArchipelagoNative is present (the Android companion app), openInNewTab()
now calls openInApp(url) so non-iframeable apps open in the in-app WebView
instead of a suppressed window.open popup. Falls back to window.open in a
plain mobile browser. Logic only; no visual change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:28:48 +01:00